diff --git a/OWNERS b/OWNERS index 26b409f49..9ce796d6e 100644 --- a/OWNERS +++ b/OWNERS @@ -1,7 +1,3 @@ set noparent -tazjin -lukegb -aspen -sterni -flokli +raitobezarius diff --git a/README.md b/README.md index a430db8a3..06312e0e6 100644 --- a/README.md +++ b/README.md @@ -1,122 +1,6 @@ -depot -===== +Snix is a modern Rust re-implementation of the components of the Nix package +manager. -[![Build status](https://badge.buildkite.com/016bff4b8ae2704a3bbbb0a250784e6692007c582983b6dea7.svg?branch=refs/heads/canon)](https://buildkite.com/tvl/depot) - -This repository is the [monorepo][] for the community around [The -Virus Lounge][tvl], containing our personal tools and infrastructure. -Everything in here is built using [Nix][]. - -A large portion of the software here is very self-referential, meaning that it -exists to sustain the operation of the repository. This is the case because we -partially see this as [an experiment][] in tooling for monorepos. - -# Highlights - -## Services - -* Source code can be viewed primarily via `cgit-pink` on - [code.tvl.fyi](https://code.tvl.fyi), with code search being available through - Livegrep on [grep.tvl.fyi](https://grep.tvl.fyi). - - The repository can be cloned using `git` from `https://cl.tvl.fyi/depot`. - -* All code in the depot, with the exception of code that is checked in to - individual `//users` folders, needs to be reviewed. We use Gerrit on - [cl.tvl.fyi](https://cl.tvl.fyi) for this. - -* Issues are tracked via our own issue tracker on - [b.tvl.fyi](https://b.tvl.fyi). Its source code lives at - [`//web/panettone/`][panettone]. - -* Smaller todo-list entries which do not warrant a separate issue are listed at - [todo.tvl.fyi](https://todo.tvl.fyi). - -* We use Buildkite for CI. Recent builds are listed on - [tvl.fyi/builds](https://tvl.fyi/builds) and pipelines are configured - dynamically via - [`//ops/pipelines`](https://code.tvl.fyi/tree/ops/pipelines). - -* A search service that makes TVL services available via textual - shortcuts is available: [atward](https://at.tvl.fyi) - -All services that we host are deployed on NixOS machines that we manage. Their -configuration is tracked in `//ops/{modules,machines}`. - -## Nix - -* [`//nix/readTree`](https://code.tvl.fyi/about/nix/readTree/README.md) - contains the Nix code which automatically registers projects in our Nix - attribute hierarchy based on their in-tree location -* [`//tools/nixery`](https://code.tvl.fyi/tree/tools/nixery) - contains the source code of [Nixery][], a container registry that - can build images ad-hoc from Nix packages -* `//nix/yants` contains **Y**et **A**nother **N**ix **T**ype **S**ystem, which - we use for a variety of things throughout the repository -* `//nix/buildGo` implements a Nix library that can build Go software in the - style of Bazel's `rules_go`. Go programs in this repository are built using - this library. -* `//nix/buildLisp` implements a Nix library that can build Common Lisp - software. Currently only SBCL is supported. Lisp programs in this repository - are built using this library. -* `//web/blog` and `//web/atom-feed`: A Nix-based static site generator which - generates the web page and Atom feed for [tazj.in](https://tazj.in) - (`//users/tazjin/homepage`) and [tvl.fyi](https://tvl.fyi) (`//web/tvl`) -* `//web/bubblegum` contains a CGI-based web framework written in Nix. -* `//nix/nint`: A shebang-compatible interpreter wrapper for Nix. -* `//tvix` contains initial work towards a modular architecture for Nix. - -We have a variety of other tools and libraries in the `//nix` folder which may -be of interest. - -## Packages / Libraries - -* `//net/alcoholic_jwt` contains an easy-to-use JWT-validation library for Rust -* `//net/crimp` contains a high-level HTTP client using cURL for Rust -* `//tools/emacs-pkgs` contains various useful Emacs libraries, for example: - * `dottime.el` provides [dottime][] in the Emacs modeline - * `nix-util.el` provides editing utilities for Nix files - * `term-switcher.el` is an ivy-function for switching between vterm buffers - * `tvl.el` provides helper functions for interacting with the TVL monorepo -* `//lisp/klatre` provides a grab-bag utility library for Common Lisp - -## User packages - -Contributors to the repository have user directories under -[`//users`](https://code.tvl.fyi/tree/users), which can be used for -personal or experimental code that does not require review. - -Some examples: - -* `//users/aspen/xanthous`: A (WIP) TUI RPG, written in Haskell. -* `//users/tazjin/emacs`: tazjin's Emacs & EXWM configuration -* `//users/tazjin/finito`: A persistent finite-state machine library for Rust. - -# Licensing - -Unless otherwise stated in a subdirectory, all code is licensed under the MIT -license. See [LICENSE](./LICENSE) for details. - -# Contributing - -If you'd like to contribute to any of the tools in here, please check out the -[contribution guidelines](./docs/CONTRIBUTING.md) and our [code of -conduct](./docs/CODE_OF_CONDUCT.md). - -IRC users can find us in [`#tvl`][tvl-irc] on [hackint][], which is also -reachable [via XMPP][hackint-xmpp] at [`#tvl@irc.hackint.org`][tvl-xmpp] (sic!). - -Hackint also provide a [web chat][tvl-webchat]. - -[monorepo]: https://en.wikipedia.org/wiki/Monorepo -[tvl]: https://tvl.fyi -[Nix]: https://nixos.org/nix -[an experiment]: https://tvl.fyi/monorepo-doc -[panettone]: https://code.tvl.fyi/tree/web/panettone -[dottime]: https://dotti.me -[tvl-irc]: ircs://irc.hackint.org:6697/#tvl -[hackint]: https://hackint.org/ -[hackint-xmpp]: https://hackint.org/transport/xmpp -[tvl-xmpp]: xmpp:#tvl@irc.hackint.org?join -[tvl-webchat]: https://webirc.hackint.org/#ircs://irc.hackint.org/#tvl -[Nixery]: https://nixery.dev +For more information, checkout the website, hosted at +[snix.dev](https://snix.dev), which also is available in the `web/` subdirectory +of this repository. diff --git a/corp/LICENSE b/corp/LICENSE deleted file mode 100644 index 6ae339dea..000000000 --- a/corp/LICENSE +++ /dev/null @@ -1,4 +0,0 @@ -Copyright 2021-2023 ООО ТВЛ - -Code under this folder may be redistributed as part of the TVL depot -repository. All other usage rights for this code are reserved. diff --git a/corp/OWNERS b/corp/OWNERS deleted file mode 100644 index e99d7151f..000000000 --- a/corp/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -group:tvl-employees diff --git a/corp/ops/.envrc b/corp/ops/.envrc deleted file mode 100644 index 26049cf42..000000000 --- a/corp/ops/.envrc +++ /dev/null @@ -1,4 +0,0 @@ -out=$(nix-build ../.. -A corp.ops.deps --out-link ../../.gcroots/corp-deps) -PATH_add "$out/bin" - -watch_file default.nix diff --git a/corp/ops/.gitignore b/corp/ops/.gitignore deleted file mode 100644 index 5def054d7..000000000 --- a/corp/ops/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.terraform -.terraform.lock.hcl -terraform.tfstate -terraform.tfstate.backup diff --git a/corp/ops/default.nix b/corp/ops/default.nix deleted file mode 100644 index c88b3bdc1..000000000 --- a/corp/ops/default.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ depot, lib, pkgs, ... }: - -depot.nix.readTree.drvTargets rec { - # Provide a Terraform wrapper with Yandex Cloud support. - terraform = pkgs.terraform.withPlugins (p: [ - p.yandex - ]); - - validate = depot.tools.checks.validateTerraform { - inherit terraform; - name = "corp"; - src = lib.cleanSource ./.; - }; - - # Yandex Cloud CLI - yc-cli = pkgs.stdenv.mkDerivation rec { - pname = "yc-cli"; - version = "0.106.0"; - - src = pkgs.fetchurl { - url = "https://storage.yandexcloud.net/yandexcloud-yc/release/${version}/linux/amd64/yc"; - sha256 = "sha256:1f7fq9rlihz91ld1vdjj9vq9ssq1ls031jin4zisxv75rcdpslh3"; - }; - - phases = [ "installPhase" ]; - installPhase = "install -D $src $out/bin/yc"; - }; - - deps = depot.tools.depot-deps.overrideDeps { - tf-yandex = { - attr = "corp.ops.terraform"; - cmd = "terraform"; - }; - - yc.attr = "corp.ops.yc-cli"; - }; -} diff --git a/corp/ops/modules/.skip-tree b/corp/ops/modules/.skip-tree deleted file mode 100644 index a6f528167..000000000 --- a/corp/ops/modules/.skip-tree +++ /dev/null @@ -1 +0,0 @@ -Only NixOS modules here. diff --git a/corp/ops/yandex/creds.fish b/corp/ops/yandex/creds.fish deleted file mode 100644 index 2985b2880..000000000 --- a/corp/ops/yandex/creds.fish +++ /dev/null @@ -1,5 +0,0 @@ -export YC_TOKEN=(yc iam create-token) -export YC_CLOUD_ID=(yc config get cloud-id) -export YC_FOLDER_ID=(yc config get folder-id) -export AWS_ACCESS_KEY_ID="YCAJE6eRLY8Az-9kveNRtz4sh" -export AWS_SECRET_ACCESS_KEY=(yc kms symmetric-crypto decrypt --name tvl-credentials --cloud-id b1ggu5m1btue982app12 --folder-name default --ciphertext-file encrypted-state-secret.key --plaintext-file /dev/stdout | head -n1) diff --git a/corp/ops/yandex/encrypted-state-secret.key b/corp/ops/yandex/encrypted-state-secret.key deleted file mode 100644 index 0d07158f2..000000000 Binary files a/corp/ops/yandex/encrypted-state-secret.key and /dev/null differ diff --git a/corp/ops/yandex/main.tf b/corp/ops/yandex/main.tf deleted file mode 100644 index cd8fa6e4c..000000000 --- a/corp/ops/yandex/main.tf +++ /dev/null @@ -1,70 +0,0 @@ -# Terraform configuration for TVL corp infrastructure (on Yandex -# Cloud). - -terraform { - required_providers { - yandex = { - source = "yandex-cloud/yandex" - } - } - - # Credentials need to be sourced from creds.fish - backend "s3" { - endpoint = "storage.yandexcloud.net" - bucket = "su-tvl-terraform-state" - region = "ru-central1" - key = "corp/ops/terraform.tfstate" - - skip_region_validation = true - skip_credentials_validation = true - } -} - -provider "yandex" { - zone = "ru-central1-b" -} - -locals { - tvl_cloud_id = "b1ggu5m1btue982app12" - tvl_folder_id = "b1gmbeqt9o5kbl7rclln" - rih_cloud_id = "b1glccvcqggi2ruibgvt" - rih_folder_id = "b1gsavcrsjn059d1sbh9" -} - -# Storage state bucket configuration - -resource "yandex_iam_service_account" "tf_state_sa" { - folder_id = local.tvl_folder_id - name = "terraform-state" -} - -resource "yandex_resourcemanager_folder_iam_member" "tf_state_sa_storage" { - folder_id = local.tvl_folder_id - role = "storage.editor" - member = "serviceAccount:${yandex_iam_service_account.tf_state_sa.id}" -} - -resource "yandex_iam_service_account_static_access_key" "tf_state_sa_key" { - service_account_id = yandex_iam_service_account.tf_state_sa.id - description = "Static access key for Terraform state" -} - -resource "yandex_storage_bucket" "tf_state" { - access_key = yandex_iam_service_account_static_access_key.tf_state_sa_key.access_key - secret_key = yandex_iam_service_account_static_access_key.tf_state_sa_key.secret_key - bucket = "su-tvl-terraform-state" -} - -# Secret management configuration - -resource "yandex_kms_symmetric_key" "tvl_credentials_key" { - name = "tvl-credentials" - folder_id = local.tvl_folder_id - default_algorithm = "AES_256" - rotation_period = "2160h" # 90 days -} - -resource "yandex_kms_secret_ciphertext" "tf_state_key" { - key_id = yandex_kms_symmetric_key.tvl_credentials_key.id - plaintext = yandex_iam_service_account_static_access_key.tf_state_sa_key.secret_key -} diff --git a/corp/ops/yandex/rih.tf b/corp/ops/yandex/rih.tf deleted file mode 100644 index 104a61f86..000000000 --- a/corp/ops/yandex/rih.tf +++ /dev/null @@ -1,307 +0,0 @@ -# Deployment configuration for russiaishiring.com -# -# The frontend of the page is served from a storage bucket, the -# backend runs in a container. - -resource "yandex_dns_zone" "russiaishiring_com" { - name = "russiaishiring-com" - zone = "russiaishiring.com." - public = true - folder_id = local.rih_folder_id -} - -resource "yandex_iam_service_account" "rih_storage_sa" { - name = "rih-storage-sa" - folder_id = local.rih_folder_id -} - -resource "yandex_resourcemanager_folder_iam_member" "rih_sa_storage_editor" { - folder_id = local.rih_folder_id - role = "storage.admin" - member = "serviceAccount:${yandex_iam_service_account.rih_storage_sa.id}" -} - -resource "yandex_iam_service_account_static_access_key" "rih_sa_static_key" { - service_account_id = yandex_iam_service_account.rih_storage_sa.id - description = "RIH bucket access key" -} - -resource "yandex_storage_bucket" "rih_storage_bucket" { - access_key = yandex_iam_service_account_static_access_key.rih_sa_static_key.access_key - secret_key = yandex_iam_service_account_static_access_key.rih_sa_static_key.secret_key - bucket = "russiaishiring.com" - folder_id = local.rih_folder_id - acl = "public-read" - - https { - certificate_id = yandex_cm_certificate.russiaishiring_com.id - } - - website { - index_document = "index.html" - } -} - -resource "yandex_cm_certificate" "russiaishiring_com" { - folder_id = local.rih_folder_id - name = "russiaishiring-com" - domains = ["russiaishiring.com"] - - managed { - challenge_type = "DNS_CNAME" - } -} - -resource "yandex_dns_recordset" "acme_russiaishiring_com" { - zone_id = yandex_dns_zone.russiaishiring_com.id - name = yandex_cm_certificate.russiaishiring_com.challenges[0].dns_name - type = yandex_cm_certificate.russiaishiring_com.challenges[0].dns_type - data = [yandex_cm_certificate.russiaishiring_com.challenges[0].dns_value] - ttl = 3600 -} - -resource "yandex_dns_recordset" "yandex_txt_russiaishiring_com" { - zone_id = yandex_dns_zone.russiaishiring_com.id - name = "@" - type = "TXT" - ttl = 21600 - - data = [ - "\"yandex-verification: b42768b04ab10b58\"", - "\"v=spf1 redirect=_spf.yandex.net\"" - ] -} - -resource "yandex_dns_recordset" "yandex_mx_russiaishiring_com" { - zone_id = yandex_dns_zone.russiaishiring_com.id - name = "@" - type = "MX" - data = ["10 mx.yandex.net."] - ttl = 21600 -} - -resource "yandex_dns_recordset" "yandex_dkim_russiaishiring_com" { - zone_id = yandex_dns_zone.russiaishiring_com.id - name = "mail._domainkey" - type = "TXT" - data = ["\"v=DKIM1; k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgRfKnq+PZS3RFcHUnsKAvnBs2HCH5zSFjiZZ8/oyaC4va6I506/88HkZbME2xxfivpFmkKc6eBBpSzg6TVws0R3hAmb02u3qUQpX29+lEossq9j2fYvYBBZDf557ioxfQrE0+bIpsqV7+LXIsybq61+egbH+MKbxhda6fr4oPqwIDAQAB\""] - ttl = 21600 -} - -resource "yandex_dns_recordset" "aname_russiaishiring_com" { - zone_id = yandex_dns_zone.russiaishiring_com.id - name = "russiaishiring.com." - type = "ANAME" - data = ["russiaishiring.com.website.yandexcloud.net"] - ttl = 3600 -} - -resource "yandex_container_registry" "rih_registry" { - name = "rih-registry" - folder_id = local.rih_folder_id -} - -resource "yandex_iam_service_account" "rih_backend" { - name = "rih-backend" - folder_id = local.rih_folder_id -} - -resource "yandex_resourcemanager_folder_iam_member" "rih_backend_image_pull" { - folder_id = local.rih_folder_id - role = "container-registry.images.puller" - member = "serviceAccount:${yandex_iam_service_account.rih_backend.id}" -} - -resource "yandex_serverless_container" "rih_backend" { - name = "rih-backend" - folder_id = local.rih_folder_id - memory = 128 - execution_timeout = "10s" - cores = 1 - core_fraction = 100 - service_account_id = yandex_iam_service_account.rih_backend.id - - image { - url = "cr.yandex/crpkcq65tn6bhq6puq2o/rih-backend:q8kfd6kwc7p4wphzw1pj916y9m6icl9q" - } - - secrets { - id = yandex_lockbox_secret.rih_backend_storage_key.id - version_id = yandex_lockbox_secret_version.rih_backend_storage_secret.id - key = "access_key" - environment_variable = "AWS_ACCESS_KEY_ID" - } - - secrets { - id = yandex_lockbox_secret.rih_backend_storage_key.id - version_id = yandex_lockbox_secret_version.rih_backend_storage_secret.id - key = "secret_key" - environment_variable = "AWS_SECRET_ACCESS_KEY" - } - - secrets { - id = data.yandex_lockbox_secret.rih_captcha_prod_key.id - version_id = data.yandex_lockbox_secret.rih_captcha_prod_key.current_version[0].id - key = "key" - environment_variable = "YANDEX_SMARTCAPTCHA_KEY" - } -} - -resource "yandex_api_gateway" "rih_gateway" { - name = "rih-gateway" - folder_id = local.rih_folder_id - - custom_domains { - fqdn = "api.russiaishiring.com" - certificate_id = yandex_cm_certificate.api_russiaishiring_com.id - } - - depends_on = [ - yandex_cm_certificate.api_russiaishiring_com, - yandex_dns_recordset.acme_api_russiaishiring_com, - ] - - spec = <<-EOT - openapi: "3.0.0" - info: - version: 1.0.0 - title: RIH API - x-yc-apigateway: - cors: - origin: 'https://russiaishiring.com' - methods: '*' - allowedHeaders: '*' - paths: - /{proxy+}: - x-yc-apigateway-any-method: - x-yc-apigateway-integration: - type: serverless_containers - container_id: ${yandex_serverless_container.rih_backend.id} - service_account_id: ${yandex_iam_service_account.rih_backend.id} - parameters: - - explode: false - in: path - name: proxy - required: false - schema: - default: '-' - type: string - style: simple - EOT -} - -resource "yandex_cm_certificate" "api_russiaishiring_com" { - folder_id = local.rih_folder_id - name = "api-russiaishiring-com" - domains = ["api.russiaishiring.com"] - - managed { - challenge_type = "DNS_CNAME" - } -} - -resource "yandex_dns_recordset" "acme_api_russiaishiring_com" { - zone_id = yandex_dns_zone.russiaishiring_com.id - name = yandex_cm_certificate.api_russiaishiring_com.challenges[0].dns_name - type = yandex_cm_certificate.api_russiaishiring_com.challenges[0].dns_type - data = [yandex_cm_certificate.api_russiaishiring_com.challenges[0].dns_value] - ttl = 60 -} - -resource "yandex_dns_recordset" "cname_api_russiaishiring_com" { - zone_id = yandex_dns_zone.russiaishiring_com.id - name = "api.russiaishiring.com." - type = "CNAME" - data = [yandex_api_gateway.rih_gateway.domain] - ttl = 600 -} - -# Bucket setup for data receival bucket -# -# The bucket is set up and controlled by the default storage account, -# but a separate key is set up for the rih-backend IAM account which -# can only access the information in this bucket. - -resource "yandex_kms_symmetric_key" "backend_data_key" { - name = "rih-backend-data-key" - default_algorithm = "AES_128" - rotation_period = "4380h" # ~6 months - - lifecycle { - prevent_destroy = true - } -} - -resource "yandex_kms_symmetric_key_iam_binding" "rih_encryption_access" { - symmetric_key_id = yandex_kms_symmetric_key.backend_data_key.id - role = "kms.keys.encrypter" - - members = [ - "serviceAccount:${yandex_iam_service_account.rih_backend.id}" - ] -} - -resource "yandex_storage_bucket" "rih_backend_data" { - access_key = yandex_iam_service_account_static_access_key.rih_sa_static_key.access_key - secret_key = yandex_iam_service_account_static_access_key.rih_sa_static_key.secret_key - bucket = "rih-backend-data" - folder_id = local.rih_folder_id - acl = "private" - - versioning { - enabled = true - } - - server_side_encryption_configuration { - rule { - apply_server_side_encryption_by_default { - kms_master_key_id = yandex_kms_symmetric_key.backend_data_key.id - sse_algorithm = "aws:kms" - } - } - } - - lifecycle { - prevent_destroy = true - } -} - -resource "yandex_iam_service_account_static_access_key" "rih_backend_static_key" { - service_account_id = yandex_iam_service_account.rih_backend.id - description = "RIH backend bucket access key" -} - -resource "yandex_lockbox_secret" "rih_backend_storage_key" { - name = "rih-backend-storage-key" - folder_id = local.rih_folder_id -} - -resource "yandex_lockbox_secret_version" "rih_backend_storage_secret" { - secret_id = yandex_lockbox_secret.rih_backend_storage_key.id - - entries { - key = "access_key" - text_value = yandex_iam_service_account_static_access_key.rih_backend_static_key.access_key - } - - entries { - key = "secret_key" - text_value = yandex_iam_service_account_static_access_key.rih_backend_static_key.secret_key - } -} - -# TODO(tazjin): automate if tf-yandex gains support for captcha resources -data "yandex_lockbox_secret" "rih_captcha_prod_key" { - secret_id = "e6qloc8913tnracefb8f" -} - -# TODO(tazjin): needs provider update -# -# resource "yandex_lockbox_secret_iam_binding" "viewer" { -# secret_id = yandex_lockbox_secret.rih_backend_storage_key.id -# role = "viewer" - -# members = [ -# "serviceAccount:${yandex_iam_service_account.rih_backend.id}" -# ] -# } diff --git a/corp/rih/.gitignore b/corp/rih/.gitignore deleted file mode 100644 index 64476c05e..000000000 --- a/corp/rih/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -result -target -dist diff --git a/corp/rih/README.md b/corp/rih/README.md deleted file mode 100644 index e44d0f2a5..000000000 --- a/corp/rih/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Implementation of russiaishiring.com. - -This is a corporate TVL project, see `//corp/LICENSE`. diff --git a/corp/rih/backend/Cargo.lock b/corp/rih/backend/Cargo.lock deleted file mode 100644 index 97b76ca60..000000000 --- a/corp/rih/backend/Cargo.lock +++ /dev/null @@ -1,1306 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] -name = "async-trait" -version = "0.1.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "attohttpc" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" -dependencies = [ - "http", - "log", - "rustls", - "serde", - "serde_json", - "url", - "webpki", - "webpki-roots", -] - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "aws-creds" -version = "0.34.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3776743bb68d4ad02ba30ba8f64373f1be4e082fe47651767171ce75bb2f6cf5" -dependencies = [ - "attohttpc", - "dirs", - "log", - "quick-xml", - "rust-ini", - "serde", - "thiserror", - "time", - "url", -] - -[[package]] -name = "aws-region" -version = "0.25.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aed3f9c7eac9be28662fdb3b0f4d1951e812f7c64fed4f0327ba702f459b3b" -dependencies = [ - "thiserror", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - -[[package]] -name = "cc" -version = "1.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "windows-targets", -] - -[[package]] -name = "chunked_transfer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "dlv-list" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" - -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "httparse" -version = "1.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "js-sys" -version = "0.3.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags", - "libc", - "redox_syscall", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "maybe-async" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "multipart" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" -dependencies = [ - "buf_redux", - "httparse", - "log", - "mime", - "mime_guess", - "quick-error", - "rand", - "safemem", - "tempfile", - "twoway", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "ordered-multimap" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" -dependencies = [ - "dlv-list", - "hashbrown", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quick-xml" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "rih-backend" -version = "0.1.0" -dependencies = [ - "anyhow", - "attohttpc", - "log", - "rouille", - "rust-s3", - "serde", - "serde_json", - "uuid", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.52.0", -] - -[[package]] -name = "rouille" -version = "3.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3716fbf57fc1084d7a706adf4e445298d123e4a44294c4e8213caf1b85fcc921" -dependencies = [ - "base64", - "chrono", - "filetime", - "multipart", - "percent-encoding", - "rand", - "serde", - "serde_derive", - "serde_json", - "sha1_smol", - "threadpool", - "time", - "tiny_http", - "url", -] - -[[package]] -name = "rust-ini" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" -dependencies = [ - "cfg-if", - "ordered-multimap", -] - -[[package]] -name = "rust-s3" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b2ac5ff6acfbe74226fa701b5ef793aaa054055c13ebb7060ad36942956e027" -dependencies = [ - "async-trait", - "attohttpc", - "aws-creds", - "aws-region", - "base64", - "bytes", - "cfg-if", - "hex", - "hmac", - "http", - "log", - "maybe-async", - "md5", - "percent-encoding", - "quick-xml", - "serde", - "serde_derive", - "sha2", - "thiserror", - "time", - "url", -] - -[[package]] -name = "rustix" -version = "0.38.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" -dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "serde" -version = "1.0.209" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.209" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.127" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "sha1_smol" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "thiserror" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "libc", - "num-conv", - "num_threads", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tiny_http" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" -dependencies = [ - "ascii", - "chunked_transfer", - "httpdate", - "log", -] - -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "uuid" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" - -[[package]] -name = "web-sys" -version = "0.3.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" -dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", -] - -[[package]] -name = "webpki-roots" -version = "0.22.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/corp/rih/backend/Cargo.toml b/corp/rih/backend/Cargo.toml deleted file mode 100644 index 97d4821e3..000000000 --- a/corp/rih/backend/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "rih-backend" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow = "1.0" -log = "0.4" -serde = { version = "1.0", features = [ "derive" ] } -serde_json = "1.0" -uuid = { version = "1.3.3", features = ["v4", "serde"] } - -[dependencies.attohttpc] -version = "0.22" -default-features = false -features = [ "tls-rustls" ] - -[dependencies.rouille] -version = "3.6" -default-features = false - -[dependencies.rust-s3] -version = "0.33" -default-features = false -features = [ "sync-rustls-tls" ] diff --git a/corp/rih/backend/default.nix b/corp/rih/backend/default.nix deleted file mode 100644 index 802479e50..000000000 --- a/corp/rih/backend/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ depot, pkgs, ... }: - -depot.nix.readTree.drvTargets rec { - binary = depot.third_party.naersk.buildPackage { - src = ./.; - }; - - image = pkgs.dockerTools.buildLayeredImage { - name = "rih-backend"; - config.Cmd = [ "${binary}/bin/rih-backend" ]; - - contents = [ - binary - ]; - }; -} diff --git a/corp/rih/backend/src/main.rs b/corp/rih/backend/src/main.rs deleted file mode 100644 index 208e0367c..000000000 --- a/corp/rih/backend/src/main.rs +++ /dev/null @@ -1,168 +0,0 @@ -use anyhow::{bail, Context, Result}; -use log::{debug, error, info, warn, LevelFilter}; -use rouille::{Request, Response}; -use serde::{Deserialize, Serialize}; -use std::collections::BTreeSet; -use std::env; -use std::net::SocketAddr; -use std::time::{SystemTime, UNIX_EPOCH}; -use uuid::Uuid; - -mod yandex_log; - -/// Represents the request sent by the frontend application. -#[derive(Debug, Deserialize)] -struct FrontendReq { - captcha_token: String, - record: Record, -} - -/// Represents a single record as filled in by a user. This is the -/// primary data structure we want to populate and persist somewhere. -#[derive(Debug, Deserialize, Serialize)] -struct Record { - // Record-specific metadata - uuid: Uuid, - - // Personal information - name: String, - email: String, - citizenship: String, // TODO - personal_details: String, - - // Job information - position: String, - technologies: BTreeSet, - job_details: String, - work_background: String, -} - -impl Record { - fn validate(&self) -> bool { - true - } -} - -fn validate_captcha(token: &str) -> Result<()> { - // TODO(tazjin): pass `ip` parameter - let url = "https://smartcaptcha.yandexcloud.net/validate"; - let backend_key = - env::var("YANDEX_SMARTCAPTCHA_KEY").context("captcha verification key not provided")?; - - #[derive(Deserialize)] - struct CaptchaResponse { - status: String, - message: String, - } - - let response: CaptchaResponse = attohttpc::get(url) - .param("secret", backend_key) - .param("token", token) - .send() - .context("failed to send captcha verification request")? - .error_for_status() - .context("captcha verification request failed")? - .json() - .context("failed to deserialize captcha verification response")?; - - if response.status != "ok" { - warn!( - "invalid captcha: {} ({})", - response.message, response.status - ); - } - - info!("captcha token was valid"); - - Ok(()) -} - -fn persist_record(ip: &SocketAddr, record: &Record) -> Result<()> { - let bucket_name = "rih-backend-data"; - let credentials = - s3::creds::Credentials::from_env().context("failed to initialise storage credentials")?; - - let yandex_region: s3::Region = s3::Region::Custom { - region: "ru-central1".to_string(), - endpoint: "storage.yandexcloud.net".to_string(), - }; - - let bucket = s3::Bucket::new(bucket_name, yandex_region, credentials) - .context("failed to initialise storage client")?; - - let path_uuid = Uuid::new_v4(); - let epoch = SystemTime::now() - .duration_since(UNIX_EPOCH) - .context("failed to get current time")? - .as_secs(); - - let path = format!("/records/{}-{}.json", epoch, path_uuid); - - info!("writing record to '{}'", path); - - let data = serde_json::json!({ - "ip": ip.to_string(), - "record": record, - }); - - let response = bucket - .put_object(path, data.to_string().as_bytes()) - .context("failed to persist storage object")?; - - debug!( - "Object Storage response: ({}) {}", - response.status_code(), - response.as_str().unwrap_or("") - ); - - Ok(()) -} - -fn handle_submit(req: &Request) -> Result { - let submitted: FrontendReq = - rouille::input::json::json_input(req).context("failed to deserialise frontend request")?; - - validate_captcha(&submitted.captcha_token)?; - - if !submitted.record.validate() { - bail!("invalid record: {:?}", submitted.record); - } - - persist_record(req.remote_addr(), &submitted.record).context("failed to persist record")?; - - Ok(Response::text("success")) -} - -fn main() -> Result<()> { - log::set_logger(&yandex_log::YANDEX_CLOUD_LOGGER) - .map(|()| log::set_max_level(LevelFilter::Info)) - .expect("log configuration must succeed"); - let port = env::var("PORT").unwrap_or_else(|_| /* rihb = */ "7442".to_string()); - let listen = format!("0.0.0.0:{port}"); - - info!("launching rih-backend on: {}", listen); - - rouille::start_server(&listen, move |request| { - if request.method() == "POST" && request.url() == "/submit" { - info!("handling submit request from {}", request.remote_addr()); - match handle_submit(request) { - Ok(response) => { - info!("submit handled successfully"); - response - } - Err(err) => { - error!("failed to handle submit: {}", err); - Response::empty_400() - } - } - } else { - warn!( - "no matching route for request: {} {}", - request.method(), - request.url() - ); - - Response::empty_404() - } - }); -} diff --git a/corp/rih/backend/src/yandex_log.rs b/corp/rih/backend/src/yandex_log.rs deleted file mode 100644 index 64bb4ff97..000000000 --- a/corp/rih/backend/src/yandex_log.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! Implements a `log::Log` logger that adheres to the structure -//! expected by Yandex Cloud Serverless logs. -//! -//! https://cloud.yandex.ru/docs/serverless-containers/concepts/logs - -use log::{Level, Log}; -use serde_json::json; - -pub struct YandexCloudLogger; - -pub const YANDEX_CLOUD_LOGGER: YandexCloudLogger = YandexCloudLogger; - -fn level_map(level: &Level) -> &'static str { - match level { - Level::Error => "ERROR", - Level::Warn => "WARN", - Level::Info => "INFO", - Level::Debug => "DEBUG", - Level::Trace => "TRACE", - } -} - -impl Log for YandexCloudLogger { - fn enabled(&self, _: &log::Metadata<'_>) -> bool { - true - } - - fn log(&self, record: &log::Record<'_>) { - if !self.enabled(record.metadata()) { - return; - } - - eprintln!( - "{}", - json!({ - "level": level_map(&record.level()), - "message": record.args().to_string(), - "target": record.target(), - "module": record.module_path(), - "file": record.file(), - "line": record.line(), - }) - ); - } - - fn flush(&self) {} -} diff --git a/corp/rih/frontend/Cargo.lock b/corp/rih/frontend/Cargo.lock deleted file mode 100644 index 402a44e52..000000000 --- a/corp/rih/frontend/Cargo.lock +++ /dev/null @@ -1,1829 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is-terminal", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" - -[[package]] -name = "anstyle-parse" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "anstyle-wincon" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" -dependencies = [ - "anstyle", - "windows-sys 0.48.0", -] - -[[package]] -name = "anymap2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "boolinator" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" -dependencies = [ - "clap_builder", - "clap_derive", - "once_cell", -] - -[[package]] -name = "clap_builder" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" -dependencies = [ - "anstream", - "anstyle", - "bitflags", - "clap_lex", - "strsim", - "terminal_size", -] - -[[package]] -name = "clap_derive" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "clap_lex" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "comrak" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "482aa5695bca086022be453c700a40c02893f1ba7098a2c88351de55341ae894" -dependencies = [ - "clap", - "entities", - "memchr", - "once_cell", - "regex", - "shell-words", - "slug", - "syntect", - "typed-arena", - "unicode_categories", - "xdg", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "csv" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - -[[package]] -name = "deunicode" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "encode_unicode" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" - -[[package]] -name = "entities" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fancy-regex" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6b8560a05112eb52f04b00e5d3790c0dd75d9d980eb8a122fb23b92a623ccf" -dependencies = [ - "bit-set", - "regex", -] - -[[package]] -name = "flate2" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fuzzy-matcher" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" -dependencies = [ - "thread_local", -] - -[[package]] -name = "getrandom" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gloo" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20" -dependencies = [ - "gloo-console", - "gloo-dialogs", - "gloo-events", - "gloo-file", - "gloo-history", - "gloo-net", - "gloo-render", - "gloo-storage", - "gloo-timers", - "gloo-utils", - "gloo-worker", -] - -[[package]] -name = "gloo-console" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-dialogs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-events" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-file" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" -dependencies = [ - "futures-channel", - "gloo-events", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-history" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd451019e0b7a2b8a7a7b23e74916601abf1135c54664e57ff71dcc26dfcdeb7" -dependencies = [ - "gloo-events", - "gloo-utils", - "serde", - "serde-wasm-bindgen", - "serde_urlencoded", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-net" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-render" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-storage" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-utils" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8fc851e9c7b9852508bc6e3f690f452f474417e8545ec9857b7f7377036b5" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-worker" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" -dependencies = [ - "anymap2", - "bincode", - "gloo-console", - "gloo-utils", - "js-sys", - "serde", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "implicit-clone" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40fc102e70475c320b185cd18c1e48bba2d7210b63970a4d581ef903e4368ef7" -dependencies = [ - "indexmap", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "is-terminal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "js-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.141" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" - -[[package]] -name = "line-wrap" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" -dependencies = [ - "safemem", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "onig" -version = "6.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" -dependencies = [ - "bitflags", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_macros", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pinned" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" -dependencies = [ - "futures", - "rustversion", - "thiserror", -] - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "plist" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590" -dependencies = [ - "base64", - "indexmap", - "line-wrap", - "quick-xml", - "serde", - "time", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "prettytable-rs" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eea25e07510aa6ab6547308ebe3c036016d162b8da920dbb079e3ba8acf3d95a" -dependencies = [ - "csv", - "encode_unicode", - "is-terminal", - "lazy_static", - "term", - "unicode-width", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prokio" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" -dependencies = [ - "futures", - "gloo", - "num_cpus", - "once_cell", - "pin-project", - "pinned", - "tokio", - "tokio-stream", - "wasm-bindgen-futures", -] - -[[package]] -name = "quick-xml" -version = "0.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.7.2", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" - -[[package]] -name = "rih" -version = "0.1.0" -dependencies = [ - "fuzzy-matcher", - "getrandom", - "gloo", - "js-sys", - "rand", - "rust_iso3166", - "serde", - "serde_json", - "serde_urlencoded", - "static_markdown", - "uuid", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yew", - "yew-router", -] - -[[package]] -name = "route-recognizer" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" - -[[package]] -name = "rust_iso3166" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e19f23f46e5d2f3f1e917ecf5cc988e23ba7fc2a2ce3ef09cb17033842d0ef8" -dependencies = [ - "js-sys", - "phf", - "prettytable-rs", - "wasm-bindgen", -] - -[[package]] -name = "rustix" -version = "0.37.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79bef90eb6d984c72722595b5b1348ab39275a5e5123faca6863bf07d75a4e0" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustversion" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "serde" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.160" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "serde_json" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "shell-words" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" - -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "slab" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg", -] - -[[package]] -name = "slug" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" -dependencies = [ - "deunicode", -] - -[[package]] -name = "static_markdown" -version = "1.0.0" -dependencies = [ - "comrak", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syntect" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c454c27d9d7d9a84c7803aaa3c50cd088d2906fe3c6e42da3209aa623576a8" -dependencies = [ - "bincode", - "bitflags", - "fancy-regex", - "flate2", - "fnv", - "lazy_static", - "once_cell", - "onig", - "plist", - "regex-syntax 0.6.29", - "serde", - "serde_derive", - "serde_json", - "thiserror", - "walkdir", - "yaml-rust", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - -[[package]] -name = "terminal_size" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" -dependencies = [ - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" -dependencies = [ - "itoa", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" - -[[package]] -name = "time-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" -dependencies = [ - "time-core", -] - -[[package]] -name = "tokio" -version = "1.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" -dependencies = [ - "autocfg", - "pin-project-lite", - "windows-sys 0.45.0", -] - -[[package]] -name = "tokio-stream" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "typed-arena" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "uuid" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.15", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.15", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "xdg" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688597db5a750e9cad4511cb94729a078e274308099a0382b5b8203bbc767fee" -dependencies = [ - "home", -] - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "yew" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" -dependencies = [ - "console_error_panic_hook", - "futures", - "gloo", - "implicit-clone", - "indexmap", - "js-sys", - "prokio", - "rustversion", - "serde", - "slab", - "thiserror", - "tokio", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yew-macro", -] - -[[package]] -name = "yew-macro" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" -dependencies = [ - "boolinator", - "once_cell", - "prettyplease", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "yew-router" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426ee0486d2572a6c5e39fbdbc48b58d59bb555f3326f54631025266cf04146e" -dependencies = [ - "gloo", - "js-sys", - "route-recognizer", - "serde", - "serde_urlencoded", - "tracing", - "wasm-bindgen", - "web-sys", - "yew", - "yew-router-macro", -] - -[[package]] -name = "yew-router-macro" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b249cdb39e0cddaf0644dedc781854524374664793479fdc01e6a65d6e6ae3" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] diff --git a/corp/rih/frontend/Cargo.toml b/corp/rih/frontend/Cargo.toml deleted file mode 100644 index d07ed7aec..000000000 --- a/corp/rih/frontend/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -version = "0.1.0" -name = "rih" -authors = [ "Vincent Ambo " ] -license = "Proprietary" -edition = "2021" - -[dependencies] -fuzzy-matcher = "0.3.7" -getrandom = { version = "0.2", features = ["js"] } -gloo = "0.8" -js-sys = "0.3" -rand = "0.8" -rust_iso3166 = "0.1.10" -serde_json = "1.0" -serde_urlencoded = "*" # pinned by yew -yew = { version = "0.20", features = ["csr"] } -yew-router = "0.17" -wasm-bindgen-futures = "0.4" - -# needs to be in sync with nixpkgs -wasm-bindgen = "= 0.2.100" -uuid = { version = "1.3.3", features = ["v4", "serde"] } - -[dependencies.serde] -version = "*" # pinned by yew -features = [ "derive" ] - -[dependencies.web-sys] -version = "*" # pinned by yew -features = [ "HtmlDetailsElement" ] - -[dependencies.static_markdown] -path = "./static-markdown" - -[profile.release] -lto = true -opt-level = 'z' -codegen-units = 1 - -[package.metadata.wasm-pack.profile.release] -wasm-opt = ['-Os'] diff --git a/corp/rih/frontend/default.nix b/corp/rih/frontend/default.nix deleted file mode 100644 index 24bbde09b..000000000 --- a/corp/rih/frontend/default.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ lib, pkgs, ... }: - -let - wasmRust = pkgs.rust-bin.stable.latest.default.override { - targets = [ "wasm32-unknown-unknown" ]; - }; - - cargoToml = with builtins; fromTOML (readFile ./Cargo.toml); - - wasmBindgenMatch = - cargoToml.dependencies.wasm-bindgen == "= ${pkgs.wasm-bindgen-cli.version}"; - - assertWasmBindgen = assert (lib.assertMsg wasmBindgenMatch '' - Due to instability in the Rust WASM ecosystem, the trunk build - tool enforces that the Cargo-dependency version of `wasm-bindgen` - MUST match the version of the CLI supplied in the environment. - - This can get out of sync when nixpkgs is updated. To resolve it, - wasm-bindgen must be bumped in the Cargo.toml file and cargo needs - to be run to resolve the dependencies. - - Versions of `wasm-bindgen` in Cargo.toml: - - Expected: '= ${pkgs.wasm-bindgen-cli.version}' - Actual: '${cargoToml.dependencies.wasm-bindgen}' - ''); pkgs.wasm-bindgen-cli; - - deps = with pkgs; [ - binaryen - sass - wasmRust - trunk - assertWasmBindgen - ]; - -in -pkgs.rustPlatform.buildRustPackage rec { - pname = "rih-frontend"; - version = "canon"; - src = lib.cleanSource ./.; - cargoLock.lockFile = ./Cargo.lock; - - buildPhase = '' - export PATH=${lib.makeBinPath deps}:$PATH - mkdir home - export HOME=$PWD/.home - env - trunk build --release -d $out - ''; - - dontInstall = true; -} diff --git a/corp/rih/frontend/fonts/IdealistSans.eot b/corp/rih/frontend/fonts/IdealistSans.eot deleted file mode 100644 index de1dfa2ed..000000000 Binary files a/corp/rih/frontend/fonts/IdealistSans.eot and /dev/null differ diff --git a/corp/rih/frontend/fonts/IdealistSans.svg b/corp/rih/frontend/fonts/IdealistSans.svg deleted file mode 100644 index 01134450e..000000000 --- a/corp/rih/frontend/fonts/IdealistSans.svg +++ /dev/null @@ -1,10438 +0,0 @@ - - - - -Created by FontForge 20190801 at Thu Jan 17 11:47:14 2013 - By www-data -Copyright (c) 2012 by Glenjan. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/corp/rih/frontend/fonts/IdealistSans.ttf b/corp/rih/frontend/fonts/IdealistSans.ttf deleted file mode 100644 index 91765b1b1..000000000 Binary files a/corp/rih/frontend/fonts/IdealistSans.ttf and /dev/null differ diff --git a/corp/rih/frontend/fonts/IdealistSans.woff b/corp/rih/frontend/fonts/IdealistSans.woff deleted file mode 100644 index 563cc4b61..000000000 Binary files a/corp/rih/frontend/fonts/IdealistSans.woff and /dev/null differ diff --git a/corp/rih/frontend/fonts/IdealistSans.woff2 b/corp/rih/frontend/fonts/IdealistSans.woff2 deleted file mode 100644 index 8123d6e9a..000000000 Binary files a/corp/rih/frontend/fonts/IdealistSans.woff2 and /dev/null differ diff --git a/corp/rih/frontend/fonts/futurabookc.eot b/corp/rih/frontend/fonts/futurabookc.eot deleted file mode 100644 index a50f47723..000000000 Binary files a/corp/rih/frontend/fonts/futurabookc.eot and /dev/null differ diff --git a/corp/rih/frontend/fonts/futurabookc.svg b/corp/rih/frontend/fonts/futurabookc.svg deleted file mode 100644 index bb271a474..000000000 --- a/corp/rih/frontend/fonts/futurabookc.svg +++ /dev/null @@ -1,992 +0,0 @@ - - - - -Created by FontForge 20190801 at Wed May 12 13:27:22 2004 - By www-data -Copyright (c) 1990 Neufville SL, Copyright (c) 1990-2000 ParaType, Inc. All Rights Reserved. Futura is a registered trade mark of Neufville SL. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/corp/rih/frontend/fonts/futurabookc.ttf b/corp/rih/frontend/fonts/futurabookc.ttf deleted file mode 100644 index 3c0347971..000000000 Binary files a/corp/rih/frontend/fonts/futurabookc.ttf and /dev/null differ diff --git a/corp/rih/frontend/fonts/futurabookc.woff b/corp/rih/frontend/fonts/futurabookc.woff deleted file mode 100644 index 7069214ae..000000000 Binary files a/corp/rih/frontend/fonts/futurabookc.woff and /dev/null differ diff --git a/corp/rih/frontend/fonts/futurabookc.woff2 b/corp/rih/frontend/fonts/futurabookc.woff2 deleted file mode 100644 index 52d8e6222..000000000 Binary files a/corp/rih/frontend/fonts/futurabookc.woff2 and /dev/null differ diff --git a/corp/rih/frontend/img/fon.png b/corp/rih/frontend/img/fon.png deleted file mode 100644 index fcf24c96d..000000000 Binary files a/corp/rih/frontend/img/fon.png and /dev/null differ diff --git a/corp/rih/frontend/img/it.png b/corp/rih/frontend/img/it.png deleted file mode 100644 index 4780bae8f..000000000 Binary files a/corp/rih/frontend/img/it.png and /dev/null differ diff --git a/corp/rih/frontend/img/mat.png b/corp/rih/frontend/img/mat.png deleted file mode 100644 index bf8028543..000000000 Binary files a/corp/rih/frontend/img/mat.png and /dev/null differ diff --git a/corp/rih/frontend/img/mat2.png b/corp/rih/frontend/img/mat2.png deleted file mode 100644 index d57e29b64..000000000 Binary files a/corp/rih/frontend/img/mat2.png and /dev/null differ diff --git a/corp/rih/frontend/img/rus.png b/corp/rih/frontend/img/rus.png deleted file mode 100644 index e5ca5f9f3..000000000 Binary files a/corp/rih/frontend/img/rus.png and /dev/null differ diff --git a/corp/rih/frontend/img/work.png b/corp/rih/frontend/img/work.png deleted file mode 100644 index 4aea813f0..000000000 Binary files a/corp/rih/frontend/img/work.png and /dev/null differ diff --git a/corp/rih/frontend/index.css b/corp/rih/frontend/index.css deleted file mode 100644 index dc067e00e..000000000 --- a/corp/rih/frontend/index.css +++ /dev/null @@ -1,248 +0,0 @@ -@font-face { - font-family: 'IdealistSans'; - src: url('fonts/IdealistSans.eot'); - src: url('fonts/IdealistSans.eot') format('embedded-opentype'), - url('fonts/IdealistSans.woff2') format('woff2'), - url('fonts/IdealistSans.woff') format('woff'), - url('fonts/IdealistSans.ttf') format('truetype'), - url('fonts/IdealistSans.svg') format('svg'); -} -@font-face { - font-family: 'futurabookc'; - src: url('fonts/futurabookc.eot'); - src: url('fonts/futurabookc.eot') format('embedded-opentype'), - url('fonts/futurabookc.woff2') format('woff2'), - url('fonts/futurabookc.woff') format('woff'), - url('fonts/futurabookc.ttf') format('truetype'), - url('fonts/futurabookc.svg') format('svg'); -} -body{ - font-size: 16px; - color: #000000; - font-family: futurabookc; -} - - -.font-india{ - font-family: IdealistSans !important; -} - -.font-size-075{ - font-size: 0.75rem!important; -} -.font-size-100{ - font-size: 1rem!important; -} -.font-size-125{ - font-size: 1.25rem!important; -} -.font-size-150{ - font-size: 1.5rem!important; -} -.font-size-200{ - font-size: 2rem!important; -} -.font-size-250{ - font-size: 2.5rem!important; -} -.font-size-300{ - font-size: 3rem!important; -} -.font-weight-bold{ - font-weight: bold!important; -} -.font-weight-500{ - font-weight: 500!important; -} -.font-weight-600{ - font-weight: 600!important; -} -.font-weight-normal{ - font-weight: normal!important; -} - -@media (min-width:576px){ - .font-size-sm-075{ - font-size: 0.75rem!important; - } - .font-size-sm-100{ - font-size: 1rem!important; - } - .font-size-sm-125{ - font-size: 1.25rem!important; - } - .font-size-sm-150{ - font-size: 1.5rem!important; - } - .font-size-sm-200{ - font-size: 2rem!important; - } - .font-size-sm-250{ - font-size: 2.5rem!important; - } - .font-size-sm-300{ - font-size: 3rem!important; - } - -} -@media (min-width:768px){ - .font-size-md-100{ - font-size: 1rem!important; - } - .font-size-md-125{ - font-size: 1.25rem!important - } - .font-size-md-150{ - font-size: 1.5rem!important; - } - .font-size-md-200{ - font-size: 2rem!important; - } - .font-size-md-250{ - font-size: 2.5rem!important; - } - .font-size-md-300{ - font-size: 3rem!important; - } - -} - -@media (min-width:992px){ - .font-size-lg-100{ - font-size: 1rem!important; - } - .font-size-lg-125{ - font-size: 1.25rem!important - } - .font-size-lg-150{ - font-size: 1.5rem!important; - } - .font-size-lg-200{ - font-size: 2rem!important; - } - .font-size-lg-250{ - font-size: 2.5rem!important; - } - .font-size-lg-300{ - font-size: 3rem!important; - } - -} - -img{ - width:auto; - height: auto; - max-width: 100%; - max-height: 100%; - vertical-align: middle; -} - -.text-white { - color: #ffffff !important; -} - -.text-red{ - color:#E32D26 !important; -} -.text-grey1{ - color:#81878d !important; -} -.text-grey2{ - color:rgba(88, 85, 85, 0.63) !important; -} -.first_block{ - background: #141F29 url(img/fon.png) left top no-repeat; - background-size: auto 100% ; - color:#ffffff; - padding-bottom: 200px; - overflow-x: hidden; -} - - -.second_block{ - margin-top:-150px; - z-index: 10; - position: relative; -} -.second_block .container > div{ - background: #ffffff; - border:10px solid #141F29; - border-radius: 10px; -} - -.footer{ - background: #141F29; - color:#ffffff; -} -.footer a{ - color:#ffffff; -} - -@media (max-width: 575.98px){ - .hidden-xs{ - display:none!important - } - -} -@media (min-width:576px) and (max-width:767.98px){ - .hidden-sm{ - display:none!important - } -} -@media (min-width:768px) and (max-width:991.98px){ - .hidden-md{ - display:none!important - } -} -@media (min-width:992px) and (max-width:1199.98px){ - .hidden-lg{ - display:none!important - } -} -@media (min-width:1200px) and (max-width:1399.98px){ - .hidden-xl{ - display:none!important - } -} -@media (min-width:1400px){ - .hidden-xxl{ - display:none!important - } -} - - -@media (min-width:768px){ - .first_block > div{ - background: url(img/mat2.png) right top no-repeat; - margin-bottom: -200px; - padding-bottom: 40px; - } - .first_block .text-block{ - height: 1100px; - } -} -@media (min-width:992px){ - .first_block > div { - min-height: 820px; - } - .first_block .text-block{ - height: 820px; - } -} -@media (min-width:1200px){ - .first_block > div{ - min-height: 950px; - } - .first_block .text-block{ - height: 950px; - } -} - -@media (min-width:1400px){ - .first_block > div{ - min-height: 1100px; - } - .first_block .text-block{ - height: 1100px; - } -} diff --git a/corp/rih/frontend/index.html b/corp/rih/frontend/index.html deleted file mode 100644 index 9fab6b127..000000000 --- a/corp/rih/frontend/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - Russia is Hiring - - - - - - - - - - - - - - diff --git a/corp/rih/frontend/privacy-policy.html b/corp/rih/frontend/privacy-policy.html deleted file mode 100644 index c1c0f8985..000000000 --- a/corp/rih/frontend/privacy-policy.html +++ /dev/null @@ -1,202 +0,0 @@ - - - - - - - Russia is Hiring - - - - - - - -
-
-
-
-
-
-
- Privacy Policy -
- -
-

Effective as of: 2023-05-26

-

This policy outlines who, how and what happens with personal - information entered on russiaishiring.com.

-
    -
  1. -

    Parties

    -

    Entities involved in the collection, storage and processing of - data are the following, all registered in Russia:

    -
      -
    • -

      VFBS LLC (Vista Foreign Business - Support), INN 7709963942, г. Москва, муниципальный округ - Таганский вн.тер.г., ул. Таганская, д. 17-23

      -

      Contact: tbis@vfbs.ru

      -
    • -
    • -

      TVL LLC, INN 9703038861, г. Москва, вн.тер.г. - муниципальный округ Беговой, ул Правды, д. 24, стр. 2, помещ. 3П

      -

      Contact: contact@tvl.su

      -
    • -
    • -

      Yandex LLC, INN 1027700229193, - 119021, город Москва, ул. Льва Толстого, д.16

      -

      Contacts: https://yandex.com/company/contacts/moscow/

      -
    • -
    -

    In the following text, VFBS LLC will be referred to as "we".

    -
  2. -
  3. -

    Information we collect

    -

    We collect information used for the purpose of matching a potential - job candidate with a vacancy. This includes:

    -
      -
    • Name
    • -
    • Contact e-mail address
    • -
    • Work background
    • -
    • Citizenship
    • -
    • Language skills
    • -
    -

    We collect other optional information, such as data about the - work background or expectations from a new job, as deemed relevant - and supplied by the user.

    -

    As part of our technical processes we also store the IP address - from which data was submitted.

    -
  4. -
  5. -

    Data storage

    -

    We store all collected data in services in Yandex Cloud, with the - help of our technical services provider TVL LLC.

    -

    Stored data is subject to the Yandex privacy - policy.

    -

    Collected data is technically accessible by employees of TVL LLC - and VFBC LLC.

    -
  6. -
  7. -

    Data processing

    -

    Data is processed by automatic systems in Yandex Cloud. During - processing, no access is granted to any parties not mentioned - above.

    -
  8. -
  9. -

    Data sharing with third-parties

    -

    As part of the operation of the service, data may be passed on to - companies looking to hire candidates based on the data set.

    -

    This is never done without the user's consent. If you submit data - to us and a suitable job opportunity is found, we will reach out to - you and confirm the further process as well as any data sharing.

    -
  10. -
  11. -

    User rights

    -

    Users that have submitted data to the service always have the right - to request its removal. Please contact us at - privacy@russiaishiring.com for help with data removal.

    -

    Note that we may require you to verify your identity through the - e-mail address you supplied to us when submitting data.

    -
  12. -
  13. -

    Tracking technologies, cookies, advertising

    -

    We do not have any tracking technologies or advertising on - russiaishiring.com. We do not use cookies. Only data explicitly - entered by the user in the form is submitted to us.

    -

    The site uses local storage on the user's machine to store form - data between visits to the site.

    -
  14. -
  15. -

    Retention period

    -

    We will retain individual data no longer than 2 years from the date - of entering the data. If updated data is received for a user, this - period is reset. - "#)

    -
  16. -
-
- -
- - Go back → - -
-
-
-
- -
-
- - diff --git a/corp/rih/frontend/rih-logo.png b/corp/rih/frontend/rih-logo.png deleted file mode 100644 index 5d12843ed..000000000 Binary files a/corp/rih/frontend/rih-logo.png and /dev/null differ diff --git a/corp/rih/frontend/src/home.html b/corp/rih/frontend/src/home.html deleted file mode 100644 index 96d81da27..000000000 --- a/corp/rih/frontend/src/home.html +++ /dev/null @@ -1,289 +0,0 @@ -html! { -<> -
- - -
-
-
-
-
-
-
-
- {"Are you an IT-specialist on the hunt for a job?"} -
- -
- {"Well, times are tough in Western countries at the moment. Meanwhile tech is booming in Russia, and national support programs make life as an IT-specialist very comfortable. Why not look East?"} -
- -
- {"We can help you find an employer in Russia, sort out the formalities and get you started. Sign up and tell us a bit about your profile, or read on below about the benefits of life in Russia."} -
- - - {"Sign up →"} - - -
- -
-
- {"Russia is well placed to draw highly-qualified specialists"} -
-
- {"looking to relocate from any part of the World."} -
-
-
-
-
-
-
-
- -
-
-
-
-
- {"Russia is"} -
- {"an industrialized country"} -
-
-
- {"and the sole European power whose economic cycle is synchronized with Asian economic growth rather than with Western economic contraction."} -
-
- {"Despite the recent sanctions and political tensions, Russia is developing rapidly and needs skilled workers to help fuel its growth. The country has a diverse economy, with strong industries in areas such as energy, technology, finance, and manufacturing. Russian economy has much less risks compared to the Western economies, it is isolated from the Western financial sector and is not a Bubble economy."} -
-
-
-
-
-
- -
-
-
-
-
- {"There are opportunities for professionals in a variety of fields, from engineering and IT to marketing and finance."} -
-
- {"So, if you're a skilled professional looking for new opportunities and want to have for you and your family a great quality of life, consider working in Russia."} -
-
-
-
- {"The country welcomes foreign workers and their families and is ready to offer you the support you need to succeed."} -
-
- {"Don't let politics or misconceptions hold you back - come see what Russia has to offer and help build a brighter future for all."} -
-
-
-
-
- -
-
-
-
- -
-
-
- {"As an IT specialist you can qualify for"} -
-
- {"a Highly Qualified Specialist work permit"} -
-
- {"a 3 year work visa that gives you a flat 13% tax rate from day 1 on your salary"} -
-
- {"Moreover, in case your Russian employer is an accredited IT company you are eligible to obtain a permanent residency in Russia within 3-4 months after employment"} -
-
-
-
-
- -
-
-
- -
-
- {"Finding Work in"} - -
- -
- {"Usually landing the most interesting jobs requires you to have a well-developed network of contacts, but this is tough when you set your eyes on a new country."} -
-
- {"Luckily we at Vista Immigration have contacts with many tech companies in Russia, large and small, and can help you with this!"} -
-
- {"Tell us a bit about yourself, the technologies you'd like to work with, and your situation in regards to relocating to Russia. We will then match up your profile with companies that match your interests, and establish contact between you and a potential employer if there is a good fit. No generic recruiter spam, guaranteed - we'd rather not send you anything, than send you something irrelevant!"} -
-
- {"If you get hired, our experts can assist you with legal and other support for your move."} -
-
-
-
-
- -
- - if !self.submitted { -
- {"Welcome to Russia"} -
- {"Добро пожаловать в Россию!"} -
- -
- {"Let's get started with you telling us a bit"} -
- {"about what kind of job you would like!"} -
- -
-
- -
- - -
- -
- -
{render_technologies(link, &self.record.technologies)}
- - -
{"Press enter after each technology."}
-
- -
- - -
{"Tell us about your work experience, and/or leave links to your CV on your site, LinkedIn or wherever."}
-
- -
- - -
{"Tell us a bit about what you're looking for in a job and in an employer."}
-
- -
- {"Now we also need some personal details about you:"} -
- -
- - -
- -
- - -
{"No newsletters, no spam - we will only reach out if there's a match!"}
-
- -
- - {citizenship_input(self, link)} -
{"We need to know this to estimate immigration-related bureaucracy. If you hold more than one citizenship, pick the one with which you'd want to receive a work visa."}
-
- - {"" /* TODO(tazjin): language knowledge selector */} - -
- - -
{"Any specific places where you'd like to live? Would you be moving with family? Any other assistance required?"}
-
- -
- - -
- -
- -
- -
- -
- - } else { -
-

{"Thank you for submitting your data! We will reach out to confirm your email address, and further if any matches are found. You can contact us at contact@russiaishiring.com with any questions you might have."}

-
- } -
- - -} diff --git a/corp/rih/frontend/src/main.rs b/corp/rih/frontend/src/main.rs deleted file mode 100644 index 65f9c79a5..000000000 --- a/corp/rih/frontend/src/main.rs +++ /dev/null @@ -1,512 +0,0 @@ -use fuzzy_matcher::skim::SkimMatcherV2; -use fuzzy_matcher::FuzzyMatcher; -use gloo::console; -use gloo::history::{BrowserHistory, History}; -use gloo::net::http; -use gloo::storage::{LocalStorage, Storage}; -use rand::seq::IteratorRandom; -use rand::thread_rng; -use serde::{Deserialize, Serialize}; -use static_markdown::markdown; -use std::collections::BTreeSet; -use uuid::Uuid; -use wasm_bindgen::closure::Closure; -use wasm_bindgen::{JsCast, JsValue}; -use web_sys::{HtmlInputElement, HtmlTextAreaElement, KeyboardEvent}; -use yew::html::Scope; -use yew::prelude::*; -use yew_router::prelude::*; - -/// Form submission is protected with a captcha. The development -/// version of the captcha does not do domain checking and works on -/// `localhost` as well. -#[cfg(debug_assertions)] -const CAPTCHA_KEY: &'static str = "ysc1_K7iOi3FSmsyO8pZGu8Im2iQClCtPsVx7jSRyhyCV435a732c"; - -#[cfg(not(debug_assertions))] -const CAPTCHA_KEY: &'static str = "ysc1_a3LVlaDRDMwU8CLSZ0WKENTI2exyOxz5J2c6x28P5339d410"; - -// Form data is submitted to different endpoints in dev/prod. -#[cfg(debug_assertions)] -const SUBMIT_URL: &'static str = "http://localhost:9090/submit"; - -#[cfg(not(debug_assertions))] -const SUBMIT_URL: &'static str = "https://api.russiaishiring.com/submit"; - -/// This code ends up being compiled for the native and for the -/// webassembly architectures during the build & test process. -/// However, the `rust_iso3166` crate exposes a different API (!) -/// based on the platform. -/// -/// This trait acts as a platform-independent wrapper for the crate. -/// -/// Upstream issue: https://github.com/rust-iso/rust_iso3166/issues/7 -trait CountryCodeAccess { - fn country_alpha2(&self) -> String; - fn country_alpha3(&self) -> String; - fn country_name(&self) -> String; -} - -#[cfg(target_arch = "wasm32")] -impl CountryCodeAccess for rust_iso3166::CountryCode { - fn country_alpha2(&self) -> String { - self.alpha2() - } - - fn country_alpha3(&self) -> String { - self.alpha3() - } - - fn country_name(&self) -> String { - self.name() - } -} - -#[cfg(not(target_arch = "wasm32"))] -impl CountryCodeAccess for rust_iso3166::CountryCode { - fn country_alpha2(&self) -> String { - self.alpha2.to_string() - } - - fn country_alpha3(&self) -> String { - self.alpha3.to_string() - } - - fn country_name(&self) -> String { - self.name.to_string() - } -} - -const VISTA_URL: &'static str = "https://vista-immigration.ru/"; - -#[derive(Debug, Clone, Copy, PartialEq, Routable)] -enum Route { - #[at("/")] - Home, - #[at("/privacy-policy")] - PrivacyPolicy, - #[not_found] - #[at("/404")] - NotFound, -} - -/// Represents a single record as filled in by a user. This is the -/// primary data structure we want to populate and persist somewhere. -#[derive(Clone, Default, Debug, Deserialize, Serialize)] -struct Record { - // Record-specific metadata - uuid: Uuid, - - // Personal information - name: String, - email: String, - citizenship: String, // TODO - personal_details: String, - - // Job information - position: String, - technologies: BTreeSet, - job_details: String, - work_background: String, -} - -impl Record { - fn is_complete(&self) -> bool { - !self.name.is_empty() - && !self.email.is_empty() - && !self.citizenship.is_empty() - && !self.position.is_empty() - && !self.technologies.is_empty() - } -} - -struct App { - // The record being populated. - record: Record, - - // Is the citizenship input focused? - citizenship_focus: bool, - - // Current query in the citizenship field. - citizenship_query: String, - - // History handler. - history: BrowserHistory, - - // Captcha token, if the captcha has been solved. - captcha_token: Option, - - // Captcha callback closure which needs to be kept alive for the - // lifecycle of the app. - captcha_callback: Closure, - - // Has data been submitted already by this user? - submitted: bool, -} - -#[derive(Clone, Debug)] -enum Msg { - NoOp, - AddTechnology(String), - RemoveTechnology(String), - - FocusCitizenship, - BlurCitizenship, - QueryCitizenship(String), - SetCitizenship(String), - - SetName(String), - SetEmail(String), - SetPersonalDetails(String), - SetPosition(String), - SetJobDetails(String), - SetWorkBackground(String), - - CaptchaSolved(String), - Submit, -} - -/// Callback handler for adding a technology. -fn add_tech(e: KeyboardEvent) -> Msg { - if e.key_code() != 13 { - return Msg::NoOp; - } - - let input = e.target_unchecked_into::(); - let tech = input.value(); - input.set_value(""); - Msg::AddTechnology(tech) -} - -fn select_country_enter(event: KeyboardEvent) -> Msg { - if event.key_code() != 13 { - return Msg::NoOp; - } - - let input = event.target_unchecked_into::(); - if let Some(country) = fuzzy_country_matches(&input.value()).next() { - input.set_value(&country.country_name()); - return Msg::SetCitizenship(country.country_name()); - } - - Msg::NoOp -} - -fn fuzzy_country_matches(query: &str) -> Box + '_> { - if query.is_empty() { - let rng = &mut thread_rng(); - return Box::new( - rust_iso3166::ALL - .iter() - .choose_multiple(rng, 5) - .into_iter() - .map(Clone::clone), - ); - } - - let matcher = SkimMatcherV2::default(); - let query = query.to_lowercase(); - let query_len = query.len(); - - let mut results: Vec<_> = rust_iso3166::ALL - .iter() - .filter_map(|code| { - let mut score = None; - // Prioritize exact matches for country codes if query length <= 3 - if query_len <= 3 { - if code.country_alpha2().eq_ignore_ascii_case(&query) - || code.country_alpha3().eq_ignore_ascii_case(&query) - { - score = Some(100); - } - } - // If no exact match, do a fuzzy match - if score.is_none() { - score = matcher.fuzzy_match(&code.country_name().to_lowercase(), &query); - } - - score.map(|score| (score, code)) - }) - .collect(); - - // Sort by score in descending order - results.sort_by(|a, b| b.0.cmp(&a.0)); - - // Get iterator over the best matches - Box::new(results.into_iter().map(|(_score, code)| *code)) -} - -// Callback for an input element's value being mapped straight into a -// message. -fn input_message(e: InputEvent, msg: fn(String) -> Msg) -> Msg { - let input = e.target_unchecked_into::(); - msg(input.value()) -} - -// Callback for a text area's value being mapped straight into a -// message. -fn textarea_message(e: InputEvent, msg: fn(String) -> Msg) -> Msg { - let textarea = e.target_unchecked_into::(); - msg(textarea.value()) -} - -fn schedule_blur(event: FocusEvent, link: Scope) -> Msg { - let input = event.target_unchecked_into::(); - let closure = Closure::once_into_js(Box::new(move || { - if let Some(app) = link.get_component() { - input.set_value(&app.record.citizenship); - } - - link.send_message(Msg::BlurCitizenship); - }) as Box); - - let window = web_sys::window().expect("no global `window` exists"); - let _ = - window.set_timeout_with_callback_and_timeout_and_arguments_0(closure.unchecked_ref(), 100); - - Msg::NoOp -} - -/// Creates an input field for citizenship selection with suggestions. -fn citizenship_input(app: &App, link: &Scope) -> Html { - let dropdown_classes = if app.citizenship_focus { - "dropdown-menu show" - } else { - "dropdown-menu" - }; - - let choices = fuzzy_country_matches(&app.citizenship_query).map(|country| { - let msg = Msg::SetCitizenship(country.country_name()); - html! { -
  • {country.country_name()}
  • - } - }); - - let blur_link = link.clone(); - html! { - - } -} - -/// Creates a list of technologies which can be deleted again by clicking them. -fn render_technologies(link: &Scope, technologies: &BTreeSet) -> Html { - if technologies.is_empty() { - return html! {}; - } - - let items = technologies.iter().map(|tech| { - let msg: Msg = Msg::RemoveTechnology(tech.to_string()); - html! { - <> - - {tech} - {" x"} - {" "} - - } - }); - html! { -
    - { items.collect::() } -
    - } -} - -/// Submit the collected data to the backend service. -async fn submit_data(captcha_token: &str, record: &Record) -> bool { - let response = http::Request::get(SUBMIT_URL) - .method(http::Method::POST) - .json(&serde_json::json!({ - "captcha_token": captcha_token, - "record": record, - })) - .expect("serialising a serde_json::Value can not fail") - .send() - .await - .unwrap(); - - // currently there is nothing we can actually do with the response - // here, but we should add some way to communicate back some - // server errors etc., even if the whole thing should be as - // forgiving as possible. - response.ok() -} - -/// Handle the submit event, if all data was successfully collected. -fn handle_submit(app: &App, _link: Scope) -> Msg { - let token = app.captcha_token.as_ref().unwrap().clone(); - let record = app.record.clone(); - - wasm_bindgen_futures::spawn_local(async move { - if !submit_data(&token, &record).await { - console::warn!("failed to submit data for some reason"); - } else { - console::log!("submitted data successfully"); - } - }); - - Msg::NoOp -} - -impl Component for App { - type Message = Msg; - type Properties = (); - - fn create(ctx: &Context) -> Self { - App { - record: LocalStorage::get("record").unwrap_or_else(|_| { - let mut new_record = Record::default(); - new_record.uuid = Uuid::new_v4(); - new_record - }), - citizenship_focus: false, - citizenship_query: String::default(), - history: BrowserHistory::default(), - captcha_token: None, - captcha_callback: { - let link = ctx.link().clone(); - Closure::wrap(Box::new(move |val| { - link.send_message(Msg::CaptchaSolved(val)); - })) - }, - submitted: false, - } - } - - fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { - console::log!("handling ", format!("{:?}", msg)); - let (state_change, view_change) = match msg { - Msg::NoOp => (false, false), - - Msg::AddTechnology(tech) => { - console::log!("adding technology", &tech); - self.record.technologies.insert(tech); - (true, true) - } - - Msg::RemoveTechnology(tech) => { - console::log!("removing technology ", &tech); - self.record.technologies.remove(&tech); - (true, true) - } - - Msg::QueryCitizenship(query) => { - self.citizenship_query = query; - (false, true) - } - - Msg::FocusCitizenship => { - self.citizenship_focus = true; - (false, true) - } - - Msg::BlurCitizenship => { - self.citizenship_focus = false; - (false, true) - } - - Msg::SetCitizenship(country) => { - self.record.citizenship = country; - (true, false) - } - - Msg::SetName(name) => { - self.record.name = name; - (true, false) - } - - Msg::SetEmail(email) => { - self.record.email = email; - (true, false) - } - - Msg::SetPersonalDetails(details) => { - self.record.personal_details = details; - (true, false) - } - - Msg::SetPosition(position) => { - self.record.position = position; - (true, false) - } - - Msg::SetJobDetails(details) => { - self.record.job_details = details; - (true, false) - } - - Msg::SetWorkBackground(background) => { - self.record.work_background = background; - (true, false) - } - - Msg::CaptchaSolved(token) => { - self.captcha_token = Some(token); - (false, true) - } - - Msg::Submit => { - if self.record.is_complete() && self.captcha_token.is_some() { - self.submitted = true; - handle_submit(self, ctx.link().clone()); - (false, true) - } else { - console::warn!("submitted data, but form or captcha was not ready"); - (false, false) - } - } - }; - - if state_change { - if let Err(err) = LocalStorage::set("record", &self.record) { - console::warn!( - "failed to persist record in local storage: ", - err.to_string() - ); - } - } - - view_change - } - - fn view(&self, ctx: &Context) -> Html { - let link = ctx.link(); - let location = self.history.location(); - let route = Route::recognize(location.path()).unwrap_or(Route::NotFound); - - match route { - Route::Home => include!("home.html"), - Route::PrivacyPolicy => html! { -
    {include!("privacy-policy.md")}
    - }, - Route::NotFound => todo!(), - } - } - - fn rendered(&mut self, _: &Context, first_render: bool) { - if first_render { - let func = - js_sys::Function::new_with_args("key, callback", "captchaOnload(key, callback)"); - let _ = func.call2( - &JsValue::NULL, - &JsValue::from_str(CAPTCHA_KEY), - &self.captcha_callback.as_ref().unchecked_ref(), - ); - } - } -} - -fn main() { - yew::Renderer::::new().render(); -} diff --git a/corp/rih/frontend/src/privacy-policy.md b/corp/rih/frontend/src/privacy-policy.md deleted file mode 100644 index 843aac4c0..000000000 --- a/corp/rih/frontend/src/privacy-policy.md +++ /dev/null @@ -1,100 +0,0 @@ -markdown!(r#" -Privacy Policy -============== - -Effective as of: 2023-05-26 - -This policy outlines who, how and what happens with personal -information entered on russiaishiring.com. - -0. Parties - - Entities involved in the collection, storage and processing of - data are the following, all registered in Russia: - - - [VFBS LLC](https://vista-immigration.ru/) (Vista Foreign Business - Support), INN 7709963942, г. Москва, муниципальный округ - Таганский вн.тер.г., ул. Таганская, д. 17-23 - - Contact: tbis@vfbs.ru - - - [TVL LLC](https://tvl.su/), INN 9703038861, г. Москва, вн.тер.г. - муниципальный округ Беговой, ул Правды, д. 24, стр. 2, помещ. 3П - - Contact: contact@tvl.su - - - [Yandex LLC](https://yandex.com/company/), INN 1027700229193, - 119021, город Москва, ул. Льва Толстого, д.16 - - Contacts: https://yandex.com/company/contacts/moscow/ - - In the following text, VFBS LLC will be referred to as "we". - -1. Information we collect - - We collect information used for the purpose of matching a potential - job candidate with a vacancy. This includes: - - - Name - - Contact e-mail address - - Work background - - Citizenship - - Language skills - - We collect other **optional** information, such as data about the - work background or expectations from a new job, as deemed relevant - and supplied by the user. - - As part of our technical processes we also store the IP address - from which data was submitted. - -2. Data storage - - We store all collected data in services in Yandex Cloud, with the - help of our technical services provider TVL LLC. - - Stored data is subject to the [Yandex privacy - policy](https://yandex.ru/legal/confidential/). - - Collected data is technically accessible by employees of TVL LLC - and VFBC LLC. - -3. Data processing - - Data is processed by automatic systems in Yandex Cloud. During - processing, no access is granted to any parties not mentioned - above. - -4. Data sharing with third-parties - - As part of the operation of the service, data may be passed on to - companies looking to hire candidates based on the data set. - - This is never done without the user's consent. If you submit data - to us and a suitable job opportunity is found, we will reach out to - you and confirm the further process as well as any data sharing. - -5. User rights - - Users that have submitted data to the service always have the right - to request its removal. Please contact us at - privacy@russiaishiring.com for help with data removal. - - Note that we may require you to verify your identity through the - e-mail address you supplied to us when submitting data. - -6. Tracking technologies, cookies, advertising - - We do not have any tracking technologies or advertising on - russiaishiring.com. We do not use cookies. Only data explicitly - entered by the user in the form is submitted to us. - - The site uses local storage on the user's machine to store form - data between visits to the site. - -7. Retention period - - We will retain individual data no longer than 2 years from the date - of entering the data. If updated data is received for a user, this - period is reset. -"#) diff --git a/corp/rih/frontend/static-markdown/Cargo.toml b/corp/rih/frontend/static-markdown/Cargo.toml deleted file mode 100644 index c0e298d44..000000000 --- a/corp/rih/frontend/static-markdown/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -version = "1.0.0" -name = "static_markdown" -edition = "2018" - -[lib] -proc-macro = true - -[dependencies] -syn = "1.0" -quote = "1.0" -comrak = "0.18" diff --git a/corp/rih/frontend/static-markdown/src/lib.rs b/corp/rih/frontend/static-markdown/src/lib.rs deleted file mode 100644 index 6a25c9292..000000000 --- a/corp/rih/frontend/static-markdown/src/lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -extern crate proc_macro; - -use comrak::{markdown_to_html, ComrakOptions}; -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, LitStr}; - -#[proc_macro] -pub fn markdown(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as LitStr); - - let mut options = ComrakOptions::default(); - options.extension.strikethrough = true; - options.extension.tagfilter = true; - options.extension.table = true; - options.extension.autolink = true; - - let rendered_html = markdown_to_html(&input.value(), &options); - - let tokens = quote! { - yew::virtual_dom::VNode::VRaw(yew::virtual_dom::VRaw { - html: #rendered_html.into(), - }) - }; - - tokens.into() -} diff --git a/corp/russian/README.md b/corp/russian/README.md deleted file mode 100644 index 23c3d594c..000000000 --- a/corp/russian/README.md +++ /dev/null @@ -1,9 +0,0 @@ -//corp/russian -============== - -This folder contains TVL corp projects related to the Russian -language, such as the code powering -[Предложник](https://predlozhnik.ru). - -Unless otherwise specified, all rights to these projects are reserved -by ООО "ТВЛ". diff --git a/corp/russian/data-import/.gitignore b/corp/russian/data-import/.gitignore deleted file mode 100644 index e918c641c..000000000 --- a/corp/russian/data-import/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target/ -all_events.txt diff --git a/corp/russian/data-import/Cargo.lock b/corp/russian/data-import/Cargo.lock deleted file mode 100644 index cd85e0581..000000000 --- a/corp/russian/data-import/Cargo.lock +++ /dev/null @@ -1,499 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "cc" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - -[[package]] -name = "data-import" -version = "0.1.0" -dependencies = [ - "csv", - "env_logger", - "log", - "rusqlite", - "serde", - "xml-rs", -] - -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69fe1fcf8b4278d860ad0548329f892a3631fb63f82574df68275f34cdbe0ffa" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "io-lifetimes" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "is-terminal" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" -dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix", - "windows-sys", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "libsqlite3-sys" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f835d03d717946d28b1d1ed632eb6f0e24a299388ee623d0c23118d3e8a7fa" -dependencies = [ - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - -[[package]] -name = "proc-macro2" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "rusqlite" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" -dependencies = [ - "bitflags", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - -[[package]] -name = "rustix" -version = "0.36.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "serde" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" - -[[package]] -name = "xml-rs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" diff --git a/corp/russian/data-import/Cargo.toml b/corp/russian/data-import/Cargo.toml deleted file mode 100644 index 1aae2e830..000000000 --- a/corp/russian/data-import/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "data-import" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -csv = "1.1" -env_logger = "0.10.0" -log = "0.4.17" -rusqlite = "0.28" -serde = { version = "1.0", features = ["derive"] } -xml-rs = "0.8" - -[profile.release-with-debug] -inherits = "release" -debug = true diff --git a/corp/russian/data-import/default.nix b/corp/russian/data-import/default.nix deleted file mode 100644 index 6aa8ad6aa..000000000 --- a/corp/russian/data-import/default.nix +++ /dev/null @@ -1,55 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - buildInputs = with pkgs; [ - sqlite - pkg-config - ]; - - # mirrored input data from OpenCorpora, as of 2023-01-17. - # - # This data is licensed under CC-BY-SA. - openCorporaArchive = pkgs.fetchurl { - name = "dict.opcorpora.xml.bz"; - url = "https://tazj.in/blobs/opencorpora-20230117.xml.bz2"; - sha256 = "04n5g43fkfc93z6xlwf2qfdrfdfl562pc2ivdb3cbbbsy56gkqg6"; - }; - - openCorpora = pkgs.runCommand "dict.opcorpora.xml" { } '' - ${pkgs.bzip2}/bin/bunzip2 -k -c ${openCorporaArchive} > $out - ''; - - # mirrored input data from OpenRussian, as of 2023-01-17. - # - # This data is licensed under CC-BY-SA. - openRussianArchive = pkgs.fetchzip { - name = "openrussian-20230117"; - url = "https://tazj.in/blobs/openrussian-20230117.tar.xz"; - sha256 = "06jl7i23cx58a0n2626hb82xlzimixvnxp7lxdw0g664kv9bmw25"; - }; - - # development shell with native deps - shell = pkgs.mkShell { - inherit buildInputs; - - # make datasets available in the environment - OPENCORPORA_DATA = openCorpora; - OPENRUSSIAN_DATA = openRussianArchive; - }; - -in -lib.fix (self: depot.third_party.naersk.buildPackage { - src = depot.third_party.gitignoreSource ./.; - inherit buildInputs; - - passthru = depot.nix.readTree.drvTargets { - inherit shell openCorpora; - - # target that actually builds an entire database - database = pkgs.runCommand "tvl-russian-db.sqlite" - { - OPENCORPORA_DATA = openCorpora; - OPENRUSSIAN_DATA = openRussianArchive; - } "${self}/bin/data-import --output $out"; - }; -}) diff --git a/corp/russian/data-import/src/db_setup.rs b/corp/russian/data-import/src/db_setup.rs deleted file mode 100644 index c9fb51738..000000000 --- a/corp/russian/data-import/src/db_setup.rs +++ /dev/null @@ -1,298 +0,0 @@ -//! This module prepares the database layout. -//! -//! The XML import may be in an arbitrary order, so importing data is -//! a multi-step process where we first set up schemas matching the -//! data layout, import the data, and then modify the schema to -//! introduce things like foreign key constraints between tables that -//! represent relations. - -use super::Ensure; -use crate::oc_parser::*; -use crate::or_parser; -use log::{debug, info}; -use rusqlite::Connection; - -/// Sets up an initial schema which matches the OpenCorpora data. -pub fn initial_oc_schema(conn: &Connection) { - conn.execute_batch( - r#" --- table for plain import of grammemes from XML -CREATE TABLE oc_grammemes ( - name TEXT PRIMARY KEY, - parent TEXT, - alias TEXT, - description TEXT -) STRICT; - --- table for plain import of lemmas (*not* their variations!) -CREATE TABLE oc_lemmas ( - id INTEGER PRIMARY KEY, - lemma TEXT NOT NULL -) STRICT; - --- table for relationship between grammemes and lemmas -CREATE TABLE oc_lemma_grammemes ( - lemma INTEGER, - grammeme TEXT NOT NULL, - FOREIGN KEY(lemma) REFERENCES oc_lemmas(id) -) STRICT; - --- table for all words, i.e. including variations of lemmata -CREATE TABLE oc_words ( - lemma INTEGER NOT NULL, - word TEXT NOT NULL, - FOREIGN KEY(lemma) REFERENCES oc_lemmas(id) -) STRICT; - --- table for relationship between words and grammemes -CREATE TABLE oc_word_grammemes ( - word INTEGER NOT NULL, - grammeme TEXT NOT NULL, - FOREIGN KEY(word) REFERENCES oc_words(ROWID) -) STRICT; - --- table for link types -CREATE TABLE oc_link_types ( - id INTEGER PRIMARY KEY, - name TEXT -) STRICT; - --- table for links between lemmata -CREATE TABLE oc_links ( - id INTEGER PRIMARY KEY, - link_type INTEGER NOT NULL, - from_lemma INTEGER NOT NULL, - to_lemma INTEGER NOT NULL, - FOREIGN KEY(link_type) REFERENCES oc_link_types(id), - FOREIGN KEY(from_lemma) REFERENCES oc_lemmas(id), - FOREIGN KEY(to_lemma) REFERENCES oc_lemmas(id) -) STRICT; - -"#, - ) - .ensure("setting up OpenCorpora table schema failed"); - - info!("set up initial table schema for OpenCorpora import"); -} - -/// Inserts a single OpenCorpora element into the initial table structure. -pub fn insert_oc_element(conn: &Connection, elem: OcElement) { - match elem { - OcElement::Grammeme(grammeme) => { - conn.execute( - "INSERT INTO oc_grammemes (name, parent, alias, description) VALUES (?1, ?2, ?3, ?4)", - ( - &grammeme.name, - &grammeme.parent, - &grammeme.alias, - &grammeme.description, - ), - ) - .ensure("failed to insert grammeme"); - - debug!("inserted grammeme {}", grammeme.name); - } - - OcElement::Lemma(lemma) => insert_lemma(conn, lemma), - - OcElement::LinkType(lt) => { - conn.execute( - "INSERT INTO oc_link_types (id, name) VALUES (?1, ?2)", - (<.id, <.name), - ) - .ensure("failed to insert link type"); - - info!("inserted link type {}", lt.name); - } - - OcElement::Link(link) => { - let mut stmt = conn - .prepare_cached( - "INSERT INTO oc_links (id, link_type, from_lemma, to_lemma) VALUES (?1, ?2, ?3, ?4)", - ) - .ensure("failed to prepare link statement"); - - stmt.execute((&link.id, &link.link_type, &link.from, &link.to)) - .ensure("failed to insert link"); - - debug!("inserted link {}", link.id); - } - } -} - -/// Insert a single lemma into the initial structure. This is somewhat -/// involved because it also establishes a bunch of relations. -fn insert_lemma(conn: &Connection, lemma: Lemma) { - // insert the lemma itself - let mut stmt = conn - .prepare_cached("INSERT INTO oc_lemmas (id, lemma) VALUES (?1, ?2)") - .ensure("failed to prepare statement"); - - stmt.execute((&lemma.id, &lemma.lemma.word)) - .ensure("failed to insert grammeme"); - - // followed by its relations to the grammemes set - let mut stmt = conn - .prepare_cached("INSERT INTO oc_lemma_grammemes (lemma, grammeme) VALUES (?1, ?2)") - .ensure("failed to prepare statement"); - - for grammeme in lemma.grammemes { - stmt.execute((&lemma.id, grammeme)) - .ensure("failed to insert grammeme<>lemma relationship"); - } - - // followed by all of its variations ... - let mut word_insert = conn - .prepare_cached("INSERT INTO oc_words (lemma, word) VALUES (?1, ?2)") - .unwrap(); - - let mut word_grammeme = conn - .prepare_cached("INSERT INTO oc_word_grammemes (word, grammeme) VALUES (?1, ?2)") - .unwrap(); - - for variation in lemma.variations { - // insert the word itself and get its rowid - word_insert - .execute((&lemma.id, &variation.word)) - .ensure("failed to insert word"); - let row_id = conn.last_insert_rowid(); - - // then insert its grammeme links - for grammeme in variation.grammemes { - word_grammeme - .execute((row_id, grammeme)) - .ensure("failed to insert word<>grammeme link"); - } - } - - debug!("inserted lemma {}", lemma.id); -} - -/// Sets up an initial schema for the OpenRussian data. -pub fn initial_or_schema(conn: &Connection) { - conn.execute_batch( - r#" -CREATE TABLE or_words ( - id INTEGER PRIMARY KEY, - bare TEXT NOT NULL, - accented TEXT, - derived_from_word_id INTEGER, - rank INTEGER, - word_type TEXT, - level TEXT -) STRICT; - -CREATE TABLE or_words_forms ( - id INTEGER PRIMARY KEY, - word_id INTEGER NOT NULL, - form_type TEXT, - position TEXT, - form TEXT, - form_bare TEXT, - FOREIGN KEY(word_id) REFERENCES words(id) -) STRICT; - -CREATE TABLE or_translations ( - id INTEGER PRIMARY KEY, - word_id INTEGER NOT NULL, - translation TEXT, - example_ru TEXT, - example_tl TEXT, - info TEXT, - FOREIGN KEY(word_id) REFERENCES words(id) -) STRICT; -"#, - ) - .ensure("setting up OpenRussian table schema failed"); - - info!("set up initial table schema for OpenRussian import"); -} - -pub fn insert_or_words>(conn: &Connection, words: I) { - let mut stmt = conn - .prepare_cached( - " -INSERT INTO or_words (id, bare, accented, derived_from_word_id, rank, word_type, level) -VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) -", - ) - .ensure("failed to prepare OR words statement"); - let mut count = 0; - - for word in words { - stmt.execute(( - word.id, - word.bare, - word.accented, - word.derived_from_word_id, - word.rank, - word.word_type, - word.level, - )) - .ensure("failed to insert OR word"); - count += 1; - } - - info!("inserted {} OpenRussian words", count); -} - -pub fn insert_or_word_forms>(conn: &Connection, forms: I) { - let mut stmt = conn - .prepare_cached( - " -INSERT INTO or_words_forms (id, word_id, form_type, position, form, form_bare) -VALUES (?1, ?2, ?3, ?4, ?5, ?6) -", - ) - .ensure("failed to prepare OR word forms statement"); - let mut count = 0; - - for form in forms { - stmt.execute(( - form.id, - form.word_id, - form.form_type, - form.position, - form.form, - form.form_bare, - )) - .ensure("failed to insert OR word form"); - count += 1; - } - - info!("inserted {} OpenRussian word forms", count); -} - -pub fn insert_or_translations>( - conn: &Connection, - translations: I, -) { - let mut stmt = conn - .prepare_cached( - "INSERT INTO or_translations (id, word_id, translation, example_ru, example_tl, info) - VALUES (?1, ?2, ?3, ?4, ?5, ?6)", - ) - .ensure("failed to prepare OR translation statement"); - - let mut count = 0; - - for tl in translations { - if tl.lang != "en" { - continue; - } - - stmt.execute(( - tl.id, - tl.word_id, - tl.tl, - tl.example_ru, - tl.example_tl, - tl.info, - )) - .ensure("failed to insert OR translation"); - - count += 1; - } - - info!("inserted {} OpenRussian translations", count); -} diff --git a/corp/russian/data-import/src/main.rs b/corp/russian/data-import/src/main.rs deleted file mode 100644 index 21da48e8d..000000000 --- a/corp/russian/data-import/src/main.rs +++ /dev/null @@ -1,298 +0,0 @@ -//! This program imports Russian language data from OpenCorpora -//! ("Открытый корпус") and OpenRussian into a SQLite database that -//! can be used for [//corp/russian][corp-russian] projects. -//! -//! [corp-russian]: https://at.tvl.fyi/?q=%2F%2Fcorp%2Frussian -//! -//! Ideally, running this on intact dumps should yield a fully -//! functional SQLite database compatible with all other tools -//! consuming it. -//! -//! ## OpenCorpora format -//! -//! The format used is partially documented on the [OpenCorpora -//! website][format-docs]. This seems to be a slightly outdated -//! format, however, hence some information about what the format -//! seems to be today. -//! -//! [format-docs]: http://opencorpora.org/?page=export -//! -//! The format is an XML file, which has several categories of data, -//! each with their own schema: -//! -//! * `grammemes`: These define units of grammar. They're *likely* pretty -//! static, and we'll *likely* want to map them into a custom set of -//! (simpler) categories. -//! -//! They form some kind of internal hierarchy, where some of them have a -//! `parent` attribute set to some other grammemes `name`. -//! -//! There's a ridiculous number of these. -//! -//! * `restrictions`: Unclear, not documented on the page. They describe -//! something about the relationship between grammemes. -//! -//! * `lemmata`: this lists the actual lemmas, as well as all their -//! included morphological variants -//! -//! Each lemma has an `id` attribute uniquely identifying its dictionary -//! form, as well as a number of sub-elements: -//! -//! * the `l` attribute contains the lemma itself -//! * the `f` attributes contain morphological variations -//! -//! Each of these sub elements again contains a number of `g` elements, -//! which refer to the IDs of grammems in their `v` attributes. -//! -//! * `` These list possible "relationships between lemmas", -//! basically just assigning them IDs and names. There's only 27 of -//! these. -//! -//! * ``: Using the types defined above, this establishes links -//! between lemmas that have some kind of relationship. -//! -//! For example, a relationship `cardinal/ordinal` might be established -//! between the lemmas "два" and "второй". -//! -//! ## OpenRussian format -//! -//! The [OpenRussian](https://en.openrussian.org/dictionary) project -//! lets users export its database as a set of CSV-files. For our -//! purposes, we download the files using `` separators. -//! -//! Whereas OpenCorpora opts for a flat structure with a "tag" system -//! (through its flexible grammemes), OpenRussian has a fixed pre-hoc -//! structure into which it sorts some words with their morphologies. -//! The OpenRussian database is much smaller as of January 2023 (~1.7 -//! million words vs. >5 million for OpenCorpora), but some of the -//! information is much more practically useful. -//! -//! Two very important bits of information OpenRussian has are accent -//! marks (most tables containing actual words have a normal form -//! containing and accent mark, and a "bare" form without) and -//! translations into English and German. -//! -//! The full dump includes the following tables (and some more): -//! -//! * `words`: List of lemmas in the corpus, with various bits of -//! metadata as well as hand-written notes. -//! -//! * `adjectives`: Contains IDs for words that are adjectives. -//! -//! * `nouns`: IDs for words that are nouns; and noun metadata (e.g. -//! gender, declinability) -//! -//! * `verbs`: IDs of words that are verbs, including their aspect and -//! "partnered" verb in the other aspect -//! -//! * `words_forms`: Contains all morphed variants of the lemmas from -//! `words`, including information about their grammeme, and accent -//! marks. -//! -//! * `words_rels`: Contains relations between words, containing -//! information like "synonyms" or general relation between words. -//! -//! * `translations`: Contains translations tagged by target language, -//! as well as examples and (occasionally) additional information. -//! -//! These tables also contain something, but have not been analysed -//! yet: -//! -//! * `expressions_words` -//! * `sentences` -//! * `sentences_translations` -//! * `sentences_words` - -use log::{error, info}; -use rusqlite::{Connection, Result}; -use std::env; -use std::fmt::Display; -use std::fs::File; -use std::io::BufReader; - -mod db_setup; -mod mappings; -mod oc_parser; -mod or_parser; - -struct Args { - output: String, - or_input: String, - oc_input: String, -} - -impl Args { - fn populated(&self) -> bool { - !(self.output.is_empty() || self.or_input.is_empty() || self.oc_input.is_empty()) - } -} - -fn usage(binary_name: &str) { - bail(format!( - "usage: {} --output --or-input --oc-input ", - binary_name - )); -} - -fn parse_args() -> Args { - let mut args_iter = env::args(); - let binary_name = args_iter.next().unwrap(); - - let mut args = Args { - output: "".into(), - or_input: env::var("OPENRUSSIAN_DATA").unwrap_or_default(), - oc_input: env::var("OPENCORPORA_DATA").unwrap_or_default(), - }; - - loop { - if args.populated() { - break; - } - - while let Some(arg) = args_iter.next() { - match arg.as_str() { - "--output" => { - args.output = args_iter.next().unwrap(); - } - - "--or-input" => { - args.or_input = args_iter.next().unwrap(); - } - - "--oc-input" => { - args.oc_input = args_iter.next().unwrap(); - } - - _ => usage(&binary_name), - } - } - } - - if args.output.is_empty() || args.or_input.is_empty() || args.oc_input.is_empty() { - usage(&binary_name); - } - - args -} - -fn open_corpora(conn: &Connection, args: &Args) { - let input_file = File::open(&args.oc_input).ensure("failed to open input file"); - let mut parser = oc_parser::OpenCorporaParser::new(BufReader::new(input_file)); - db_setup::initial_oc_schema(&conn); - - let mut tx = conn - .unchecked_transaction() - .ensure("failed to start transaction"); - - let mut count = 0; - - while let Some(elem) = parser.next_element() { - // commit every 1000 things - if count % 1000 == 0 { - tx.commit().ensure("transaction failed"); - tx = conn - .unchecked_transaction() - .ensure("failed to start new transaction"); - info!("transaction committed at watermark {}", count); - } - - db_setup::insert_oc_element(&tx, elem); - - count += 1; - } - - tx.commit().ensure("final OpenCorpora commit failed"); - - info!("finished OpenCorpora import"); -} - -fn open_russian(conn: &Connection, args: &Args) { - let parser = or_parser::OpenRussianParser::new(&args.or_input); - - db_setup::initial_or_schema(conn); - - { - let tx = conn - .unchecked_transaction() - .ensure("failed to start transaction"); - - db_setup::insert_or_words(&tx, parser.words()); - tx.commit().ensure("OpenRussian words commit failed"); - } - - { - let tx = conn - .unchecked_transaction() - .ensure("failed to start transaction"); - - db_setup::insert_or_word_forms(&tx, parser.words_forms()); - tx.commit().ensure("OpenRussian word forms commit failed"); - } - - { - let tx = conn - .unchecked_transaction() - .ensure("failed to start transaction"); - - db_setup::insert_or_translations(&tx, parser.translations()); - tx.commit().ensure("OpenRussian translations commit failed"); - } - - info!("finished OpenRussian import"); -} - -fn main() { - env_logger::builder() - .filter_level(log::LevelFilter::Info) - .init(); - - let args = parse_args(); - - info!("output path: {}", args.output); - info!("OpenCorpora input path: {}", args.oc_input); - info!("OpenRussian input path: {}", args.or_input); - - let conn = Connection::open(&args.output).ensure("failed to open DB connection"); - - open_corpora(&conn, &args); - open_russian(&conn, &args); - - // afterwards: - // add actual IDs to grammemes - // properly reference keys internally - // add foreign key constraint on lemma_grammemes.grammeme -} - -/// It's like `expect`, but through `log::error`. -trait Ensure { - fn ensure>(self, msg: S) -> T; -} - -impl Ensure for Result { - fn ensure>(self, msg: S) -> T { - match self { - Ok(x) => x, - Err(err) => { - error!("{}: {}", msg.into(), err); - std::process::exit(1); - } - } - } -} - -impl Ensure for Option { - fn ensure>(self, msg: S) -> T { - match self { - Some(x) => x, - None => { - error!("{}", msg.into()); - std::process::exit(1); - } - } - } -} - -fn bail>(msg: S) -> ! { - error!("{}", msg.into()); - std::process::exit(1); -} diff --git a/corp/russian/data-import/src/mappings.rs b/corp/russian/data-import/src/mappings.rs deleted file mode 100644 index 985088a56..000000000 --- a/corp/russian/data-import/src/mappings.rs +++ /dev/null @@ -1,185 +0,0 @@ -//! Manual mapping of some data structures in OC/OR corpora. - -/// Maps the *names* of OpenRussian word types (the `word_type` field -/// in the `or_words` table) to the *set* of OpenCorpora grammemes -/// commonly attached to lemmata of this type in OC. -/// -/// Some word types just don't map over, and are omitted. Many words -/// also have an empty word type. -pub const WORD_TYPES_GRAMMEME_MAP: &'static [(&'static str, &'static [&'static str])] = &[ - ("adjective", &["ADJF"]), - ("adverb", &["ADVB"]), - ("noun", &["NOUN"]), - ("verb", &["INFN"]), // or "VERB" ... -]; - -/// Maps the *names* of OpenRussian grammemes (the `form_type` fields -/// in the `or_word_forms` table) to the *set* of OpenCorpora -/// grammemes attached to them corresponding lemma in the `oc_lemmas` -/// table. -/// -/// This *only* includes grammatical information about the lemma of -/// the word (such as whether it is a verb or other type), but *not* -/// information about the specific instance of the word (such as its -/// gender). -/// -/// Correctly corresponding these requires use of all mapping tables. -pub const FORMS_LEMMATA_GRAMMEME_MAP: &'static [(&'static str, &'static [&'static str])] = &[ - ("ru_adj_comparative", &["COMP"]), - ("ru_adj_superlative", &["ADJF", "Supr"]), - ("ru_adj_f_acc", &["ADJF"]), - ("ru_adj_f_dat", &["ADJF"]), - ("ru_adj_f_gen", &["ADJF"]), - ("ru_adj_f_inst", &["ADJF"]), - ("ru_adj_f_nom", &["ADJF"]), - ("ru_adj_f_prep", &["ADJF"]), - ("ru_adj_m_acc", &["ADJF"]), - ("ru_adj_m_dat", &["ADJF"]), - ("ru_adj_m_gen", &["ADJF"]), - ("ru_adj_m_inst", &["ADJF"]), - ("ru_adj_m_nom", &["ADJF"]), - ("ru_adj_m_prep", &["ADJF"]), - ("ru_adj_n_acc", &["ADJF"]), - ("ru_adj_n_dat", &["ADJF"]), - ("ru_adj_n_gen", &["ADJF"]), - ("ru_adj_n_inst", &["ADJF"]), - ("ru_adj_n_nom", &["ADJF"]), - ("ru_adj_n_prep", &["ADJF"]), - ("ru_adj_pl_acc", &["ADJF"]), - ("ru_adj_pl_dat", &["ADJF"]), - ("ru_adj_pl_gen", &["ADJF"]), - ("ru_adj_pl_inst", &["ADJF"]), - ("ru_adj_pl_nom", &["ADJF"]), - ("ru_adj_pl_prep", &["ADJF"]), - ("ru_adj_short_f", &["ADJS"]), - ("ru_adj_short_m", &["ADJS"]), - ("ru_adj_short_n", &["ADJS"]), - ("ru_adj_short_pl", &["ADJS"]), - ("ru_noun_pl_acc", &["NOUN"]), - ("ru_noun_pl_dat", &["NOUN"]), - ("ru_noun_pl_gen", &["NOUN"]), - ("ru_noun_pl_inst", &["NOUN"]), - ("ru_noun_pl_nom", &["NOUN"]), - ("ru_noun_pl_prep", &["NOUN"]), - ("ru_noun_sg_acc", &["NOUN"]), - ("ru_noun_sg_dat", &["NOUN"]), - ("ru_noun_sg_gen", &["NOUN"]), - ("ru_noun_sg_inst", &["NOUN"]), - ("ru_noun_sg_nom", &["NOUN"]), - ("ru_noun_sg_prep", &["NOUN"]), - ("ru_verb_gerund_past", &["GRND"]), - ("ru_verb_gerund_present", &["GRND"]), - ("ru_verb_imperative_pl", &["VERB"]), - ("ru_verb_imperative_sg", &["VERB"]), - ("ru_verb_past_f", &["VERB"]), - ("ru_verb_past_m", &["VERB"]), - ("ru_verb_past_n", &["VERB"]), - ("ru_verb_past_pl", &["VERB"]), - ("ru_verb_presfut_pl1", &["VERB"]), - ("ru_verb_presfut_pl2", &["VERB"]), - ("ru_verb_presfut_pl3", &["VERB"]), - ("ru_verb_presfut_sg1", &["VERB"]), - ("ru_verb_presfut_sg2", &["VERB"]), - ("ru_verb_presfut_sg3", &["VERB"]), - ( - "ru_base", - &[ /* nothing consistent, except often 'Fixd' */ ], - ), - ("ru_verb_participle_active_past", &["PRTF", "past", "actv"]), - ( - "ru_verb_participle_active_present", - &["PRTF", "pres", "actv"], - ), - ( - "ru_verb_participle_passive_past", - &["PRTF", "past", "passv"], - ), - ( - "ru_verb_participle_passive_present", - &["PRTF", "pres", "passv"], - ), -]; - -/// Maps the *names* of OpenRussian grammemes (the `form_type` fields -/// in the `or_word_forms` table) to the *set* of OpenCorpora -/// grammemes attached to them corresponding words in the `oc_words` -/// table. -/// -/// This includes grammatical information about the "instance" of the -/// word (such as its gender), but *not* the higher-level type -/// information about its lemma. -/// -/// Correctly corresponding these requires use of all mapping tables. -pub const FORMS_WORDS_GRAMMEME_MAP: &'static [(&'static str, &'static [&'static str])] = &[ - ("ru_adj_comparative", &["Cmp2"]), - ("ru_adj_f_acc", &["femn", "sing", "accs"]), - ("ru_adj_f_dat", &["femn", "sing", "datv"]), - ("ru_adj_f_gen", &["femn", "sing", "gent"]), - ("ru_adj_f_inst", &["femn", "sing", "ablt"]), - ("ru_adj_f_nom", &["femn", "sing", "nomn"]), - ("ru_adj_f_prep", &["femn", "sing", "loct"]), - ("ru_adj_m_acc", &["masc", "sing", "accs"]), - ("ru_adj_m_dat", &["masc", "sing", "datv"]), - ("ru_adj_m_gen", &["masc", "sing", "gent"]), - ("ru_adj_m_inst", &["masc", "sing", "ablt"]), - ("ru_adj_m_nom", &["masc", "sing", "nomn"]), - ("ru_adj_m_prep", &["masc", "sing", "loct"]), - ("ru_adj_n_acc", &["neut", "sing", "accs"]), - ("ru_adj_n_dat", &["neut", "sing", "datv"]), - ("ru_adj_n_gen", &["neut", "sing", "gent"]), - ("ru_adj_n_inst", &["neut", "sing", "ablt"]), - ("ru_adj_n_nom", &["neut", "sing", "nomn"]), - ("ru_adj_n_prep", &["neut", "sing", "loct"]), - ("ru_adj_pl_acc", &["plur", "accs"]), - ("ru_adj_pl_dat", &["plur", "datv"]), - ("ru_adj_pl_gen", &["plur", "gent"]), - ("ru_adj_pl_inst", &["plur", "ablt"]), - ("ru_adj_pl_nom", &["plur", "nomn"]), - ("ru_adj_pl_prep", &["plur", "loct"]), - ("ru_adj_short_f", &["femn", "sing"]), - ("ru_adj_short_m", &["masc", "sing"]), - ("ru_adj_short_n", &["neut", "sing"]), - ("ru_adj_short_pl", &["plur"]), - ("ru_noun_pl_acc", &["plur", "accs"]), - ("ru_noun_pl_dat", &["plur", "datv"]), - ("ru_noun_pl_gen", &["plur", "gent"]), - ("ru_noun_pl_inst", &["plur", "ablt"]), - ("ru_noun_pl_nom", &["plur", "nomn"]), - ("ru_noun_pl_prep", &["plur", "loct"]), - ("ru_noun_sg_acc", &["sing", "accs"]), - ("ru_noun_sg_dat", &["sing", "datv"]), - ("ru_noun_sg_gen", &["sing", "gent"]), - ("ru_noun_sg_inst", &["sing", "ablt"]), - ("ru_noun_sg_nom", &["sing", "nomn"]), - ("ru_noun_sg_prep", &["sing", "loct"]), - ("ru_verb_gerund_past", &["past", "V-sh"]), - ("ru_verb_imperative_pl", &["plur", "impr"]), - ("ru_verb_imperative_sg", &["sing", "impr"]), - ("ru_verb_past_f", &["femn", "sing", "past"]), - ("ru_verb_past_m", &["masc", "sing", "past"]), - ("ru_verb_past_n", &["neut", "sing", "past"]), - ("ru_verb_past_pl", &["plur", "past"]), - // these also contain "pres" or "futr", depending on the verb. - ("ru_verb_presfut_pl1", &["plur", "1per"]), - ("ru_verb_presfut_pl2", &["plur", "2per"]), - ("ru_verb_presfut_pl3", &["plur", "3per"]), - ("ru_verb_presfut_sg1", &["sing", "1per"]), - ("ru_verb_presfut_sg2", &["sing", "2per"]), - ("ru_verb_presfut_sg3", &["sing", "3per"]), - // Unclear items, probably only useful tags on lemmata - ( - "ru_verb_gerund_present", - &["pres" /* prob. something missing? */], - ), - ( - "ru_adj_superlative", - &[/* TODO: unclear, random list of grammemes?! */], - ), - ("ru_base", &[/* TODO: unclear */]), - // These have no useful tags in the forms table, only gender & - // case tagging. - ("ru_verb_participle_active_past", &[]), - ("ru_verb_participle_active_present", &[]), - ("ru_verb_participle_passive_past", &[]), - ("ru_verb_participle_passive_present", &[]), -]; diff --git a/corp/russian/data-import/src/oc_parser.rs b/corp/russian/data-import/src/oc_parser.rs deleted file mode 100644 index 8103ebd92..000000000 --- a/corp/russian/data-import/src/oc_parser.rs +++ /dev/null @@ -1,470 +0,0 @@ -use super::{bail, Ensure}; -use log::{info, warn}; -use std::str::FromStr; -use xml::attribute::OwnedAttribute; -use xml::name::OwnedName; -use xml::reader::XmlEvent; -use xml::EventReader; - -#[derive(Default, Debug)] -pub struct Grammeme { - pub parent: Option, - pub name: String, - pub alias: String, - pub description: String, -} - -/// Single form of a word (either its lemma, or the variations). -#[derive(Debug, Default)] -pub struct Variation { - pub word: String, - pub grammemes: Vec, -} - -#[derive(Debug, Default)] -pub struct Lemma { - pub id: u64, - pub lemma: Variation, - pub grammemes: Vec, - pub variations: Vec, -} - -#[derive(Debug, Default)] -pub struct LinkType { - pub id: u64, - pub name: String, -} - -#[derive(Debug, Default)] -pub struct Link { - pub id: u64, // link itself - pub from: u64, // lemma - pub to: u64, // lemma - pub link_type: u64, -} - -#[derive(Debug)] -pub enum OcElement { - Grammeme(Grammeme), - Lemma(Lemma), - LinkType(LinkType), - Link(Link), -} - -#[derive(Debug, PartialEq)] -enum ParserState { - /// Parser is not parsing any particular section and waiting for a - /// start tag instead. - Init, - - /// Parser is parsing grammemes. - Grammemes, - - /// Parser is parsing lemmata. - Lemmata, - - /// Parser is inside a lemma's actual lemma. - Lemma, - - /// Parser is parsing a morphological variation of a lemma. - Variation, - - /// Parser is parsing link types. - LinkTypes, - - /// Parser is parsing links. - Links, - - /// Parser has seen the end of the line and nothing more is - /// available. - Ended, -} - -pub struct OpenCorporaParser { - reader: EventReader, - state: ParserState, -} - -#[derive(PartialEq)] -enum SectionState { - /// Actively interested in parsing this section. - Active, - - /// Section is known, but currently ignored. - Inactive, - - /// Section is unknown (probably a bug). - Unknown, -} - -fn section_state(section: &str) -> SectionState { - match section { - "grammemes" | "lemmata" | "link_types" | "links" => SectionState::Active, - "restrictions" => SectionState::Inactive, - _ => SectionState::Unknown, - } -} - -impl OpenCorporaParser { - pub fn new(reader: R) -> Self { - let config = xml::ParserConfig::new().trim_whitespace(true); - let reader = EventReader::new_with_config(reader, config); - - Self { - reader, - state: ParserState::Init, - } - } - - /// Pull an `OcElement` out of the parser. Returns `None` if the - /// parser stream has ended. - pub fn next_element(&mut self) -> Option { - if self.state == ParserState::Ended { - return None; - } - - // Pull the next element to determine what context to enter - // next. - loop { - match &self.next() { - // no-op events that do not affect parser state - XmlEvent::Comment(_) - | XmlEvent::Whitespace(_) - | XmlEvent::ProcessingInstruction { .. } - | XmlEvent::StartDocument { .. } => continue, - XmlEvent::StartElement { name, .. } | XmlEvent::EndElement { name } - if name.local_name == "dictionary" => - { - continue - } - - // end of the file, nothing more to return - XmlEvent::EndDocument => { - self.state = ParserState::Ended; - return None; - } - - // some sections are skipped - XmlEvent::StartElement { name, .. } | XmlEvent::EndElement { name } - if section_state(&name.local_name) == SectionState::Inactive => - { - info!("skipping {} section", name.local_name); - self.skip_section(&name.local_name); - } - - // active section events start specific parser states ... - XmlEvent::StartElement { name, .. } - if section_state(&name.local_name) == SectionState::Active => - { - self.state = match name.local_name.as_str() { - "grammemes" => ParserState::Grammemes, - "lemmata" => ParserState::Lemmata, - "link_types" => ParserState::LinkTypes, - "links" => ParserState::Links, - _ => unreachable!(), - }; - } - - // ... or end them - XmlEvent::EndElement { name, .. } - if section_state(&name.local_name) == SectionState::Active => - { - // TODO: assert that the right section ended - self.state = ParserState::Init; - } - - // actual beginning of an actual element, dispatch accordingly - event @ XmlEvent::StartElement { - name, attributes, .. - } => match &self.state { - ParserState::Grammemes => { - return Some(OcElement::Grammeme(self.parse_grammeme(name, attributes))) - } - - ParserState::Lemmata => { - return Some(OcElement::Lemma(self.parse_lemma(name, attributes))) - } - - ParserState::LinkTypes => { - return Some(OcElement::LinkType(self.parse_link_type(name, attributes))) - } - - ParserState::Links if name.local_name == "link" => { - return Some(OcElement::Link(self.parse_link(attributes))) - } - - ParserState::Init | ParserState::Ended => bail(format!( - "parser received an unexpected start element while in state {:?}: {:?}", - self.state, event - )), - - other => bail(format!( - "next_element() called while parser was in state {:?}", - other - )), - }, - - // finally, events that indicate a bug if they're - // encountered here - event @ XmlEvent::EndElement { .. } - | event @ XmlEvent::CData(_) - | event @ XmlEvent::Characters(_) => { - bail(format!("unexpected XML event: {:?}", event)) - } - } - } - } - - /// Skip a section by advancing the parser state until we see an - /// end element for the skipped section. - fn skip_section(&mut self, section: &str) { - loop { - match self.next() { - XmlEvent::EndElement { name } if name.local_name == section => return, - _ => continue, - } - } - } - - fn next(&mut self) -> XmlEvent { - self.reader.next().ensure("XML parsing failed") - } - - /// Parse a tag that should have plain string content. - fn parse_string(&mut self, tag_name: &str) -> String { - let mut out = String::new(); - - loop { - match self.next() { - // ignore irrelevant things - XmlEvent::Comment(_) | XmlEvent::Whitespace(_) => continue, - - // set the content - XmlEvent::Characters(content) => { - out = content; - } - - // expect the end of the element - XmlEvent::EndElement { name } if name.local_name == tag_name => return out, - - // fail on everything unexpected - event => bail(format!( - "unexpected element while parsing <{}>: {:?}", - tag_name, event - )), - } - } - } - - /// Parse a single `` tag. - fn parse_grammeme(&mut self, name: &OwnedName, attributes: &[OwnedAttribute]) -> Grammeme { - if name.local_name != "grammeme" { - bail(format!( - "expected to parse a grammeme, but found <{}>", - name.local_name - )); - } - - let mut grammeme = Grammeme::default(); - - for attr in attributes { - if attr.name.local_name == "parent" && !attr.value.is_empty() { - grammeme.parent = Some(attr.value.clone()); - } - } - - loop { - match self.next() { - // ignore irrelevant things - XmlEvent::Comment(_) | XmlEvent::Whitespace(_) => continue, - - // expect known tags - XmlEvent::StartElement { name, .. } if name.local_name == "name" => { - grammeme.name = self.parse_string("name"); - } - - XmlEvent::StartElement { name, .. } if name.local_name == "alias" => { - grammeme.alias = self.parse_string("alias"); - } - - XmlEvent::StartElement { name, .. } if name.local_name == "description" => { - grammeme.description = self.parse_string("description"); - } - - // handle end of the grammeme - XmlEvent::EndElement { name } if name.local_name == "grammeme" => break, - - // fail on everything unexpected - event => bail(format!( - "unexpected element while parsing : {:?}", - event - )), - } - } - - grammeme - } - - fn parse_lemma(&mut self, name: &OwnedName, attributes: &[OwnedAttribute]) -> Lemma { - if name.local_name != "lemma" { - bail(format!( - "expected to parse a lemma, but found <{}>", - name.local_name - )); - } - - self.state = ParserState::Lemma; - let mut lemma = Lemma::default(); - - for attr in attributes { - if attr.name.local_name == "id" { - lemma.id = u64::from_str(&attr.value).ensure("failed to parse lemma ID"); - } - } - - loop { - match self.next() { - // has ended - XmlEvent::EndElement { name } if name.local_name == "lemma" => { - self.state = ParserState::Lemmata; - return lemma; - } - - // actual lemma content - XmlEvent::StartElement { - name, attributes, .. - } => { - match name.local_name.as_str() { - // beginning to parse the lemma itself - "l" => { - lemma.lemma.word = attributes - .into_iter() - .find(|attr| attr.name.local_name == "t") - .map(|attr| attr.value) - .ensure(format!("lemma {} had no actual word", lemma.id)); - } - - // parsing a lemma variation - "f" => { - self.state = ParserState::Variation; - - let word = attributes - .into_iter() - .find(|attr| attr.name.local_name == "t") - .map(|attr| attr.value) - .ensure(format!( - "variation of lemma {} had no actual word", - lemma.id - )); - - lemma.variations.push(Variation { - word, - grammemes: vec![], - }); - } - - // parse a grammeme association - "g" => { - let grammeme = attributes - .into_iter() - .find(|attr| attr.name.local_name == "v") - .map(|attr| attr.value) - .ensure(format!( - "grammeme association in lemma {} missing ID", - lemma.id - )); - - match self.state { - ParserState::Lemma => { - lemma.grammemes.push(grammeme); - } - - ParserState::Variation => { - lemma - .variations - .last_mut() - .ensure("variations should be non-empty") - .grammemes - .push(grammeme); - } - - _ => bail(format!("invalid parser state: encountered grammeme association while in {:?}", self.state)), - } - } - - other => bail(format!("unexpected element while parsing lemma: {other}")), - }; - } - - XmlEvent::EndElement { name } => match name.local_name.as_str() { - "l" if self.state == ParserState::Lemma => continue, - "f" if self.state == ParserState::Variation => { - self.state = ParserState::Lemma; - continue; - } - "g" => continue, - other => bail(format!( - "unexpected while parsing lemma {}", - lemma.id - )), - }, - - _ => continue, - } - } - } - - fn parse_link_type(&mut self, name: &OwnedName, attributes: &[OwnedAttribute]) -> LinkType { - if name.local_name != "type" { - bail(format!( - "expected to parse a link type, but found <{}>", - name.local_name - )); - } - - let mut link_type = LinkType::default(); - - for attr in attributes { - if attr.name.local_name == "id" { - link_type.id = u64::from_str(&attr.value).ensure("failed to parse link type ID"); - } - } - - link_type.name = self.parse_string("type"); - link_type - } - - fn parse_link(&mut self, attributes: &[OwnedAttribute]) -> Link { - let mut link = Link::default(); - - for attr in attributes { - let i_val = || u64::from_str(&attr.value).ensure("failed to parse link field"); - - match attr.name.local_name.as_str() { - "id" => { - link.id = i_val(); - } - "from" => { - link.from = i_val(); - } - "to" => { - link.to = i_val(); - } - "type" => { - link.link_type = i_val(); - } - - other => { - warn!("unexpected attribute {} on ", other); - continue; - } - } - } - - // expect the end of the element, though since these - // are empty it should be immediate. - self.skip_section("link"); - - link - } -} diff --git a/corp/russian/data-import/src/or_parser.rs b/corp/russian/data-import/src/or_parser.rs deleted file mode 100644 index 8bfc61dbe..000000000 --- a/corp/russian/data-import/src/or_parser.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Parser for the OpenRussian data format. -//! -//! Note that when exporting OpenRussian data from the project you -//! have to choose an encoding. We choose tab-separated CSV files, as -//! tabs have a very low probability of actually appearing in the -//! input data and this skips some potential encoding issues. - -use super::Ensure; -use serde::Deserialize; -use std::fs::File; -use std::io::BufReader; -use std::path::PathBuf; - -/// A word from the `words` table. -#[derive(Debug, Deserialize)] -pub struct Word { - pub id: usize, - pub position: String, // TODO: unknown - pub bare: String, // TODO: unknown - pub accented: String, // TODO: unknown - pub derived_from_word_id: Option, - pub rank: Option, - pub disabled: String, // TODO: unknown - pub audio: String, // TODO: unknown - pub usage_en: String, // TODO: unknown - pub usage_de: String, // TODO: unknown - pub number_value: String, // TODO: unknown - - #[serde(rename = "type")] - pub word_type: String, // TODO: unknown - - pub level: String, // TODO: unknown - pub created_at: String, // TODO: unknown -} - -/// A word form from the `words_forms` table. -#[derive(Debug, Deserialize)] -pub struct WordForm { - pub id: usize, - pub word_id: usize, - pub form_type: String, - pub position: String, - pub form: String, - pub form_bare: String, -} - -/// A translation from the `translations` table. -#[derive(Debug, Deserialize)] -pub struct Translation { - pub id: usize, - pub lang: String, - pub word_id: usize, - pub position: String, - pub tl: String, // unknown - pub example_ru: String, - pub example_tl: String, - pub info: String, -} - -pub struct OpenRussianParser { - or_directory: PathBuf, -} - -pub type DynIter = Box>; - -impl OpenRussianParser { - pub fn new>(path: P) -> Self { - OpenRussianParser { - or_directory: path.into(), - } - } - - pub fn words(&self) -> DynIter { - self.parser_for("words.csv") - } - - pub fn words_forms(&self) -> DynIter { - self.parser_for("words_forms.csv") - } - - pub fn translations(&self) -> DynIter { - self.parser_for("translations.csv") - } - - fn parser_for( - &self, - file_name: &str, - ) -> Box> { - let mut path = self.or_directory.clone(); - path.push(file_name); - - let reader = csv::ReaderBuilder::new() - .delimiter(b'\t') - .from_reader(BufReader::new( - File::open(&path).ensure("failed to open words.csv"), - )); - - Box::new(reader.into_deserialize().map(|result| { - result.ensure(format!( - "failed to deserialize {}", - std::any::type_name::() - )) - })) - } -} diff --git a/corp/russian/predlozhnik/.gitignore b/corp/russian/predlozhnik/.gitignore deleted file mode 100644 index 58eaf3e32..000000000 --- a/corp/russian/predlozhnik/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target/ -**/*.rs.bk -dist/ diff --git a/corp/russian/predlozhnik/Cargo.lock b/corp/russian/predlozhnik/Cargo.lock deleted file mode 100644 index 369b54271..000000000 --- a/corp/russian/predlozhnik/Cargo.lock +++ /dev/null @@ -1,481 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "boolinator" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" - -[[package]] -name = "bumpalo" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "gloo" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23947965eee55e3e97a5cd142dd4c10631cc349b48cecca0ed230fd296f568cd" -dependencies = [ - "gloo-console", - "gloo-dialogs", - "gloo-events", - "gloo-file", - "gloo-render", - "gloo-storage", - "gloo-timers", - "gloo-utils", -] - -[[package]] -name = "gloo-console" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-dialogs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-events" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-file" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" -dependencies = [ - "gloo-events", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-render" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-storage" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-timers" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-utils" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40913a05c8297adca04392f707b1e73b12ba7b8eab7244a4961580b1fd34063c" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itoa" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "once_cell" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" - -[[package]] -name = "predlozhnik" -version = "0.1.0" -dependencies = [ - "lazy_static", - "maplit", - "wasm-bindgen", - "yew", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.101", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustversion" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "scoped-tls-hkt" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e9d7eaddb227e8fbaaa71136ae0e1e913ca159b86c7da82f3e8f0044ad3a63" - -[[package]] -name = "serde" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.101", -] - -[[package]] -name = "serde_json" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "syn" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.101", -] - -[[package]] -name = "unicode-ident" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.28", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.28", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "yew" -version = "0.19.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1ccb53e57d3f7d847338cf5758befa811cabe207df07f543c06f502f9998cd" -dependencies = [ - "console_error_panic_hook", - "gloo", - "gloo-utils", - "indexmap", - "js-sys", - "scoped-tls-hkt", - "slab", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yew-macro", -] - -[[package]] -name = "yew-macro" -version = "0.19.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fab79082b556d768d6e21811869c761893f0450e1d550a67892b9bce303b7bb" -dependencies = [ - "boolinator", - "lazy_static", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.101", -] diff --git a/corp/russian/predlozhnik/Cargo.toml b/corp/russian/predlozhnik/Cargo.toml deleted file mode 100644 index 7e42da891..000000000 --- a/corp/russian/predlozhnik/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "predlozhnik" -version = "0.1.0" -edition = "2021" - -[dependencies] -maplit = "1.0" -lazy_static = "1.4" -yew = "0.19" - -# needs to be in sync with nixpkgs -wasm-bindgen = "= 0.2.100" diff --git a/corp/russian/predlozhnik/default.nix b/corp/russian/predlozhnik/default.nix deleted file mode 100644 index 495e977c1..000000000 --- a/corp/russian/predlozhnik/default.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ lib, pkgs, ... }: - -let - wasmRust = pkgs.rust-bin.stable.latest.default.override { - targets = [ "wasm32-unknown-unknown" ]; - }; - - cargoToml = with builtins; fromTOML (readFile ./Cargo.toml); - - wasmBindgenMatch = - cargoToml.dependencies.wasm-bindgen == "= ${pkgs.wasm-bindgen-cli.version}"; - - assertWasmBindgen = assert (lib.assertMsg wasmBindgenMatch '' - Due to instability in the Rust WASM ecosystem, the trunk build - tool enforces that the Cargo-dependency version of `wasm-bindgen` - MUST match the version of the CLI supplied in the environment. - - This can get out of sync when nixpkgs is updated. To resolve it, - wasm-bindgen must be bumped in the Cargo.toml file and cargo needs - to be run to resolve the dependencies. - - Versions of `wasm-bindgen` in Cargo.toml: - - Expected: '= ${pkgs.wasm-bindgen-cli.version}' - Actual: '${cargoToml.dependencies.wasm-bindgen}' - ''); pkgs.wasm-bindgen-cli; - - deps = with pkgs; [ - binaryen - sass - wasmRust - trunk - assertWasmBindgen - ]; - -in -pkgs.rustPlatform.buildRustPackage rec { - pname = "predlozhnik"; - version = "canon"; - src = lib.cleanSource ./.; - cargoLock.lockFile = ./Cargo.lock; - - buildPhase = '' - export PATH=${lib.makeBinPath deps}:$PATH - mkdir home - export HOME=$PWD/.home - trunk build --release -d $out - ''; - - dontInstall = true; -} diff --git a/corp/russian/predlozhnik/index.css b/corp/russian/predlozhnik/index.css deleted file mode 100644 index 3529574c4..000000000 --- a/corp/russian/predlozhnik/index.css +++ /dev/null @@ -1,29 +0,0 @@ -body { - max-width: 800px; - margin: 40px auto; -} - -#header { - display: flex; - flex-direction: column; -} - -.btn.btn-ghost:disabled { - border-color: #9f9f9f; - color: #9f9f9f; -} - -#predlogi,#padezhi { - display: flex; - flex-direction: row; - flex-wrap: wrap; -} - -.btn { - margin: 3px; - flex-grow: 1; -} - -.footer { - text-align: right; -} diff --git a/corp/russian/predlozhnik/index.html b/corp/russian/predlozhnik/index.html deleted file mode 100644 index 6af1adc0b..000000000 --- a/corp/russian/predlozhnik/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - Предложник - - - - - - - - - diff --git a/corp/russian/predlozhnik/src/main.rs b/corp/russian/predlozhnik/src/main.rs deleted file mode 100644 index 56ff04808..000000000 --- a/corp/russian/predlozhnik/src/main.rs +++ /dev/null @@ -1,345 +0,0 @@ -use yew::html::Scope; -use yew::prelude::*; - -use lazy_static::lazy_static; -use maplit::hashmap; -use std::collections::BTreeSet; -use std::collections::HashMap; - -#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -enum Падеж { - Именительный, - Родительный, - Дательный, - Винительный, - Творительный, - Предложный, -} - -impl Падеж { - const ВСЕ: [Self; 6] = [ - Self::Именительный, - Self::Родительный, - Self::Дательный, - Self::Винительный, - Self::Творительный, - Self::Предложный, - ]; - - fn вопрос(&self) -> &str { - use Падеж::*; - match self { - Именительный => "кто? Что?", - Родительный => "кого? Чего?", - Дательный => "кому? Чему?", - Винительный => "кого? Что?", - Творительный => "кем? Чем?", - Предложный => "ком? Чём?", - } - } -} - -lazy_static! { - static ref ПО_ПРЕДЛОГУ: HashMap<&'static str, BTreeSet<Падеж>> = { - use Падеж::*; - - hashmap! { - "без" => BTreeSet::from([Родительный]), - "близ" => BTreeSet::from([Родительный]), - "в" => BTreeSet::from([Винительный, Предложный]), - "вместо" => BTreeSet::from([Родительный]), - "вне" => BTreeSet::from([Родительный]), - "внутри" => BTreeSet::from([Родительный]), - "возле" => BTreeSet::from([Родительный]), - "вокруг" => BTreeSet::from([Родительный]), - "вроде" => BTreeSet::from([Родительный]), - "для" => BTreeSet::from([Родительный]), - "до" => BTreeSet::from([Родительный]), - "за" => BTreeSet::from([Винительный, Творительный]), - "из" => BTreeSet::from([Родительный]), - "из-за" => BTreeSet::from([Родительный]), - "из-под" => BTreeSet::from([Родительный]), - "к" => BTreeSet::from([Дательный]), - "кроме" => BTreeSet::from([Родительный]), - "между" => BTreeSet::from([Творительный, Родительный]), - "на" => BTreeSet::from([Винительный, Предложный]), - "над" => BTreeSet::from([Творительный]), - "нет" => BTreeSet::from([Родительный]), - "о" => BTreeSet::from([Винительный, Предложный]), - "около" => BTreeSet::from([Родительный]), - "от" => BTreeSet::from([Родительный]), - "перед" => BTreeSet::from([Творительный]), - "по" => BTreeSet::from([Винительный, Дательный, Предложный]), - "под" => BTreeSet::from([Винительный, Творительный]), - "после" => BTreeSet::from([Родительный]), - "при" => BTreeSet::from([Предложный]), - "про" => BTreeSet::from([Винительный]), - "ради" => BTreeSet::from([Родительный]), - "с" => BTreeSet::from([Родительный, Винительный, Творительный]), - "сквозь" => BTreeSet::from([Винительный]), - "среди" => BTreeSet::from([Родительный]), - "у" => BTreeSet::from([Родительный]), - "через" => BTreeSet::from([Винительный]), - } - }; - static ref ПО_ПАДЕЖУ: HashMap<Падеж, BTreeSet<&'static str>> = { - let mut m = hashmap!(); - - for c in Падеж::ВСЕ { - let mut предлоги: BTreeSet<&'static str> = BTreeSet::new(); - for (k, v) in &*ПО_ПРЕДЛОГУ { - if v.contains(&c) { - предлоги.insert(k); - } - } - - m.insert(c, предлоги); - } - - m - }; - static ref ПАДЕЖИ: BTreeSet<Падеж> = BTreeSet::from(Падеж::ВСЕ); - static ref ПРЕДЛОГИ: BTreeSet<&'static str> = { - let mut s: BTreeSet<&'static str> = BTreeSet::new(); - - for п in ПО_ПРЕДЛОГУ.keys() { - s.insert(п); - } - - s - }; -} - -fn исключение(предлог: &str, падеж: Падеж) -> Option { - use Падеж::*; - - match (предлог, падеж) { - ("в", Винительный) => Some(html! {"Во что? В кого?"}), - - ("о", Винительный) => Some(html! { - <> -

    {"О кого? Обо что?"}

    -

    {"Редко используется. Например:"}

    -
      -
    • {"Удариться о притолоку."}
    • -
    • {"точить о камень."}
    • -
    - - }), - - ("между", Родительный) => Some(html! { - <> -

    {"Между чего?"}

    -

    {"Редко используется. Только в идиомах и старой литературе:"}

    -
      -
    • {"Читаю между строк."}
    • -
    - - }), - - _ => None, - } -} - -enum Сообщение { - ВыбралПадеж(Option<Падеж>), - ВыбралПредлог(Option<&'static str>), -} - -#[derive(Default)] -struct Модель { - падеж: Option<Падеж>, - предлог: Option<&'static str>, -} - -struct Вывод { - доступные_падежи: BTreeSet<Падеж>, - доступные_предлоги: BTreeSet<&'static str>, - объяснение: Option, -} - -fn объясни(падеж: Падеж, предлог: &str) -> Html { - let иск = match исключение(предлог, падеж) { - Some(exp) => html! { exp }, - None => html! { format!("{} {}", предлог, падеж.вопрос()) }, - }; - - html! { -
    -
    -

    {"Пример:"}

    - {иск} -
    - } -} - -fn ограничить(м: &Модель) -> Вывод { - match (м.падеж, &м.предлог) { - (Some(пж), Some(пл)) => Вывод { - доступные_падежи: (*ПО_ПРЕДЛОГУ)[пл].clone(), - доступные_предлоги: (*ПО_ПАДЕЖУ)[&пж].clone(), - объяснение: Some(объясни(пж, пл)), - }, - - (Some(пж), None) => Вывод { - доступные_падежи: BTreeSet::from([пж]), - доступные_предлоги: (*ПО_ПАДЕЖУ)[&пж].clone(), - объяснение: None, - }, - - (None, Some(пл)) => Вывод { - доступные_падежи: (*ПО_ПРЕДЛОГУ)[пл].clone(), - доступные_предлоги: BTreeSet::from([*пл]), - объяснение: None, - }, - - (None, None) => Вывод { - доступные_падежи: ПАДЕЖИ.clone(), - доступные_предлоги: ПРЕДЛОГИ.clone(), - объяснение: None, - }, - } -} - -fn класс_кнопки(выбран: bool, доступен: bool) -> String { - let класс = "btn ".to_string(); - класс - + match (выбран, доступен) { - (true, _) => "btn-primary", - (false, true) => "btn-ghost btn-primary", - (false, false) => "btn-ghost btn-default", - } -} - -fn покажи_предлог( - link: &Scope<Модель>, - м: &Модель, - вв: &Вывод, - п: &'static str, -) -> Html { - let выбран = м.предлог == Some(п); - let доступен = вв.доступные_предлоги.contains(п); - let класс = класс_кнопки(выбран, доступен); - - html! { - - } -} - -fn покажи_падеж( - link: &Scope<Модель>, м: &Модель, вв: &Вывод, п: Падеж -) -> Html { - let выбран = м.падеж == Some(п); - let доступен = вв.доступные_падежи.contains(&п); - let класс = класс_кнопки(выбран, доступен); - - html! { - - } -} - -impl Component for Модель { - type Message = Сообщение; - type Properties = (); - - fn create(_ctx: &Context) -> Self { - Default::default() - } - - fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { - match msg { - Сообщение::ВыбралПадеж(пж) => self.падеж = пж, - Сообщение::ВыбралПредлог(пл) => self.предлог = пл, - } - - true - } - - fn view(&self, ctx: &Context) -> Html { - let вв = ограничить(self); - let link = ctx.link(); - - let кнопки_предлогов = ПРЕДЛОГИ - .iter() - .map(|п| покажи_предлог(link, self, &вв, п)) - .collect::(); - - let кнопки_падежов = ПАДЕЖИ - .iter() - .map(|п| покажи_падеж(link, self, &вв, *п)) - .collect::(); - - let объяснение = вв.объяснение.map(|exp| exp).unwrap_or_else(|| html! {}); - - let footer = html! { - - }; - - let код_рекламы = r#" -window.yaContextCb.push(()=>{ - Ya.Context.AdvManager.render({ - renderTo: 'yandex_rtb_R-A-1773485-1', - blockId: 'R-A-1773485-1' - }) -}) -"#; - - let реклама = html! { - - }; - - html! { - <> - - -

    {"Выбирай предлог:"}

    -
    - {кнопки_предлогов} -
    -
    - -

    {"Выбирай падеж:"}

    -
    - {кнопки_падежов} -
    - - {объяснение} - {footer} - {реклама} - - } - } -} - -fn main() { - yew::start_app::<Модель>(); -} diff --git a/corp/website/content-en.md b/corp/website/content-en.md deleted file mode 100644 index 6d27cf671..000000000 --- a/corp/website/content-en.md +++ /dev/null @@ -1,94 +0,0 @@ - - - ----------------- - -Welcome to the website of TVL LLC, the corporate face of the [**TVL**][tvl] Community. -We are a technology company headquartered in Moscow, working with a variety of topics: - -*
    Monorepos. Effective ways for an organisation to - structure their internal codebase in a single repository, unify tooling across - languages, and reduce accidental - complexity in software development. - - With experience from companies like Google, Spotify and DeepMind, we help - organisations of different sizes to find streamlined software development - workflows that reduce mental load and increase code quality. - - We use our own monorepo solutions in our internal software development flows, - and all of this is visible in our [public monorepo][depot]. -
    -*
    Nix. We believe that functional and declarative - computer systems are a massive and as-of-yet underrated step forward for - computing, and that Nix is the most promising solution for this - purpose. - - Nix allows companies to significantly improve in areas such as: - - 1. Unification of development and production environments, leading to fewer - surprises when deploying an application. - - 2. Tailoring their stack to their use-case. Avoid the complexity of running - something like Kubernetes while you are scaling up, but *also* avoid the - complexity of rewriting your infrastructure stack once you need it. - - 3. Unified developer tooling across different programming languages, without - the overhead of using something like Bazel. - - Its radically new model can bring many other advantages which depend - on the exact use-cases. -
    - -* **Software development**. We offer a wide range of software development - services. Whether you need assistance with existing projects, or want to create - a new solution from scratch, we can help. We specialize in helping - organizations avoid the trap of building overly complex systems that don't - meet their needs. - -* **Site Reliability Engineering (SRE)**. We can help with many infrastructure - concerns, such as deployment, scaling, monitoring, troubleshooting analysing - failure points in existing solutions. We offer this for any Linux-based - technology stack. - --------------- - -We support open-source software development, and prefer to work on our projects -in the open. Some of our projects are: - -* The public TVL [monorepo][depot], the **depot**, is a demonstration of the - monorepo tooling we have been working on for the last couple of years. - - It contains many open-source projects, work by lots of international - open-source contributors, and all public code of the company. - -* [**Tvix**][tvix], a new implementation of Nix that is fully compatible with - existing Nix code. Architectural differences between Nix and Tvix allow us to - develop tooling that is better tailored to collaborative software development, - and to develop domestic, high-quality solutions for CI/CD. - - We run a demonstration of some parts of Tvix online as [tvixbolt]. - -* [**Nixery**][nixery] is a service that lets users easily build and deploy - ad-hoc container images from their software build definitions. - -* Out of personal interest, we also develop free tools that help with learning - the Russian language, such as [**Предложник**][predlozhnik]. - --------------- - -Reach out to us at **contact@tvl.su** if you are interested in working with us. - -TVL originated as an international community of software developers that wanted -to socialise and collaborate on projects. Many people from all over the world -contribute to our open-source software projects. Check out the [TVL community -website][tvl] for more information. - -[tvl]: https://tvl.fyi -[tvix]: https://tvl.fyi/blog/rewriting-nix -[nixery]: https://nixery.dev -[predlozhnik]: https://predlozhnik.ru/ -[depot]: https://cs.tvl.fyi/depot diff --git a/corp/website/content-ru.md b/corp/website/content-ru.md deleted file mode 100644 index 637f366a1..000000000 --- a/corp/website/content-ru.md +++ /dev/null @@ -1,98 +0,0 @@ - - - ----------------- - -Добро пожаловать на официальный сайт ТВЛ. Мы - технологическая компания в -Москве, занимающаяся следующими направлениями: - -*
    Монорепозитории. Набор эффективных способов по - структурированию внутренней кодовой базы в едином репозитории, унификации - инструментов разработки между различными языками, а также снижения побочныx - сложностей в разработке ПО. - - Наш опыт работы с такими компаниями, как Google, Spotify и DeepMind, позволяет - нам помочь организациям любого размера оптимизировать процессы разработки ПО, - уменьшить нагрузку на разработчиков и улучшить качество кода. - - Мы используем собственные монорепо-решения во внутренних процессах разработки - ПО. Всё это можно увидеть в нашем [публичном монорепозитории][depot]. -
    -*
    Nix. Мы считаем, что функциональные и декларативные - компьютерные системы являются важным и пока ещё недооцененным подходом к - вычислениям, и Nix является наиболее - перспективным решением в этом направлении. - - Nix позволяет компаниям значительно улучшить следующие области: - - 1. Унификация сред разработки и производства, что приводит к меньшему - количеству сюрпризов при развертывании приложения. - - 2. Настройка стека компании под конкретные задачи. Избегайте сложности - инструментов вроде Kubernetes при масштабировании, но также избегайте - изменения всей инфраструктуры по малейшей необходимости. - - 3. Единый набор инструментов разработки для различных языков программирования, - без сложностей, связанных с использованием Bazel и подобных. - - Nix прелагает радикально новую модель, которая может принести множество - преимуществ для каждого способа использования. -
    - -* **Разработка программного обеспечения**. Мы предлагаем широкий спектр услуг по - разработке ПО. Вне зависимости от того, нуждаетесь вы в поддержке существующих - проектов или хотите создать новое решение с нуля, мы можем вам помочь. Наша - задача - помочь компаниям избежать ловушки излишне сложных систем, которые не - соответствуют их потребностям. - -* **Site Reliability Engineering (SRE)**. Мы можем помочь с множеством - инфраструктурных проблем, таких как развертывание, масштабирование, - мониторинг, анализ и устранение неполадок в существующих решениях. Мы - работаем с любыми технологическими стеками на базе Linux. - --------------- - -Мы поддерживаем разработку программного обеспечения с открытым исходным кодом и -предпочитаем работать над нашими проектами в открытом доступе. Некоторые из -наших проектов: - -* Публичный репозиторий ТВЛ, [**depot**][depot], является демонстрацией - инструментов монорепо, над которыми мы работаем в течение последних нескольких - лет. - - В нем содержится множество проектов c открытым исходным кодом, результат - работы разработчиков из разных стран, а также весь публичный код компании. - -* [**Tvix**][tvix] - это новая реализация Nix, которая полностью совместима с - существующим кодом Nix. Архитектурные различия между Nix и Tvix позволяют нам - разрабатывать инструменты, которые лучше подходят для совместной разработки - программного обеспечения, и разрабатывать отечественные качественные решения - для CI/CD. - - Мы запускаем демонстрацию некоторых компонентов Tvix онлайн: [tvixbolt][]. - -* [Nixery][nixery] - это сервис, который позволяет пользователям с легкостью - создавать и развёртывать образы контейнеров напрямую из их инструкций сборки - софта. - -* Из личных интересов, мы также разрабатываем бесплатные инструменты, которые - помогают в изучении русского языка, такие как [**Предложник**][predlozhnik]. - -Свяжитесь с нами по адресу **contact@tvl.su**, если вы заинтересованы в -сотрудничестве с нами. - -ТВЛ возникла как международное сообщество программистов для общения и совместной -работы над проектами. Люди из разных стран вносят свой вклад в наши открытые -проекты по разработке программного обеспечения. Посетите [веб-сайт сообщества -TVL][tvl], чтобы узнать больше. - -[tvl]: https://tvl.fyi -[tvix]: https://tvl.fyi/blog/rewriting-nix -[nixery]: https://nixery.dev -[predlozhnik]: https://predlozhnik.ru/ -[depot]: https://cs.tvl.fyi/depot -[tvixbolt]: https://bolt.tvix.dev/ diff --git a/corp/website/default.nix b/corp/website/default.nix deleted file mode 100644 index a8ac132cb..000000000 --- a/corp/website/default.nix +++ /dev/null @@ -1,59 +0,0 @@ -{ depot, pkgs, ... }: - - -let - # https://developers.google.com/search/docs/advanced/structured-data/logo - structuredData = { - "@context" = "https://schema.org"; - "@type" = "Organisation"; - url = "https://tvl.su"; - logo = "https://static.tvl.fyi/latest/logo-animated.svg"; - }; - - common = description: { - extraFooter = "\n|\n © ООО ТВЛ"; - staticUrl = "https://static.tvl.su/latest"; - - extraHead = '' - - - - ''; - }; - - descEn = "TVL provides technology consulting for monorepos, Nix, and other SRE/DevOps/Software Engineering topics."; - indexEn = depot.web.tvl.template ({ - title = "TVL (The Virus Lounge) - Software consulting"; - content = builtins.readFile ./content-en.md; - } // common descEn); - - descRu = "TVL предоставляет технологическое консультирование по монорепозиториям, Nix и другим темам SRE/DevOps/Software Engineering."; - indexRu = depot.web.tvl.template ({ - title = "ТВЛ - Монорепозитории, SRE, Nix, программное обеспечение"; - content = builtins.readFile ./content-ru.md; - } // common descRu); -in -pkgs.runCommand "corp-website" { } '' - mkdir -p $out/{en,ru} - cp ${indexEn} $out/index.html - cp ${indexEn} $out/en/index.html - cp ${indexRu} $out/ru/index.html -'' diff --git a/default.nix b/default.nix index 8ccb8125d..c6454843a 100644 --- a/default.nix +++ b/default.nix @@ -23,13 +23,6 @@ let ''; exceptions = [ - # machines is allowed to access //users for several reasons: - # - # 1. User SSH keys are set in //users. - # 2. Some personal websites or demo projects are served from there. - [ "ops" "machines" "bugry" ] - [ "ops" "machines" "nevsky" ] - # Due to evaluation order this also affects these targets. # TODO(tazjin): Can this one be removed somehow? [ "ops" "nixos" ] @@ -37,28 +30,13 @@ let ]; }; - # Disallow access to //corp from other depot parts. - corpFilter = readTree.restrictFolder { - folder = "corp"; - reason = '' - Code under //corp may use incompatible licensing terms with - other depot parts and should not be used anywhere else. - ''; - - exceptions = [ - # For the same reason as above, machines are exempt to serve the corp - # website. - [ "ops" "nixos" ] - [ "ops" "machines" "all-systems" ] - ]; - }; - readDepot = depotArgs: readTree { args = depotArgs; path = ./.; - filter = parts: args: corpFilter parts (usersFilter parts args); + filter = parts: args: usersFilter parts args; scopedArgs = { - __findFile = _: _: throw "Do not import from NIX_PATH in the depot!"; + # FIXME(Lix): this cannot work in Lix itself. + # __findFile = _: _: throw "Do not import from NIX_PATH in the depot!"; builtins = builtins // { currentSystem = throw "Use localSystem from the readTree args instead of builtins.currentSystem!"; }; @@ -103,20 +81,6 @@ readTree.fix (self: (readDepot { # Additionally targets can be excluded from CI by adding them to the # list below. ci.excluded = [ - # xanthous and related targets are disabled until cl/9186 is submitted - self.users.aspen.xanthous - self.users.aspen.system.system.mugwumpSystem - - # Temporarily disabled after cl/11289. Hopefully these failures are transient - # and will disappear with the next channel bump. - self.users.wpcarro.nixos.avaSystem - self.users.wpcarro.nixos.kyokoSystem - self.users.wpcarro.nixos.marcusSystem - self.users.wpcarro.nixos.tarascoSystem - - # Disabled because it depends on an unstable FOD, which, when updated, - # breaks the build. Needs to be investigated by flokli. - self.users.flokli.keyboards.corneish_zen.firmware ]; # List of all buildable targets, for CI purposes. diff --git a/fun/defer_rs/.gitignore b/fun/defer_rs/.gitignore deleted file mode 100644 index 6aa106405..000000000 --- a/fun/defer_rs/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target/ -**/*.rs.bk -Cargo.lock diff --git a/fun/defer_rs/Cargo.toml b/fun/defer_rs/Cargo.toml deleted file mode 100644 index 0fcd60373..000000000 --- a/fun/defer_rs/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "defer" -version = "0.1.0" -authors = ["Vincent Ambo "] - -[dependencies] diff --git a/fun/defer_rs/README.md b/fun/defer_rs/README.md deleted file mode 100644 index 160158d17..000000000 --- a/fun/defer_rs/README.md +++ /dev/null @@ -1,53 +0,0 @@ -defer in Rust -============= - -After a Hacker News discussion about implementing Go's `defer` keyword in C++, -I stumbled upon [this comment](https://news.ycombinator.com/item?id=15523589) -and more specifically this response to it by "Occivink": - -> There's plenty of one-time cases where you don't want to declare an entire -> class but still enjoy scope-based functions. - -Specificall the "don't want to declare an entire class" suggests that languages -like C++ have high friction for explaining your desired invariant (cleanup is -run when `$thing` is destroyed) to the compiler. - -It seems like most languages either hand-wave this away (*cough* Java *cough*) -or use what seems like a workaround (`defer`). - -Rust has the so-called `Drop` trait, which is a typeclass that contains a single -method with no return value that is run when a variable is dropped (i.e. goes out -of scope). - -This works fine for most general cases - i.e. closing file handlers - but can -get complicated if other use-cases of `defer` are considered: - -* returning an error-value by mutating a reference in the enclosing scope (oh boy) -* deferring a decision about when/whether to run cleanup to the caller - -While thinking about how to do this with the `Drop` trait I realised that `defer` -can actually be trivially implemented in Rust, using `Drop`. - -A simple implementation of `defer` can be seen in [defer.rs](examples/defer.rs), -an implementation using shared mutable state for error returns is in the file -[defer-with-error.rs](examples/defer-with-error.rs) and an implementation that -allows cleanup to be *cancelled* (don't _actually_ do this, it leaks a pointer) -is in [undefer.rs](examples/undefer.rs). - -Whether any of this is actually useful is not up to me to decide. I haven't -actually had a real-life need for this. - -You can run the examples with `cargo run --example defer`, etc. - -## Notes - -* `Drop` is not guaranteed to run in case of panics or program aborts, if you - need support for that check out [scopeguard](https://github.com/bluss/scopeguard) -* `undefer` could be implemented safely by, for example, carrying a boolean that - by default causes execution to happen but can be flipped to disable it - -## Further reading: - -* [The Pain Of Real Linear Types in Rust](https://gankro.github.io/blah/linear-rust/) -* [Go's defer](https://tour.golang.org/flowcontrol/12) -* [Rust's Drop](https://doc.rust-lang.org/std/ops/trait.Drop.html) diff --git a/fun/defer_rs/examples/defer-with-error.rs b/fun/defer_rs/examples/defer-with-error.rs deleted file mode 100644 index f8b8a0141..000000000 --- a/fun/defer_rs/examples/defer-with-error.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Go's defer in Rust, with error value return. - -use std::rc::Rc; -use std::sync::RwLock; - -struct Defer { - f: F, -} - -impl Drop for Defer { - fn drop(&mut self) { - (self.f)() - } -} - -// Only added this for Go-syntax familiarity ;-) -fn defer(f: F) -> Defer { - Defer { f } -} - -// Convenience type synonym. This is a reference-counted smart pointer to -// a shareable, mutable variable. -// Rust does not allow willy-nilly mutation of shared variables, so explicit -// write-locking must be performed. -type ErrorHandle = Rc>>; - -/////////////////// -// Usage example // -/////////////////// - -#[derive(Debug)] // Debug trait for some default way to print the type. -enum Error { - DropError, -} - -fn main() { - // Create a place to store the error. - let drop_err: ErrorHandle = Default::default(); // create empty error - - // Introduce an arbitrary scope block (so that we still have control after - // the defer runs): - { - let mut i = 1; - - // Rc types are safe to clone and share for multiple ownership. - let err_handle = drop_err.clone(); - - // Call defer and let the closure own the cloned handle to the error: - let token = defer(move || { - // do something! - println!("Value is: {}", i); - - // ... oh no, it went wrong! - *err_handle.write().unwrap() = Some(Error::DropError); - }); - - i += 1; - println!("Value is: {}", i); - - // token goes out of scope here - drop() is called. - } - - match *drop_err.read().unwrap() { - Some(ref err) => println!("Oh no, an error occured: {:?}!", err), - None => println!("Phew, everything went well."), - }; -} - -// Prints: -// Value is: 2 -// Value is: 1 -// Oh no, an error occured: DropError! diff --git a/fun/defer_rs/examples/defer.rs b/fun/defer_rs/examples/defer.rs deleted file mode 100644 index 0c99d00c8..000000000 --- a/fun/defer_rs/examples/defer.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Go's defer in Rust! - -struct Defer { - f: F, -} - -impl Drop for Defer { - fn drop(&mut self) { - (self.f)() - } -} - -// Only added this for Go-syntax familiarity ;-) -fn defer(f: F) -> Defer { - Defer { f } -} - -fn main() { - let mut i = 1; - - // Calling it "token" ... could be something else. The lifetime of this - // controls when the action is run. - let _token = defer(move || println!("Value is: {}", i)); - - i += 1; - println!("Value is: {}", i); -} - -// Prints: -// Value is: 2 -// Value is: 1 diff --git a/fun/defer_rs/examples/undefer.rs b/fun/defer_rs/examples/undefer.rs deleted file mode 100644 index fa659de89..000000000 --- a/fun/defer_rs/examples/undefer.rs +++ /dev/null @@ -1,40 +0,0 @@ -// Go's defer in Rust, with a little twist! - -struct Defer { - f: F, -} - -impl Drop for Defer { - fn drop(&mut self) { - (self.f)() - } -} - -// Only added this for Go-syntax familiarity ;-) -fn defer(f: F) -> Defer { - Defer { f } -} - -// Changed your mind about the defer? -// (Note: This leaks the closure! Don't actually do this!) -fn undefer(token: Defer) { - use std::mem; - mem::forget(token); -} - -fn main() { - let mut i = 1; - - // Calling it "token" ... could be something else. The lifetime of this - // controls when the action is run. - let token = defer(move || println!("Value is: {}", i)); - - i += 1; - println!("Value is: {}", i); - - // Oh, now I changed my mind about the previous defer: - undefer(token); -} - -// Prints: -// Value is: 2 diff --git a/fun/elblog/.gitignore b/fun/elblog/.gitignore deleted file mode 100644 index c531d9867..000000000 --- a/fun/elblog/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.elc diff --git a/fun/elblog/README.md b/fun/elblog/README.md deleted file mode 100644 index 994b1138e..000000000 --- a/fun/elblog/README.md +++ /dev/null @@ -1,11 +0,0 @@ -elblog -====== - -This is a simple blogging software written in Emacs Lisp. - -The idea is that it should be able to do most of the things [my actual blog][] -does at the moment. - -No documentation exists for now besides the commit messages, but it works! - -[my actual blog]: https://www.tazj.in/ diff --git a/fun/elblog/blog.css b/fun/elblog/blog.css deleted file mode 100644 index 0d021f78e..000000000 --- a/fun/elblog/blog.css +++ /dev/null @@ -1,37 +0,0 @@ - diff --git a/fun/elblog/blog.el b/fun/elblog/blog.el deleted file mode 100644 index 102aa3791..000000000 --- a/fun/elblog/blog.el +++ /dev/null @@ -1,123 +0,0 @@ -;;; blog.el --- A simple org-mode & elnode blog software. -;;; -*- lexical-binding: t; -*- - -(require 'dash) -(require 'elnode) -(require 'f) -(require 'ht) - -;; Definition of customization options - -(defgroup elblog nil - "Configuration for the Emacs Lisp blog software" - :link '(url-link "https://github.com/tazjin/elblog")) - -(defcustom elblog-port 8010 - "Port to run elblog's HTTP server on" - :group 'elblog - :type 'integer) - -(defcustom elblog-host "localhost" - "Host for elblog's HTTP server to listen on" - :group 'elblog - :type 'string) - -(defcustom elblog-title "Elblog" - "Title text for this elblog instance" - :group 'elblog - :type 'string) - -(defcustom elblog-article-directory nil - "Directory in which elblog articles are stored" - :group 'elblog - :type 'string) - -(defcustom elblog-additional-routes '() - "Additional Elnode routes to register in the Elblog instance" - :group 'elblog - :type '(alist :key-type regexp :value-type function)) - -;; Declare user-configurable variables needed at runtime. - -(defvar elblog-articles (ht-create) - "A hash-table of blog articles. This is used for looking up articles from - URL fragments as well as for rendering the index.") - -;; HTML templating setup - -(defun template-preamble () - "Templates the preamble snippet with the correct blog title." - (format (f-read-text "preamble.html") elblog-title)) - -(defun configure-org-html-export () - "Configure org-mode settings for elblog's HTML templating to work correctly." - (setq org-html-postamble t) - (setq org-html-doctype "html5") - (setq org-html-head-include-scripts nil) - (setq org-html-style-default (f-read-text "blog.css")) - (setq org-html-preamble-format `(("en" ,(template-preamble)))) - (setq org-html-postamble-format `(("en" ,(f-read-text "postamble.html"))))) - -;; Article fetching & rendering functions - -(defun render-org-buffer (input-buffer &optional force) - "Renders an org-mode buffer as HTML and returns the name of the output buffer." - (letrec ((output-buffer (concat (buffer-name input-buffer) "-rendered")) - ;; Don't re-render articles unless forced. - (must-render (or force - (not (get-buffer output-buffer))))) - (if (and input-buffer must-render) - (with-current-buffer input-buffer - (org-export-to-buffer 'html output-buffer nil nil t))) - (if input-buffer output-buffer nil))) - -(defun get-buffer-string (buffer) - "Returns the contents of the specified buffer as a string." - (with-current-buffer (get-buffer buffer) - (buffer-string))) - -(defvar-local article-not-found - '(404 . "

    Oh no, the article was not found.

    ")) - -(defvar-local text-html '("Content-Type" . "text/html")) - -(defun render-article (article) - "Renders an article, if it exists." - (letrec ((rendered (-some->> - (ht-get elblog-articles article) - (concat elblog-article-directory) - (find-file) - (render-org-buffer)))) - (if rendered `(200 . ,(get-buffer-string rendered)) - article-not-found))) - -(defun blog-post-handler (httpcon) - "This handler servers a blog post from the configured blog post directory." - (let ((response (render-article (elnode-http-mapping httpcon 1)))) - (elnode-http-start httpcon (car response) text-html) - (elnode-http-return httpcon (cdr response)))) - -;; Web server implementation - -(defvar elblog-routes - '(("^.*//\\(.*\\)" . blog-post-handler)) - "The default routes available in elblog. They can be extended by the user -by setting the elblog-additional-routes customize option.") - -(defun elblog-handler (httpcon) - (elnode-hostpath-dispatcher - httpcon - (-concat elblog-additional-routes elblog-routes))) - -(defun start-elblog () - (interactive) - (configure-org-html-export) - (elnode-start 'elblog-handler - :port elblog-port - :host elblog-host)) - -(defun stop-elblog () - (interactive) - (elnode-stop elblog-port)) - -(provide 'elblog) diff --git a/fun/elblog/postamble.html b/fun/elblog/postamble.html deleted file mode 100644 index 16a26218a..000000000 --- a/fun/elblog/postamble.html +++ /dev/null @@ -1,9 +0,0 @@ -
    - diff --git a/fun/elblog/preamble.html b/fun/elblog/preamble.html deleted file mode 100644 index be74b9207..000000000 --- a/fun/elblog/preamble.html +++ /dev/null @@ -1,6 +0,0 @@ -
    -

    - %s -

    -
    -
    diff --git a/fun/gemma/CODE_OF_CONDUCT.md b/fun/gemma/CODE_OF_CONDUCT.md deleted file mode 100644 index c4013ac13..000000000 --- a/fun/gemma/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,20 +0,0 @@ -A SERMON ON ETHICS AND LOVE -=========================== - -One day Mal-2 asked the messenger spirit Saint Gulik to approach the Goddess and request Her presence for some desperate advice. Shortly afterwards the radio came on by itself, and an ethereal female Voice said **YES?** - -"O! Eris! Blessed Mother of Man! Queen of Chaos! Daughter of Discord! Concubine of Confusion! O! Exquisite Lady, I beseech You to lift a heavy burden from my heart!" - -**WHAT BOTHERS YOU, MAL? YOU DON'T SOUND WELL.** - -"I am filled with fear and tormented with terrible visions of pain. Everywhere people are hurting one another, the planet is rampant with injustices, whole societies plunder groups of their own people, mothers imprison sons, children perish while brothers war. O, woe." - -**WHAT IS THE MATTER WITH THAT, IF IT IS WHAT YOU WANT TO DO?** - -"But nobody Wants it! Everybody hates it." - -**OH. WELL, THEN *STOP*.** - -At which moment She turned herself into an aspirin commercial and left The Polyfather stranded alone with his species. - -SINISTER DEXTER HAS A BROKEN SPIROMETER. diff --git a/fun/gemma/LICENSE b/fun/gemma/LICENSE deleted file mode 100644 index 94a9ed024..000000000 --- a/fun/gemma/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/fun/gemma/README.md b/fun/gemma/README.md deleted file mode 100644 index 064742c00..000000000 --- a/fun/gemma/README.md +++ /dev/null @@ -1,96 +0,0 @@ -# Gemma - -Gemma is a simple application to track *recurring* tasks, named after Gemma -Hartley who [wrote an article][] about task distribution issues in households. - -## Background - -(Skip this if you just want the technical bits) - -Gemma's article launched a discussion in my friend circle about what causes an -uneven distribution of household workload. I theorised that this is not so much -a gender issue, but mostly a discoverability issue. - -Usually one person in a household is aware of what needs to be done, but in many -cases the "overhead" of delegating the tasks would actually take more time than -simply doing the task. - -I theorise further that the person (or people) who do a smaller share of the -household work would often do the work if they had a convenient way to become -aware of what needs to be done. Many times the "household manager" has the -function of tracking non-obvious tasks like when bedsheets were last changed - -shouldn't it be possible to actually distribute this information somehow? - -## The Project - -This project is an initial attempt at sketching out a little application that -aids with reminding users of recurring tasks. Some basic ideas: - -* The system should be blame-free. -* There should be as little usage overhead as possible so that people actually - do use it. -* It should work mostly passively without much user interaction. - -I believe that the basic (*very* simple) idea behind Gemma solves these issues. -Unfortunately my living situation changed before I actually got to test this out -in a real-life situation involving multiple people, but feedback from other -potential test subjects would be welcome! :) - -## Overview - -Gemma is a Common Lisp application in which a list of recurring tasks is -declared, together with the *maximum interval* at which they should be completed -(in days). Example: - -```lisp -;; Bathroom tasks -(deftask bathroom/wipe-mirror 7) -(deftask bathroom/wipe-counter 7) - -;; Bedroom tasks -(deftask bedroom/change-sheets 7) -(deftask bedroom/vacuum 10) - -;; Kitchen tasks -(deftask kitchen/trash 3) -(deftask kitchen/wipe-counters 3) -(deftask kitchen/vacuum 5 "Kitchen has more crumbs and such!") - -;; Entire place -(deftask clean-windows 60) -``` - -These tasks are marked with their last completion time and tracked by Gemma. A -simple Elm-based frontend application displays the tasks sorted by their -"urgency" and features a button to mark a task as completed: - -![Gemma screenshot](http://i.imgur.com/n7FFMJH.png) - -Marking a task as completed resets its counter and moves it to the bottom of the -task list. - -In theory this *should be it*, the frontend is made available to household -members in some easily accessible place (e.g. an old phone glued to the fridge!) -and people should attempt to develop a habit of checking what needs to be done -occasionally. - -The "household manager" still exists as a role of the household because someone -is entering the tasks into the application, but if my theory about people not -actually being actively *unwilling* to do tasks is correct this could help a -lot. - -## Usage - -(*Note*: Gemma is alpha software so the below is clearly not the final goal) - -Right now using this is non-trivial, but I'll eventually make a better -distribution. Basically you need to know Common Lisp (in which case you'll know -how to get the backend running) and have `elm-reactor` installed to run the -development version of the frontend application. - -Gemma is configured via a configuration file that should be located either at -`/etc/gemma/config.lisp` or at a custom location specified via the environment -variable `GEMMA_CONFIG`. Have a look at the `config.lisp` file in the repository -root for an example. - -[wrote an article]: http://www.harpersbazaar.com/culture/features/a12063822/emotional-labor-gender-equality/ diff --git a/fun/gemma/config.lisp b/fun/gemma/config.lisp deleted file mode 100644 index 54f8e5f34..000000000 --- a/fun/gemma/config.lisp +++ /dev/null @@ -1,21 +0,0 @@ -;; Example configuration file for Gemma - -(config :port 4242 - :data-dir "/tmp/gemma/") - -(deftask bathroom/wipe-mirror 7) -(deftask bathroom/wipe-counter 7) - -;; Bedroom tasks -(deftask bedroom/change-sheets 7) -(deftask bedroom/vacuum 10) - -;; Kitchen tasks -(deftask kitchen/normal-trash 3) -(deftask kitchen/green-trash 5) -(deftask kitchen/blue-trash 5) -(deftask kitchen/wipe-counters 3) -(deftask kitchen/vacuum 5 "Kitchen has more crumbs and such!") - -;; Entire place -(deftask clean-windows 60) diff --git a/fun/gemma/default.nix b/fun/gemma/default.nix deleted file mode 100644 index 339b86d26..000000000 --- a/fun/gemma/default.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.third_party.elmPackages_0_18) cacert iana-etc libredirect stdenv runCommand writeText elmPackages; - - frontend = stdenv.mkDerivation { - name = "gemma-frontend.html"; - src = ./frontend; - buildInputs = [ cacert iana-etc elmPackages.elm ]; - - # The individual Elm packages this requires are not packaged and I - # can't be bothered to do that now, so lets open the escape hatch: - outputHashAlgo = "sha256"; - outputHash = "000xhds5bsig3kbi7dhgbv9h7myacf34bqvw7avvz7m5mwnqlqg7"; - - phases = [ "unpackPhase" "buildPhase" ]; - buildPhase = '' - export NIX_REDIRECTS=/etc/protocols=${iana-etc}/etc/protocols \ - LD_PRELOAD=${libredirect}/lib/libredirect.so - - export SYSTEM_CERTIFICATE_PATH=${cacert}/etc/ssl/certs - - mkdir .home && export HOME="$PWD/.home" - elm-make --yes Main.elm --output $out - ''; - }; - - injectFrontend = writeText "gemma-frontend.lisp" '' - (in-package :gemma) - (setq *static-file-location* "${runCommand "frontend" {} '' - mkdir -p $out - cp ${frontend} $out/index.html - ''}/") - ''; -in -depot.nix.buildLisp.program { - name = "gemma"; - - deps = with depot.third_party.lisp; [ - cl-json - cl-prevalence - hunchentoot - local-time - ]; - - srcs = [ - ./src/gemma.lisp - injectFrontend - ]; - - # depends on SBCL - brokenOn = [ - "ccl" - "ecl" - ]; -} diff --git a/fun/gemma/frontend/Main.elm b/fun/gemma/frontend/Main.elm deleted file mode 100644 index e449908e4..000000000 --- a/fun/gemma/frontend/Main.elm +++ /dev/null @@ -1,221 +0,0 @@ --- Copyright (C) 2016-2017 Vincent Ambo --- --- This file is part of Gemma. --- --- Gemma is free software: you can redistribute it and/or modify it --- under the terms of the GNU General Public License as published by --- the Free Software Foundation, either version 3 of the License, or --- (at your option) any later version. - - -module Main exposing (..) - -import Html exposing (Html, text, div, span) -import Html.Attributes exposing (style) -import Json.Decode exposing (..) -import Http -import Time - - --- Material design imports - -import Material -import Material.Card as Card -import Material.Color as Color -import Material.Grid exposing (grid, cell, size, Device(..)) -import Material.Layout as Layout -import Material.Scheme as Scheme -import Material.Options as Options -import Material.Elevation as Elevation -import Material.Button as Button - - --- API interface to Gemma - - -type alias Task = - { name : String - , description : Maybe String - , remaining : Int - } - - -emptyStringFilter s = - if s == "" then - Nothing - else - Just s - - -decodeEmptyString : Decoder (Maybe String) -decodeEmptyString = - map emptyStringFilter string - - -decodeTask : Decoder Task -decodeTask = - map3 Task - (field "name" string) - (field "description" decodeEmptyString) - (field "remaining" int) - - -loadTasks : Cmd Msg -loadTasks = - let - request = - Http.get "/tasks" (list decodeTask) - in - Http.send NewTasks request - - -completeTask : Task -> Cmd Msg -completeTask task = - let - request = - Http.getString - (String.concat - [ "/complete?task=" - , task.name - ] - ) - in - Http.send (\_ -> LoadTasks) request - - - --- Elm architecture implementation - - -type Msg - = None - | LoadTasks - | NewTasks (Result Http.Error (List Task)) - | Mdl (Material.Msg Msg) - | Complete Task - - -type alias Model = - { tasks : List Task - , error : Maybe String - , mdl : Material.Model - } - - -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = - case msg of - LoadTasks -> - ( model, loadTasks ) - - Complete task -> - ( model, completeTask task ) - - NewTasks (Ok tasks) -> - ( { model | tasks = tasks, error = Nothing }, Cmd.none ) - - NewTasks (Err err) -> - ( { model | error = Just (toString err) }, Cmd.none ) - - _ -> - ( model, Cmd.none ) - - - --- View implementation - - -white = - Color.text Color.white - - -taskColor : Task -> Color.Hue -taskColor task = - if task.remaining > 2 then - Color.Green - else if task.remaining < 0 then - Color.Red - else - Color.Yellow - - -within : Task -> String -within task = - if task.remaining < 0 then - "This task is overdue!" - else if task.remaining > 2 then - String.concat - [ "Relax, this task has " - , toString task.remaining - , " days left before it is due." - ] - else - String.concat - [ "This task should be completed within " - , toString task.remaining - , " days. Consider doing it now!" - ] - - -renderTask : Model -> Task -> Html Msg -renderTask model task = - Card.view - [ Color.background (Color.color (taskColor task) Color.S800) - , Elevation.e3 - ] - [ Card.title [] [ Card.head [ white ] [ text task.name ] ] - , Card.text [ white ] - [ text (Maybe.withDefault "" task.description) - , Html.br [] [] - , text (within task) - ] - , Card.actions - [ Card.border ] - [ Button.render Mdl - [ 0 ] - model.mdl - [ white, Button.ripple, Button.accent, Options.onClick (Complete task) ] - [ text "Completed" ] - ] - ] - - -gemmaView : Model -> Html Msg -gemmaView model = - grid [] - (List.map (\t -> cell [ size All 4 ] [ renderTask model t ]) - model.tasks - ) - - -view : Model -> Html Msg -view model = - gemmaView model |> Scheme.top - - - --- subscriptions : Model -> Sub Msg - - -subscriptions model = - Sub.batch - [ Material.subscriptions Mdl model - , Time.every (15 * Time.second) (\_ -> LoadTasks) - ] - - -main : Program Never Model Msg -main = - let - model = - { tasks = [] - , error = Nothing - , mdl = Material.model - } - in - Html.program - { init = ( model, Cmd.batch [ loadTasks, Material.init Mdl ] ) - , view = view - , update = update - , subscriptions = subscriptions - } diff --git a/fun/gemma/frontend/elm-package.json b/fun/gemma/frontend/elm-package.json deleted file mode 100644 index 2ae541ae0..000000000 --- a/fun/gemma/frontend/elm-package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "version": "1.0.0", - "summary": "helpful summary of your project, less than 80 characters", - "repository": "https://github.com/user/project.git", - "license": "BSD3", - "source-directories": [ - "." - ], - "exposed-modules": [], - "dependencies": { - "elm-lang/core": "5.1.1 <= v < 6.0.0", - "elm-lang/html": "2.0.0 <= v < 3.0.0", - "elm-lang/http": "1.0.0 <= v < 2.0.0", - "debois/elm-mdl": "8.1.0 <= v < 9.0.0" - }, - "elm-version": "0.18.0 <= v < 0.19.0" -} diff --git a/fun/gemma/src/gemma.lisp b/fun/gemma/src/gemma.lisp deleted file mode 100644 index 20a76caae..000000000 --- a/fun/gemma/src/gemma.lisp +++ /dev/null @@ -1,192 +0,0 @@ -;; Copyright (C) 2016-2020 Vincent Ambo -;; -;; This file is part of Gemma. -;; -;; Gemma is free software: you can redistribute it and/or modify it -;; under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -(defpackage gemma - (:use :cl - :local-time - :cl-json) - (:import-from :sb-posix :getenv) - (:shadowing-import-from :sb-posix :getcwd) - (:export :start-gemma :config :main)) -(in-package :gemma) - -;; TODO: Store an average of how many days it was between task -;; completions. Some of the current numbers are just guesses -;; anyways. - -(defmacro in-case-of (x &body body) - "Evaluate BODY if X is non-nil, binding the value of X to IT." - `(let ((it ,x)) - (when it ,@body))) - -;; Set default configuration parameters -(defvar *gemma-port* 4242 - "Port on which the Gemma web server listens.") - -(defvar *gemma-acceptor* nil - "Hunchentoot acceptor for Gemma's web server.") - -(defvar *static-file-location* "frontend/" - "Folder from which to serve static assets. If built inside of Nix, - the path is injected during the build.") - -(defvar *p-tasks* nil - "All tasks registered in this Gemma instance.") - -(defun initialise-persistence (data-dir) - (setq *p-tasks* (cl-prevalence:make-prevalence-system data-dir)) - - ;; Initialise database ID counter - (or (> (length (cl-prevalence:find-all-objects *p-tasks* 'task)) 0) - (cl-prevalence:tx-create-id-counter *p-tasks*))) - -(defun config (&key port data-dir) - "Configuration function for use in the Gemma configuration file." - - (in-package :gemma) - (in-case-of port (defparameter *gemma-port* it)) - (initialise-persistence (or data-dir "data/"))) - -;; -;; Define task management system -;; - -(defclass task () - ((id :reader id - :initarg :id) - - ;; (Unique) name of the task - (name :type symbol - :initarg :name - :accessor name-of) - - ;; Maximum completion interval - (days :type integer - :initarg :days - :accessor days-of) - - ;; Optional description - (description :type string - :initarg :description - :accessor description-of) - - ;; Last completion time - (done-at :type timestamp - :initarg :done-at - :accessor last-done-at))) - -(defmacro deftask (task-name days &optional description) - (unless (get-task task-name) - `(progn (cl-prevalence:tx-create-object - *p-tasks* - 'task - (quote ((name ,task-name) - (days ,days) - (description ,(or description "")) - (done-at ,(now))))) - (cl-prevalence:snapshot *p-tasks*)))) - -(defun get-task (name) - (cl-prevalence:find-object-with-slot *p-tasks* 'task 'name name)) - -(defun list-tasks () - (cl-prevalence:find-all-objects *p-tasks* 'task)) - -(defun days-remaining (task) - "Returns the number of days remaining before the supplied TASK reaches its -maximum interval." - (let* ((expires-at (timestamp+ (last-done-at task) - (days-of task) :day)) - (secs-until-expiry (timestamp-difference expires-at (now)))) - (round (/ secs-until-expiry 60 60 24)))) - -(defun sort-tasks (tasks) - "Sorts TASKS in descending order by number of days remaining." - (sort (copy-list tasks) - (lambda (t1 t2) (< (days-remaining t1) - (days-remaining t2))))) - -(defun complete-task (name &optional at) - "Mark the task with NAME as completed, either now or AT specified time." - (cl-prevalence:tx-change-object-slots *p-tasks* 'task - (id (get-task name)) - `((done-at ,(or at (now))))) - (cl-prevalence:snapshot *p-tasks*)) - -;; -;; Define web API -;; - -(defun response-for (task) - "Create a response object to be JSON encoded for TASK." - `((:name . ,(name-of task)) - (:description . ,(description-of task)) - (:remaining . ,(days-remaining task)))) - -(defun start-gemma () - (in-package :gemma) - - ;; Load configuration - (load (pathname (or (getenv "GEMMA_CONFIG") - "/etc/gemma/config.lisp"))) - - ;; Set up web server - (setq *gemma-acceptor* (make-instance 'hunchentoot:easy-acceptor - :port *gemma-port* - :document-root *static-file-location*)) - (hunchentoot:start *gemma-acceptor*) - - ;; Task listing handler - (hunchentoot:define-easy-handler - (get-tasks :uri "/tasks") () - - (setf (hunchentoot:content-type*) "application/json") - (setf (hunchentoot:header-out "Access-Control-Allow-Origin") "*") - (encode-json-to-string - ;; Construct a frontend-friendly representation of the tasks. - (mapcar #'response-for (sort-tasks (list-tasks))))) - - ;; Task completion handler - (hunchentoot:define-easy-handler - (complete-task-handler :uri "/complete") (task) - (setf (hunchentoot:content-type*) "application/json") - (let* ((key (find-symbol (camel-case-to-lisp task) "GEMMA"))) - (format t "Marking task ~A as completed" key) - (complete-task key) - (encode-json-to-string (response-for (get-task key)))))) - -(defun main () - "This function serves as the entrypoint for ASDF-built executables. - It joins the Hunchentoot server thread to keep the process running - for as long as the server is alive." - - (start-gemma) - (sb-thread:join-thread - (find-if (lambda (th) - (string= (sb-thread:thread-name th) - (format nil "hunchentoot-listener-*:~A" *gemma-port*))) - (sb-thread:list-all-threads)))) - -;; Experimentation / testing stuff - -(defun randomise-completion-times () - "Set some random completion timestamps for all tasks" - (mapcar - (lambda (task) - (complete-task (name-of task) - (timestamp- (now) - (random 14) - :day))) - (cl-prevalence:find-all-objects *p-tasks* 'task))) - -(defun clear-all-tasks () - (mapcar (lambda (task) (cl-prevalence:tx-delete-object *p-tasks* 'task (id task))) - (cl-prevalence:find-all-objects *p-tasks* 'task))) - -;; (randomise-completion-times) diff --git a/fun/idual/README.md b/fun/idual/README.md deleted file mode 100644 index 922047617..000000000 --- a/fun/idual/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# iDual light control - -This folder contains some tooling for controlling iDual LED lights -(which use infrared controls) using a "Broadlink RM Pro" infrared -controller. - -The supported colour codes of the iDual remote are stored in -`codes.txt`. - -The point of this is to make it possible for me to automate my lights -in the morning, so that I can actually get out of bed. - -## Capturing codes - -Capturing codes is relatively easy, assuming that the broadlink device -is set up: - -```python -import broadlink -import base64 - -devices = broadlink.discover(timeout=5) -devices[0].auth() -``` - -For each code, the procedure is as follows: - -```python -devices[0].find_rf_packet() -# wait until this returns True - -devices[0].check_data() -# this will return the code -``` diff --git a/fun/idual/default.nix b/fun/idual/default.nix deleted file mode 100644 index 1acf287bf..000000000 --- a/fun/idual/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - inherit (pkgs) python3 python3Packages; - - opts = { - pname = "idualctl"; - version = "0.1"; - src = ./.; - - propagatedBuildInputs = [ - depot.third_party.python.broadlink - ]; - }; - package = python3Packages.buildPythonPackage opts; - script = python3Packages.buildPythonApplication opts; -in -depot.nix.readTree.drvTargets { - inherit script; - python = python3.withPackages (_: [ package ]); - setAlarm = pkgs.writeShellScriptBin "set-alarm" '' - echo "setting an alarm for ''${1}" - ${pkgs.systemd}/bin/systemd-run --user --on-calendar="''${1} Europe/London" --unit=light-alarm.service - ''; -} diff --git a/fun/idual/idual/__init__.py b/fun/idual/idual/__init__.py deleted file mode 100644 index 35c3bbae9..000000000 --- a/fun/idual/idual/__init__.py +++ /dev/null @@ -1,65 +0,0 @@ -import base64 -import broadlink -import time -import sys - -commands = { - # system commands - 'on' : 'JgBIAAABK5AVERQ2FBEUERQSFBEUERQSFBEUNhQ2FDUUNhQ2FDYUNRU1FBIUERQRFBIUERQRFBIUERQ2FDYUNRQ2FDYUNhQ1FQANBQ==', - 'off' : 'JgBIAAABLJAUERQ2FBEUEhQRFBEUEhQRFBEUNhQ2FDUVNRQ2FDYUNhQRFDYUERQSFBEUERQSFBEUNhQRFDYUNhQ2FDUUNhQ2FAANBQ==', - 'darker' : 'JgBIAAABLI8VERQ2FBEUERURFBEUEhQRFBEUNhQ2FDYUNRU1FDYUNhQRFBIUERQRFDYUEhQRFBEVNRQ2FDYUNhQRFDYUNhQ1FQANBQ==', - 'brighter' : 'JgBIAAABLI8VERQ2FBEUERQSFBEUEhQRFBEUNhQ2FDUVNRQ2FDYUNRU1FBIUERQ2FBEUEhQRFBEUEhQ1FTUUEhQ1FTUUNhQ2FAANBQ==', - - # presets - 'candle' : 'JgBQAAABKZISExI4EhMSFBITEhQRFBITEhQROBI4EjgSOBE4EjgSOBI4ERQSExIUEjgRFBITEhQSExI4EjgROBIUEjcSOBI4EgAFJgABKUkSAA0FAAAAAAAAAAA=', - 'bulb' : 'JgBYAAABK5AUERQ2FBEVERQRFBEVERQRFBEVNRQ2FDYUNRU1FDYUNhQRFDYUNRURFBEUEhQRFBEUNhQRFREUNhQ1FDYUNhQ2FAAFIwABKkgVAAxOAAErRxUADQU=', - 'sun' : 'JgBQAAABLI8VERQ2FBEUERURFBEUEhQRFBEUNhQ2FDYUNRU1FTUUNhQSFDUUEhQ2FBEUERURFBEUNhQSFDUUEhQ2FDUVNRQ2FAAFJQABK0cVAA0FAAAAAAAAAAA=', - 'cold' : 'JgBQAAABK5AUERQ2FBEUEhQRFBEUEhQRFBEUNhQ2FDYUNRQ2FDYUNhQ1FTUUEhQRFBEUEhQRFBIUERQRFDYUNhQ2FDYUNRQ2FAAFJAABK0cVAA0FAAAAAAAAAAA=', - 'eve_dark' : 'JgBQAAABK5AUERQ2FBEUEhQRFBEUEhQRFBEUNhQ2FDYUNRU1FDYUNhQRFDYUERQSFDUUEhQRFBIUNRQSFDUUNhQSFDUUNhQ2FAAFIwABLEYVAA0FAAAAAAAAAAA=', - 'eve_fade' : 'JgBIAAABK5AUERQ2FBEUEhQRFBEUEhQRFBEUNhQ2FDYUNRQ2FDYUNhQ1FDYUNhQRFDYUERQSFBEUEhQRFBEUNhQSEzYUNhQ2FAANBQ==', - 'reading' : 'JgBQAAABK5AUERQ2FBEUEhQRFBEUEhQRFBEUNhQ2FDUVNRQ2FDYUNhQ1FDYUEhQ1FBIUERQRFBIUERQSFDUUEhQ1FTUUNhQ2FAAFJAABK0YVAA0FAAAAAAAAAAA=', - 'yoga' : 'JgBYAAABLI8VERQ1FREUERQSFBEUERURFBEUNhQ1FTUUNhQ2FDYUNRURFBEUNhQRFBIUERMSExMTNxM2ExMTNxM2EzcTNxM3EwAFJQABKkgTAAxRAAErRxUADQU=', - 'morning' : 'JgBQAAABK5AUERQ2FBEUEhQRFBEUEhQRFBEUNhQ2FDUVNRQ2FDYUNRU1FDYUERURFDUVERQRFBIUERQRFTUUNhQRFDYUNhQ2FAAFIwABK0cVAA0FAAAAAAAAAAA=', - 'colours' : 'JgBQAAABLI8VERQ2FBEUERQSFBEUERURFBEUNhQ1FTUUNhQ2FDYUNRQSFBEUERQ2FDYUERQSFBEUNhQ1FTUUEhQRFDYUNRU1FAAFJAABKkcVAA0FAAAAAAAAAAA=', - 'random' : 'JgBQAAABK5AUEhQ1FREUERQSFBEUERQSExIUNhQ1EzcTNxM3EzYTNxMTEhMTNxM2ExMTEhMSExMTNxM2ExMTEhM3EzcTNhM3EwAFJQABK0cVAA0FAAAAAAAAAAA=', - 'island' : 'JgBQAAABK5AUERQ2FBEUEhQRFBEUEhQRFBEUNhQ2FDUVNRQ2FDYUNRU1FBIUNRURFBEUEhQRFBEUEhQ1FREUNhQ1FDYUNhQ2FAAFIwABK0cVAA0FAAAAAAAAAAA=', - 'forest' : 'JgBQAAABK5AUEhQ1FREUERQSFBEUERQSFBEUNhQ1FTUUNhQ2FDUVNRQSFBEUNhQRFDYUERQSFBEUNhQ2FBEUNhQRFDYUNhQ1FQAFIwABK0cVAA0FAAAAAAAAAAA=', - 'ocean' : 'JgBQAAABK5AUEhQ1FREUERQSFBEUERQRFREUNhQ1FTUUNhQ2FDUVNRQ2FBEUEhQ1FTUUEhQRFBEUEhQ1FTUUEhQRFDYUNRU1FAAFJAABK0cVAA0FAAAAAAAAAAA=', - 'fire' : 'JgBQAAABK5AUERQ2FBEUEhQRFBEUEhQRFBEUNhQ2FDUVNRQ2FDYUNRU1FBIUNRU1FBIUERQRFBIUERQ2FBEUEhQ1FTUUNhQ2FAAFIwABLEYVAA0FAAAAAAAAAAA=', - 'love' : 'JgBQAAABL5AUEhQ1FREUERQSFBEUERQSFBEUNhQ1FDYUNhQ2FDUVNRQSFDUUNhQSFBEUERQSFBEUNhQRFBIUNRQ2FDYUNhQ1FAAFJAABK0cVAA0FAAAAAAAAAAA=', - - # colour commands - 'red' : 'JgBIAAABK5AUERQ2FBEUEhQRFBEVERQRFBEUNhQ2FDYUNRU1FDYUNhQRFDYUNhQ1FREUERQSFBEUNhQRFBIUERQ2FDUVNRQ2FAANBQ==', - 'yellow' : 'JgBIAAABLI8UEhQ2FBEUERQSFBEUEhMSFBEUNhQ2FDUUNhQ2FDYUNRQ2FDYUNhQRFBIUERQRFBIUERQSExIUNhQ1FDYUNhQ2FAANBQ==', - 'green' : 'JgBIAAABK5AUEhQ1FREUERQSFBEUERQSFBEUNhQ1FDYUNhQ2FDUVNRQSFBEUERQ2FBIUERQRFBIUNRU1FDYUERQ2FDYUNhQ1FQANBQ==', - 'blue' : 'JgBIAAABK5AUERQ2FBEUEhQRFBITEhQRFBEUNhQ2FDYUNRQ2FDYUNhQ2ExIUNhQRFDYUERQSExIUERQ2FBEUNhQSEzYUNhQ2FAANBQ==', - 'saturate' : 'JgBIAAABK5AUERQ2FBEUEhQRFBIUERQRFBEUNhQ2FDYUNRU1FDYUNhQRFDYUERQ2FDYUERQSFBEUNhQRFDYUERQSFDUUNhQ2FAANBQ==', - 'desaturate' : 'JgBIAAABLI8VERQ2FBEUERQSFBEUERURFBEUNhQ1FTUUNhQ2FDYUNRQ2FDYUNhQ1FREUERQSFBEUERQSFBEUERQ2FDYUNhQ1FQANBQ==', -} - -def cmd(name): - return base64.b64decode(commands[name]) - -class LightController: - def __init__(self): - self.devices = broadlink.discover(timeout=10, max_devices=2) - if self.devices == []: - raise Exception('no devices found') - for device in self.devices: - device.auth() - - def send_cmd(self, name, iterations=5): - "Send a command, repeatedly for reliability" - packet = cmd(name) - for i in range(iterations): - for device in self.devices: - device.send_data(packet) - - def wakey(self): - "Turn on the lights in the morning, try repeatedly for reasons." - print('Turning on the lights. Wakey, wakey!') - for i in range(5): - self.send_cmd('random') - time.sleep(0.3) - self.send_cmd('on') - time.sleep(0.3) diff --git a/fun/idual/idualctl b/fun/idual/idualctl deleted file mode 100644 index 10a85eba0..000000000 --- a/fun/idual/idualctl +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -import idual -import sys - -def help(): - print('Available commands:') - for cmd in idual.commands: - print('- ' + cmd) - sys.exit(0) - -def handle(ctrl, cmd): - if cmd == 'help': - help() - elif cmd == 'wakey': - ctrl.wakey() - sys.exit(0) - elif cmd == 'on': - print('Turning on the lights') - ctrl.send_cmd(cmd) - elif cmd == 'off': - print('Turning off the lights') - ctrl.send_cmd(cmd) - elif cmd in idual.commands: - print('Sending ' + cmd + '-command') - ctrl.send_cmd(cmd) - else: - print('unknown command \'' + cmd + '\'') - sys.exit(1) - -if __name__ == "__main__": - if len(sys.argv) == 1: - help() - - print('Initialising light controller') - ctrl = idual.LightController() - - for cmd in sys.argv[1:]: - handle(ctrl, cmd) diff --git a/fun/idual/setup.py b/fun/idual/setup.py deleted file mode 100644 index f10c3b86f..000000000 --- a/fun/idual/setup.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from setuptools import setup - -setup( - name='idualctl', - version='0.1', - author='Vincent Ambo', - author_email='mail@tazj.in', - url='https://git.tazj.in/about/fun/idual', - packages=['idual'], - scripts = ['idualctl'], - install_requires=['broadlink>=0.13.2'], - include_package_data=True, -) diff --git a/fun/owothia/.envrc b/fun/owothia/.envrc deleted file mode 100644 index 051d09d29..000000000 --- a/fun/owothia/.envrc +++ /dev/null @@ -1 +0,0 @@ -eval "$(lorri direnv)" diff --git a/fun/owothia/.gitignore b/fun/owothia/.gitignore deleted file mode 100644 index 8e850e7a0..000000000 --- a/fun/owothia/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -dist -dist-* -build/ -cabal-dev -*.o -*.hi -*.hie -*.chi -*.chs.h -*.dyn_o -*.dyn_hi -.hpc -.hsenv -.cabal-sandbox/ -cabal.sandbox.config -*.prof -*.aux -*.hp -*.eventlog -.stack-work/ -cabal.project.local -cabal.project.local~ -.HTF/ -.ghc.environment.* - -# from nix-build -result - -# grr -*_flymake.hs diff --git a/fun/owothia/chatter.patch b/fun/owothia/chatter.patch deleted file mode 100644 index c2a6179bf..000000000 --- a/fun/owothia/chatter.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff --git a/src/NLP/POS/LiteralTagger.hs b/src/NLP/POS/LiteralTagger.hs -index 913bee8..3c2f71d 100644 ---- a/src/NLP/POS/LiteralTagger.hs -+++ b/src/NLP/POS/LiteralTagger.hs -@@ -1,4 +1,4 @@ --{-# LANGUAGE OverloadedStrings #-} -+{-# LANGUAGE OverloadedStrings, PackageImports #-} - module NLP.POS.LiteralTagger - ( tag - , tagSentence -@@ -27,7 +27,7 @@ import NLP.FullStop (segment) - import NLP.Types ( tagUNK, Sentence, TaggedSentence(..), applyTags - , Tag, POSTagger(..), CaseSensitive(..), tokens, showTok) - import Text.Regex.TDFA --import Text.Regex.TDFA.Text (compile) -+import "regex-tdfa" Text.Regex.TDFA.Text (compile) - - taggerID :: ByteString - taggerID = pack "NLP.POS.LiteralTagger" diff --git a/fun/owothia/default.nix b/fun/owothia/default.nix deleted file mode 100644 index 04f98e97f..000000000 --- a/fun/owothia/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ depot ? (import ../../../. { }) -, pkgs ? depot.third_party.nixpkgs -, ... -}: - -let - basePkg = pkgs.haskellPackages.callPackage ./pkg.nix { }; -in - -pkgs.haskell.lib.overrideSrc basePkg { - src = depot.third_party.gitignoreSource ./.; - version = "canon"; -} diff --git a/fun/owothia/hie.yaml b/fun/owothia/hie.yaml deleted file mode 100644 index 16a6c1526..000000000 --- a/fun/owothia/hie.yaml +++ /dev/null @@ -1,4 +0,0 @@ -cradle: - cabal: - - path: './app' - component: 'exe:owothia' diff --git a/fun/owothia/owothia.cabal b/fun/owothia/owothia.cabal deleted file mode 100644 index ef5477ea1..000000000 --- a/fun/owothia/owothia.cabal +++ /dev/null @@ -1,53 +0,0 @@ -cabal-version: 2.2 -name: owothia -version: 0.0.1.0 - -executable owothia - main-is: Main.hs - build-depends: base - , relude - , irc-client - , lens - , chatter - , containers - , text - , bytestring - , random - , envy - - mixins: base hiding (Prelude) - , relude (Relude as Prelude) - - hs-source-dirs: - src - - default-extensions: - BlockArguments - ConstraintKinds - DataKinds - DeriveAnyClass - DeriveGeneric - DerivingStrategies - DerivingVia - FlexibleContexts - FlexibleInstances - FunctionalDependencies - GADTSyntax - GeneralizedNewtypeDeriving - KindSignatures - LambdaCase - MultiWayIf - NoStarIsType - OverloadedStrings - PolyKinds - RankNTypes - ScopedTypeVariables - TupleSections - TypeApplications - TypeFamilies - TypeOperators - ViewPatterns - - ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N -O2 - - default-language: Haskell2010 diff --git a/fun/owothia/pkg.nix b/fun/owothia/pkg.nix deleted file mode 100644 index c812e5e11..000000000 --- a/fun/owothia/pkg.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ mkDerivation -, base -, bytestring -, chatter -, containers -, envy -, irc-client -, lens -, lib -, random -, relude -, text -}: -mkDerivation { - pname = "owothia"; - version = "0.0.1.0"; - src = ./.; - isLibrary = false; - isExecutable = true; - executableHaskellDepends = [ - base - bytestring - chatter - containers - envy - irc-client - lens - random - relude - text - ]; - license = "unknown"; - hydraPlatforms = lib.platforms.none; -} diff --git a/fun/owothia/regex-tdfa-text.patch b/fun/owothia/regex-tdfa-text.patch deleted file mode 100644 index 6b2c34654..000000000 --- a/fun/owothia/regex-tdfa-text.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/Text/Regex/TDFA/Text.hs b/Text/Regex/TDFA/Text.hs -index c4ef9db..9299272 100644 ---- a/Text/Regex/TDFA/Text.hs -+++ b/Text/Regex/TDFA/Text.hs -@@ -38,13 +38,6 @@ import Text.Regex.TDFA.NewDFA.Uncons(Uncons(uncons)) - import qualified Text.Regex.TDFA.NewDFA.Engine as Engine(execMatch) - import qualified Text.Regex.TDFA.NewDFA.Tester as Tester(matchTest) - --instance Extract T.Text where -- before = T.take; after = T.drop; empty = T.empty -- --instance Uncons T.Text where -- {- INLINE uncons #-} -- uncons = T.uncons -- - instance RegexContext Regex T.Text T.Text where - match = polymatch - matchM = polymatchM -diff --git a/Text/Regex/TDFA/Text/Lazy.hs b/Text/Regex/TDFA/Text/Lazy.hs -index 73ca4a0..52958fb 100644 ---- a/Text/Regex/TDFA/Text/Lazy.hs -+++ b/Text/Regex/TDFA/Text/Lazy.hs -@@ -38,17 +38,10 @@ import Text.Regex.TDFA.NewDFA.Uncons(Uncons(uncons)) - import qualified Text.Regex.TDFA.NewDFA.Engine as Engine(execMatch) - import qualified Text.Regex.TDFA.NewDFA.Tester as Tester(matchTest) - --instance Extract L.Text where -- before = L.take . toEnum; after = L.drop . toEnum; empty = L.empty -- - instance RegexContext Regex L.Text L.Text where - match = polymatch - matchM = polymatchM - --instance Uncons L.Text where -- {- INLINE uncons #-} -- uncons = L.uncons -- - instance RegexMaker Regex CompOption ExecOption L.Text where - makeRegexOptsM c e source = makeRegexOptsM c e (L.unpack source) - diff --git a/fun/owothia/shell.nix b/fun/owothia/shell.nix deleted file mode 100644 index 0304581d9..000000000 --- a/fun/owothia/shell.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ pkgs ? (import ../../../. { }).third_party, ... }: - -let - inherit (pkgs) - haskellPackages - haskell - gitignoreSource - ; -in - -(haskellPackages.extend (haskell.lib.packageSourceOverrides { - owothia = gitignoreSource ./.; -})).shellFor { - packages = p: [ p.owothia ]; - withHoogle = true; - doBenchmark = true; - buildInputs = with haskellPackages; [ - cabal-install - hlint - haskell-language-server - ]; -} diff --git a/fun/owothia/src/Main.hs b/fun/owothia/src/Main.hs deleted file mode 100644 index 3bf5e51db..000000000 --- a/fun/owothia/src/Main.hs +++ /dev/null @@ -1,168 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -module Main where - -import Network.IRC.Client -import Control.Lens -import NLP.POS -import NLP.Types (POSTagger) -import qualified NLP.Types.Tags as Tags -import NLP.Types.Tree -import qualified NLP.Corpora.Conll as Conll -import NLP.Corpora.Conll (Tag) -import qualified Data.ByteString as BS -import System.Random -import System.Envy -import System.IO as S -import Data.Maybe -import Data.Foldable (traverse_) -import qualified Data.Text --------------------------------------------------------------------------------- - -data Config = Config - { _owoChance :: Int - , _ircServer :: ByteString - , _ircPort :: Int - , _ircServerPassword :: Maybe Text - , _nickservPassword :: Maybe Text - , _ircNick :: Maybe Text - , _ircIdent :: Maybe Text - , _ircChannels :: [Text] - } - deriving stock (Show, Eq, Generic) -makeLenses ''Config - -instance Var [Text] where - toVar ts = show ts - fromVar s = readMaybe s >>= (pure . map Data.Text.pack) - -instance FromEnv Config where - fromEnv _ = - Config <$> env "OWO_CHANCE" - <*> env "IRC_SERVER" - <*> env "IRC_PORT" - <*> envMaybe "IRC_SERVER_PASSWORD" - <*> envMaybe "NICKSERV_PASSWORD" - <*> envMaybe "IRC_NICK" - <*> envMaybe "IRC_IDENT" - <*> env "IRC_CHANNELS" - -stopWord :: Text -> Bool -stopWord "'s" = True -stopWord "\"" = True -stopWord "is" = True -stopWord "are" = True -stopWord "am" = True -stopWord "were" = True -stopWord "was" = True -stopWord "be" = True -stopWord _ = False - -pickVerb :: POS Tag -> Maybe Text -pickVerb (POS Conll.VB (Token verb)) = Just verb -pickVerb (POS Conll.VBD (Token verb)) = Just verb -pickVerb (POS Conll.VBG (Token verb)) = Just verb -pickVerb (POS Conll.VBN (Token verb)) = Just verb -pickVerb (POS Conll.VBZ (Token verb)) = Just verb -pickVerb _ = Nothing - -pickNoun :: POS Tag -> Maybe Text -pickNoun (POS Conll.NN (Token noun)) = Just noun -pickNoun _ = Nothing - -randomPOS - :: Tags.Tag tag - => (POS tag -> Maybe Text) - -> POSTagger tag - -> Text - -> IO (Maybe Text) -randomPOS pickPOS tagger s = do - let candidates - = filter (not . stopWord) - . mapMaybe pickPOS - $ tag tagger s >>= \(TaggedSent ps) -> ps - i <- randomRIO (0, length candidates - 1) - pure $ candidates ^? ix i - -doOwo :: MonadIO m => Config -> m Bool -doOwo conf = do - n <- liftIO (randomRIO @Int (0, conf ^. owoChance)) - pure $ n == 0 - -data OwoType = Noun | Verb - deriving stock (Show, Eq) - -instance Random OwoType where - random = over _1 (bool Noun Verb) . random - randomR = const random - -vowels :: [Char] -vowels = "aeiou" - -article :: Text -> Text -article (x :< _) | x `elem` vowels = "an" -article _ = "a" - -owo :: OwoType -> Text -> Text -owo Noun n = mconcat - [ "I'm " - , article n - , " " - , n - , if "o" `Data.Text.isSuffixOf` n - then "wo" - else " owo" - ] -owo Verb v = v <> " me owo" - -pickOwo :: OwoType -> POS Tag -> Maybe Text -pickOwo Verb = pickVerb -pickOwo Noun = pickNoun - -randomOwo :: OwoType -> POSTagger Tag -> Text -> IO (Maybe Text) -randomOwo = randomPOS . pickOwo - -owothiaHandler :: Config -> Text -> IORef Bool -> POSTagger Tag -> EventHandler s -owothiaHandler conf nick state tagger = EventHandler Just $ \src ev -> do - hasIdentified <- readIORef state - when (not hasIdentified) $ do - nickservAuth - traverse_ (send . Join) (conf ^. ircChannels) - writeIORef state True - - when ("You are now identified" `BS.isInfixOf` (ev ^. raw)) $ - traverse_ (send . Join) (conf ^. ircChannels) - - case (src, ev ^. message) of - (Channel chan nick, Privmsg _ (Right m)) -> do - willOwo <- doOwo conf - when willOwo $ owoMessage chan m - _ -> pure() - - pure () - - where - owoMessage chan m = do - owoType <- liftIO randomIO - mWord <- liftIO $ randomOwo owoType tagger m - for_ mWord $ \word -> send $ Privmsg chan $ Right $ owo owoType word - nickservAuthMsg = "IDENTIFY " <> nick <> " " <> fromJust (conf ^. nickservPassword) - nickservAuth = send $ Privmsg "NickServ" $ Right nickservAuthMsg - -main :: IO () -main = do - conf <- either fail pure =<< decodeEnv - tagger <- defaultTagger - state <- newIORef $ not . isJust $ (conf ^. nickservPassword) - S.hSetBuffering stdout LineBuffering - let nick = fromMaybe "owothia" (conf ^. ircNick) - conn = - plainConnection (conf ^. ircServer) (conf ^. ircPort) - & realname .~ "Owothia Revströwö" - & password .~ (conf ^. ircServerPassword) - & username .~ fromMaybe "owothia" (conf ^. ircIdent) - & logfunc .~ stdoutLogger - cfg = - defaultInstanceConfig nick - & channels .~ (conf ^. ircChannels) - & handlers %~ (owothiaHandler conf nick state tagger : ) - runClient conn cfg () diff --git a/fun/paroxysm/.gitignore b/fun/paroxysm/.gitignore deleted file mode 100644 index 8cb01f2e3..000000000 --- a/fun/paroxysm/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/target -irc.toml -paroxysm-irc.toml -paroxysm.toml -**/*.rs.bk diff --git a/fun/paroxysm/Cargo.lock b/fun/paroxysm/Cargo.lock deleted file mode 100644 index 11b0408f7..000000000 --- a/fun/paroxysm/Cargo.lock +++ /dev/null @@ -1,1881 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if 1.0.0", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" - -[[package]] -name = "bufstream" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] - -[[package]] -name = "cc" -version = "1.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits 0.2.19", - "wasm-bindgen", - "windows-targets", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "config" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9107d78ed62b3fa5a86e7d18e647abed48cfd8f8fab6c72f4cdb982d196f7e6" -dependencies = [ - "lazy_static 1.5.0", - "nom", - "rust-ini", - "serde 1.0.217", - "serde-hjson", - "serde_json", - "toml", - "yaml-rust", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "crimp" -version = "4087.0.0" -dependencies = [ - "curl", - "serde 1.0.217", - "serde_json", -] - -[[package]] -name = "crossbeam-deque" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "crossbeam-utils", - "lazy_static 1.5.0", - "maybe-uninit", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -dependencies = [ - "cfg-if 0.1.10", - "crossbeam-utils", - "maybe-uninit", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "lazy_static 1.5.0", -] - -[[package]] -name = "curl" -version = "0.4.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "curl-sys" -version = "0.4.79+curl-8.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a9bbeeb3996717ef1248018db20d1b0b5ba7165bff60e3b5135b4f4c2b37a5" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.52.0", -] - -[[package]] -name = "diesel" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b28135ecf6b7d446b43e27e225622a038cc4e2930a1022f51cdb97ada19b8e4d" -dependencies = [ - "bitflags 1.3.2", - "byteorder", - "chrono", - "diesel_derives", - "pq-sys", - "r2d2", -] - -[[package]] -name = "diesel_derives" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "encoding" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" -dependencies = [ - "encoding-index-japanese", - "encoding-index-korean", - "encoding-index-simpchinese", - "encoding-index-singlebyte", - "encoding-index-tradchinese", -] - -[[package]] -name = "encoding-index-japanese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-korean" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-simpchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-singlebyte" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding-index-tradchinese" -version = "1.20141219.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" -dependencies = [ - "encoding_index_tests", -] - -[[package]] -name = "encoding_index_tests" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" - -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "errno" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags 1.3.2", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - -[[package]] -name = "futures" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - -[[package]] -name = "irc" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb7666c9ae95dc77b874467e347bde3789773b6f48887fb3384bfe29552b466" -dependencies = [ - "bufstream", - "bytes", - "chrono", - "encoding", - "failure", - "futures", - "log", - "native-tls", - "serde 1.0.217", - "serde_derive", - "tokio-codec", - "tokio-core", - "tokio-io", - "tokio-mockstream", - "tokio-timer 0.1.2", - "tokio-tls", - "toml", -] - -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "lazy_static" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - -[[package]] -name = "libz-sys" -version = "1.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linked-hash-map" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" -dependencies = [ - "serde 0.8.23", - "serde_test", -] - -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memoffset" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" -dependencies = [ - "autocfg", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "0.6.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" -dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "libc", - "log", - "miow", - "net2", - "slab 0.4.9", - "winapi 0.2.8", -] - -[[package]] -name = "mio-uds" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" -dependencies = [ - "iovec", - "libc", - "mio", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - -[[package]] -name = "native-tls" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "net2" -version = "0.2.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" -dependencies = [ - "memchr", - "version_check", -] - -[[package]] -name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -dependencies = [ - "num-traits 0.2.19", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" - -[[package]] -name = "openssl" -version = "0.10.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" -dependencies = [ - "bitflags 2.8.0", - "cfg-if 1.0.0", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parking_lot" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -dependencies = [ - "lock_api 0.3.4", - "parking_lot_core 0.6.3", - "rustc_version", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api 0.4.12", - "parking_lot_core 0.9.10", -] - -[[package]] -name = "parking_lot_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66b810a62be75176a80873726630147a5ca780cd33921e0b5709033e66b0a" -dependencies = [ - "cfg-if 0.1.10", - "cloudabi", - "libc", - "redox_syscall 0.1.57", - "rustc_version", - "smallvec 0.6.14", - "winapi 0.3.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall 0.5.8", - "smallvec 1.14.0", - "windows-targets", -] - -[[package]] -name = "paroxysm" -version = "0.1.0" -dependencies = [ - "chrono", - "config", - "crimp", - "diesel", - "env_logger", - "failure", - "irc", - "lazy_static 1.5.0", - "log", - "pq-sys", - "rand", - "regex", - "serde 1.0.217", -] - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "pq-sys" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0052426df997c0cbd30789eb44ca097e3541717a7b8fa36b1c464ee7edebd" -dependencies = [ - "pkg-config", - "vcpkg", -] - -[[package]] -name = "proc-macro2" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot 0.12.3", - "scheduled-thread-pool", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha", - "rand_core", - "rand_hc", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" -dependencies = [ - "bitflags 2.8.0", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rust-ini" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.8.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustversion" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" - -[[package]] -name = "ryu" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" -dependencies = [ - "parking_lot 0.12.3", -] - -[[package]] -name = "scoped-tls" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.8.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" - -[[package]] -name = "serde" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-hjson" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b833c5ad67d52ced5f5938b2980f32a9c1c5ef047f0b4fb3127e7a423c76153" -dependencies = [ - "lazy_static 0.2.11", - "linked-hash-map 0.3.0", - "num-traits 0.1.43", - "regex", - "serde 0.8.23", -] - -[[package]] -name = "serde_derive" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] - -[[package]] -name = "serde_json" -version = "1.0.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde 1.0.217", -] - -[[package]] -name = "serde_test" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" -dependencies = [ - "serde 0.8.23", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "slab" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" -dependencies = [ - "maybe-uninit", -] - -[[package]] -name = "smallvec" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" - -[[package]] -name = "socket2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" -dependencies = [ - "cfg-if 1.0.0", - "fastrand", - "getrandom 0.3.1", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "tokio" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -dependencies = [ - "bytes", - "futures", - "mio", - "num_cpus", - "tokio-codec", - "tokio-current-thread", - "tokio-executor", - "tokio-fs", - "tokio-io", - "tokio-reactor", - "tokio-sync", - "tokio-tcp", - "tokio-threadpool", - "tokio-timer 0.2.13", - "tokio-udp", - "tokio-uds", -] - -[[package]] -name = "tokio-codec" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b2998660ba0e70d18684de5d06b70b70a3a747469af9dea7618cc59e75976b" -dependencies = [ - "bytes", - "futures", - "tokio-io", -] - -[[package]] -name = "tokio-core" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87b1395334443abca552f63d4f61d0486f12377c2ba8b368e523f89e828cffd4" -dependencies = [ - "bytes", - "futures", - "iovec", - "log", - "mio", - "scoped-tls", - "tokio", - "tokio-executor", - "tokio-io", - "tokio-reactor", - "tokio-timer 0.2.13", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -dependencies = [ - "futures", - "tokio-executor", -] - -[[package]] -name = "tokio-executor" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -dependencies = [ - "crossbeam-utils", - "futures", -] - -[[package]] -name = "tokio-fs" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" -dependencies = [ - "futures", - "tokio-io", - "tokio-threadpool", -] - -[[package]] -name = "tokio-io" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -dependencies = [ - "bytes", - "futures", - "log", -] - -[[package]] -name = "tokio-mockstream" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41bfc436ef8b7f60c19adf3df086330ae9992385e4d8c53b17a323cad288e155" -dependencies = [ - "futures", - "tokio-io", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -dependencies = [ - "crossbeam-utils", - "futures", - "lazy_static 1.5.0", - "log", - "mio", - "num_cpus", - "parking_lot 0.9.0", - "slab 0.4.9", - "tokio-executor", - "tokio-io", - "tokio-sync", -] - -[[package]] -name = "tokio-sync" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -dependencies = [ - "fnv", - "futures", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -dependencies = [ - "bytes", - "futures", - "iovec", - "mio", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -dependencies = [ - "crossbeam-deque", - "crossbeam-queue", - "crossbeam-utils", - "futures", - "lazy_static 1.5.0", - "log", - "num_cpus", - "slab 0.4.9", - "tokio-executor", -] - -[[package]] -name = "tokio-timer" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" -dependencies = [ - "futures", - "slab 0.3.0", -] - -[[package]] -name = "tokio-timer" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" -dependencies = [ - "crossbeam-utils", - "futures", - "slab 0.4.9", - "tokio-executor", -] - -[[package]] -name = "tokio-tls" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c" -dependencies = [ - "futures", - "native-tls", - "tokio-io", -] - -[[package]] -name = "tokio-udp" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" -dependencies = [ - "bytes", - "futures", - "log", - "mio", - "tokio-codec", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "tokio-uds" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab57a4ac4111c8c9dbcf70779f6fc8bc35ae4b2454809febac840ad19bd7e4e0" -dependencies = [ - "bytes", - "futures", - "iovec", - "libc", - "log", - "mio", - "mio-uds", - "tokio-codec", - "tokio-io", - "tokio-reactor", -] - -[[package]] -name = "toml" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -dependencies = [ - "serde 1.0.217", -] - -[[package]] -name = "unicode-ident" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.13.3+wasi-0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if 1.0.0", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.98", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "wit-bindgen-rt" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags 2.8.0", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map 0.5.6", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.98", -] diff --git a/fun/paroxysm/Cargo.nix b/fun/paroxysm/Cargo.nix deleted file mode 100644 index 0a7c1af22..000000000 --- a/fun/paroxysm/Cargo.nix +++ /dev/null @@ -1,6566 +0,0 @@ -# This file was @generated by crate2nix 0.14.1 with the command: -# "generate" -# See https://github.com/kolloch/crate2nix for more info. - -{ nixpkgs ? -, pkgs ? import nixpkgs { config = { }; } -, lib ? pkgs.lib -, stdenv ? pkgs.stdenv -, buildRustCrateForPkgs ? pkgs: pkgs.buildRustCrate - # This is used as the `crateOverrides` argument for `buildRustCrate`. -, defaultCrateOverrides ? pkgs.defaultCrateOverrides - # The features to enable for the root_crate or the workspace_members. -, rootFeatures ? [ "default" ] - # If true, throw errors instead of issueing deprecation warnings. -, strictDeprecation ? false - # Elements to add to the `-C target-feature=` argument passed to `rustc` - # (separated by `,`, prefixed with `+`). - # Used for conditional compilation based on CPU feature detection. -, targetFeatures ? [ ] - # Whether to perform release builds: longer compile times, faster binaries. -, release ? true - # Additional crate2nix configuration if it exists. -, crateConfig ? if builtins.pathExists ./crate-config.nix - then pkgs.callPackage ./crate-config.nix { } - else { } -}: - -rec { - # - # "public" attributes that we attempt to keep stable with new versions of crate2nix. - # - - rootCrate = rec { - packageId = "paroxysm"; - - # Use this attribute to refer to the derivation building your root crate package. - # You can override the features with rootCrate.build.override { features = [ "default" "feature1" ... ]; }. - build = internal.buildRustCrateWithFeatures { - inherit packageId; - }; - - # Debug support which might change between releases. - # File a bug if you depend on any for non-debug work! - debug = internal.debugCrate { inherit packageId; }; - }; - # Refer your crate build derivation by name here. - # You can override the features with - # workspaceMembers."${crateName}".build.override { features = [ "default" "feature1" ... ]; }. - workspaceMembers = { - "paroxysm" = rec { - packageId = "paroxysm"; - build = internal.buildRustCrateWithFeatures { - packageId = "paroxysm"; - }; - - # Debug support which might change between releases. - # File a bug if you depend on any for non-debug work! - debug = internal.debugCrate { inherit packageId; }; - }; - }; - - # A derivation that joins the outputs of all workspace members together. - allWorkspaceMembers = pkgs.symlinkJoin { - name = "all-workspace-members"; - paths = - let members = builtins.attrValues workspaceMembers; - in builtins.map (m: m.build) members; - }; - - # - # "internal" ("private") attributes that may change in every new version of crate2nix. - # - - internal = rec { - # Build and dependency information for crates. - # Many of the fields are passed one-to-one to buildRustCrate. - # - # Noteworthy: - # * `dependencies`/`buildDependencies`: similar to the corresponding fields for buildRustCrate. - # but with additional information which is used during dependency/feature resolution. - # * `resolvedDependencies`: the selected default features reported by cargo - only included for debugging. - # * `devDependencies` as of now not used by `buildRustCrate` but used to - # inject test dependencies into the build - - crates = { - "addr2line" = rec { - crateName = "addr2line"; - version = "0.24.2"; - edition = "2018"; - crateBin = [ ]; - sha256 = "1hd1i57zxgz08j6h5qrhsnm2fi0bcqvsh389fw400xm3arz2ggnz"; - dependencies = [ - { - name = "gimli"; - packageId = "gimli"; - usesDefaultFeatures = false; - features = [ "read" ]; - } - ]; - features = { - "all" = [ "bin" ]; - "alloc" = [ "dep:alloc" ]; - "bin" = [ "loader" "rustc-demangle" "cpp_demangle" "fallible-iterator" "smallvec" "dep:clap" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "cpp_demangle" = [ "dep:cpp_demangle" ]; - "default" = [ "rustc-demangle" "cpp_demangle" "loader" "fallible-iterator" "smallvec" ]; - "fallible-iterator" = [ "dep:fallible-iterator" ]; - "loader" = [ "std" "dep:object" "dep:memmap2" "dep:typed-arena" ]; - "rustc-demangle" = [ "dep:rustc-demangle" ]; - "rustc-dep-of-std" = [ "core" "alloc" "compiler_builtins" "gimli/rustc-dep-of-std" ]; - "smallvec" = [ "dep:smallvec" ]; - "std" = [ "gimli/std" ]; - }; - }; - "adler2" = rec { - crateName = "adler2"; - version = "2.0.0"; - edition = "2021"; - sha256 = "09r6drylvgy8vv8k20lnbvwq8gp09h7smfn6h1rxsy15pgh629si"; - authors = [ - "Jonas Schievink " - "oyvindln " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - }; - "aho-corasick" = rec { - crateName = "aho-corasick"; - version = "1.1.3"; - edition = "2021"; - sha256 = "05mrpkvdgp5d20y2p989f187ry9diliijgwrs254fs9s1m1x6q4f"; - libName = "aho_corasick"; - authors = [ - "Andrew Gallant " - ]; - dependencies = [ - { - name = "memchr"; - packageId = "memchr"; - optional = true; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "std" "perf-literal" ]; - "logging" = [ "dep:log" ]; - "perf-literal" = [ "dep:memchr" ]; - "std" = [ "memchr?/std" ]; - }; - resolvedDefaultFeatures = [ "perf-literal" "std" ]; - }; - "android-tzdata" = rec { - crateName = "android-tzdata"; - version = "0.1.1"; - edition = "2018"; - sha256 = "1w7ynjxrfs97xg3qlcdns4kgfpwcdv824g611fq32cag4cdr96g9"; - libName = "android_tzdata"; - authors = [ - "RumovZ" - ]; - - }; - "android_system_properties" = rec { - crateName = "android_system_properties"; - version = "0.1.5"; - edition = "2018"; - sha256 = "04b3wrz12837j7mdczqd95b732gw5q7q66cv4yn4646lvccp57l1"; - authors = [ - "Nicolas Silva " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - } - ]; - - }; - "atty" = rec { - crateName = "atty"; - version = "0.2.14"; - edition = "2015"; - sha256 = "1s7yslcs6a28c5vz7jwj63lkfgyx8mx99fdirlhi9lbhhzhrpcyr"; - authors = [ - "softprops " - ]; - dependencies = [ - { - name = "hermit-abi"; - packageId = "hermit-abi 0.1.19"; - target = { target, features }: ("hermit" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (target."unix" or false); - } - { - name = "winapi"; - packageId = "winapi 0.3.9"; - target = { target, features }: (target."windows" or false); - features = [ "consoleapi" "processenv" "minwinbase" "minwindef" "winbase" ]; - } - ]; - - }; - "autocfg" = rec { - crateName = "autocfg"; - version = "1.4.0"; - edition = "2015"; - sha256 = "09lz3by90d2hphbq56znag9v87gfpd9gb8nr82hll8z6x2nhprdc"; - authors = [ - "Josh Stone " - ]; - - }; - "backtrace" = rec { - crateName = "backtrace"; - version = "0.3.74"; - edition = "2021"; - sha256 = "06pfif7nwx66qf2zaanc2fcq7m64i91ki9imw9xd3bnz5hrwp0ld"; - authors = [ - "The Rust Project Developers" - ]; - dependencies = [ - { - name = "addr2line"; - packageId = "addr2line"; - usesDefaultFeatures = false; - target = { target, features }: (!((target."windows" or false) && ("msvc" == target."env" or null) && (!("uwp" == target."vendor" or null)))); - } - { - name = "cfg-if"; - packageId = "cfg-if 1.0.0"; - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (!((target."windows" or false) && ("msvc" == target."env" or null) && (!("uwp" == target."vendor" or null)))); - } - { - name = "miniz_oxide"; - packageId = "miniz_oxide"; - usesDefaultFeatures = false; - target = { target, features }: (!((target."windows" or false) && ("msvc" == target."env" or null) && (!("uwp" == target."vendor" or null)))); - } - { - name = "object"; - packageId = "object"; - usesDefaultFeatures = false; - target = { target, features }: (!((target."windows" or false) && ("msvc" == target."env" or null) && (!("uwp" == target."vendor" or null)))); - features = [ "read_core" "elf" "macho" "pe" "xcoff" "unaligned" "archive" ]; - } - { - name = "rustc-demangle"; - packageId = "rustc-demangle"; - } - { - name = "windows-targets"; - packageId = "windows-targets"; - target = { target, features }: (target."windows" or false); - } - ]; - features = { - "cpp_demangle" = [ "dep:cpp_demangle" ]; - "default" = [ "std" ]; - "serde" = [ "dep:serde" ]; - "serialize-serde" = [ "serde" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "bitflags 1.3.2" = rec { - crateName = "bitflags"; - version = "1.3.2"; - edition = "2018"; - sha256 = "12ki6w8gn1ldq7yz9y680llwk5gmrhrzszaa17g1sbrw2r2qvwxy"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "bitflags 2.8.0" = rec { - crateName = "bitflags"; - version = "2.8.0"; - edition = "2021"; - sha256 = "0dixc6168i98652jxf0z9nbyn0zcis3g6hi6qdr7z5dbhcygas4g"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "arbitrary" = [ "dep:arbitrary" ]; - "bytemuck" = [ "dep:bytemuck" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "bufstream" = rec { - crateName = "bufstream"; - version = "0.1.4"; - edition = "2015"; - sha256 = "1j7f52rv73hd1crzrrfb9dr50ccmi3hb1ybd6s5dyg6jmllqkqs0"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "futures" = [ "dep:futures" ]; - "tokio" = [ "futures" "tokio-io" ]; - "tokio-io" = [ "dep:tokio-io" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "bumpalo" = rec { - crateName = "bumpalo"; - version = "3.17.0"; - edition = "2021"; - sha256 = "1gxxsn2fsjmv03g8p3m749mczv2k4m8xspifs5l7bcx0vx3gna0n"; - authors = [ - "Nick Fitzgerald " - ]; - features = { - "allocator-api2" = [ "dep:allocator-api2" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "byteorder" = rec { - crateName = "byteorder"; - version = "1.5.0"; - edition = "2021"; - sha256 = "0jzncxyf404mwqdbspihyzpkndfgda450l0893pz5xj685cg5l0z"; - authors = [ - "Andrew Gallant " - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "bytes" = rec { - crateName = "bytes"; - version = "0.4.12"; - edition = "2015"; - sha256 = "0768a55q2fsqdjsvcv98ndg9dq7w2g44dvq1avhwpxrdzbydyvr0"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "byteorder"; - packageId = "byteorder"; - } - { - name = "iovec"; - packageId = "iovec"; - } - ]; - features = { - "either" = [ "dep:either" ]; - "i128" = [ "byteorder/i128" ]; - "serde" = [ "dep:serde" ]; - }; - }; - "cc" = rec { - crateName = "cc"; - version = "1.2.14"; - edition = "2018"; - sha256 = "1jg38k6a2hirhsfk8mdg3k8l3f8b9h7dn6hllq07nfjsj0p1ng8c"; - authors = [ - "Alex Crichton " - ]; - dependencies = [ - { - name = "shlex"; - packageId = "shlex"; - } - ]; - features = { - "parallel" = [ "dep:libc" "dep:jobserver" ]; - }; - }; - "cfg-if 0.1.10" = rec { - crateName = "cfg-if"; - version = "0.1.10"; - edition = "2018"; - sha256 = "08h80ihs74jcyp24cd75wwabygbbdgl05k6p5dmq8akbr78vv1a7"; - libName = "cfg_if"; - authors = [ - "Alex Crichton " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - }; - "cfg-if 1.0.0" = rec { - crateName = "cfg-if"; - version = "1.0.0"; - edition = "2018"; - sha256 = "1za0vb97n4brpzpv8lsbnzmq5r8f2b0cpqqr0sy8h5bn751xxwds"; - libName = "cfg_if"; - authors = [ - "Alex Crichton " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - }; - "chrono" = rec { - crateName = "chrono"; - version = "0.4.39"; - edition = "2021"; - sha256 = "09g8nf409lb184kl9j4s85k0kn8wzgjkp5ls9zid50b886fwqdky"; - dependencies = [ - { - name = "android-tzdata"; - packageId = "android-tzdata"; - optional = true; - target = { target, features }: ("android" == target."os" or null); - } - { - name = "iana-time-zone"; - packageId = "iana-time-zone"; - optional = true; - target = { target, features }: (target."unix" or false); - features = [ "fallback" ]; - } - { - name = "js-sys"; - packageId = "js-sys"; - optional = true; - target = { target, features }: (("wasm32" == target."arch" or null) && (!(("emscripten" == target."os" or null) || ("wasi" == target."os" or null)))); - } - { - name = "num-traits"; - packageId = "num-traits 0.2.19"; - usesDefaultFeatures = false; - } - { - name = "wasm-bindgen"; - packageId = "wasm-bindgen"; - optional = true; - target = { target, features }: (("wasm32" == target."arch" or null) && (!(("emscripten" == target."os" or null) || ("wasi" == target."os" or null)))); - } - { - name = "windows-targets"; - packageId = "windows-targets"; - optional = true; - target = { target, features }: (target."windows" or false); - } - ]; - features = { - "android-tzdata" = [ "dep:android-tzdata" ]; - "arbitrary" = [ "dep:arbitrary" ]; - "clock" = [ "winapi" "iana-time-zone" "android-tzdata" "now" ]; - "default" = [ "clock" "std" "oldtime" "wasmbind" ]; - "iana-time-zone" = [ "dep:iana-time-zone" ]; - "js-sys" = [ "dep:js-sys" ]; - "now" = [ "std" ]; - "pure-rust-locales" = [ "dep:pure-rust-locales" ]; - "rkyv" = [ "dep:rkyv" "rkyv/size_32" ]; - "rkyv-16" = [ "dep:rkyv" "rkyv?/size_16" ]; - "rkyv-32" = [ "dep:rkyv" "rkyv?/size_32" ]; - "rkyv-64" = [ "dep:rkyv" "rkyv?/size_64" ]; - "rkyv-validation" = [ "rkyv?/validation" ]; - "serde" = [ "dep:serde" ]; - "std" = [ "alloc" ]; - "unstable-locales" = [ "pure-rust-locales" ]; - "wasm-bindgen" = [ "dep:wasm-bindgen" ]; - "wasmbind" = [ "wasm-bindgen" "js-sys" ]; - "winapi" = [ "windows-targets" ]; - "windows-targets" = [ "dep:windows-targets" ]; - }; - resolvedDefaultFeatures = [ "alloc" "android-tzdata" "clock" "default" "iana-time-zone" "js-sys" "now" "oldtime" "std" "wasm-bindgen" "wasmbind" "winapi" "windows-targets" ]; - }; - "cloudabi" = rec { - crateName = "cloudabi"; - version = "0.0.3"; - edition = "2015"; - sha256 = "0kxcg83jlihy0phnd2g8c2c303px3l2p3pkjz357ll6llnd5pz6x"; - libPath = "cloudabi.rs"; - authors = [ - "Nuxi (https://nuxi.nl/) and contributors" - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 1.3.2"; - optional = true; - } - ]; - features = { - "bitflags" = [ "dep:bitflags" ]; - "default" = [ "bitflags" ]; - }; - resolvedDefaultFeatures = [ "bitflags" "default" ]; - }; - "config" = rec { - crateName = "config"; - version = "0.9.3"; - edition = "2015"; - sha256 = "1rppjv8q5ffdyir6rawgizyqrm5yg9j8xlg7hrdgmcv2xmw7s47r"; - authors = [ - "Ryan Leckey " - ]; - dependencies = [ - { - name = "lazy_static"; - packageId = "lazy_static 1.5.0"; - } - { - name = "nom"; - packageId = "nom"; - } - { - name = "rust-ini"; - packageId = "rust-ini"; - optional = true; - } - { - name = "serde"; - packageId = "serde 1.0.217"; - } - { - name = "serde-hjson"; - packageId = "serde-hjson"; - optional = true; - } - { - name = "serde_json"; - packageId = "serde_json"; - optional = true; - } - { - name = "toml"; - packageId = "toml"; - optional = true; - } - { - name = "yaml-rust"; - packageId = "yaml-rust"; - optional = true; - } - ]; - features = { - "default" = [ "toml" "json" "yaml" "hjson" "ini" ]; - "hjson" = [ "serde-hjson" ]; - "ini" = [ "rust-ini" ]; - "json" = [ "serde_json" ]; - "rust-ini" = [ "dep:rust-ini" ]; - "serde-hjson" = [ "dep:serde-hjson" ]; - "serde_json" = [ "dep:serde_json" ]; - "toml" = [ "dep:toml" ]; - "yaml" = [ "yaml-rust" ]; - "yaml-rust" = [ "dep:yaml-rust" ]; - }; - resolvedDefaultFeatures = [ "default" "hjson" "ini" "json" "rust-ini" "serde-hjson" "serde_json" "toml" "yaml" "yaml-rust" ]; - }; - "core-foundation" = rec { - crateName = "core-foundation"; - version = "0.9.4"; - edition = "2018"; - sha256 = "13zvbbj07yk3b61b8fhwfzhy35535a583irf23vlcg59j7h9bqci"; - libName = "core_foundation"; - authors = [ - "The Servo Project Developers" - ]; - dependencies = [ - { - name = "core-foundation-sys"; - packageId = "core-foundation-sys"; - usesDefaultFeatures = false; - } - { - name = "libc"; - packageId = "libc"; - } - ]; - features = { - "chrono" = [ "dep:chrono" ]; - "default" = [ "link" ]; - "link" = [ "core-foundation-sys/link" ]; - "mac_os_10_7_support" = [ "core-foundation-sys/mac_os_10_7_support" ]; - "mac_os_10_8_features" = [ "core-foundation-sys/mac_os_10_8_features" ]; - "uuid" = [ "dep:uuid" ]; - "with-chrono" = [ "chrono" ]; - "with-uuid" = [ "uuid" ]; - }; - resolvedDefaultFeatures = [ "default" "link" ]; - }; - "core-foundation-sys" = rec { - crateName = "core-foundation-sys"; - version = "0.8.7"; - edition = "2018"; - sha256 = "12w8j73lazxmr1z0h98hf3z623kl8ms7g07jch7n4p8f9nwlhdkp"; - libName = "core_foundation_sys"; - authors = [ - "The Servo Project Developers" - ]; - features = { - "default" = [ "link" ]; - }; - resolvedDefaultFeatures = [ "default" "link" ]; - }; - "crimp" = rec { - crateName = "crimp"; - version = "4087.0.0"; - edition = "2015"; - src = lib.cleanSourceWith { filter = sourceFilter; src = ../../net/crimp; }; - authors = [ - "Vincent Ambo " - ]; - dependencies = [ - { - name = "curl"; - packageId = "curl"; - } - { - name = "serde"; - packageId = "serde 1.0.217"; - optional = true; - } - { - name = "serde_json"; - packageId = "serde_json"; - optional = true; - } - ]; - features = { - "default" = [ "json" ]; - "json" = [ "serde" "serde_json" ]; - "serde" = [ "dep:serde" ]; - "serde_json" = [ "dep:serde_json" ]; - }; - resolvedDefaultFeatures = [ "default" "json" "serde" "serde_json" ]; - }; - "crossbeam-deque" = rec { - crateName = "crossbeam-deque"; - version = "0.7.4"; - edition = "2015"; - sha256 = "1v99xcdjk4zixvxnq7pssip670mlyhw1ma3qc88ca11jxnfz43y2"; - libName = "crossbeam_deque"; - authors = [ - "The Crossbeam Project Developers" - ]; - dependencies = [ - { - name = "crossbeam-epoch"; - packageId = "crossbeam-epoch"; - } - { - name = "crossbeam-utils"; - packageId = "crossbeam-utils"; - } - { - name = "maybe-uninit"; - packageId = "maybe-uninit"; - } - ]; - - }; - "crossbeam-epoch" = rec { - crateName = "crossbeam-epoch"; - version = "0.8.2"; - edition = "2015"; - sha256 = "1knsf0zz7rgzxn0nwz5gajjcrivxpw3zrdcp946gdhdgr9sd53h5"; - libName = "crossbeam_epoch"; - authors = [ - "The Crossbeam Project Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 0.1.10"; - } - { - name = "crossbeam-utils"; - packageId = "crossbeam-utils"; - usesDefaultFeatures = false; - } - { - name = "lazy_static"; - packageId = "lazy_static 1.5.0"; - optional = true; - } - { - name = "maybe-uninit"; - packageId = "maybe-uninit"; - } - { - name = "memoffset"; - packageId = "memoffset"; - } - { - name = "scopeguard"; - packageId = "scopeguard"; - usesDefaultFeatures = false; - } - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { - "alloc" = [ "crossbeam-utils/alloc" ]; - "default" = [ "std" ]; - "lazy_static" = [ "dep:lazy_static" ]; - "nightly" = [ "crossbeam-utils/nightly" ]; - "std" = [ "crossbeam-utils/std" "lazy_static" ]; - }; - resolvedDefaultFeatures = [ "default" "lazy_static" "std" ]; - }; - "crossbeam-queue" = rec { - crateName = "crossbeam-queue"; - version = "0.2.3"; - edition = "2015"; - sha256 = "0w15z68nz3ac4f2s4djhwha8vmlwsh9dlfrmsl4x84y2ah5acjvp"; - libName = "crossbeam_queue"; - authors = [ - "The Crossbeam Project Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 0.1.10"; - } - { - name = "crossbeam-utils"; - packageId = "crossbeam-utils"; - usesDefaultFeatures = false; - } - { - name = "maybe-uninit"; - packageId = "maybe-uninit"; - } - ]; - features = { - "alloc" = [ "crossbeam-utils/alloc" ]; - "default" = [ "std" ]; - "std" = [ "crossbeam-utils/std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "crossbeam-utils" = rec { - crateName = "crossbeam-utils"; - version = "0.7.2"; - edition = "2015"; - sha256 = "1a31wbrda1320gj2a6az1lin2d34xfc3xf88da4c17qy5lxcgiy3"; - libName = "crossbeam_utils"; - authors = [ - "The Crossbeam Project Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 0.1.10"; - } - { - name = "lazy_static"; - packageId = "lazy_static 1.5.0"; - optional = true; - } - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { - "default" = [ "std" ]; - "lazy_static" = [ "dep:lazy_static" ]; - "std" = [ "lazy_static" ]; - }; - resolvedDefaultFeatures = [ "default" "lazy_static" "std" ]; - }; - "curl" = rec { - crateName = "curl"; - version = "0.4.47"; - edition = "2018"; - sha256 = "0rcjdrl35xs8l5v3wv6q5z37hjw3r5bvmbb09pqmhaxyl49lvyyr"; - authors = [ - "Alex Crichton " - ]; - dependencies = [ - { - name = "curl-sys"; - packageId = "curl-sys"; - usesDefaultFeatures = false; - } - { - name = "libc"; - packageId = "libc"; - } - { - name = "openssl-probe"; - packageId = "openssl-probe"; - optional = true; - target = { target, features }: ((target."unix" or false) && (!("macos" == target."os" or null))); - } - { - name = "openssl-sys"; - packageId = "openssl-sys"; - optional = true; - target = { target, features }: ((target."unix" or false) && (!("macos" == target."os" or null))); - } - { - name = "schannel"; - packageId = "schannel"; - target = { target, features }: ("msvc" == target."env" or null); - } - { - name = "socket2"; - packageId = "socket2"; - } - { - name = "windows-sys"; - packageId = "windows-sys 0.52.0"; - target = { target, features }: ("msvc" == target."env" or null); - features = [ "Win32_Foundation" "Win32_System_LibraryLoader" "Win32_Security_Cryptography" ]; - } - ]; - features = { - "default" = [ "ssl" ]; - "force-system-lib-on-osx" = [ "curl-sys/force-system-lib-on-osx" ]; - "http2" = [ "curl-sys/http2" ]; - "mesalink" = [ "curl-sys/mesalink" ]; - "ntlm" = [ "curl-sys/ntlm" ]; - "openssl-probe" = [ "dep:openssl-probe" ]; - "openssl-sys" = [ "dep:openssl-sys" ]; - "poll_7_68_0" = [ "curl-sys/poll_7_68_0" ]; - "protocol-ftp" = [ "curl-sys/protocol-ftp" ]; - "rustls" = [ "curl-sys/rustls" ]; - "spnego" = [ "curl-sys/spnego" ]; - "ssl" = [ "openssl-sys" "openssl-probe" "curl-sys/ssl" ]; - "static-curl" = [ "curl-sys/static-curl" ]; - "static-ssl" = [ "curl-sys/static-ssl" ]; - "upkeep_7_62_0" = [ "curl-sys/upkeep_7_62_0" ]; - "windows-static-ssl" = [ "static-curl" "curl-sys/windows-static-ssl" ]; - "zlib-ng-compat" = [ "curl-sys/zlib-ng-compat" "static-curl" ]; - }; - resolvedDefaultFeatures = [ "default" "openssl-probe" "openssl-sys" "ssl" ]; - }; - "curl-sys" = rec { - crateName = "curl-sys"; - version = "0.4.79+curl-8.12.0"; - edition = "2018"; - links = "curl"; - sha256 = "199p5d64ynqknpin1zsv2skmn2qv1nr8s0a82bpifrwrngpbpa8q"; - libName = "curl_sys"; - libPath = "lib.rs"; - authors = [ - "Alex Crichton " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - } - { - name = "libz-sys"; - packageId = "libz-sys"; - usesDefaultFeatures = false; - features = [ "libc" ]; - } - { - name = "openssl-sys"; - packageId = "openssl-sys"; - optional = true; - target = { target, features }: ((target."unix" or false) && (!("macos" == target."os" or null))); - } - { - name = "windows-sys"; - packageId = "windows-sys 0.52.0"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Networking_WinSock" ]; - } - ]; - buildDependencies = [ - { - name = "cc"; - packageId = "cc"; - } - { - name = "pkg-config"; - packageId = "pkg-config"; - } - { - name = "vcpkg"; - packageId = "vcpkg"; - target = { target, features }: ("msvc" == target."env" or null); - } - ]; - features = { - "default" = [ "ssl" ]; - "http2" = [ "libnghttp2-sys" ]; - "libnghttp2-sys" = [ "dep:libnghttp2-sys" ]; - "openssl-sys" = [ "dep:openssl-sys" ]; - "rustls" = [ "rustls-ffi" ]; - "rustls-ffi" = [ "dep:rustls-ffi" ]; - "ssl" = [ "openssl-sys" ]; - "static-ssl" = [ "openssl-sys/vendored" ]; - "zlib-ng-compat" = [ "libz-sys/zlib-ng" "static-curl" ]; - }; - resolvedDefaultFeatures = [ "openssl-sys" "ssl" ]; - }; - "diesel" = rec { - crateName = "diesel"; - version = "1.4.8"; - edition = "2015"; - sha256 = "0kcfkfhsv5yv3ksj440ajgic930359i2bqi77ss4dm5pyvn3b0dj"; - authors = [ - "Sean Griffin " - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 1.3.2"; - optional = true; - } - { - name = "byteorder"; - packageId = "byteorder"; - } - { - name = "chrono"; - packageId = "chrono"; - optional = true; - } - { - name = "diesel_derives"; - packageId = "diesel_derives"; - } - { - name = "pq-sys"; - packageId = "pq-sys"; - optional = true; - } - { - name = "r2d2"; - packageId = "r2d2"; - optional = true; - } - ]; - features = { - "128-column-tables" = [ "64-column-tables" ]; - "64-column-tables" = [ "32-column-tables" ]; - "bigdecimal" = [ "dep:bigdecimal" ]; - "bitflags" = [ "dep:bitflags" ]; - "chrono" = [ "dep:chrono" ]; - "default" = [ "with-deprecated" "32-column-tables" ]; - "deprecated-time" = [ "time" ]; - "extras" = [ "chrono" "serde_json" "uuid" "deprecated-time" "network-address" "numeric" "r2d2" ]; - "huge-tables" = [ "64-column-tables" ]; - "ipnetwork" = [ "dep:ipnetwork" ]; - "large-tables" = [ "32-column-tables" ]; - "libc" = [ "dep:libc" ]; - "libsqlite3-sys" = [ "dep:libsqlite3-sys" ]; - "mysql" = [ "mysqlclient-sys" "url" "diesel_derives/mysql" ]; - "mysqlclient-sys" = [ "dep:mysqlclient-sys" ]; - "network-address" = [ "ipnetwork" "libc" ]; - "num-bigint" = [ "dep:num-bigint" ]; - "num-integer" = [ "dep:num-integer" ]; - "num-traits" = [ "dep:num-traits" ]; - "numeric" = [ "num-bigint" "bigdecimal" "num-traits" "num-integer" ]; - "postgres" = [ "pq-sys" "bitflags" "diesel_derives/postgres" ]; - "pq-sys" = [ "dep:pq-sys" ]; - "quickcheck" = [ "dep:quickcheck" ]; - "r2d2" = [ "dep:r2d2" ]; - "serde_json" = [ "dep:serde_json" ]; - "sqlite" = [ "libsqlite3-sys" "diesel_derives/sqlite" ]; - "time" = [ "dep:time" ]; - "unstable" = [ "diesel_derives/nightly" ]; - "url" = [ "dep:url" ]; - "uuid" = [ "dep:uuid" ]; - "uuidv07" = [ "dep:uuidv07" ]; - "x128-column-tables" = [ "128-column-tables" ]; - "x32-column-tables" = [ "32-column-tables" ]; - "x64-column-tables" = [ "64-column-tables" ]; - }; - resolvedDefaultFeatures = [ "32-column-tables" "bitflags" "chrono" "default" "postgres" "pq-sys" "r2d2" "with-deprecated" ]; - }; - "diesel_derives" = rec { - crateName = "diesel_derives"; - version = "1.4.1"; - edition = "2015"; - sha256 = "1lsq133fwk0zj8xvxhdxqgg0xs31zf3abnwdyshaf0ldca7hkxa5"; - procMacro = true; - authors = [ - "Sean Griffin " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn 1.0.109"; - features = [ "full" "fold" ]; - } - ]; - features = { - "nightly" = [ "proc-macro2/nightly" ]; - }; - resolvedDefaultFeatures = [ "default" "postgres" ]; - }; - "encoding" = rec { - crateName = "encoding"; - version = "0.2.33"; - edition = "2015"; - sha256 = "1v1ndmkarh9z3n5hk53da4z56hgk9wa5kcsm7cnx345raqw983bb"; - authors = [ - "Kang Seonghoon " - ]; - dependencies = [ - { - name = "encoding-index-japanese"; - packageId = "encoding-index-japanese"; - } - { - name = "encoding-index-korean"; - packageId = "encoding-index-korean"; - } - { - name = "encoding-index-simpchinese"; - packageId = "encoding-index-simpchinese"; - } - { - name = "encoding-index-singlebyte"; - packageId = "encoding-index-singlebyte"; - } - { - name = "encoding-index-tradchinese"; - packageId = "encoding-index-tradchinese"; - } - ]; - - }; - "encoding-index-japanese" = rec { - crateName = "encoding-index-japanese"; - version = "1.20141219.5"; - edition = "2015"; - sha256 = "148c1lmd640p1d7fzk0nv7892mbyavvwddgqvcsm78798bzv5s04"; - libName = "encoding_index_japanese"; - libPath = "lib.rs"; - authors = [ - "Kang Seonghoon " - ]; - dependencies = [ - { - name = "encoding_index_tests"; - packageId = "encoding_index_tests"; - } - ]; - - }; - "encoding-index-korean" = rec { - crateName = "encoding-index-korean"; - version = "1.20141219.5"; - edition = "2015"; - sha256 = "10cxabp5ppygbq4y6y680856zl9zjvq7ahpiw8zj3fmwwsw3zhsd"; - libName = "encoding_index_korean"; - libPath = "lib.rs"; - authors = [ - "Kang Seonghoon " - ]; - dependencies = [ - { - name = "encoding_index_tests"; - packageId = "encoding_index_tests"; - } - ]; - - }; - "encoding-index-simpchinese" = rec { - crateName = "encoding-index-simpchinese"; - version = "1.20141219.5"; - edition = "2015"; - sha256 = "1xria2i7mc5dqdrpqxasdbxv1qx46jjbm53if3y1i4cvj2a72ynq"; - libName = "encoding_index_simpchinese"; - libPath = "lib.rs"; - authors = [ - "Kang Seonghoon " - ]; - dependencies = [ - { - name = "encoding_index_tests"; - packageId = "encoding_index_tests"; - } - ]; - - }; - "encoding-index-singlebyte" = rec { - crateName = "encoding-index-singlebyte"; - version = "1.20141219.5"; - edition = "2015"; - sha256 = "0jp85bz2pprzvg9m95w4q0vibh67b6w3bx35lafay95jzyndal9k"; - libName = "encoding_index_singlebyte"; - libPath = "lib.rs"; - authors = [ - "Kang Seonghoon " - ]; - dependencies = [ - { - name = "encoding_index_tests"; - packageId = "encoding_index_tests"; - } - ]; - - }; - "encoding-index-tradchinese" = rec { - crateName = "encoding-index-tradchinese"; - version = "1.20141219.5"; - edition = "2015"; - sha256 = "060ci4iz6xfvzk38syfbjvs7pix5hch3mvxkksswmqwcd3aj03px"; - libName = "encoding_index_tradchinese"; - libPath = "lib.rs"; - authors = [ - "Kang Seonghoon " - ]; - dependencies = [ - { - name = "encoding_index_tests"; - packageId = "encoding_index_tests"; - } - ]; - - }; - "encoding_index_tests" = rec { - crateName = "encoding_index_tests"; - version = "0.1.4"; - edition = "2015"; - sha256 = "0s85y091gl17ixass49bzaivng7w8p82p6nyvz2r3my9w4mxhim2"; - libPath = "index_tests.rs"; - authors = [ - "Kang Seonghoon " - ]; - - }; - "env_logger" = rec { - crateName = "env_logger"; - version = "0.7.1"; - edition = "2018"; - sha256 = "0djx8h8xfib43g5w94r1m1mkky5spcw4wblzgnhiyg5vnfxknls4"; - authors = [ - "The Rust Project Developers" - ]; - dependencies = [ - { - name = "atty"; - packageId = "atty"; - optional = true; - } - { - name = "humantime"; - packageId = "humantime"; - optional = true; - } - { - name = "log"; - packageId = "log"; - features = [ "std" ]; - } - { - name = "regex"; - packageId = "regex"; - optional = true; - } - { - name = "termcolor"; - packageId = "termcolor"; - optional = true; - } - ]; - features = { - "atty" = [ "dep:atty" ]; - "default" = [ "termcolor" "atty" "humantime" "regex" ]; - "humantime" = [ "dep:humantime" ]; - "regex" = [ "dep:regex" ]; - "termcolor" = [ "dep:termcolor" ]; - }; - resolvedDefaultFeatures = [ "atty" "default" "humantime" "regex" "termcolor" ]; - }; - "errno" = rec { - crateName = "errno"; - version = "0.3.10"; - edition = "2018"; - sha256 = "0pgblicz1kjz9wa9m0sghkhh2zw1fhq1mxzj7ndjm746kg5m5n1k"; - authors = [ - "Chris Wong " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: ("hermit" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: ("wasi" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (target."unix" or false); - } - { - name = "windows-sys"; - packageId = "windows-sys 0.59.0"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Foundation" "Win32_System_Diagnostics_Debug" ]; - } - ]; - features = { - "default" = [ "std" ]; - "std" = [ "libc/std" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "failure" = rec { - crateName = "failure"; - version = "0.1.8"; - edition = "2015"; - sha256 = "11jg1wmbkijrs6bk9fqnbrm9zf0850whnqpgnxyswbn0dk8rnbnk"; - authors = [ - "Without Boats " - ]; - dependencies = [ - { - name = "backtrace"; - packageId = "backtrace"; - optional = true; - } - { - name = "failure_derive"; - packageId = "failure_derive"; - optional = true; - } - ]; - features = { - "backtrace" = [ "dep:backtrace" ]; - "default" = [ "std" "derive" ]; - "derive" = [ "failure_derive" ]; - "failure_derive" = [ "dep:failure_derive" ]; - "std" = [ "backtrace" ]; - }; - resolvedDefaultFeatures = [ "backtrace" "default" "derive" "failure_derive" "std" ]; - }; - "failure_derive" = rec { - crateName = "failure_derive"; - version = "0.1.8"; - edition = "2015"; - sha256 = "1936adqqk080439kx2bjf1bds7h89sg6wcif4jw0syndcv3s6kda"; - procMacro = true; - authors = [ - "Without Boats " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn 1.0.109"; - } - { - name = "synstructure"; - packageId = "synstructure"; - } - ]; - features = { }; - }; - "fastrand" = rec { - crateName = "fastrand"; - version = "2.3.0"; - edition = "2018"; - sha256 = "1ghiahsw1jd68df895cy5h3gzwk30hndidn3b682zmshpgmrx41p"; - authors = [ - "Stjepan Glavina " - ]; - features = { - "default" = [ "std" ]; - "getrandom" = [ "dep:getrandom" ]; - "js" = [ "std" "getrandom" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "fnv" = rec { - crateName = "fnv"; - version = "1.0.7"; - edition = "2015"; - sha256 = "1hc2mcqha06aibcaza94vbi81j6pr9a1bbxrxjfhc91zin8yr7iz"; - libPath = "lib.rs"; - authors = [ - "Alex Crichton " - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "foreign-types" = rec { - crateName = "foreign-types"; - version = "0.3.2"; - edition = "2015"; - sha256 = "1cgk0vyd7r45cj769jym4a6s7vwshvd0z4bqrb92q1fwibmkkwzn"; - libName = "foreign_types"; - authors = [ - "Steven Fackler " - ]; - dependencies = [ - { - name = "foreign-types-shared"; - packageId = "foreign-types-shared"; - } - ]; - - }; - "foreign-types-shared" = rec { - crateName = "foreign-types-shared"; - version = "0.1.1"; - edition = "2015"; - sha256 = "0jxgzd04ra4imjv8jgkmdq59kj8fsz6w4zxsbmlai34h26225c00"; - libName = "foreign_types_shared"; - authors = [ - "Steven Fackler " - ]; - - }; - "fuchsia-zircon" = rec { - crateName = "fuchsia-zircon"; - version = "0.3.3"; - edition = "2015"; - sha256 = "10jxc5ks1x06gpd0xg51kcjrxr35nj6qhx2zlc5n7bmskv3675rf"; - libName = "fuchsia_zircon"; - authors = [ - "Raph Levien " - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 1.3.2"; - } - { - name = "fuchsia-zircon-sys"; - packageId = "fuchsia-zircon-sys"; - } - ]; - - }; - "fuchsia-zircon-sys" = rec { - crateName = "fuchsia-zircon-sys"; - version = "0.3.3"; - edition = "2015"; - sha256 = "19zp2085qsyq2bh1gvcxq1lb8w6v6jj9kbdkhpdjrl95fypakjix"; - libName = "fuchsia_zircon_sys"; - authors = [ - "Raph Levien " - ]; - - }; - "futures" = rec { - crateName = "futures"; - version = "0.1.31"; - edition = "2015"; - sha256 = "0y46qbmhi37dqkch8dlfq5aninqpzqgrr98awkb3rn4fxww1lirs"; - authors = [ - "Alex Crichton " - ]; - features = { - "default" = [ "use_std" "with-deprecated" ]; - }; - resolvedDefaultFeatures = [ "default" "use_std" "with-deprecated" ]; - }; - "getrandom 0.1.16" = rec { - crateName = "getrandom"; - version = "0.1.16"; - edition = "2018"; - sha256 = "1kjzmz60qx9mn615ks1akjbf36n3lkv27zfwbcam0fzmj56wphwg"; - authors = [ - "The Rand Project Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 1.0.0"; - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (target."unix" or false); - } - { - name = "wasi"; - packageId = "wasi 0.9.0+wasi-snapshot-preview1"; - target = { target, features }: ("wasi" == target."os" or null); - } - ]; - features = { - "bindgen" = [ "dep:bindgen" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "js-sys" = [ "dep:js-sys" ]; - "log" = [ "dep:log" ]; - "rustc-dep-of-std" = [ "compiler_builtins" "core" ]; - "stdweb" = [ "dep:stdweb" ]; - "test-in-browser" = [ "wasm-bindgen" ]; - "wasm-bindgen" = [ "bindgen" "js-sys" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "getrandom 0.3.1" = rec { - crateName = "getrandom"; - version = "0.3.1"; - edition = "2021"; - sha256 = "1y154yzby383p63ndw6zpfm0fz3vf6c0zdwc7df6vkl150wrr923"; - authors = [ - "The Rand Project Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 1.0.0"; - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: ((("linux" == target."os" or null) || ("android" == target."os" or null)) && (!(("custom" == target."getrandom_backend" or null) || ("rdrand" == target."getrandom_backend" or null) || ("rndr" == target."getrandom_backend" or null)))); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (("dragonfly" == target."os" or null) || ("freebsd" == target."os" or null) || ("hurd" == target."os" or null) || ("illumos" == target."os" or null) || (("horizon" == target."os" or null) && ("arm" == target."arch" or null))); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (("haiku" == target."os" or null) || ("redox" == target."os" or null) || ("nto" == target."os" or null) || ("aix" == target."os" or null)); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (("ios" == target."os" or null) || ("visionos" == target."os" or null) || ("watchos" == target."os" or null) || ("tvos" == target."os" or null)); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (("macos" == target."os" or null) || ("openbsd" == target."os" or null) || ("vita" == target."os" or null) || ("emscripten" == target."os" or null)); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: ("netbsd" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: ("solaris" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: ("vxworks" == target."os" or null); - } - { - name = "wasi"; - packageId = "wasi 0.13.3+wasi-0.2.2"; - usesDefaultFeatures = false; - target = { target, features }: (("wasm32" == target."arch" or null) && ("wasi" == target."os" or null) && ("p2" == target."env" or null)); - } - { - name = "windows-targets"; - packageId = "windows-targets"; - target = { target, features }: ((target."windows" or false) && (!("win7" == target."vendor" or null))); - } - ]; - features = { - "rustc-dep-of-std" = [ "dep:compiler_builtins" "dep:core" ]; - "wasm_js" = [ "dep:wasm-bindgen" "dep:js-sys" ]; - }; - }; - "gimli" = rec { - crateName = "gimli"; - version = "0.31.1"; - edition = "2018"; - sha256 = "0gvqc0ramx8szv76jhfd4dms0zyamvlg4whhiz11j34hh3dqxqh7"; - features = { - "default" = [ "read-all" "write" ]; - "endian-reader" = [ "read" "dep:stable_deref_trait" ]; - "fallible-iterator" = [ "dep:fallible-iterator" ]; - "read" = [ "read-core" ]; - "read-all" = [ "read" "std" "fallible-iterator" "endian-reader" ]; - "rustc-dep-of-std" = [ "dep:core" "dep:alloc" "dep:compiler_builtins" ]; - "std" = [ "fallible-iterator?/std" "stable_deref_trait?/std" ]; - "write" = [ "dep:indexmap" ]; - }; - resolvedDefaultFeatures = [ "read" "read-core" ]; - }; - "hermit-abi 0.1.19" = rec { - crateName = "hermit-abi"; - version = "0.1.19"; - edition = "2018"; - sha256 = "0cxcm8093nf5fyn114w8vxbrbcyvv91d4015rdnlgfll7cs6gd32"; - libName = "hermit_abi"; - authors = [ - "Stefan Lankes" - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - } - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins/rustc-dep-of-std" "libc/rustc-dep-of-std" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "hermit-abi 0.3.9" = rec { - crateName = "hermit-abi"; - version = "0.3.9"; - edition = "2021"; - sha256 = "092hxjbjnq5fmz66grd9plxd0sh6ssg5fhgwwwqbrzgzkjwdycfj"; - libName = "hermit_abi"; - authors = [ - "Stefan Lankes" - ]; - features = { - "alloc" = [ "dep:alloc" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "alloc" "compiler_builtins/rustc-dep-of-std" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "humantime" = rec { - crateName = "humantime"; - version = "1.3.0"; - edition = "2015"; - sha256 = "0krwgbf35pd46xvkqg14j070vircsndabahahlv3rwhflpy4q06z"; - authors = [ - "Paul Colomiets " - ]; - dependencies = [ - { - name = "quick-error"; - packageId = "quick-error"; - } - ]; - - }; - "iana-time-zone" = rec { - crateName = "iana-time-zone"; - version = "0.1.61"; - edition = "2018"; - sha256 = "085jjsls330yj1fnwykfzmb2f10zp6l7w4fhq81ng81574ghhpi3"; - libName = "iana_time_zone"; - authors = [ - "Andrew Straw " - "René Kijewski " - "Ryan Lopopolo " - ]; - dependencies = [ - { - name = "android_system_properties"; - packageId = "android_system_properties"; - target = { target, features }: ("android" == target."os" or null); - } - { - name = "core-foundation-sys"; - packageId = "core-foundation-sys"; - target = { target, features }: (("macos" == target."os" or null) || ("ios" == target."os" or null)); - } - { - name = "iana-time-zone-haiku"; - packageId = "iana-time-zone-haiku"; - target = { target, features }: ("haiku" == target."os" or null); - } - { - name = "js-sys"; - packageId = "js-sys"; - target = { target, features }: (("wasm32" == target."arch" or null) && ("unknown" == target."os" or null)); - } - { - name = "wasm-bindgen"; - packageId = "wasm-bindgen"; - target = { target, features }: (("wasm32" == target."arch" or null) && ("unknown" == target."os" or null)); - } - { - name = "windows-core"; - packageId = "windows-core"; - target = { target, features }: ("windows" == target."os" or null); - } - ]; - features = { }; - resolvedDefaultFeatures = [ "fallback" ]; - }; - "iana-time-zone-haiku" = rec { - crateName = "iana-time-zone-haiku"; - version = "0.1.2"; - edition = "2018"; - sha256 = "17r6jmj31chn7xs9698r122mapq85mfnv98bb4pg6spm0si2f67k"; - libName = "iana_time_zone_haiku"; - authors = [ - "René Kijewski " - ]; - buildDependencies = [ - { - name = "cc"; - packageId = "cc"; - } - ]; - - }; - "iovec" = rec { - crateName = "iovec"; - version = "0.1.4"; - edition = "2015"; - sha256 = "0ph73qygwx8i0mblrf110cj59l00gkmsgrpzz1rm85syz5pymcxj"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - ]; - - }; - "irc" = rec { - crateName = "irc"; - version = "0.13.6"; - edition = "2015"; - sha256 = "0rmlaaay5gw46gxqg27lnrrrfy73pm3y6rs4hxxwfpg9k9n6ddwf"; - authors = [ - "Aaron Weiss " - ]; - dependencies = [ - { - name = "bufstream"; - packageId = "bufstream"; - } - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "chrono"; - packageId = "chrono"; - } - { - name = "encoding"; - packageId = "encoding"; - } - { - name = "failure"; - packageId = "failure"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "native-tls"; - packageId = "native-tls"; - } - { - name = "serde"; - packageId = "serde 1.0.217"; - } - { - name = "serde_derive"; - packageId = "serde_derive"; - } - { - name = "tokio-codec"; - packageId = "tokio-codec"; - } - { - name = "tokio-core"; - packageId = "tokio-core"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - { - name = "tokio-mockstream"; - packageId = "tokio-mockstream"; - } - { - name = "tokio-timer"; - packageId = "tokio-timer 0.1.2"; - } - { - name = "tokio-tls"; - packageId = "tokio-tls"; - } - { - name = "toml"; - packageId = "toml"; - optional = true; - } - ]; - features = { - "default" = [ "ctcp" "toml" ]; - "json" = [ "serde_json" ]; - "serde_json" = [ "dep:serde_json" ]; - "serde_yaml" = [ "dep:serde_yaml" ]; - "toml" = [ "dep:toml" ]; - "yaml" = [ "serde_yaml" ]; - }; - resolvedDefaultFeatures = [ "ctcp" "default" "toml" ]; - }; - "itoa" = rec { - crateName = "itoa"; - version = "1.0.14"; - edition = "2018"; - sha256 = "0x26kr9m062mafaxgcf2p6h2x7cmixm0zw95aipzn2hr3d5jlnnp"; - authors = [ - "David Tolnay " - ]; - features = { - "no-panic" = [ "dep:no-panic" ]; - }; - }; - "js-sys" = rec { - crateName = "js-sys"; - version = "0.3.77"; - edition = "2021"; - sha256 = "13x2qcky5l22z4xgivi59xhjjx4kxir1zg7gcj0f1ijzd4yg7yhw"; - libName = "js_sys"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "once_cell"; - packageId = "once_cell"; - usesDefaultFeatures = false; - } - { - name = "wasm-bindgen"; - packageId = "wasm-bindgen"; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "std" ]; - "std" = [ "wasm-bindgen/std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "kernel32-sys" = rec { - crateName = "kernel32-sys"; - version = "0.2.2"; - edition = "2015"; - sha256 = "1389av0601a9yz8dvx5zha9vmkd6ik7ax0idpb032d28555n41vm"; - libName = "kernel32"; - authors = [ - "Peter Atashian " - ]; - dependencies = [ - { - name = "winapi"; - packageId = "winapi 0.2.8"; - } - ]; - buildDependencies = [ - { - name = "winapi-build"; - packageId = "winapi-build"; - } - ]; - - }; - "lazy_static 0.2.11" = rec { - crateName = "lazy_static"; - version = "0.2.11"; - edition = "2015"; - sha256 = "0wxy8vak7jsx6r8gx475pjqpx11p2bfq4wvw6idmqi31mp3k7w3n"; - authors = [ - "Marvin Löbel " - ]; - features = { - "compiletest" = [ "compiletest_rs" ]; - "compiletest_rs" = [ "dep:compiletest_rs" ]; - "spin" = [ "dep:spin" ]; - "spin_no_std" = [ "nightly" "spin" ]; - }; - }; - "lazy_static 1.5.0" = rec { - crateName = "lazy_static"; - version = "1.5.0"; - edition = "2015"; - sha256 = "1zk6dqqni0193xg6iijh7i3i44sryglwgvx20spdvwk3r6sbrlmv"; - authors = [ - "Marvin Löbel " - ]; - features = { - "spin" = [ "dep:spin" ]; - "spin_no_std" = [ "spin" ]; - }; - }; - "libc" = rec { - crateName = "libc"; - version = "0.2.169"; - edition = "2021"; - sha256 = "02m253hs8gw0m1n8iyrsc4n15yzbqwhddi7w1l0ds7i92kdsiaxm"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "default" = [ "std" ]; - "rustc-dep-of-std" = [ "align" "rustc-std-workspace-core" ]; - "rustc-std-workspace-core" = [ "dep:rustc-std-workspace-core" ]; - "use_std" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "extra_traits" "std" ]; - }; - "libz-sys" = rec { - crateName = "libz-sys"; - version = "1.1.21"; - edition = "2018"; - links = "z"; - sha256 = "1ajfpf413j9m7kmf4fwvvgv5jxxm5s438f2pfbv2c2vf1vjni6yz"; - libName = "libz_sys"; - authors = [ - "Alex Crichton " - "Josh Triplett " - "Sebastian Thiel " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - optional = true; - } - ]; - buildDependencies = [ - { - name = "cc"; - packageId = "cc"; - } - { - name = "pkg-config"; - packageId = "pkg-config"; - } - { - name = "vcpkg"; - packageId = "vcpkg"; - } - ]; - features = { - "cmake" = [ "dep:cmake" ]; - "default" = [ "libc" "stock-zlib" ]; - "libc" = [ "dep:libc" ]; - "zlib-ng" = [ "libc" "cmake" ]; - "zlib-ng-no-cmake-experimental-community-maintained" = [ "libc" ]; - }; - resolvedDefaultFeatures = [ "libc" ]; - }; - "linked-hash-map 0.3.0" = rec { - crateName = "linked-hash-map"; - version = "0.3.0"; - edition = "2015"; - sha256 = "1kaf95grvfqchxn8pl0854g8ab0fzl56217hndhhhz5qqm2j09kd"; - libName = "linked_hash_map"; - authors = [ - "Stepan Koltsov " - "Andrew Paseltiner " - ]; - dependencies = [ - { - name = "serde"; - packageId = "serde 0.8.23"; - optional = true; - } - { - name = "serde_test"; - packageId = "serde_test"; - optional = true; - } - ]; - features = { - "clippy" = [ "dep:clippy" ]; - "serde" = [ "dep:serde" ]; - "serde_impl" = [ "serde" "serde_test" ]; - "serde_test" = [ "dep:serde_test" ]; - }; - resolvedDefaultFeatures = [ "serde" "serde_impl" "serde_test" ]; - }; - "linked-hash-map 0.5.6" = rec { - crateName = "linked-hash-map"; - version = "0.5.6"; - edition = "2015"; - sha256 = "03vpgw7x507g524nx5i1jf5dl8k3kv0fzg8v3ip6qqwbpkqww5q7"; - libName = "linked_hash_map"; - authors = [ - "Stepan Koltsov " - "Andrew Paseltiner " - ]; - features = { - "heapsize" = [ "dep:heapsize" ]; - "heapsize_impl" = [ "heapsize" ]; - "serde" = [ "dep:serde" ]; - "serde_impl" = [ "serde" ]; - }; - }; - "linux-raw-sys" = rec { - crateName = "linux-raw-sys"; - version = "0.4.15"; - edition = "2021"; - sha256 = "1aq7r2g7786hyxhv40spzf2nhag5xbw2axxc1k8z5k1dsgdm4v6j"; - libName = "linux_raw_sys"; - authors = [ - "Dan Gohman " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" "general" "errno" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" "no_std" ]; - }; - resolvedDefaultFeatures = [ "elf" "errno" "general" "ioctl" "no_std" ]; - }; - "lock_api 0.3.4" = rec { - crateName = "lock_api"; - version = "0.3.4"; - edition = "2018"; - sha256 = "0xgc5dzmajh0akbh5d6d7rj9mh5rzpk74pyrc946v2ixgakj9nn4"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "scopeguard"; - packageId = "scopeguard"; - usesDefaultFeatures = false; - } - ]; - features = { - "owning_ref" = [ "dep:owning_ref" ]; - "serde" = [ "dep:serde" ]; - }; - }; - "lock_api 0.4.12" = rec { - crateName = "lock_api"; - version = "0.4.12"; - edition = "2021"; - sha256 = "05qvxa6g27yyva25a5ghsg85apdxkvr77yhkyhapj6r8vnf8pbq7"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "scopeguard"; - packageId = "scopeguard"; - usesDefaultFeatures = false; - } - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { - "default" = [ "atomic_usize" ]; - "owning_ref" = [ "dep:owning_ref" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "atomic_usize" "default" ]; - }; - "log" = rec { - crateName = "log"; - version = "0.4.25"; - edition = "2021"; - sha256 = "17ydv5zhfv1zzygy458bmg3f3jx1vfziv9d74817w76yhfqgbjq4"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "kv_serde" = [ "kv_std" "value-bag/serde" "serde" ]; - "kv_std" = [ "std" "kv" "value-bag/error" ]; - "kv_sval" = [ "kv" "value-bag/sval" "sval" "sval_ref" ]; - "kv_unstable" = [ "kv" "value-bag" ]; - "kv_unstable_serde" = [ "kv_serde" "kv_unstable_std" ]; - "kv_unstable_std" = [ "kv_std" "kv_unstable" ]; - "kv_unstable_sval" = [ "kv_sval" "kv_unstable" ]; - "serde" = [ "dep:serde" ]; - "sval" = [ "dep:sval" ]; - "sval_ref" = [ "dep:sval_ref" ]; - "value-bag" = [ "dep:value-bag" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "maybe-uninit" = rec { - crateName = "maybe-uninit"; - version = "2.0.0"; - edition = "2015"; - sha256 = "004y0nzmpfdrhz251278341z6ql34iv1k6dp1h6af7d6nd6jwc30"; - libName = "maybe_uninit"; - authors = [ - "est31 " - "The Rust Project Developers" - ]; - - }; - "memchr" = rec { - crateName = "memchr"; - version = "2.7.4"; - edition = "2021"; - sha256 = "18z32bhxrax0fnjikv475z7ii718hq457qwmaryixfxsl2qrmjkq"; - authors = [ - "Andrew Gallant " - "bluss" - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" ]; - "logging" = [ "dep:log" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - "std" = [ "alloc" ]; - "use_std" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "std" "use_std" ]; - }; - "memoffset" = rec { - crateName = "memoffset"; - version = "0.5.6"; - edition = "2015"; - sha256 = "1ahi51aa650s2p9ib1a4ifgqv0pzmsxlm9z4xdgvi9zdd7q7ac84"; - authors = [ - "Gilad Naaman " - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "miniz_oxide" = rec { - crateName = "miniz_oxide"; - version = "0.8.4"; - edition = "2021"; - sha256 = "06ydc8zp00832jwyyl2pbqc2dam1njrrxsznhyrziw719yywkcdk"; - authors = [ - "Frommi " - "oyvindln " - "Rich Geldreich richgel99@gmail.com" - ]; - dependencies = [ - { - name = "adler2"; - packageId = "adler2"; - usesDefaultFeatures = false; - } - ]; - features = { - "alloc" = [ "dep:alloc" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "with-alloc" ]; - "rustc-dep-of-std" = [ "core" "alloc" "compiler_builtins" "adler2/rustc-dep-of-std" ]; - "simd" = [ "simd-adler32" ]; - "simd-adler32" = [ "dep:simd-adler32" ]; - }; - }; - "mio" = rec { - crateName = "mio"; - version = "0.6.23"; - edition = "2015"; - sha256 = "1i2c1vl8lr45apkh8xbh9k56ihfsmqff5l7s2fya7whvp7sndzaa"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 0.1.10"; - } - { - name = "fuchsia-zircon"; - packageId = "fuchsia-zircon"; - target = { target, features }: ("fuchsia" == target."os" or null); - } - { - name = "fuchsia-zircon-sys"; - packageId = "fuchsia-zircon-sys"; - target = { target, features }: ("fuchsia" == target."os" or null); - } - { - name = "iovec"; - packageId = "iovec"; - } - { - name = "kernel32-sys"; - packageId = "kernel32-sys"; - target = { target, features }: (target."windows" or false); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "log"; - packageId = "log"; - } - { - name = "miow"; - packageId = "miow"; - target = { target, features }: (target."windows" or false); - } - { - name = "net2"; - packageId = "net2"; - } - { - name = "slab"; - packageId = "slab 0.4.9"; - } - { - name = "winapi"; - packageId = "winapi 0.2.8"; - target = { target, features }: (target."windows" or false); - } - ]; - features = { - "default" = [ "with-deprecated" ]; - }; - resolvedDefaultFeatures = [ "default" "with-deprecated" ]; - }; - "mio-uds" = rec { - crateName = "mio-uds"; - version = "0.6.8"; - edition = "2015"; - sha256 = "1w36w09gd8as1mah80wdy0kgpshmphmljj68gij34hvdnag6kjxg"; - libName = "mio_uds"; - authors = [ - "Alex Crichton " - ]; - dependencies = [ - { - name = "iovec"; - packageId = "iovec"; - target = { target, features }: (target."unix" or false); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "mio"; - packageId = "mio"; - target = { target, features }: (target."unix" or false); - } - ]; - - }; - "miow" = rec { - crateName = "miow"; - version = "0.2.2"; - edition = "2015"; - sha256 = "0kcl8rnv0bhiarcdakik670w8fnxzlxhi1ys7152sck68510in7b"; - authors = [ - "Alex Crichton " - ]; - dependencies = [ - { - name = "kernel32-sys"; - packageId = "kernel32-sys"; - } - { - name = "net2"; - packageId = "net2"; - usesDefaultFeatures = false; - } - { - name = "winapi"; - packageId = "winapi 0.2.8"; - } - { - name = "ws2_32-sys"; - packageId = "ws2_32-sys"; - } - ]; - - }; - "native-tls" = rec { - crateName = "native-tls"; - version = "0.2.13"; - edition = "2015"; - sha256 = "0v0rafrzmr5dcnizvj8awa1s8rbgzc394zfq9n7dzmahw3w5kaqd"; - libName = "native_tls"; - authors = [ - "Steven Fackler " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - target = { target, features }: ("apple" == target."vendor" or null); - } - { - name = "log"; - packageId = "log"; - target = { target, features }: (!(("windows" == target."os" or null) || ("apple" == target."vendor" or null))); - } - { - name = "openssl"; - packageId = "openssl"; - target = { target, features }: (!(("windows" == target."os" or null) || ("apple" == target."vendor" or null))); - } - { - name = "openssl-probe"; - packageId = "openssl-probe"; - target = { target, features }: (!(("windows" == target."os" or null) || ("apple" == target."vendor" or null))); - } - { - name = "openssl-sys"; - packageId = "openssl-sys"; - target = { target, features }: (!(("windows" == target."os" or null) || ("apple" == target."vendor" or null))); - } - { - name = "schannel"; - packageId = "schannel"; - target = { target, features }: ("windows" == target."os" or null); - } - { - name = "security-framework"; - packageId = "security-framework"; - target = { target, features }: ("apple" == target."vendor" or null); - } - { - name = "security-framework-sys"; - packageId = "security-framework-sys"; - target = { target, features }: ("apple" == target."vendor" or null); - } - { - name = "tempfile"; - packageId = "tempfile"; - target = { target, features }: ("macos" == target."os" or null); - } - ]; - devDependencies = [ - { - name = "tempfile"; - packageId = "tempfile"; - } - ]; - features = { - "alpn" = [ "security-framework/alpn" ]; - "vendored" = [ "openssl/vendored" ]; - }; - }; - "net2" = rec { - crateName = "net2"; - version = "0.2.39"; - edition = "2015"; - sha256 = "1b1lxvs192xsvqnszcz7dn4dw3fsvzxnc23qvq39scx26s068fxi"; - authors = [ - "Alex Crichton " - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 0.1.10"; - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: ((target."unix" or false) || ("wasi" == target."os" or null)); - } - { - name = "winapi"; - packageId = "winapi 0.3.9"; - target = { target, features }: (target."windows" or false); - features = [ "handleapi" "winsock2" "ws2def" "ws2ipdef" "ws2tcpip" ]; - } - ]; - features = { - "default" = [ "duration" ]; - }; - resolvedDefaultFeatures = [ "default" "duration" ]; - }; - "nom" = rec { - crateName = "nom"; - version = "4.2.3"; - edition = "2015"; - sha256 = "1mkvby8b4m61p4g1px0pwr58yfkphyp1jcfbp4qfp7l6iqdaklia"; - authors = [ - "contact@geoffroycouprie.com" - ]; - dependencies = [ - { - name = "memchr"; - packageId = "memchr"; - usesDefaultFeatures = false; - } - ]; - buildDependencies = [ - { - name = "version_check"; - packageId = "version_check"; - } - ]; - features = { - "default" = [ "std" ]; - "lazy_static" = [ "dep:lazy_static" ]; - "regex" = [ "dep:regex" ]; - "regexp" = [ "regex" ]; - "regexp_macros" = [ "regexp" "lazy_static" ]; - "std" = [ "alloc" "memchr/use_std" ]; - "verbose-errors" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "num-traits 0.1.43" = rec { - crateName = "num-traits"; - version = "0.1.43"; - edition = "2015"; - sha256 = "0c9whknf2dm74a3cqirafy6gj83a76gl56g4v3g19k6lkwz13rcj"; - libName = "num_traits"; - authors = [ - "The Rust Project Developers" - ]; - dependencies = [ - { - name = "num-traits"; - packageId = "num-traits 0.2.19"; - } - ]; - - }; - "num-traits 0.2.19" = rec { - crateName = "num-traits"; - version = "0.2.19"; - edition = "2021"; - sha256 = "0h984rhdkkqd4ny9cif7y2azl3xdfb7768hb9irhpsch4q3gq787"; - libName = "num_traits"; - authors = [ - "The Rust Project Developers" - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { - "default" = [ "std" ]; - "libm" = [ "dep:libm" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "num_cpus" = rec { - crateName = "num_cpus"; - version = "1.16.0"; - edition = "2015"; - sha256 = "0hra6ihpnh06dvfvz9ipscys0xfqa9ca9hzp384d5m02ssvgqqa1"; - authors = [ - "Sean McArthur " - ]; - dependencies = [ - { - name = "hermit-abi"; - packageId = "hermit-abi 0.3.9"; - target = { target, features }: ("hermit" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (!(target."windows" or false)); - } - ]; - - }; - "object" = rec { - crateName = "object"; - version = "0.36.7"; - edition = "2018"; - sha256 = "11vv97djn9nc5n6w1gc6bd96d2qk2c8cg1kw5km9bsi3v4a8x532"; - dependencies = [ - { - name = "memchr"; - packageId = "memchr"; - usesDefaultFeatures = false; - } - ]; - features = { - "all" = [ "read" "write" "build" "std" "compression" "wasm" ]; - "alloc" = [ "dep:alloc" ]; - "build" = [ "build_core" "write_std" "elf" ]; - "build_core" = [ "read_core" "write_core" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "compression" = [ "dep:flate2" "dep:ruzstd" "std" ]; - "core" = [ "dep:core" ]; - "default" = [ "read" "compression" ]; - "doc" = [ "read_core" "write_std" "build_core" "std" "compression" "archive" "coff" "elf" "macho" "pe" "wasm" "xcoff" ]; - "pe" = [ "coff" ]; - "read" = [ "read_core" "archive" "coff" "elf" "macho" "pe" "xcoff" "unaligned" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" "alloc" "memchr/rustc-dep-of-std" ]; - "std" = [ "memchr/std" ]; - "unstable-all" = [ "all" "unstable" ]; - "wasm" = [ "dep:wasmparser" ]; - "write" = [ "write_std" "coff" "elf" "macho" "pe" "xcoff" ]; - "write_core" = [ "dep:crc32fast" "dep:indexmap" "dep:hashbrown" ]; - "write_std" = [ "write_core" "std" "indexmap?/std" "crc32fast?/std" ]; - }; - resolvedDefaultFeatures = [ "archive" "coff" "elf" "macho" "pe" "read_core" "unaligned" "xcoff" ]; - }; - "once_cell" = rec { - crateName = "once_cell"; - version = "1.20.3"; - edition = "2021"; - sha256 = "0bp6rgrsri1vfdcahsimk08zdiilv14ppgcnpbiw8hqyp2j64m4l"; - authors = [ - "Aleksey Kladov " - ]; - features = { - "alloc" = [ "race" ]; - "atomic-polyfill" = [ "critical-section" ]; - "critical-section" = [ "dep:critical-section" "portable-atomic" ]; - "default" = [ "std" ]; - "parking_lot" = [ "dep:parking_lot_core" ]; - "portable-atomic" = [ "dep:portable-atomic" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "race" "std" ]; - }; - "openssl" = rec { - crateName = "openssl"; - version = "0.10.71"; - edition = "2021"; - sha256 = "1kgvk6wi57bacn6b5z6b57vkyd2j85s6vyxhvj7jbkcqd861652y"; - authors = [ - "Steven Fackler " - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 2.8.0"; - } - { - name = "cfg-if"; - packageId = "cfg-if 1.0.0"; - } - { - name = "foreign-types"; - packageId = "foreign-types"; - } - { - name = "libc"; - packageId = "libc"; - } - { - name = "once_cell"; - packageId = "once_cell"; - } - { - name = "openssl-macros"; - packageId = "openssl-macros"; - } - { - name = "openssl-sys"; - packageId = "openssl-sys"; - rename = "ffi"; - } - ]; - features = { - "bindgen" = [ "ffi/bindgen" ]; - "unstable_boringssl" = [ "ffi/unstable_boringssl" ]; - "vendored" = [ "ffi/vendored" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "openssl-macros" = rec { - crateName = "openssl-macros"; - version = "0.1.1"; - edition = "2018"; - sha256 = "173xxvfc63rr5ybwqwylsir0vq6xsj4kxiv4hmg4c3vscdmncj59"; - procMacro = true; - libName = "openssl_macros"; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn 2.0.98"; - features = [ "full" ]; - } - ]; - - }; - "openssl-probe" = rec { - crateName = "openssl-probe"; - version = "0.1.6"; - edition = "2021"; - sha256 = "0bl52x55laalqb707k009h8kfawliwp992rlsvkzy49n47p2fpnh"; - libName = "openssl_probe"; - authors = [ - "Alex Crichton " - ]; - - }; - "openssl-sys" = rec { - crateName = "openssl-sys"; - version = "0.9.106"; - edition = "2021"; - links = "openssl"; - sha256 = "1pbwfy5x8znchsbqf7rnkdbdhw1fis5hpx3940y9xhqwh6lixdlb"; - build = "build/main.rs"; - libName = "openssl_sys"; - authors = [ - "Alex Crichton " - "Steven Fackler " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - } - ]; - buildDependencies = [ - { - name = "cc"; - packageId = "cc"; - } - { - name = "pkg-config"; - packageId = "pkg-config"; - } - { - name = "vcpkg"; - packageId = "vcpkg"; - } - ]; - features = { - "bindgen" = [ "dep:bindgen" ]; - "bssl-sys" = [ "dep:bssl-sys" ]; - "openssl-src" = [ "dep:openssl-src" ]; - "unstable_boringssl" = [ "bssl-sys" ]; - "vendored" = [ "openssl-src" ]; - }; - }; - "parking_lot 0.12.3" = rec { - crateName = "parking_lot"; - version = "0.12.3"; - edition = "2021"; - sha256 = "09ws9g6245iiq8z975h8ycf818a66q3c6zv4b5h8skpm7hc1igzi"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "lock_api"; - packageId = "lock_api 0.4.12"; - } - { - name = "parking_lot_core"; - packageId = "parking_lot_core 0.9.10"; - } - ]; - features = { - "arc_lock" = [ "lock_api/arc_lock" ]; - "deadlock_detection" = [ "parking_lot_core/deadlock_detection" ]; - "nightly" = [ "parking_lot_core/nightly" "lock_api/nightly" ]; - "owning_ref" = [ "lock_api/owning_ref" ]; - "serde" = [ "lock_api/serde" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "parking_lot 0.9.0" = rec { - crateName = "parking_lot"; - version = "0.9.0"; - edition = "2018"; - sha256 = "0lk2vq3hp88ygpgsrypdr3ss71fidnqbykva0csgxhmn5scb2hpq"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "lock_api"; - packageId = "lock_api 0.3.4"; - } - { - name = "parking_lot_core"; - packageId = "parking_lot_core 0.6.3"; - } - ]; - buildDependencies = [ - { - name = "rustc_version"; - packageId = "rustc_version"; - } - ]; - features = { - "deadlock_detection" = [ "parking_lot_core/deadlock_detection" ]; - "nightly" = [ "parking_lot_core/nightly" "lock_api/nightly" ]; - "owning_ref" = [ "lock_api/owning_ref" ]; - "serde" = [ "lock_api/serde" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "parking_lot_core 0.6.3" = rec { - crateName = "parking_lot_core"; - version = "0.6.3"; - edition = "2018"; - sha256 = "02kbwqrr0w5mw0hkklqcg35aaiq1cck3g1w0d8bpbgk21a0np9mx"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 0.1.10"; - } - { - name = "cloudabi"; - packageId = "cloudabi"; - target = { target, features }: ("cloudabi" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "redox_syscall"; - packageId = "redox_syscall 0.1.57"; - target = { target, features }: ("redox" == target."os" or null); - } - { - name = "smallvec"; - packageId = "smallvec 0.6.14"; - } - { - name = "winapi"; - packageId = "winapi 0.3.9"; - target = { target, features }: (target."windows" or false); - features = [ "winnt" "ntstatus" "minwindef" "winerror" "winbase" "errhandlingapi" "handleapi" ]; - } - ]; - buildDependencies = [ - { - name = "rustc_version"; - packageId = "rustc_version"; - } - ]; - features = { - "backtrace" = [ "dep:backtrace" ]; - "deadlock_detection" = [ "petgraph" "thread-id" "backtrace" ]; - "petgraph" = [ "dep:petgraph" ]; - "thread-id" = [ "dep:thread-id" ]; - }; - }; - "parking_lot_core 0.9.10" = rec { - crateName = "parking_lot_core"; - version = "0.9.10"; - edition = "2021"; - sha256 = "1y3cf9ld9ijf7i4igwzffcn0xl16dxyn4c5bwgjck1dkgabiyh0y"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 1.0.0"; - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "redox_syscall"; - packageId = "redox_syscall 0.5.8"; - target = { target, features }: ("redox" == target."os" or null); - } - { - name = "smallvec"; - packageId = "smallvec 1.14.0"; - } - { - name = "windows-targets"; - packageId = "windows-targets"; - target = { target, features }: (target."windows" or false); - } - ]; - features = { - "backtrace" = [ "dep:backtrace" ]; - "deadlock_detection" = [ "petgraph" "thread-id" "backtrace" ]; - "petgraph" = [ "dep:petgraph" ]; - "thread-id" = [ "dep:thread-id" ]; - }; - }; - "paroxysm" = rec { - crateName = "paroxysm"; - version = "0.1.0"; - edition = "2018"; - crateBin = [ - { - name = "paroxysm"; - path = "src/main.rs"; - requiredFeatures = [ ]; - } - ]; - src = lib.cleanSourceWith { filter = sourceFilter; src = ./.; }; - authors = [ - "eeeeeta " - ]; - dependencies = [ - { - name = "chrono"; - packageId = "chrono"; - } - { - name = "config"; - packageId = "config"; - } - { - name = "crimp"; - packageId = "crimp"; - } - { - name = "diesel"; - packageId = "diesel"; - features = [ "postgres" "chrono" "r2d2" ]; - } - { - name = "env_logger"; - packageId = "env_logger"; - } - { - name = "failure"; - packageId = "failure"; - } - { - name = "irc"; - packageId = "irc"; - } - { - name = "lazy_static"; - packageId = "lazy_static 1.5.0"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "pq-sys"; - packageId = "pq-sys"; - features = [ "pkg-config" ]; - } - { - name = "rand"; - packageId = "rand"; - } - { - name = "regex"; - packageId = "regex"; - } - { - name = "serde"; - packageId = "serde 1.0.217"; - features = [ "derive" ]; - } - ]; - - }; - "pkg-config" = rec { - crateName = "pkg-config"; - version = "0.3.31"; - edition = "2018"; - sha256 = "1wk6yp2phl91795ia0lwkr3wl4a9xkrympvhqq8cxk4d75hwhglm"; - libName = "pkg_config"; - authors = [ - "Alex Crichton " - ]; - - }; - "ppv-lite86" = rec { - crateName = "ppv-lite86"; - version = "0.2.20"; - edition = "2021"; - sha256 = "017ax9ssdnpww7nrl1hvqh2lzncpv04nnsibmnw9nxjnaqlpp5bp"; - libName = "ppv_lite86"; - authors = [ - "The CryptoCorrosion Contributors" - ]; - dependencies = [ - { - name = "zerocopy"; - packageId = "zerocopy"; - features = [ "simd" "derive" ]; - } - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "simd" "std" ]; - }; - "pq-sys" = rec { - crateName = "pq-sys"; - version = "0.4.8"; - edition = "2015"; - links = "pq"; - sha256 = "1gfygvp69i5i6vxbi9qp2xaf75x09js9wy1hpl67r6fz4qj0bh1i"; - libName = "pq_sys"; - buildDependencies = [ - { - name = "pkg-config"; - packageId = "pkg-config"; - optional = true; - } - { - name = "vcpkg"; - packageId = "vcpkg"; - target = { target, features }: ("msvc" == target."env" or null); - } - ]; - features = { - "pkg-config" = [ "dep:pkg-config" ]; - }; - resolvedDefaultFeatures = [ "pkg-config" ]; - }; - "proc-macro2" = rec { - crateName = "proc-macro2"; - version = "1.0.93"; - edition = "2021"; - sha256 = "169dw9wch753if1mgyi2nfl1il77gslvh6y2q46qplprwml6m530"; - libName = "proc_macro2"; - authors = [ - "David Tolnay " - "Alex Crichton " - ]; - dependencies = [ - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - features = { - "default" = [ "proc-macro" ]; - }; - resolvedDefaultFeatures = [ "default" "proc-macro" ]; - }; - "quick-error" = rec { - crateName = "quick-error"; - version = "1.2.3"; - edition = "2015"; - sha256 = "1q6za3v78hsspisc197bg3g7rpc989qycy8ypr8ap8igv10ikl51"; - libName = "quick_error"; - authors = [ - "Paul Colomiets " - "Colin Kiegel " - ]; - - }; - "quote" = rec { - crateName = "quote"; - version = "1.0.38"; - edition = "2018"; - sha256 = "1k0s75w61k6ch0rs263r4j69b7vj1wadqgb9dia4ylc9mymcqk8f"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "proc-macro" ]; - "proc-macro" = [ "proc-macro2/proc-macro" ]; - }; - resolvedDefaultFeatures = [ "default" "proc-macro" ]; - }; - "r2d2" = rec { - crateName = "r2d2"; - version = "0.8.10"; - edition = "2018"; - sha256 = "14qw32y4m564xb1f5ya8ii7dwqyknvk8bsx2r0lljlmn7zxqbpji"; - authors = [ - "Steven Fackler " - ]; - dependencies = [ - { - name = "log"; - packageId = "log"; - } - { - name = "parking_lot"; - packageId = "parking_lot 0.12.3"; - } - { - name = "scheduled-thread-pool"; - packageId = "scheduled-thread-pool"; - } - ]; - - }; - "rand" = rec { - crateName = "rand"; - version = "0.7.3"; - edition = "2018"; - sha256 = "00sdaimkbz491qgi6qxkv582yivl32m2jd401kzbn94vsiwicsva"; - authors = [ - "The Rand Project Developers" - "The Rust Project Developers" - ]; - dependencies = [ - { - name = "getrandom"; - packageId = "getrandom 0.1.16"; - rename = "getrandom_package"; - optional = true; - } - { - name = "libc"; - packageId = "libc"; - optional = true; - usesDefaultFeatures = false; - target = { target, features }: (target."unix" or false); - } - { - name = "rand_chacha"; - packageId = "rand_chacha"; - usesDefaultFeatures = false; - target = { target, features }: (!("emscripten" == target."os" or null)); - } - { - name = "rand_core"; - packageId = "rand_core"; - } - { - name = "rand_hc"; - packageId = "rand_hc"; - target = { target, features }: ("emscripten" == target."os" or null); - } - ]; - devDependencies = [ - { - name = "rand_hc"; - packageId = "rand_hc"; - } - ]; - features = { - "alloc" = [ "rand_core/alloc" ]; - "default" = [ "std" ]; - "getrandom" = [ "getrandom_package" "rand_core/getrandom" ]; - "getrandom_package" = [ "dep:getrandom_package" ]; - "libc" = [ "dep:libc" ]; - "log" = [ "dep:log" ]; - "nightly" = [ "simd_support" ]; - "packed_simd" = [ "dep:packed_simd" ]; - "rand_pcg" = [ "dep:rand_pcg" ]; - "simd_support" = [ "packed_simd" ]; - "small_rng" = [ "rand_pcg" ]; - "std" = [ "rand_core/std" "rand_chacha/std" "alloc" "getrandom" "libc" ]; - "stdweb" = [ "getrandom_package/stdweb" ]; - "wasm-bindgen" = [ "getrandom_package/wasm-bindgen" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "getrandom" "getrandom_package" "libc" "std" ]; - }; - "rand_chacha" = rec { - crateName = "rand_chacha"; - version = "0.2.2"; - edition = "2018"; - sha256 = "00il36fkdbsmpr99p9ksmmp6dn1md7rmnwmz0rr77jbrca2yvj7l"; - authors = [ - "The Rand Project Developers" - "The Rust Project Developers" - "The CryptoCorrosion Contributors" - ]; - dependencies = [ - { - name = "ppv-lite86"; - packageId = "ppv-lite86"; - usesDefaultFeatures = false; - features = [ "simd" ]; - } - { - name = "rand_core"; - packageId = "rand_core"; - } - ]; - features = { - "default" = [ "std" "simd" ]; - "std" = [ "ppv-lite86/std" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "rand_core" = rec { - crateName = "rand_core"; - version = "0.5.1"; - edition = "2018"; - sha256 = "06bdvx08v3rkz451cm7z59xwwqn1rkfh6v9ay77b14f8dwlybgch"; - authors = [ - "The Rand Project Developers" - "The Rust Project Developers" - ]; - dependencies = [ - { - name = "getrandom"; - packageId = "getrandom 0.1.16"; - optional = true; - } - ]; - features = { - "getrandom" = [ "dep:getrandom" ]; - "serde" = [ "dep:serde" ]; - "serde1" = [ "serde" ]; - "std" = [ "alloc" "getrandom" "getrandom/std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "getrandom" "std" ]; - }; - "rand_hc" = rec { - crateName = "rand_hc"; - version = "0.2.0"; - edition = "2018"; - sha256 = "0g31sqwpmsirdlwr0svnacr4dbqyz339im4ssl9738cjgfpjjcfa"; - authors = [ - "The Rand Project Developers" - ]; - dependencies = [ - { - name = "rand_core"; - packageId = "rand_core"; - } - ]; - - }; - "redox_syscall 0.1.57" = rec { - crateName = "redox_syscall"; - version = "0.1.57"; - edition = "2015"; - sha256 = "1kh59fpwy33w9nwd5iyc283yglq8pf2s41hnhvl48iax9mz0zk21"; - libName = "syscall"; - authors = [ - "Jeremy Soller " - ]; - - }; - "redox_syscall 0.5.8" = rec { - crateName = "redox_syscall"; - version = "0.5.8"; - edition = "2021"; - sha256 = "0d48ylyd6gsamynyp257p6n2zl4dw2fhnn5z9y3nhgpri6rn5a03"; - libName = "syscall"; - authors = [ - "Jeremy Soller " - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 2.8.0"; - } - ]; - features = { - "core" = [ "dep:core" ]; - "default" = [ "userspace" ]; - "rustc-dep-of-std" = [ "core" "bitflags/rustc-dep-of-std" ]; - }; - resolvedDefaultFeatures = [ "default" "userspace" ]; - }; - "regex" = rec { - crateName = "regex"; - version = "1.11.1"; - edition = "2021"; - sha256 = "148i41mzbx8bmq32hsj1q4karkzzx5m60qza6gdw4pdc9qdyyi5m"; - authors = [ - "The Rust Project Developers" - "Andrew Gallant " - ]; - dependencies = [ - { - name = "aho-corasick"; - packageId = "aho-corasick"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "memchr"; - packageId = "memchr"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "regex-automata"; - packageId = "regex-automata"; - usesDefaultFeatures = false; - features = [ "alloc" "syntax" "meta" "nfa-pikevm" ]; - } - { - name = "regex-syntax"; - packageId = "regex-syntax"; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "std" "perf" "unicode" "regex-syntax/default" ]; - "logging" = [ "aho-corasick?/logging" "memchr?/logging" "regex-automata/logging" ]; - "perf" = [ "perf-cache" "perf-dfa" "perf-onepass" "perf-backtrack" "perf-inline" "perf-literal" ]; - "perf-backtrack" = [ "regex-automata/nfa-backtrack" ]; - "perf-dfa" = [ "regex-automata/hybrid" ]; - "perf-dfa-full" = [ "regex-automata/dfa-build" "regex-automata/dfa-search" ]; - "perf-inline" = [ "regex-automata/perf-inline" ]; - "perf-literal" = [ "dep:aho-corasick" "dep:memchr" "regex-automata/perf-literal" ]; - "perf-onepass" = [ "regex-automata/dfa-onepass" ]; - "std" = [ "aho-corasick?/std" "memchr?/std" "regex-automata/std" "regex-syntax/std" ]; - "unicode" = [ "unicode-age" "unicode-bool" "unicode-case" "unicode-gencat" "unicode-perl" "unicode-script" "unicode-segment" "regex-automata/unicode" "regex-syntax/unicode" ]; - "unicode-age" = [ "regex-automata/unicode-age" "regex-syntax/unicode-age" ]; - "unicode-bool" = [ "regex-automata/unicode-bool" "regex-syntax/unicode-bool" ]; - "unicode-case" = [ "regex-automata/unicode-case" "regex-syntax/unicode-case" ]; - "unicode-gencat" = [ "regex-automata/unicode-gencat" "regex-syntax/unicode-gencat" ]; - "unicode-perl" = [ "regex-automata/unicode-perl" "regex-automata/unicode-word-boundary" "regex-syntax/unicode-perl" ]; - "unicode-script" = [ "regex-automata/unicode-script" "regex-syntax/unicode-script" ]; - "unicode-segment" = [ "regex-automata/unicode-segment" "regex-syntax/unicode-segment" ]; - "unstable" = [ "pattern" ]; - "use_std" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "perf" "perf-backtrack" "perf-cache" "perf-dfa" "perf-inline" "perf-literal" "perf-onepass" "std" "unicode" "unicode-age" "unicode-bool" "unicode-case" "unicode-gencat" "unicode-perl" "unicode-script" "unicode-segment" ]; - }; - "regex-automata" = rec { - crateName = "regex-automata"; - version = "0.4.9"; - edition = "2021"; - sha256 = "02092l8zfh3vkmk47yjc8d631zhhcd49ck2zr133prvd3z38v7l0"; - libName = "regex_automata"; - authors = [ - "The Rust Project Developers" - "Andrew Gallant " - ]; - dependencies = [ - { - name = "aho-corasick"; - packageId = "aho-corasick"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "memchr"; - packageId = "memchr"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "regex-syntax"; - packageId = "regex-syntax"; - optional = true; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "std" "syntax" "perf" "unicode" "meta" "nfa" "dfa" "hybrid" ]; - "dfa" = [ "dfa-build" "dfa-search" "dfa-onepass" ]; - "dfa-build" = [ "nfa-thompson" "dfa-search" ]; - "dfa-onepass" = [ "nfa-thompson" ]; - "hybrid" = [ "alloc" "nfa-thompson" ]; - "internal-instrument" = [ "internal-instrument-pikevm" ]; - "internal-instrument-pikevm" = [ "logging" "std" ]; - "logging" = [ "dep:log" "aho-corasick?/logging" "memchr?/logging" ]; - "meta" = [ "syntax" "nfa-pikevm" ]; - "nfa" = [ "nfa-thompson" "nfa-pikevm" "nfa-backtrack" ]; - "nfa-backtrack" = [ "nfa-thompson" ]; - "nfa-pikevm" = [ "nfa-thompson" ]; - "nfa-thompson" = [ "alloc" ]; - "perf" = [ "perf-inline" "perf-literal" ]; - "perf-literal" = [ "perf-literal-substring" "perf-literal-multisubstring" ]; - "perf-literal-multisubstring" = [ "std" "dep:aho-corasick" ]; - "perf-literal-substring" = [ "aho-corasick?/perf-literal" "dep:memchr" ]; - "std" = [ "regex-syntax?/std" "memchr?/std" "aho-corasick?/std" "alloc" ]; - "syntax" = [ "dep:regex-syntax" "alloc" ]; - "unicode" = [ "unicode-age" "unicode-bool" "unicode-case" "unicode-gencat" "unicode-perl" "unicode-script" "unicode-segment" "unicode-word-boundary" "regex-syntax?/unicode" ]; - "unicode-age" = [ "regex-syntax?/unicode-age" ]; - "unicode-bool" = [ "regex-syntax?/unicode-bool" ]; - "unicode-case" = [ "regex-syntax?/unicode-case" ]; - "unicode-gencat" = [ "regex-syntax?/unicode-gencat" ]; - "unicode-perl" = [ "regex-syntax?/unicode-perl" ]; - "unicode-script" = [ "regex-syntax?/unicode-script" ]; - "unicode-segment" = [ "regex-syntax?/unicode-segment" ]; - }; - resolvedDefaultFeatures = [ "alloc" "dfa-onepass" "hybrid" "meta" "nfa-backtrack" "nfa-pikevm" "nfa-thompson" "perf-inline" "perf-literal" "perf-literal-multisubstring" "perf-literal-substring" "std" "syntax" "unicode" "unicode-age" "unicode-bool" "unicode-case" "unicode-gencat" "unicode-perl" "unicode-script" "unicode-segment" "unicode-word-boundary" ]; - }; - "regex-syntax" = rec { - crateName = "regex-syntax"; - version = "0.8.5"; - edition = "2021"; - sha256 = "0p41p3hj9ww7blnbwbj9h7rwxzxg0c1hvrdycgys8rxyhqqw859b"; - libName = "regex_syntax"; - authors = [ - "The Rust Project Developers" - "Andrew Gallant " - ]; - features = { - "arbitrary" = [ "dep:arbitrary" ]; - "default" = [ "std" "unicode" ]; - "unicode" = [ "unicode-age" "unicode-bool" "unicode-case" "unicode-gencat" "unicode-perl" "unicode-script" "unicode-segment" ]; - }; - resolvedDefaultFeatures = [ "default" "std" "unicode" "unicode-age" "unicode-bool" "unicode-case" "unicode-gencat" "unicode-perl" "unicode-script" "unicode-segment" ]; - }; - "rust-ini" = rec { - crateName = "rust-ini"; - version = "0.13.0"; - edition = "2015"; - sha256 = "1hifnbgaz01zja5995chy6vjacbif2m76nlxsisw7y1pxx4c2liy"; - libName = "ini"; - authors = [ - "Y. T. Chung " - ]; - - }; - "rustc-demangle" = rec { - crateName = "rustc-demangle"; - version = "0.1.24"; - edition = "2015"; - sha256 = "07zysaafgrkzy2rjgwqdj2a8qdpsm6zv6f5pgpk9x0lm40z9b6vi"; - libName = "rustc_demangle"; - authors = [ - "Alex Crichton " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - }; - "rustc_version" = rec { - crateName = "rustc_version"; - version = "0.2.3"; - edition = "2015"; - sha256 = "02h3x57lcr8l2pm0a645s9whdh33pn5cnrwvn5cb57vcrc53x3hk"; - authors = [ - "Marvin Löbel " - ]; - dependencies = [ - { - name = "semver"; - packageId = "semver"; - } - ]; - - }; - "rustix" = rec { - crateName = "rustix"; - version = "0.38.44"; - edition = "2021"; - sha256 = "0m61v0h15lf5rrnbjhcb9306bgqrhskrqv7i1n0939dsw8dbrdgx"; - authors = [ - "Dan Gohman " - "Jakub Konka " - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 2.8.0"; - usesDefaultFeatures = false; - } - { - name = "errno"; - packageId = "errno"; - rename = "libc_errno"; - optional = true; - usesDefaultFeatures = false; - target = { target, features }: ((!(target."rustix_use_libc" or false)) && (!(target."miri" or false)) && ("linux" == target."os" or null) && (("little" == target."endian" or null) || ("s390x" == target."arch" or null)) && (("arm" == target."arch" or null) || (("aarch64" == target."arch" or null) && ("64" == target."pointer_width" or null)) || ("riscv64" == target."arch" or null) || ((target."rustix_use_experimental_asm" or false) && ("powerpc64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("s390x" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips32r6" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64r6" == target."arch" or null)) || ("x86" == target."arch" or null) || (("x86_64" == target."arch" or null) && ("64" == target."pointer_width" or null)))); - } - { - name = "errno"; - packageId = "errno"; - rename = "libc_errno"; - usesDefaultFeatures = false; - target = { target, features }: ((!(target."windows" or false)) && ((target."rustix_use_libc" or false) || (target."miri" or false) || (!(("linux" == target."os" or null) && (("little" == target."endian" or null) || ("s390x" == target."arch" or null)) && (("arm" == target."arch" or null) || (("aarch64" == target."arch" or null) && ("64" == target."pointer_width" or null)) || ("riscv64" == target."arch" or null) || ((target."rustix_use_experimental_asm" or false) && ("powerpc64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("s390x" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips32r6" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64r6" == target."arch" or null)) || ("x86" == target."arch" or null) || (("x86_64" == target."arch" or null) && ("64" == target."pointer_width" or null))))))); - } - { - name = "errno"; - packageId = "errno"; - rename = "libc_errno"; - usesDefaultFeatures = false; - target = { target, features }: (target."windows" or false); - } - { - name = "libc"; - packageId = "libc"; - optional = true; - usesDefaultFeatures = false; - target = { target, features }: ((!(target."rustix_use_libc" or false)) && (!(target."miri" or false)) && ("linux" == target."os" or null) && (("little" == target."endian" or null) || ("s390x" == target."arch" or null)) && (("arm" == target."arch" or null) || (("aarch64" == target."arch" or null) && ("64" == target."pointer_width" or null)) || ("riscv64" == target."arch" or null) || ((target."rustix_use_experimental_asm" or false) && ("powerpc64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("s390x" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips32r6" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64r6" == target."arch" or null)) || ("x86" == target."arch" or null) || (("x86_64" == target."arch" or null) && ("64" == target."pointer_width" or null)))); - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: ((!(target."windows" or false)) && ((target."rustix_use_libc" or false) || (target."miri" or false) || (!(("linux" == target."os" or null) && (("little" == target."endian" or null) || ("s390x" == target."arch" or null)) && (("arm" == target."arch" or null) || (("aarch64" == target."arch" or null) && ("64" == target."pointer_width" or null)) || ("riscv64" == target."arch" or null) || ((target."rustix_use_experimental_asm" or false) && ("powerpc64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("s390x" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips32r6" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64r6" == target."arch" or null)) || ("x86" == target."arch" or null) || (("x86_64" == target."arch" or null) && ("64" == target."pointer_width" or null))))))); - } - { - name = "linux-raw-sys"; - packageId = "linux-raw-sys"; - usesDefaultFeatures = false; - target = { target, features }: ((("android" == target."os" or null) || ("linux" == target."os" or null)) && ((target."rustix_use_libc" or false) || (target."miri" or false) || (!(("linux" == target."os" or null) && (("little" == target."endian" or null) || ("s390x" == target."arch" or null)) && (("arm" == target."arch" or null) || (("aarch64" == target."arch" or null) && ("64" == target."pointer_width" or null)) || ("riscv64" == target."arch" or null) || ((target."rustix_use_experimental_asm" or false) && ("powerpc64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("s390x" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips32r6" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64r6" == target."arch" or null)) || ("x86" == target."arch" or null) || (("x86_64" == target."arch" or null) && ("64" == target."pointer_width" or null))))))); - features = [ "general" "ioctl" "no_std" ]; - } - { - name = "linux-raw-sys"; - packageId = "linux-raw-sys"; - usesDefaultFeatures = false; - target = { target, features }: ((!(target."rustix_use_libc" or false)) && (!(target."miri" or false)) && ("linux" == target."os" or null) && (("little" == target."endian" or null) || ("s390x" == target."arch" or null)) && (("arm" == target."arch" or null) || (("aarch64" == target."arch" or null) && ("64" == target."pointer_width" or null)) || ("riscv64" == target."arch" or null) || ((target."rustix_use_experimental_asm" or false) && ("powerpc64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("s390x" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips32r6" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64" == target."arch" or null)) || ((target."rustix_use_experimental_asm" or false) && ("mips64r6" == target."arch" or null)) || ("x86" == target."arch" or null) || (("x86_64" == target."arch" or null) && ("64" == target."pointer_width" or null)))); - features = [ "general" "errno" "ioctl" "no_std" "elf" ]; - } - { - name = "windows-sys"; - packageId = "windows-sys 0.59.0"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Foundation" "Win32_Networking_WinSock" "Win32_NetworkManagement_IpHelper" "Win32_System_Threading" ]; - } - ]; - devDependencies = [ - { - name = "errno"; - packageId = "errno"; - rename = "libc_errno"; - usesDefaultFeatures = false; - } - { - name = "libc"; - packageId = "libc"; - } - ]; - features = { - "all-apis" = [ "event" "fs" "io_uring" "mm" "mount" "net" "param" "pipe" "process" "procfs" "pty" "rand" "runtime" "shm" "stdio" "system" "termios" "thread" "time" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" "use-libc-auxv" ]; - "io_uring" = [ "event" "fs" "net" "linux-raw-sys/io_uring" ]; - "itoa" = [ "dep:itoa" ]; - "libc" = [ "dep:libc" ]; - "libc-extra-traits" = [ "libc?/extra_traits" ]; - "libc_errno" = [ "dep:libc_errno" ]; - "linux_latest" = [ "linux_4_11" ]; - "net" = [ "linux-raw-sys/net" "linux-raw-sys/netlink" "linux-raw-sys/if_ether" "linux-raw-sys/xdp" ]; - "once_cell" = [ "dep:once_cell" ]; - "param" = [ "fs" ]; - "process" = [ "linux-raw-sys/prctl" ]; - "procfs" = [ "once_cell" "itoa" "fs" ]; - "pty" = [ "itoa" "fs" ]; - "runtime" = [ "linux-raw-sys/prctl" ]; - "rustc-dep-of-std" = [ "core" "rustc-std-workspace-alloc" "compiler_builtins" "linux-raw-sys/rustc-dep-of-std" "bitflags/rustc-dep-of-std" "compiler_builtins?/rustc-dep-of-std" ]; - "rustc-std-workspace-alloc" = [ "dep:rustc-std-workspace-alloc" ]; - "shm" = [ "fs" ]; - "std" = [ "bitflags/std" "alloc" "libc?/std" "libc_errno?/std" "libc-extra-traits" ]; - "system" = [ "linux-raw-sys/system" ]; - "thread" = [ "linux-raw-sys/prctl" ]; - "use-libc" = [ "libc_errno" "libc" "libc-extra-traits" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "fs" "libc-extra-traits" "std" "use-libc-auxv" ]; - }; - "rustversion" = rec { - crateName = "rustversion"; - version = "1.0.19"; - edition = "2018"; - sha256 = "1m39qd65jcd1xgqzdm3017ppimiggh2446xngwp1ngr8hjbmpi7p"; - procMacro = true; - build = "build/build.rs"; - authors = [ - "David Tolnay " - ]; - - }; - "ryu" = rec { - crateName = "ryu"; - version = "1.0.19"; - edition = "2018"; - sha256 = "1pg6a0b80m32ahygsdkwzs3bfydk4snw695akz4rqxj4lv8a58bf"; - authors = [ - "David Tolnay " - ]; - features = { - "no-panic" = [ "dep:no-panic" ]; - }; - }; - "schannel" = rec { - crateName = "schannel"; - version = "0.1.27"; - edition = "2018"; - sha256 = "0gbbhy28v72kd5iina0z2vcdl3vz63mk5idvkzn5r52z6jmfna8z"; - authors = [ - "Steven Fackler " - "Steffen Butzer " - ]; - dependencies = [ - { - name = "windows-sys"; - packageId = "windows-sys 0.59.0"; - features = [ "Win32_Foundation" "Win32_Security_Cryptography" "Win32_Security_Authentication_Identity" "Win32_Security_Credentials" "Win32_System_LibraryLoader" "Win32_System_Memory" "Win32_System_SystemInformation" ]; - } - ]; - devDependencies = [ - { - name = "windows-sys"; - packageId = "windows-sys 0.59.0"; - features = [ "Win32_System_SystemInformation" "Win32_System_Time" ]; - } - ]; - - }; - "scheduled-thread-pool" = rec { - crateName = "scheduled-thread-pool"; - version = "0.2.7"; - edition = "2018"; - sha256 = "068s77f9xcpvzl70nsxk8750dzzc6f9pixajhd979815cj0ndg1w"; - libName = "scheduled_thread_pool"; - authors = [ - "Steven Fackler " - ]; - dependencies = [ - { - name = "parking_lot"; - packageId = "parking_lot 0.12.3"; - } - ]; - - }; - "scoped-tls" = rec { - crateName = "scoped-tls"; - version = "0.1.2"; - edition = "2015"; - sha256 = "0a2bn9d2mb07c6l16sadijy4p540g498zddfxyiq4rsqpwrglbrk"; - libName = "scoped_tls"; - authors = [ - "Alex Crichton " - ]; - features = { }; - }; - "scopeguard" = rec { - crateName = "scopeguard"; - version = "1.2.0"; - edition = "2015"; - sha256 = "0jcz9sd47zlsgcnm1hdw0664krxwb5gczlif4qngj2aif8vky54l"; - authors = [ - "bluss" - ]; - features = { - "default" = [ "use_std" ]; - }; - }; - "security-framework" = rec { - crateName = "security-framework"; - version = "2.11.1"; - edition = "2021"; - sha256 = "00ldclwx78dm61v7wkach9lcx76awlrv0fdgjdwch4dmy12j4yw9"; - libName = "security_framework"; - authors = [ - "Steven Fackler " - "Kornel " - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 2.8.0"; - } - { - name = "core-foundation"; - packageId = "core-foundation"; - } - { - name = "core-foundation-sys"; - packageId = "core-foundation-sys"; - } - { - name = "libc"; - packageId = "libc"; - } - { - name = "security-framework-sys"; - packageId = "security-framework-sys"; - usesDefaultFeatures = false; - } - ]; - features = { - "OSX_10_10" = [ "OSX_10_9" "security-framework-sys/OSX_10_10" ]; - "OSX_10_11" = [ "OSX_10_10" "security-framework-sys/OSX_10_11" ]; - "OSX_10_12" = [ "OSX_10_11" "security-framework-sys/OSX_10_12" ]; - "OSX_10_13" = [ "OSX_10_12" "security-framework-sys/OSX_10_13" "alpn" "session-tickets" "serial-number-bigint" ]; - "OSX_10_14" = [ "OSX_10_13" "security-framework-sys/OSX_10_14" ]; - "OSX_10_15" = [ "OSX_10_14" "security-framework-sys/OSX_10_15" ]; - "OSX_10_9" = [ "security-framework-sys/OSX_10_9" ]; - "default" = [ "OSX_10_12" ]; - "log" = [ "dep:log" ]; - "serial-number-bigint" = [ "dep:num-bigint" ]; - }; - resolvedDefaultFeatures = [ "OSX_10_10" "OSX_10_11" "OSX_10_12" "OSX_10_9" "default" ]; - }; - "security-framework-sys" = rec { - crateName = "security-framework-sys"; - version = "2.14.0"; - edition = "2021"; - sha256 = "0chwn01qrnvs59i5220bymd38iddy4krbnmfnhf4k451aqfj7ns9"; - libName = "security_framework_sys"; - authors = [ - "Steven Fackler " - "Kornel " - ]; - dependencies = [ - { - name = "core-foundation-sys"; - packageId = "core-foundation-sys"; - } - { - name = "libc"; - packageId = "libc"; - } - ]; - features = { - "OSX_10_10" = [ "OSX_10_9" ]; - "OSX_10_11" = [ "OSX_10_10" ]; - "OSX_10_12" = [ "OSX_10_11" ]; - "OSX_10_13" = [ "OSX_10_12" ]; - "OSX_10_14" = [ "OSX_10_13" ]; - "OSX_10_15" = [ "OSX_10_14" ]; - "default" = [ "OSX_10_12" ]; - }; - resolvedDefaultFeatures = [ "OSX_10_10" "OSX_10_11" "OSX_10_12" "OSX_10_9" "default" ]; - }; - "semver" = rec { - crateName = "semver"; - version = "0.9.0"; - edition = "2015"; - sha256 = "00q4lkcj0rrgbhviv9sd4p6qmdsipkwkbra7rh11jrhq5kpvjzhx"; - authors = [ - "Steve Klabnik " - "The Rust Project Developers" - ]; - dependencies = [ - { - name = "semver-parser"; - packageId = "semver-parser"; - } - ]; - features = { - "ci" = [ "serde" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "semver-parser" = rec { - crateName = "semver-parser"; - version = "0.7.0"; - edition = "2015"; - sha256 = "18vhypw6zgccnrlm5ps1pwa0khz7ry927iznpr88b87cagr1v2iq"; - libName = "semver_parser"; - authors = [ - "Steve Klabnik " - ]; - - }; - "serde 0.8.23" = rec { - crateName = "serde"; - version = "0.8.23"; - edition = "2015"; - sha256 = "1j4ajipn0sf4ya0crgcb94s848qp7mfc35n6d0q2rf8rk5skzbcx"; - authors = [ - "Erick Tryzelaar " - ]; - features = { - "alloc" = [ "unstable" ]; - "clippy" = [ "dep:clippy" ]; - "collections" = [ "alloc" ]; - "default" = [ "std" ]; - "unstable-testing" = [ "clippy" "unstable" "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "serde 1.0.217" = rec { - crateName = "serde"; - version = "1.0.217"; - edition = "2018"; - sha256 = "0w2ck1p1ajmrv1cf51qf7igjn2nc51r0izzc00fzmmhkvxjl5z02"; - authors = [ - "Erick Tryzelaar " - "David Tolnay " - ]; - dependencies = [ - { - name = "serde_derive"; - packageId = "serde_derive"; - optional = true; - } - { - name = "serde_derive"; - packageId = "serde_derive"; - target = { target, features }: false; - } - ]; - devDependencies = [ - { - name = "serde_derive"; - packageId = "serde_derive"; - } - ]; - features = { - "default" = [ "std" ]; - "derive" = [ "serde_derive" ]; - "serde_derive" = [ "dep:serde_derive" ]; - }; - resolvedDefaultFeatures = [ "default" "derive" "serde_derive" "std" ]; - }; - "serde-hjson" = rec { - crateName = "serde-hjson"; - version = "0.8.2"; - edition = "2015"; - sha256 = "0lv1qwis9rr767xv9w27y1g1r71ayf02k2wkypawwlkxsrd3r0qb"; - libName = "serde_hjson"; - authors = [ - "Christian Zangl " - ]; - dependencies = [ - { - name = "lazy_static"; - packageId = "lazy_static 0.2.11"; - } - { - name = "linked-hash-map"; - packageId = "linked-hash-map 0.3.0"; - optional = true; - } - { - name = "num-traits"; - packageId = "num-traits 0.1.43"; - } - { - name = "regex"; - packageId = "regex"; - } - { - name = "serde"; - packageId = "serde 0.8.23"; - } - ]; - features = { - "clippy" = [ "dep:clippy" ]; - "default" = [ "preserve_order" ]; - "linked-hash-map" = [ "dep:linked-hash-map" ]; - "preserve_order" = [ "linked-hash-map" "linked-hash-map/serde_impl" ]; - "unstable-testing" = [ "clippy" ]; - }; - resolvedDefaultFeatures = [ "default" "linked-hash-map" "preserve_order" ]; - }; - "serde_derive" = rec { - crateName = "serde_derive"; - version = "1.0.217"; - edition = "2015"; - sha256 = "180r3rj5gi5s1m23q66cr5wlfgc5jrs6n1mdmql2njnhk37zg6ss"; - procMacro = true; - authors = [ - "Erick Tryzelaar " - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - features = [ "proc-macro" ]; - } - { - name = "quote"; - packageId = "quote"; - usesDefaultFeatures = false; - features = [ "proc-macro" ]; - } - { - name = "syn"; - packageId = "syn 2.0.98"; - usesDefaultFeatures = false; - features = [ "clone-impls" "derive" "parsing" "printing" "proc-macro" ]; - } - ]; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "serde_json" = rec { - crateName = "serde_json"; - version = "1.0.138"; - edition = "2021"; - sha256 = "0j99hyp2plvdcyrfzdz0875d0dm04q5ngsd7dr5fk1x7glp1jd6l"; - authors = [ - "Erick Tryzelaar " - "David Tolnay " - ]; - dependencies = [ - { - name = "itoa"; - packageId = "itoa"; - } - { - name = "memchr"; - packageId = "memchr"; - usesDefaultFeatures = false; - } - { - name = "ryu"; - packageId = "ryu"; - } - { - name = "serde"; - packageId = "serde 1.0.217"; - usesDefaultFeatures = false; - } - ]; - devDependencies = [ - { - name = "serde"; - packageId = "serde 1.0.217"; - features = [ "derive" ]; - } - ]; - features = { - "alloc" = [ "serde/alloc" ]; - "default" = [ "std" ]; - "indexmap" = [ "dep:indexmap" ]; - "preserve_order" = [ "indexmap" "std" ]; - "std" = [ "memchr/std" "serde/std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "serde_test" = rec { - crateName = "serde_test"; - version = "0.8.23"; - edition = "2015"; - sha256 = "1m939j7cgs7i58r6vxf0ffp3nbr8advr8p9dqa9w8zk0z2yks2qi"; - authors = [ - "Erick Tryzelaar " - ]; - dependencies = [ - { - name = "serde"; - packageId = "serde 0.8.23"; - } - ]; - - }; - "shlex" = rec { - crateName = "shlex"; - version = "1.3.0"; - edition = "2015"; - sha256 = "0r1y6bv26c1scpxvhg2cabimrmwgbp4p3wy6syj9n0c4s3q2znhg"; - authors = [ - "comex " - "Fenhl " - "Adrian Taylor " - "Alex Touchet " - "Daniel Parks " - "Garrett Berg " - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "slab 0.3.0" = rec { - crateName = "slab"; - version = "0.3.0"; - edition = "2015"; - sha256 = "08xw8w61zdfn1094qkq1d554vh5wmm9bqdys8gqqxc4sv2pgrd0p"; - authors = [ - "Carl Lerche " - ]; - - }; - "slab 0.4.9" = rec { - crateName = "slab"; - version = "0.4.9"; - edition = "2018"; - sha256 = "0rxvsgir0qw5lkycrqgb1cxsvxzjv9bmx73bk5y42svnzfba94lg"; - authors = [ - "Carl Lerche " - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { - "default" = [ "std" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "smallvec 0.6.14" = rec { - crateName = "smallvec"; - version = "0.6.14"; - edition = "2015"; - sha256 = "1q4hz0ssnv24s6fq5kfp2wzrrprrrjiwc42a0h7s7nwym3mwlzxr"; - libPath = "lib.rs"; - authors = [ - "Simon Sapin " - ]; - dependencies = [ - { - name = "maybe-uninit"; - packageId = "maybe-uninit"; - } - ]; - features = { - "default" = [ "std" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "smallvec 1.14.0" = rec { - crateName = "smallvec"; - version = "1.14.0"; - edition = "2018"; - sha256 = "1z8wpr53x6jisklqhkkvkgyi8s5cn69h2d2alhqfxahzxwiq7kvz"; - authors = [ - "The Servo Project Developers" - ]; - features = { - "arbitrary" = [ "dep:arbitrary" ]; - "const_new" = [ "const_generics" ]; - "drain_keep_rest" = [ "drain_filter" ]; - "malloc_size_of" = [ "dep:malloc_size_of" ]; - "serde" = [ "dep:serde" ]; - }; - }; - "socket2" = rec { - crateName = "socket2"; - version = "0.5.8"; - edition = "2021"; - sha256 = "1s7vjmb5gzp3iaqi94rh9r63k9cj00kjgbfn7gn60kmnk6fjcw69"; - authors = [ - "Alex Crichton " - "Thomas de Zeeuw " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "windows-sys"; - packageId = "windows-sys 0.52.0"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Foundation" "Win32_Networking_WinSock" "Win32_System_IO" "Win32_System_Threading" "Win32_System_WindowsProgramming" ]; - } - ]; - features = { }; - }; - "syn 1.0.109" = rec { - crateName = "syn"; - version = "1.0.109"; - edition = "2018"; - sha256 = "0ds2if4600bd59wsv7jjgfkayfzy3hnazs394kz6zdkmna8l3dkj"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - } - { - name = "quote"; - packageId = "quote"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - features = { - "default" = [ "derive" "parsing" "printing" "clone-impls" "proc-macro" ]; - "printing" = [ "quote" ]; - "proc-macro" = [ "proc-macro2/proc-macro" "quote/proc-macro" ]; - "quote" = [ "dep:quote" ]; - "test" = [ "syn-test-suite/all-features" ]; - }; - resolvedDefaultFeatures = [ "clone-impls" "default" "derive" "extra-traits" "fold" "full" "parsing" "printing" "proc-macro" "quote" "visit" ]; - }; - "syn 2.0.98" = rec { - crateName = "syn"; - version = "2.0.98"; - edition = "2021"; - sha256 = "1cfk0qqbl4fbr3dz61nw21d5amvl4rym6nxwnfsw43mf90d7y51n"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - } - { - name = "quote"; - packageId = "quote"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - features = { - "default" = [ "derive" "parsing" "printing" "clone-impls" "proc-macro" ]; - "printing" = [ "dep:quote" ]; - "proc-macro" = [ "proc-macro2/proc-macro" "quote?/proc-macro" ]; - "test" = [ "syn-test-suite/all-features" ]; - }; - resolvedDefaultFeatures = [ "clone-impls" "default" "derive" "full" "parsing" "printing" "proc-macro" "visit" "visit-mut" ]; - }; - "synstructure" = rec { - crateName = "synstructure"; - version = "0.12.6"; - edition = "2018"; - sha256 = "03r1lydbf3japnlpc4wka7y90pmz1i0danaj3f9a7b431akdlszk"; - authors = [ - "Nika Layzell " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - } - { - name = "quote"; - packageId = "quote"; - usesDefaultFeatures = false; - } - { - name = "syn"; - packageId = "syn 1.0.109"; - usesDefaultFeatures = false; - features = [ "derive" "parsing" "printing" "clone-impls" "visit" "extra-traits" ]; - } - { - name = "unicode-xid"; - packageId = "unicode-xid"; - } - ]; - features = { - "default" = [ "proc-macro" ]; - "proc-macro" = [ "proc-macro2/proc-macro" "syn/proc-macro" "quote/proc-macro" ]; - }; - resolvedDefaultFeatures = [ "default" "proc-macro" ]; - }; - "tempfile" = rec { - crateName = "tempfile"; - version = "3.16.0"; - edition = "2021"; - sha256 = "14dvm3lys05wxzb1ahxjg3chb3krk0ir18liw25g893xblhldhiq"; - authors = [ - "Steven Allen " - "The Rust Project Developers" - "Ashley Mannix " - "Jason White " - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 1.0.0"; - } - { - name = "fastrand"; - packageId = "fastrand"; - } - { - name = "getrandom"; - packageId = "getrandom 0.3.1"; - optional = true; - usesDefaultFeatures = false; - target = { target, features }: ((target."unix" or false) || (target."windows" or false) || ("wasi" == target."os" or null)); - } - { - name = "once_cell"; - packageId = "once_cell"; - usesDefaultFeatures = false; - features = [ "std" ]; - } - { - name = "rustix"; - packageId = "rustix"; - target = { target, features }: ((target."unix" or false) || ("wasi" == target."os" or null)); - features = [ "fs" ]; - } - { - name = "windows-sys"; - packageId = "windows-sys 0.59.0"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Storage_FileSystem" "Win32_Foundation" ]; - } - ]; - features = { - "default" = [ "getrandom" ]; - "getrandom" = [ "dep:getrandom" ]; - }; - resolvedDefaultFeatures = [ "default" "getrandom" ]; - }; - "termcolor" = rec { - crateName = "termcolor"; - version = "1.4.1"; - edition = "2018"; - sha256 = "0mappjh3fj3p2nmrg4y7qv94rchwi9mzmgmfflr8p2awdj7lyy86"; - authors = [ - "Andrew Gallant " - ]; - dependencies = [ - { - name = "winapi-util"; - packageId = "winapi-util"; - target = { target, features }: (target."windows" or false); - } - ]; - - }; - "tokio" = rec { - crateName = "tokio"; - version = "0.1.22"; - edition = "2015"; - sha256 = "1xhaadfmm6m37f79xv5020gc3np9wqza3bq95ymp522qpfsw02as"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - optional = true; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "mio"; - packageId = "mio"; - optional = true; - } - { - name = "num_cpus"; - packageId = "num_cpus"; - optional = true; - } - { - name = "tokio-codec"; - packageId = "tokio-codec"; - optional = true; - } - { - name = "tokio-current-thread"; - packageId = "tokio-current-thread"; - optional = true; - } - { - name = "tokio-executor"; - packageId = "tokio-executor"; - optional = true; - } - { - name = "tokio-fs"; - packageId = "tokio-fs"; - optional = true; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - optional = true; - } - { - name = "tokio-reactor"; - packageId = "tokio-reactor"; - optional = true; - } - { - name = "tokio-sync"; - packageId = "tokio-sync"; - optional = true; - } - { - name = "tokio-tcp"; - packageId = "tokio-tcp"; - optional = true; - } - { - name = "tokio-threadpool"; - packageId = "tokio-threadpool"; - optional = true; - } - { - name = "tokio-timer"; - packageId = "tokio-timer 0.2.13"; - optional = true; - } - { - name = "tokio-udp"; - packageId = "tokio-udp"; - optional = true; - } - { - name = "tokio-uds"; - packageId = "tokio-uds"; - optional = true; - target = { target, features }: (target."unix" or false); - } - ]; - devDependencies = [ - { - name = "num_cpus"; - packageId = "num_cpus"; - } - ]; - features = { - "bytes" = [ "dep:bytes" ]; - "codec" = [ "io" "tokio-codec" ]; - "default" = [ "codec" "fs" "io" "reactor" "rt-full" "sync" "tcp" "timer" "udp" "uds" ]; - "experimental-tracing" = [ "tracing-core" ]; - "fs" = [ "tokio-fs" ]; - "io" = [ "bytes" "tokio-io" ]; - "mio" = [ "dep:mio" ]; - "num_cpus" = [ "dep:num_cpus" ]; - "reactor" = [ "io" "mio" "tokio-reactor" ]; - "rt-full" = [ "num_cpus" "reactor" "timer" "tokio-current-thread" "tokio-executor" "tokio-threadpool" ]; - "sync" = [ "tokio-sync" ]; - "tcp" = [ "tokio-tcp" ]; - "timer" = [ "tokio-timer" ]; - "tokio-codec" = [ "dep:tokio-codec" ]; - "tokio-current-thread" = [ "dep:tokio-current-thread" ]; - "tokio-executor" = [ "dep:tokio-executor" ]; - "tokio-fs" = [ "dep:tokio-fs" ]; - "tokio-io" = [ "dep:tokio-io" ]; - "tokio-reactor" = [ "dep:tokio-reactor" ]; - "tokio-sync" = [ "dep:tokio-sync" ]; - "tokio-tcp" = [ "dep:tokio-tcp" ]; - "tokio-threadpool" = [ "dep:tokio-threadpool" ]; - "tokio-timer" = [ "dep:tokio-timer" ]; - "tokio-udp" = [ "dep:tokio-udp" ]; - "tokio-uds" = [ "dep:tokio-uds" ]; - "tracing-core" = [ "dep:tracing-core" ]; - "udp" = [ "tokio-udp" ]; - "uds" = [ "tokio-uds" ]; - }; - resolvedDefaultFeatures = [ "bytes" "codec" "default" "fs" "io" "mio" "num_cpus" "reactor" "rt-full" "sync" "tcp" "timer" "tokio-codec" "tokio-current-thread" "tokio-executor" "tokio-fs" "tokio-io" "tokio-reactor" "tokio-sync" "tokio-tcp" "tokio-threadpool" "tokio-timer" "tokio-udp" "tokio-uds" "udp" "uds" ]; - }; - "tokio-codec" = rec { - crateName = "tokio-codec"; - version = "0.1.2"; - edition = "2015"; - sha256 = "0swpfngcb331lzggk6j68yks6w0bnw35vpl4hv8p03msc239kci5"; - libName = "tokio_codec"; - authors = [ - "Carl Lerche " - "Bryan Burgers " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - ]; - - }; - "tokio-core" = rec { - crateName = "tokio-core"; - version = "0.1.18"; - edition = "2015"; - sha256 = "1m7zij19xy13wmlb7a1bghvi4vs8s1hlyggnaajvqfj46i9kkcc7"; - libName = "tokio_core"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "iovec"; - packageId = "iovec"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "mio"; - packageId = "mio"; - } - { - name = "scoped-tls"; - packageId = "scoped-tls"; - } - { - name = "tokio"; - packageId = "tokio"; - } - { - name = "tokio-executor"; - packageId = "tokio-executor"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - { - name = "tokio-reactor"; - packageId = "tokio-reactor"; - } - { - name = "tokio-timer"; - packageId = "tokio-timer 0.2.13"; - } - ]; - - }; - "tokio-current-thread" = rec { - crateName = "tokio-current-thread"; - version = "0.1.7"; - edition = "2015"; - sha256 = "03p2w316ha0irgzvy37njx9hl71133gcrmrq4801w4rzm0r0xpmi"; - libName = "tokio_current_thread"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "futures"; - packageId = "futures"; - } - { - name = "tokio-executor"; - packageId = "tokio-executor"; - } - ]; - - }; - "tokio-executor" = rec { - crateName = "tokio-executor"; - version = "0.1.10"; - edition = "2015"; - sha256 = "0w8n78d2vixs1vghqc4wy9w0d1h6qkli51c1yzhzbns88n7inbgv"; - libName = "tokio_executor"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "crossbeam-utils"; - packageId = "crossbeam-utils"; - } - { - name = "futures"; - packageId = "futures"; - } - ]; - - }; - "tokio-fs" = rec { - crateName = "tokio-fs"; - version = "0.1.7"; - edition = "2015"; - sha256 = "1x3gkdi5x7bjlzzg7qlnymb549rb546p0nykxsh04qyaw0314yi9"; - libName = "tokio_fs"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "futures"; - packageId = "futures"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - { - name = "tokio-threadpool"; - packageId = "tokio-threadpool"; - } - ]; - devDependencies = [ - { - name = "tokio-io"; - packageId = "tokio-io"; - } - ]; - - }; - "tokio-io" = rec { - crateName = "tokio-io"; - version = "0.1.13"; - edition = "2015"; - sha256 = "0x06zyzinans1pn90g6i150lgixijdf1cg8y2gipjd09ms58dz2p"; - libName = "tokio_io"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "log"; - packageId = "log"; - } - ]; - - }; - "tokio-mockstream" = rec { - crateName = "tokio-mockstream"; - version = "1.1.0"; - edition = "2015"; - sha256 = "0mg1i39cl8x32wxwbn74hlirks8a6f3g0gfzkb0n0zwbxwvc9gs1"; - libName = "tokio_mockstream"; - authors = [ - "Aaron Weiss " - ]; - dependencies = [ - { - name = "futures"; - packageId = "futures"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - ]; - - }; - "tokio-reactor" = rec { - crateName = "tokio-reactor"; - version = "0.1.12"; - edition = "2015"; - sha256 = "0l8klnd41q55f3ialzz0lb7s5bfwa38nh86sa9vai2xsqh75kg09"; - libName = "tokio_reactor"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "crossbeam-utils"; - packageId = "crossbeam-utils"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "lazy_static"; - packageId = "lazy_static 1.5.0"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "mio"; - packageId = "mio"; - } - { - name = "num_cpus"; - packageId = "num_cpus"; - } - { - name = "parking_lot"; - packageId = "parking_lot 0.9.0"; - } - { - name = "slab"; - packageId = "slab 0.4.9"; - } - { - name = "tokio-executor"; - packageId = "tokio-executor"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - { - name = "tokio-sync"; - packageId = "tokio-sync"; - } - ]; - devDependencies = [ - { - name = "num_cpus"; - packageId = "num_cpus"; - } - ]; - - }; - "tokio-sync" = rec { - crateName = "tokio-sync"; - version = "0.1.8"; - edition = "2015"; - sha256 = "1vkxz0y7qf9sshfpxvn506pvxy4vza8piavd8p64y5n85cam1zpd"; - libName = "tokio_sync"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "fnv"; - packageId = "fnv"; - } - { - name = "futures"; - packageId = "futures"; - } - ]; - - }; - "tokio-tcp" = rec { - crateName = "tokio-tcp"; - version = "0.1.4"; - edition = "2015"; - sha256 = "0whzqnkyfym1ipzznibyjl3j9281walq4n0q5xs2xdz3cvniipwq"; - libName = "tokio_tcp"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "iovec"; - packageId = "iovec"; - } - { - name = "mio"; - packageId = "mio"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - { - name = "tokio-reactor"; - packageId = "tokio-reactor"; - } - ]; - - }; - "tokio-threadpool" = rec { - crateName = "tokio-threadpool"; - version = "0.1.18"; - edition = "2015"; - sha256 = "12azq8jm71b7hdm72pxrgqm2879bn6b0fcdl1s7i2k3qh5jhnwnz"; - libName = "tokio_threadpool"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "crossbeam-deque"; - packageId = "crossbeam-deque"; - } - { - name = "crossbeam-queue"; - packageId = "crossbeam-queue"; - } - { - name = "crossbeam-utils"; - packageId = "crossbeam-utils"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "lazy_static"; - packageId = "lazy_static 1.5.0"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "num_cpus"; - packageId = "num_cpus"; - } - { - name = "slab"; - packageId = "slab 0.4.9"; - } - { - name = "tokio-executor"; - packageId = "tokio-executor"; - } - ]; - - }; - "tokio-timer 0.1.2" = rec { - crateName = "tokio-timer"; - version = "0.1.2"; - edition = "2015"; - sha256 = "1z0fwbh5bm6hdbfm0y17fa5l60na7fl9vbca7wdzz1vp0f0ffcb1"; - libName = "tokio_timer"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "futures"; - packageId = "futures"; - } - { - name = "slab"; - packageId = "slab 0.3.0"; - } - ]; - - }; - "tokio-timer 0.2.13" = rec { - crateName = "tokio-timer"; - version = "0.2.13"; - edition = "2015"; - sha256 = "15pjjj6daks3sii8p24a509b0dapl2kyk740nwfgz59w64nly14k"; - libName = "tokio_timer"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "crossbeam-utils"; - packageId = "crossbeam-utils"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "slab"; - packageId = "slab 0.4.9"; - } - { - name = "tokio-executor"; - packageId = "tokio-executor"; - } - ]; - - }; - "tokio-tls" = rec { - crateName = "tokio-tls"; - version = "0.2.1"; - edition = "2015"; - sha256 = "0z0gmvv7jrpan6y42p5f5wd48rqcd96igp592w1c5cr573c8qjrm"; - libName = "tokio_tls"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "futures"; - packageId = "futures"; - } - { - name = "native-tls"; - packageId = "native-tls"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - ]; - - }; - "tokio-udp" = rec { - crateName = "tokio-udp"; - version = "0.1.6"; - edition = "2015"; - sha256 = "10hdcnxdp0dxvj44jl1nrrpg30jbisqclbqs0f5w6f8bc47b3872"; - libName = "tokio_udp"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "mio"; - packageId = "mio"; - } - { - name = "tokio-codec"; - packageId = "tokio-codec"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - { - name = "tokio-reactor"; - packageId = "tokio-reactor"; - } - ]; - - }; - "tokio-uds" = rec { - crateName = "tokio-uds"; - version = "0.2.7"; - edition = "2015"; - sha256 = "1q74sydx22l4mkmrz02l4i5swddwr1pryxvhrzdwkj0i86na8mxb"; - libName = "tokio_uds"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures"; - packageId = "futures"; - } - { - name = "iovec"; - packageId = "iovec"; - } - { - name = "libc"; - packageId = "libc"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "mio"; - packageId = "mio"; - } - { - name = "mio-uds"; - packageId = "mio-uds"; - } - { - name = "tokio-codec"; - packageId = "tokio-codec"; - } - { - name = "tokio-io"; - packageId = "tokio-io"; - } - { - name = "tokio-reactor"; - packageId = "tokio-reactor"; - } - ]; - - }; - "toml" = rec { - crateName = "toml"; - version = "0.4.10"; - edition = "2015"; - sha256 = "07qilkzinn8z13vq2sss65n2lza7wrmqpvkbclw919m3f7y691km"; - authors = [ - "Alex Crichton " - ]; - dependencies = [ - { - name = "serde"; - packageId = "serde 1.0.217"; - } - ]; - - }; - "unicode-ident" = rec { - crateName = "unicode-ident"; - version = "1.0.16"; - edition = "2018"; - sha256 = "0d2hji0i16naw43l02dplrz8fbv625n7475s463iqw4by1hd2452"; - libName = "unicode_ident"; - authors = [ - "David Tolnay " - ]; - - }; - "unicode-xid" = rec { - crateName = "unicode-xid"; - version = "0.2.6"; - edition = "2015"; - sha256 = "0lzqaky89fq0bcrh6jj6bhlz37scfd8c7dsj5dq7y32if56c1hgb"; - libName = "unicode_xid"; - authors = [ - "erick.tryzelaar " - "kwantam " - "Manish Goregaokar " - ]; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "vcpkg" = rec { - crateName = "vcpkg"; - version = "0.2.15"; - edition = "2015"; - sha256 = "09i4nf5y8lig6xgj3f7fyrvzd3nlaw4znrihw8psidvv5yk4xkdc"; - authors = [ - "Jim McGrath " - ]; - - }; - "version_check" = rec { - crateName = "version_check"; - version = "0.1.5"; - edition = "2015"; - sha256 = "1pf91pvj8n6akh7w6j5ypka6aqz08b3qpzgs0ak2kjf4frkiljwi"; - authors = [ - "Sergio Benitez " - ]; - - }; - "wasi 0.13.3+wasi-0.2.2" = rec { - crateName = "wasi"; - version = "0.13.3+wasi-0.2.2"; - edition = "2021"; - sha256 = "1lnapbvdcvi3kc749wzqvwrpd483win2kicn1faa4dja38p6v096"; - authors = [ - "The Cranelift Project Developers" - ]; - dependencies = [ - { - name = "wit-bindgen-rt"; - packageId = "wit-bindgen-rt"; - features = [ "bitflags" ]; - } - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" ]; - "rustc-dep-of-std" = [ "compiler_builtins" "core" "rustc-std-workspace-alloc" ]; - "rustc-std-workspace-alloc" = [ "dep:rustc-std-workspace-alloc" ]; - }; - }; - "wasi 0.9.0+wasi-snapshot-preview1" = rec { - crateName = "wasi"; - version = "0.9.0+wasi-snapshot-preview1"; - edition = "2018"; - sha256 = "06g5v3vrdapfzvfq662cij7v8a1flwr2my45nnncdv2galrdzkfc"; - authors = [ - "The Cranelift Project Developers" - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" ]; - "rustc-dep-of-std" = [ "compiler_builtins" "core" "rustc-std-workspace-alloc" ]; - "rustc-std-workspace-alloc" = [ "dep:rustc-std-workspace-alloc" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "wasm-bindgen" = rec { - crateName = "wasm-bindgen"; - version = "0.2.100"; - edition = "2021"; - sha256 = "1x8ymcm6yi3i1rwj78myl1agqv2m86i648myy3lc97s9swlqkp0y"; - libName = "wasm_bindgen"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if 1.0.0"; - } - { - name = "once_cell"; - packageId = "once_cell"; - usesDefaultFeatures = false; - } - { - name = "rustversion"; - packageId = "rustversion"; - optional = true; - } - { - name = "wasm-bindgen-macro"; - packageId = "wasm-bindgen-macro"; - } - ]; - devDependencies = [ - { - name = "once_cell"; - packageId = "once_cell"; - } - ]; - features = { - "default" = [ "std" "msrv" ]; - "enable-interning" = [ "std" ]; - "msrv" = [ "rustversion" ]; - "rustversion" = [ "dep:rustversion" ]; - "serde" = [ "dep:serde" ]; - "serde-serialize" = [ "serde" "serde_json" "std" ]; - "serde_json" = [ "dep:serde_json" ]; - "strict-macro" = [ "wasm-bindgen-macro/strict-macro" ]; - "xxx_debug_only_print_generated_code" = [ "wasm-bindgen-macro/xxx_debug_only_print_generated_code" ]; - }; - resolvedDefaultFeatures = [ "default" "msrv" "rustversion" "std" ]; - }; - "wasm-bindgen-backend" = rec { - crateName = "wasm-bindgen-backend"; - version = "0.2.100"; - edition = "2021"; - sha256 = "1ihbf1hq3y81c4md9lyh6lcwbx6a5j0fw4fygd423g62lm8hc2ig"; - libName = "wasm_bindgen_backend"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "bumpalo"; - packageId = "bumpalo"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn 2.0.98"; - features = [ "full" ]; - } - { - name = "wasm-bindgen-shared"; - packageId = "wasm-bindgen-shared"; - } - ]; - features = { - "extra-traits" = [ "syn/extra-traits" ]; - }; - }; - "wasm-bindgen-macro" = rec { - crateName = "wasm-bindgen-macro"; - version = "0.2.100"; - edition = "2021"; - sha256 = "01xls2dvzh38yj17jgrbiib1d3nyad7k2yw9s0mpklwys333zrkz"; - procMacro = true; - libName = "wasm_bindgen_macro"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "quote"; - packageId = "quote"; - } - { - name = "wasm-bindgen-macro-support"; - packageId = "wasm-bindgen-macro-support"; - } - ]; - features = { - "strict-macro" = [ "wasm-bindgen-macro-support/strict-macro" ]; - }; - }; - "wasm-bindgen-macro-support" = rec { - crateName = "wasm-bindgen-macro-support"; - version = "0.2.100"; - edition = "2021"; - sha256 = "1plm8dh20jg2id0320pbmrlsv6cazfv6b6907z19ys4z1jj7xs4a"; - libName = "wasm_bindgen_macro_support"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn 2.0.98"; - features = [ "visit" "visit-mut" "full" ]; - } - { - name = "wasm-bindgen-backend"; - packageId = "wasm-bindgen-backend"; - } - { - name = "wasm-bindgen-shared"; - packageId = "wasm-bindgen-shared"; - } - ]; - features = { - "extra-traits" = [ "syn/extra-traits" ]; - }; - }; - "wasm-bindgen-shared" = rec { - crateName = "wasm-bindgen-shared"; - version = "0.2.100"; - edition = "2021"; - links = "wasm_bindgen"; - sha256 = "0gffxvqgbh9r9xl36gprkfnh3w9gl8wgia6xrin7v11sjcxxf18s"; - libName = "wasm_bindgen_shared"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - - }; - "winapi 0.2.8" = rec { - crateName = "winapi"; - version = "0.2.8"; - edition = "2015"; - sha256 = "0yh816lh6lf56dpsgxy189c2ai1z3j8mw9si6izqb6wsjkbcjz8n"; - authors = [ - "Peter Atashian " - ]; - - }; - "winapi 0.3.9" = rec { - crateName = "winapi"; - version = "0.3.9"; - edition = "2015"; - sha256 = "06gl025x418lchw1wxj64ycr7gha83m44cjr5sarhynd9xkrm0sw"; - authors = [ - "Peter Atashian " - ]; - dependencies = [ - { - name = "winapi-i686-pc-windows-gnu"; - packageId = "winapi-i686-pc-windows-gnu"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "i686-pc-windows-gnu"); - } - { - name = "winapi-x86_64-pc-windows-gnu"; - packageId = "winapi-x86_64-pc-windows-gnu"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "x86_64-pc-windows-gnu"); - } - ]; - features = { - "debug" = [ "impl-debug" ]; - }; - resolvedDefaultFeatures = [ "consoleapi" "errhandlingapi" "handleapi" "minwinbase" "minwindef" "ntstatus" "processenv" "winbase" "winerror" "winnt" "winsock2" "ws2def" "ws2ipdef" "ws2tcpip" ]; - }; - "winapi-build" = rec { - crateName = "winapi-build"; - version = "0.1.1"; - edition = "2015"; - sha256 = "1g4rqsgjky0a7530qajn2bbfcrl2v0zb39idgdws9b1l7gp5wc9d"; - libName = "build"; - authors = [ - "Peter Atashian " - ]; - - }; - "winapi-i686-pc-windows-gnu" = rec { - crateName = "winapi-i686-pc-windows-gnu"; - version = "0.4.0"; - edition = "2015"; - sha256 = "1dmpa6mvcvzz16zg6d5vrfy4bxgg541wxrcip7cnshi06v38ffxc"; - libName = "winapi_i686_pc_windows_gnu"; - authors = [ - "Peter Atashian " - ]; - - }; - "winapi-util" = rec { - crateName = "winapi-util"; - version = "0.1.9"; - edition = "2021"; - sha256 = "1fqhkcl9scd230cnfj8apfficpf5c9vhwnk4yy9xfc1sw69iq8ng"; - libName = "winapi_util"; - authors = [ - "Andrew Gallant " - ]; - dependencies = [ - { - name = "windows-sys"; - packageId = "windows-sys 0.59.0"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Foundation" "Win32_Storage_FileSystem" "Win32_System_Console" "Win32_System_SystemInformation" ]; - } - ]; - - }; - "winapi-x86_64-pc-windows-gnu" = rec { - crateName = "winapi-x86_64-pc-windows-gnu"; - version = "0.4.0"; - edition = "2015"; - sha256 = "0gqq64czqb64kskjryj8isp62m2sgvx25yyj3kpc2myh85w24bki"; - libName = "winapi_x86_64_pc_windows_gnu"; - authors = [ - "Peter Atashian " - ]; - - }; - "windows-core" = rec { - crateName = "windows-core"; - version = "0.52.0"; - edition = "2021"; - sha256 = "1nc3qv7sy24x0nlnb32f7alzpd6f72l4p24vl65vydbyil669ark"; - libName = "windows_core"; - authors = [ - "Microsoft" - ]; - dependencies = [ - { - name = "windows-targets"; - packageId = "windows-targets"; - } - ]; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "windows-sys 0.52.0" = rec { - crateName = "windows-sys"; - version = "0.52.0"; - edition = "2021"; - sha256 = "0gd3v4ji88490zgb6b5mq5zgbvwv7zx1ibn8v3x83rwcdbryaar8"; - libName = "windows_sys"; - authors = [ - "Microsoft" - ]; - dependencies = [ - { - name = "windows-targets"; - packageId = "windows-targets"; - } - ]; - features = { - "Wdk_Foundation" = [ "Wdk" ]; - "Wdk_Graphics" = [ "Wdk" ]; - "Wdk_Graphics_Direct3D" = [ "Wdk_Graphics" ]; - "Wdk_Storage" = [ "Wdk" ]; - "Wdk_Storage_FileSystem" = [ "Wdk_Storage" ]; - "Wdk_Storage_FileSystem_Minifilters" = [ "Wdk_Storage_FileSystem" ]; - "Wdk_System" = [ "Wdk" ]; - "Wdk_System_IO" = [ "Wdk_System" ]; - "Wdk_System_OfflineRegistry" = [ "Wdk_System" ]; - "Wdk_System_Registry" = [ "Wdk_System" ]; - "Wdk_System_SystemInformation" = [ "Wdk_System" ]; - "Wdk_System_SystemServices" = [ "Wdk_System" ]; - "Wdk_System_Threading" = [ "Wdk_System" ]; - "Win32_Data" = [ "Win32" ]; - "Win32_Data_HtmlHelp" = [ "Win32_Data" ]; - "Win32_Data_RightsManagement" = [ "Win32_Data" ]; - "Win32_Devices" = [ "Win32" ]; - "Win32_Devices_AllJoyn" = [ "Win32_Devices" ]; - "Win32_Devices_BiometricFramework" = [ "Win32_Devices" ]; - "Win32_Devices_Bluetooth" = [ "Win32_Devices" ]; - "Win32_Devices_Communication" = [ "Win32_Devices" ]; - "Win32_Devices_DeviceAndDriverInstallation" = [ "Win32_Devices" ]; - "Win32_Devices_DeviceQuery" = [ "Win32_Devices" ]; - "Win32_Devices_Display" = [ "Win32_Devices" ]; - "Win32_Devices_Enumeration" = [ "Win32_Devices" ]; - "Win32_Devices_Enumeration_Pnp" = [ "Win32_Devices_Enumeration" ]; - "Win32_Devices_Fax" = [ "Win32_Devices" ]; - "Win32_Devices_HumanInterfaceDevice" = [ "Win32_Devices" ]; - "Win32_Devices_PortableDevices" = [ "Win32_Devices" ]; - "Win32_Devices_Properties" = [ "Win32_Devices" ]; - "Win32_Devices_Pwm" = [ "Win32_Devices" ]; - "Win32_Devices_Sensors" = [ "Win32_Devices" ]; - "Win32_Devices_SerialCommunication" = [ "Win32_Devices" ]; - "Win32_Devices_Tapi" = [ "Win32_Devices" ]; - "Win32_Devices_Usb" = [ "Win32_Devices" ]; - "Win32_Devices_WebServicesOnDevices" = [ "Win32_Devices" ]; - "Win32_Foundation" = [ "Win32" ]; - "Win32_Gaming" = [ "Win32" ]; - "Win32_Globalization" = [ "Win32" ]; - "Win32_Graphics" = [ "Win32" ]; - "Win32_Graphics_Dwm" = [ "Win32_Graphics" ]; - "Win32_Graphics_Gdi" = [ "Win32_Graphics" ]; - "Win32_Graphics_GdiPlus" = [ "Win32_Graphics" ]; - "Win32_Graphics_Hlsl" = [ "Win32_Graphics" ]; - "Win32_Graphics_OpenGL" = [ "Win32_Graphics" ]; - "Win32_Graphics_Printing" = [ "Win32_Graphics" ]; - "Win32_Graphics_Printing_PrintTicket" = [ "Win32_Graphics_Printing" ]; - "Win32_Management" = [ "Win32" ]; - "Win32_Management_MobileDeviceManagementRegistration" = [ "Win32_Management" ]; - "Win32_Media" = [ "Win32" ]; - "Win32_Media_Audio" = [ "Win32_Media" ]; - "Win32_Media_DxMediaObjects" = [ "Win32_Media" ]; - "Win32_Media_KernelStreaming" = [ "Win32_Media" ]; - "Win32_Media_Multimedia" = [ "Win32_Media" ]; - "Win32_Media_Streaming" = [ "Win32_Media" ]; - "Win32_Media_WindowsMediaFormat" = [ "Win32_Media" ]; - "Win32_NetworkManagement" = [ "Win32" ]; - "Win32_NetworkManagement_Dhcp" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Dns" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_InternetConnectionWizard" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_IpHelper" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Multicast" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Ndis" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetBios" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetManagement" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetShell" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetworkDiagnosticsFramework" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_P2P" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_QoS" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Rras" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Snmp" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WNet" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WebDav" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WiFi" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsConnectionManager" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsFilteringPlatform" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsFirewall" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsNetworkVirtualization" = [ "Win32_NetworkManagement" ]; - "Win32_Networking" = [ "Win32" ]; - "Win32_Networking_ActiveDirectory" = [ "Win32_Networking" ]; - "Win32_Networking_Clustering" = [ "Win32_Networking" ]; - "Win32_Networking_HttpServer" = [ "Win32_Networking" ]; - "Win32_Networking_Ldap" = [ "Win32_Networking" ]; - "Win32_Networking_WebSocket" = [ "Win32_Networking" ]; - "Win32_Networking_WinHttp" = [ "Win32_Networking" ]; - "Win32_Networking_WinInet" = [ "Win32_Networking" ]; - "Win32_Networking_WinSock" = [ "Win32_Networking" ]; - "Win32_Networking_WindowsWebServices" = [ "Win32_Networking" ]; - "Win32_Security" = [ "Win32" ]; - "Win32_Security_AppLocker" = [ "Win32_Security" ]; - "Win32_Security_Authentication" = [ "Win32_Security" ]; - "Win32_Security_Authentication_Identity" = [ "Win32_Security_Authentication" ]; - "Win32_Security_Authorization" = [ "Win32_Security" ]; - "Win32_Security_Credentials" = [ "Win32_Security" ]; - "Win32_Security_Cryptography" = [ "Win32_Security" ]; - "Win32_Security_Cryptography_Catalog" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_Certificates" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_Sip" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_UI" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_DiagnosticDataQuery" = [ "Win32_Security" ]; - "Win32_Security_DirectoryServices" = [ "Win32_Security" ]; - "Win32_Security_EnterpriseData" = [ "Win32_Security" ]; - "Win32_Security_ExtensibleAuthenticationProtocol" = [ "Win32_Security" ]; - "Win32_Security_Isolation" = [ "Win32_Security" ]; - "Win32_Security_LicenseProtection" = [ "Win32_Security" ]; - "Win32_Security_NetworkAccessProtection" = [ "Win32_Security" ]; - "Win32_Security_WinTrust" = [ "Win32_Security" ]; - "Win32_Security_WinWlx" = [ "Win32_Security" ]; - "Win32_Storage" = [ "Win32" ]; - "Win32_Storage_Cabinets" = [ "Win32_Storage" ]; - "Win32_Storage_CloudFilters" = [ "Win32_Storage" ]; - "Win32_Storage_Compression" = [ "Win32_Storage" ]; - "Win32_Storage_DistributedFileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_FileHistory" = [ "Win32_Storage" ]; - "Win32_Storage_FileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_Imapi" = [ "Win32_Storage" ]; - "Win32_Storage_IndexServer" = [ "Win32_Storage" ]; - "Win32_Storage_InstallableFileSystems" = [ "Win32_Storage" ]; - "Win32_Storage_IscsiDisc" = [ "Win32_Storage" ]; - "Win32_Storage_Jet" = [ "Win32_Storage" ]; - "Win32_Storage_Nvme" = [ "Win32_Storage" ]; - "Win32_Storage_OfflineFiles" = [ "Win32_Storage" ]; - "Win32_Storage_OperationRecorder" = [ "Win32_Storage" ]; - "Win32_Storage_Packaging" = [ "Win32_Storage" ]; - "Win32_Storage_Packaging_Appx" = [ "Win32_Storage_Packaging" ]; - "Win32_Storage_ProjectedFileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_StructuredStorage" = [ "Win32_Storage" ]; - "Win32_Storage_Vhd" = [ "Win32_Storage" ]; - "Win32_Storage_Xps" = [ "Win32_Storage" ]; - "Win32_System" = [ "Win32" ]; - "Win32_System_AddressBook" = [ "Win32_System" ]; - "Win32_System_Antimalware" = [ "Win32_System" ]; - "Win32_System_ApplicationInstallationAndServicing" = [ "Win32_System" ]; - "Win32_System_ApplicationVerifier" = [ "Win32_System" ]; - "Win32_System_ClrHosting" = [ "Win32_System" ]; - "Win32_System_Com" = [ "Win32_System" ]; - "Win32_System_Com_Marshal" = [ "Win32_System_Com" ]; - "Win32_System_Com_StructuredStorage" = [ "Win32_System_Com" ]; - "Win32_System_Com_Urlmon" = [ "Win32_System_Com" ]; - "Win32_System_ComponentServices" = [ "Win32_System" ]; - "Win32_System_Console" = [ "Win32_System" ]; - "Win32_System_CorrelationVector" = [ "Win32_System" ]; - "Win32_System_DataExchange" = [ "Win32_System" ]; - "Win32_System_DeploymentServices" = [ "Win32_System" ]; - "Win32_System_DeveloperLicensing" = [ "Win32_System" ]; - "Win32_System_Diagnostics" = [ "Win32_System" ]; - "Win32_System_Diagnostics_Ceip" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_Debug" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_Debug_Extensions" = [ "Win32_System_Diagnostics_Debug" ]; - "Win32_System_Diagnostics_Etw" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_ProcessSnapshotting" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_ToolHelp" = [ "Win32_System_Diagnostics" ]; - "Win32_System_DistributedTransactionCoordinator" = [ "Win32_System" ]; - "Win32_System_Environment" = [ "Win32_System" ]; - "Win32_System_ErrorReporting" = [ "Win32_System" ]; - "Win32_System_EventCollector" = [ "Win32_System" ]; - "Win32_System_EventLog" = [ "Win32_System" ]; - "Win32_System_EventNotificationService" = [ "Win32_System" ]; - "Win32_System_GroupPolicy" = [ "Win32_System" ]; - "Win32_System_HostCompute" = [ "Win32_System" ]; - "Win32_System_HostComputeNetwork" = [ "Win32_System" ]; - "Win32_System_HostComputeSystem" = [ "Win32_System" ]; - "Win32_System_Hypervisor" = [ "Win32_System" ]; - "Win32_System_IO" = [ "Win32_System" ]; - "Win32_System_Iis" = [ "Win32_System" ]; - "Win32_System_Ioctl" = [ "Win32_System" ]; - "Win32_System_JobObjects" = [ "Win32_System" ]; - "Win32_System_Js" = [ "Win32_System" ]; - "Win32_System_Kernel" = [ "Win32_System" ]; - "Win32_System_LibraryLoader" = [ "Win32_System" ]; - "Win32_System_Mailslots" = [ "Win32_System" ]; - "Win32_System_Mapi" = [ "Win32_System" ]; - "Win32_System_Memory" = [ "Win32_System" ]; - "Win32_System_Memory_NonVolatile" = [ "Win32_System_Memory" ]; - "Win32_System_MessageQueuing" = [ "Win32_System" ]; - "Win32_System_MixedReality" = [ "Win32_System" ]; - "Win32_System_Ole" = [ "Win32_System" ]; - "Win32_System_PasswordManagement" = [ "Win32_System" ]; - "Win32_System_Performance" = [ "Win32_System" ]; - "Win32_System_Performance_HardwareCounterProfiling" = [ "Win32_System_Performance" ]; - "Win32_System_Pipes" = [ "Win32_System" ]; - "Win32_System_Power" = [ "Win32_System" ]; - "Win32_System_ProcessStatus" = [ "Win32_System" ]; - "Win32_System_Recovery" = [ "Win32_System" ]; - "Win32_System_Registry" = [ "Win32_System" ]; - "Win32_System_RemoteDesktop" = [ "Win32_System" ]; - "Win32_System_RemoteManagement" = [ "Win32_System" ]; - "Win32_System_RestartManager" = [ "Win32_System" ]; - "Win32_System_Restore" = [ "Win32_System" ]; - "Win32_System_Rpc" = [ "Win32_System" ]; - "Win32_System_Search" = [ "Win32_System" ]; - "Win32_System_Search_Common" = [ "Win32_System_Search" ]; - "Win32_System_SecurityCenter" = [ "Win32_System" ]; - "Win32_System_Services" = [ "Win32_System" ]; - "Win32_System_SetupAndMigration" = [ "Win32_System" ]; - "Win32_System_Shutdown" = [ "Win32_System" ]; - "Win32_System_StationsAndDesktops" = [ "Win32_System" ]; - "Win32_System_SubsystemForLinux" = [ "Win32_System" ]; - "Win32_System_SystemInformation" = [ "Win32_System" ]; - "Win32_System_SystemServices" = [ "Win32_System" ]; - "Win32_System_Threading" = [ "Win32_System" ]; - "Win32_System_Time" = [ "Win32_System" ]; - "Win32_System_TpmBaseServices" = [ "Win32_System" ]; - "Win32_System_UserAccessLogging" = [ "Win32_System" ]; - "Win32_System_Variant" = [ "Win32_System" ]; - "Win32_System_VirtualDosMachines" = [ "Win32_System" ]; - "Win32_System_WindowsProgramming" = [ "Win32_System" ]; - "Win32_System_Wmi" = [ "Win32_System" ]; - "Win32_UI" = [ "Win32" ]; - "Win32_UI_Accessibility" = [ "Win32_UI" ]; - "Win32_UI_ColorSystem" = [ "Win32_UI" ]; - "Win32_UI_Controls" = [ "Win32_UI" ]; - "Win32_UI_Controls_Dialogs" = [ "Win32_UI_Controls" ]; - "Win32_UI_HiDpi" = [ "Win32_UI" ]; - "Win32_UI_Input" = [ "Win32_UI" ]; - "Win32_UI_Input_Ime" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_KeyboardAndMouse" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_Pointer" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_Touch" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_XboxController" = [ "Win32_UI_Input" ]; - "Win32_UI_InteractionContext" = [ "Win32_UI" ]; - "Win32_UI_Magnification" = [ "Win32_UI" ]; - "Win32_UI_Shell" = [ "Win32_UI" ]; - "Win32_UI_Shell_PropertiesSystem" = [ "Win32_UI_Shell" ]; - "Win32_UI_TabletPC" = [ "Win32_UI" ]; - "Win32_UI_TextServices" = [ "Win32_UI" ]; - "Win32_UI_WindowsAndMessaging" = [ "Win32_UI" ]; - "Win32_Web" = [ "Win32" ]; - "Win32_Web_InternetExplorer" = [ "Win32_Web" ]; - }; - resolvedDefaultFeatures = [ "Win32" "Win32_Foundation" "Win32_Networking" "Win32_Networking_WinSock" "Win32_Security" "Win32_Security_Cryptography" "Win32_System" "Win32_System_IO" "Win32_System_LibraryLoader" "Win32_System_Threading" "Win32_System_WindowsProgramming" "default" ]; - }; - "windows-sys 0.59.0" = rec { - crateName = "windows-sys"; - version = "0.59.0"; - edition = "2021"; - sha256 = "0fw5672ziw8b3zpmnbp9pdv1famk74f1l9fcbc3zsrzdg56vqf0y"; - libName = "windows_sys"; - authors = [ - "Microsoft" - ]; - dependencies = [ - { - name = "windows-targets"; - packageId = "windows-targets"; - } - ]; - features = { - "Wdk" = [ "Win32_Foundation" ]; - "Wdk_Devices" = [ "Wdk" ]; - "Wdk_Devices_Bluetooth" = [ "Wdk_Devices" ]; - "Wdk_Devices_HumanInterfaceDevice" = [ "Wdk_Devices" ]; - "Wdk_Foundation" = [ "Wdk" ]; - "Wdk_Graphics" = [ "Wdk" ]; - "Wdk_Graphics_Direct3D" = [ "Wdk_Graphics" ]; - "Wdk_NetworkManagement" = [ "Wdk" ]; - "Wdk_NetworkManagement_Ndis" = [ "Wdk_NetworkManagement" ]; - "Wdk_NetworkManagement_WindowsFilteringPlatform" = [ "Wdk_NetworkManagement" ]; - "Wdk_Storage" = [ "Wdk" ]; - "Wdk_Storage_FileSystem" = [ "Wdk_Storage" ]; - "Wdk_Storage_FileSystem_Minifilters" = [ "Wdk_Storage_FileSystem" ]; - "Wdk_System" = [ "Wdk" ]; - "Wdk_System_IO" = [ "Wdk_System" ]; - "Wdk_System_Memory" = [ "Wdk_System" ]; - "Wdk_System_OfflineRegistry" = [ "Wdk_System" ]; - "Wdk_System_Registry" = [ "Wdk_System" ]; - "Wdk_System_SystemInformation" = [ "Wdk_System" ]; - "Wdk_System_SystemServices" = [ "Wdk_System" ]; - "Wdk_System_Threading" = [ "Wdk_System" ]; - "Win32" = [ "Win32_Foundation" ]; - "Win32_Data" = [ "Win32" ]; - "Win32_Data_HtmlHelp" = [ "Win32_Data" ]; - "Win32_Data_RightsManagement" = [ "Win32_Data" ]; - "Win32_Devices" = [ "Win32" ]; - "Win32_Devices_AllJoyn" = [ "Win32_Devices" ]; - "Win32_Devices_BiometricFramework" = [ "Win32_Devices" ]; - "Win32_Devices_Bluetooth" = [ "Win32_Devices" ]; - "Win32_Devices_Communication" = [ "Win32_Devices" ]; - "Win32_Devices_DeviceAndDriverInstallation" = [ "Win32_Devices" ]; - "Win32_Devices_DeviceQuery" = [ "Win32_Devices" ]; - "Win32_Devices_Display" = [ "Win32_Devices" ]; - "Win32_Devices_Enumeration" = [ "Win32_Devices" ]; - "Win32_Devices_Enumeration_Pnp" = [ "Win32_Devices_Enumeration" ]; - "Win32_Devices_Fax" = [ "Win32_Devices" ]; - "Win32_Devices_HumanInterfaceDevice" = [ "Win32_Devices" ]; - "Win32_Devices_PortableDevices" = [ "Win32_Devices" ]; - "Win32_Devices_Properties" = [ "Win32_Devices" ]; - "Win32_Devices_Pwm" = [ "Win32_Devices" ]; - "Win32_Devices_Sensors" = [ "Win32_Devices" ]; - "Win32_Devices_SerialCommunication" = [ "Win32_Devices" ]; - "Win32_Devices_Tapi" = [ "Win32_Devices" ]; - "Win32_Devices_Usb" = [ "Win32_Devices" ]; - "Win32_Devices_WebServicesOnDevices" = [ "Win32_Devices" ]; - "Win32_Foundation" = [ "Win32" ]; - "Win32_Gaming" = [ "Win32" ]; - "Win32_Globalization" = [ "Win32" ]; - "Win32_Graphics" = [ "Win32" ]; - "Win32_Graphics_Dwm" = [ "Win32_Graphics" ]; - "Win32_Graphics_Gdi" = [ "Win32_Graphics" ]; - "Win32_Graphics_GdiPlus" = [ "Win32_Graphics" ]; - "Win32_Graphics_Hlsl" = [ "Win32_Graphics" ]; - "Win32_Graphics_OpenGL" = [ "Win32_Graphics" ]; - "Win32_Graphics_Printing" = [ "Win32_Graphics" ]; - "Win32_Graphics_Printing_PrintTicket" = [ "Win32_Graphics_Printing" ]; - "Win32_Management" = [ "Win32" ]; - "Win32_Management_MobileDeviceManagementRegistration" = [ "Win32_Management" ]; - "Win32_Media" = [ "Win32" ]; - "Win32_Media_Audio" = [ "Win32_Media" ]; - "Win32_Media_DxMediaObjects" = [ "Win32_Media" ]; - "Win32_Media_KernelStreaming" = [ "Win32_Media" ]; - "Win32_Media_Multimedia" = [ "Win32_Media" ]; - "Win32_Media_Streaming" = [ "Win32_Media" ]; - "Win32_Media_WindowsMediaFormat" = [ "Win32_Media" ]; - "Win32_NetworkManagement" = [ "Win32" ]; - "Win32_NetworkManagement_Dhcp" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Dns" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_InternetConnectionWizard" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_IpHelper" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Multicast" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Ndis" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetBios" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetManagement" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetShell" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetworkDiagnosticsFramework" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_P2P" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_QoS" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Rras" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Snmp" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WNet" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WebDav" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WiFi" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsConnectionManager" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsFilteringPlatform" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsFirewall" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsNetworkVirtualization" = [ "Win32_NetworkManagement" ]; - "Win32_Networking" = [ "Win32" ]; - "Win32_Networking_ActiveDirectory" = [ "Win32_Networking" ]; - "Win32_Networking_Clustering" = [ "Win32_Networking" ]; - "Win32_Networking_HttpServer" = [ "Win32_Networking" ]; - "Win32_Networking_Ldap" = [ "Win32_Networking" ]; - "Win32_Networking_WebSocket" = [ "Win32_Networking" ]; - "Win32_Networking_WinHttp" = [ "Win32_Networking" ]; - "Win32_Networking_WinInet" = [ "Win32_Networking" ]; - "Win32_Networking_WinSock" = [ "Win32_Networking" ]; - "Win32_Networking_WindowsWebServices" = [ "Win32_Networking" ]; - "Win32_Security" = [ "Win32" ]; - "Win32_Security_AppLocker" = [ "Win32_Security" ]; - "Win32_Security_Authentication" = [ "Win32_Security" ]; - "Win32_Security_Authentication_Identity" = [ "Win32_Security_Authentication" ]; - "Win32_Security_Authorization" = [ "Win32_Security" ]; - "Win32_Security_Credentials" = [ "Win32_Security" ]; - "Win32_Security_Cryptography" = [ "Win32_Security" ]; - "Win32_Security_Cryptography_Catalog" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_Certificates" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_Sip" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_UI" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_DiagnosticDataQuery" = [ "Win32_Security" ]; - "Win32_Security_DirectoryServices" = [ "Win32_Security" ]; - "Win32_Security_EnterpriseData" = [ "Win32_Security" ]; - "Win32_Security_ExtensibleAuthenticationProtocol" = [ "Win32_Security" ]; - "Win32_Security_Isolation" = [ "Win32_Security" ]; - "Win32_Security_LicenseProtection" = [ "Win32_Security" ]; - "Win32_Security_NetworkAccessProtection" = [ "Win32_Security" ]; - "Win32_Security_WinTrust" = [ "Win32_Security" ]; - "Win32_Security_WinWlx" = [ "Win32_Security" ]; - "Win32_Storage" = [ "Win32" ]; - "Win32_Storage_Cabinets" = [ "Win32_Storage" ]; - "Win32_Storage_CloudFilters" = [ "Win32_Storage" ]; - "Win32_Storage_Compression" = [ "Win32_Storage" ]; - "Win32_Storage_DistributedFileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_FileHistory" = [ "Win32_Storage" ]; - "Win32_Storage_FileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_Imapi" = [ "Win32_Storage" ]; - "Win32_Storage_IndexServer" = [ "Win32_Storage" ]; - "Win32_Storage_InstallableFileSystems" = [ "Win32_Storage" ]; - "Win32_Storage_IscsiDisc" = [ "Win32_Storage" ]; - "Win32_Storage_Jet" = [ "Win32_Storage" ]; - "Win32_Storage_Nvme" = [ "Win32_Storage" ]; - "Win32_Storage_OfflineFiles" = [ "Win32_Storage" ]; - "Win32_Storage_OperationRecorder" = [ "Win32_Storage" ]; - "Win32_Storage_Packaging" = [ "Win32_Storage" ]; - "Win32_Storage_Packaging_Appx" = [ "Win32_Storage_Packaging" ]; - "Win32_Storage_ProjectedFileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_StructuredStorage" = [ "Win32_Storage" ]; - "Win32_Storage_Vhd" = [ "Win32_Storage" ]; - "Win32_Storage_Xps" = [ "Win32_Storage" ]; - "Win32_System" = [ "Win32" ]; - "Win32_System_AddressBook" = [ "Win32_System" ]; - "Win32_System_Antimalware" = [ "Win32_System" ]; - "Win32_System_ApplicationInstallationAndServicing" = [ "Win32_System" ]; - "Win32_System_ApplicationVerifier" = [ "Win32_System" ]; - "Win32_System_ClrHosting" = [ "Win32_System" ]; - "Win32_System_Com" = [ "Win32_System" ]; - "Win32_System_Com_Marshal" = [ "Win32_System_Com" ]; - "Win32_System_Com_StructuredStorage" = [ "Win32_System_Com" ]; - "Win32_System_Com_Urlmon" = [ "Win32_System_Com" ]; - "Win32_System_ComponentServices" = [ "Win32_System" ]; - "Win32_System_Console" = [ "Win32_System" ]; - "Win32_System_CorrelationVector" = [ "Win32_System" ]; - "Win32_System_DataExchange" = [ "Win32_System" ]; - "Win32_System_DeploymentServices" = [ "Win32_System" ]; - "Win32_System_DeveloperLicensing" = [ "Win32_System" ]; - "Win32_System_Diagnostics" = [ "Win32_System" ]; - "Win32_System_Diagnostics_Ceip" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_Debug" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_Debug_Extensions" = [ "Win32_System_Diagnostics_Debug" ]; - "Win32_System_Diagnostics_Etw" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_ProcessSnapshotting" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_ToolHelp" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_TraceLogging" = [ "Win32_System_Diagnostics" ]; - "Win32_System_DistributedTransactionCoordinator" = [ "Win32_System" ]; - "Win32_System_Environment" = [ "Win32_System" ]; - "Win32_System_ErrorReporting" = [ "Win32_System" ]; - "Win32_System_EventCollector" = [ "Win32_System" ]; - "Win32_System_EventLog" = [ "Win32_System" ]; - "Win32_System_EventNotificationService" = [ "Win32_System" ]; - "Win32_System_GroupPolicy" = [ "Win32_System" ]; - "Win32_System_HostCompute" = [ "Win32_System" ]; - "Win32_System_HostComputeNetwork" = [ "Win32_System" ]; - "Win32_System_HostComputeSystem" = [ "Win32_System" ]; - "Win32_System_Hypervisor" = [ "Win32_System" ]; - "Win32_System_IO" = [ "Win32_System" ]; - "Win32_System_Iis" = [ "Win32_System" ]; - "Win32_System_Ioctl" = [ "Win32_System" ]; - "Win32_System_JobObjects" = [ "Win32_System" ]; - "Win32_System_Js" = [ "Win32_System" ]; - "Win32_System_Kernel" = [ "Win32_System" ]; - "Win32_System_LibraryLoader" = [ "Win32_System" ]; - "Win32_System_Mailslots" = [ "Win32_System" ]; - "Win32_System_Mapi" = [ "Win32_System" ]; - "Win32_System_Memory" = [ "Win32_System" ]; - "Win32_System_Memory_NonVolatile" = [ "Win32_System_Memory" ]; - "Win32_System_MessageQueuing" = [ "Win32_System" ]; - "Win32_System_MixedReality" = [ "Win32_System" ]; - "Win32_System_Ole" = [ "Win32_System" ]; - "Win32_System_PasswordManagement" = [ "Win32_System" ]; - "Win32_System_Performance" = [ "Win32_System" ]; - "Win32_System_Performance_HardwareCounterProfiling" = [ "Win32_System_Performance" ]; - "Win32_System_Pipes" = [ "Win32_System" ]; - "Win32_System_Power" = [ "Win32_System" ]; - "Win32_System_ProcessStatus" = [ "Win32_System" ]; - "Win32_System_Recovery" = [ "Win32_System" ]; - "Win32_System_Registry" = [ "Win32_System" ]; - "Win32_System_RemoteDesktop" = [ "Win32_System" ]; - "Win32_System_RemoteManagement" = [ "Win32_System" ]; - "Win32_System_RestartManager" = [ "Win32_System" ]; - "Win32_System_Restore" = [ "Win32_System" ]; - "Win32_System_Rpc" = [ "Win32_System" ]; - "Win32_System_Search" = [ "Win32_System" ]; - "Win32_System_Search_Common" = [ "Win32_System_Search" ]; - "Win32_System_SecurityCenter" = [ "Win32_System" ]; - "Win32_System_Services" = [ "Win32_System" ]; - "Win32_System_SetupAndMigration" = [ "Win32_System" ]; - "Win32_System_Shutdown" = [ "Win32_System" ]; - "Win32_System_StationsAndDesktops" = [ "Win32_System" ]; - "Win32_System_SubsystemForLinux" = [ "Win32_System" ]; - "Win32_System_SystemInformation" = [ "Win32_System" ]; - "Win32_System_SystemServices" = [ "Win32_System" ]; - "Win32_System_Threading" = [ "Win32_System" ]; - "Win32_System_Time" = [ "Win32_System" ]; - "Win32_System_TpmBaseServices" = [ "Win32_System" ]; - "Win32_System_UserAccessLogging" = [ "Win32_System" ]; - "Win32_System_Variant" = [ "Win32_System" ]; - "Win32_System_VirtualDosMachines" = [ "Win32_System" ]; - "Win32_System_WindowsProgramming" = [ "Win32_System" ]; - "Win32_System_Wmi" = [ "Win32_System" ]; - "Win32_UI" = [ "Win32" ]; - "Win32_UI_Accessibility" = [ "Win32_UI" ]; - "Win32_UI_ColorSystem" = [ "Win32_UI" ]; - "Win32_UI_Controls" = [ "Win32_UI" ]; - "Win32_UI_Controls_Dialogs" = [ "Win32_UI_Controls" ]; - "Win32_UI_HiDpi" = [ "Win32_UI" ]; - "Win32_UI_Input" = [ "Win32_UI" ]; - "Win32_UI_Input_Ime" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_KeyboardAndMouse" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_Pointer" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_Touch" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_XboxController" = [ "Win32_UI_Input" ]; - "Win32_UI_InteractionContext" = [ "Win32_UI" ]; - "Win32_UI_Magnification" = [ "Win32_UI" ]; - "Win32_UI_Shell" = [ "Win32_UI" ]; - "Win32_UI_Shell_Common" = [ "Win32_UI_Shell" ]; - "Win32_UI_Shell_PropertiesSystem" = [ "Win32_UI_Shell" ]; - "Win32_UI_TabletPC" = [ "Win32_UI" ]; - "Win32_UI_TextServices" = [ "Win32_UI" ]; - "Win32_UI_WindowsAndMessaging" = [ "Win32_UI" ]; - "Win32_Web" = [ "Win32" ]; - "Win32_Web_InternetExplorer" = [ "Win32_Web" ]; - }; - resolvedDefaultFeatures = [ "Win32" "Win32_Foundation" "Win32_NetworkManagement" "Win32_NetworkManagement_IpHelper" "Win32_Networking" "Win32_Networking_WinSock" "Win32_Security" "Win32_Security_Authentication" "Win32_Security_Authentication_Identity" "Win32_Security_Credentials" "Win32_Security_Cryptography" "Win32_Storage" "Win32_Storage_FileSystem" "Win32_System" "Win32_System_Console" "Win32_System_Diagnostics" "Win32_System_Diagnostics_Debug" "Win32_System_LibraryLoader" "Win32_System_Memory" "Win32_System_SystemInformation" "Win32_System_Threading" "default" ]; - }; - "windows-targets" = rec { - crateName = "windows-targets"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0wwrx625nwlfp7k93r2rra568gad1mwd888h1jwnl0vfg5r4ywlv"; - libName = "windows_targets"; - authors = [ - "Microsoft" - ]; - dependencies = [ - { - name = "windows_aarch64_gnullvm"; - packageId = "windows_aarch64_gnullvm"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "aarch64-pc-windows-gnullvm"); - } - { - name = "windows_aarch64_msvc"; - packageId = "windows_aarch64_msvc"; - target = { target, features }: (("aarch64" == target."arch" or null) && ("msvc" == target."env" or null) && (!(target."windows_raw_dylib" or false))); - } - { - name = "windows_i686_gnu"; - packageId = "windows_i686_gnu"; - target = { target, features }: (("x86" == target."arch" or null) && ("gnu" == target."env" or null) && (!("llvm" == target."abi" or null)) && (!(target."windows_raw_dylib" or false))); - } - { - name = "windows_i686_gnullvm"; - packageId = "windows_i686_gnullvm"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "i686-pc-windows-gnullvm"); - } - { - name = "windows_i686_msvc"; - packageId = "windows_i686_msvc"; - target = { target, features }: (("x86" == target."arch" or null) && ("msvc" == target."env" or null) && (!(target."windows_raw_dylib" or false))); - } - { - name = "windows_x86_64_gnu"; - packageId = "windows_x86_64_gnu"; - target = { target, features }: (("x86_64" == target."arch" or null) && ("gnu" == target."env" or null) && (!("llvm" == target."abi" or null)) && (!(target."windows_raw_dylib" or false))); - } - { - name = "windows_x86_64_gnullvm"; - packageId = "windows_x86_64_gnullvm"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "x86_64-pc-windows-gnullvm"); - } - { - name = "windows_x86_64_msvc"; - packageId = "windows_x86_64_msvc"; - target = { target, features }: ((("x86_64" == target."arch" or null) || ("arm64ec" == target."arch" or null)) && ("msvc" == target."env" or null) && (!(target."windows_raw_dylib" or false))); - } - ]; - - }; - "windows_aarch64_gnullvm" = rec { - crateName = "windows_aarch64_gnullvm"; - version = "0.52.6"; - edition = "2021"; - sha256 = "1lrcq38cr2arvmz19v32qaggvj8bh1640mdm9c2fr877h0hn591j"; - authors = [ - "Microsoft" - ]; - - }; - "windows_aarch64_msvc" = rec { - crateName = "windows_aarch64_msvc"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0sfl0nysnz32yyfh773hpi49b1q700ah6y7sacmjbqjjn5xjmv09"; - authors = [ - "Microsoft" - ]; - - }; - "windows_i686_gnu" = rec { - crateName = "windows_i686_gnu"; - version = "0.52.6"; - edition = "2021"; - sha256 = "02zspglbykh1jh9pi7gn8g1f97jh1rrccni9ivmrfbl0mgamm6wf"; - authors = [ - "Microsoft" - ]; - - }; - "windows_i686_gnullvm" = rec { - crateName = "windows_i686_gnullvm"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0rpdx1537mw6slcpqa0rm3qixmsb79nbhqy5fsm3q2q9ik9m5vhf"; - authors = [ - "Microsoft" - ]; - - }; - "windows_i686_msvc" = rec { - crateName = "windows_i686_msvc"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0rkcqmp4zzmfvrrrx01260q3xkpzi6fzi2x2pgdcdry50ny4h294"; - authors = [ - "Microsoft" - ]; - - }; - "windows_x86_64_gnu" = rec { - crateName = "windows_x86_64_gnu"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0y0sifqcb56a56mvn7xjgs8g43p33mfqkd8wj1yhrgxzma05qyhl"; - authors = [ - "Microsoft" - ]; - - }; - "windows_x86_64_gnullvm" = rec { - crateName = "windows_x86_64_gnullvm"; - version = "0.52.6"; - edition = "2021"; - sha256 = "03gda7zjx1qh8k9nnlgb7m3w3s1xkysg55hkd1wjch8pqhyv5m94"; - authors = [ - "Microsoft" - ]; - - }; - "windows_x86_64_msvc" = rec { - crateName = "windows_x86_64_msvc"; - version = "0.52.6"; - edition = "2021"; - sha256 = "1v7rb5cibyzx8vak29pdrk8nx9hycsjs4w0jgms08qk49jl6v7sq"; - authors = [ - "Microsoft" - ]; - - }; - "wit-bindgen-rt" = rec { - crateName = "wit-bindgen-rt"; - version = "0.33.0"; - edition = "2021"; - sha256 = "0g4lwfp9x6a2i1hgjn8k14nr4fsnpd5izxhc75zpi2s5cvcg6s1j"; - libName = "wit_bindgen_rt"; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 2.8.0"; - optional = true; - } - ]; - features = { - "bitflags" = [ "dep:bitflags" ]; - }; - resolvedDefaultFeatures = [ "bitflags" ]; - }; - "ws2_32-sys" = rec { - crateName = "ws2_32-sys"; - version = "0.2.1"; - edition = "2015"; - sha256 = "0ppscg5qfqaw0gzwv2a4nhn5bn01ff9iwn6ysqnzm4n8s3myz76m"; - libName = "ws2_32"; - authors = [ - "Peter Atashian " - ]; - dependencies = [ - { - name = "winapi"; - packageId = "winapi 0.2.8"; - } - ]; - buildDependencies = [ - { - name = "winapi-build"; - packageId = "winapi-build"; - } - ]; - - }; - "yaml-rust" = rec { - crateName = "yaml-rust"; - version = "0.4.5"; - edition = "2018"; - sha256 = "118wbqrr4n6wgk5rjjnlrdlahawlxc1bdsx146mwk8f79in97han"; - libName = "yaml_rust"; - authors = [ - "Yuheng Chen " - ]; - dependencies = [ - { - name = "linked-hash-map"; - packageId = "linked-hash-map 0.5.6"; - } - ]; - - }; - "zerocopy" = rec { - crateName = "zerocopy"; - version = "0.7.35"; - edition = "2018"; - sha256 = "1w36q7b9il2flg0qskapgi9ymgg7p985vniqd09vi0mwib8lz6qv"; - authors = [ - "Joshua Liebow-Feeser " - ]; - dependencies = [ - { - name = "byteorder"; - packageId = "byteorder"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "zerocopy-derive"; - packageId = "zerocopy-derive"; - optional = true; - } - { - name = "zerocopy-derive"; - packageId = "zerocopy-derive"; - target = { target, features }: false; - } - ]; - devDependencies = [ - { - name = "zerocopy-derive"; - packageId = "zerocopy-derive"; - } - ]; - features = { - "__internal_use_only_features_that_work_on_stable" = [ "alloc" "derive" "simd" ]; - "byteorder" = [ "dep:byteorder" ]; - "default" = [ "byteorder" ]; - "derive" = [ "zerocopy-derive" ]; - "simd-nightly" = [ "simd" ]; - "zerocopy-derive" = [ "dep:zerocopy-derive" ]; - }; - resolvedDefaultFeatures = [ "byteorder" "default" "derive" "simd" "zerocopy-derive" ]; - }; - "zerocopy-derive" = rec { - crateName = "zerocopy-derive"; - version = "0.7.35"; - edition = "2018"; - sha256 = "0gnf2ap2y92nwdalzz3x7142f2b83sni66l39vxp2ijd6j080kzs"; - procMacro = true; - libName = "zerocopy_derive"; - authors = [ - "Joshua Liebow-Feeser " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn 2.0.98"; - } - ]; - - }; - }; - - # - # crate2nix/default.nix (excerpt start) - # - - /* Target (platform) data for conditional dependencies. - This corresponds roughly to what buildRustCrate is setting. - */ - makeDefaultTarget = platform: { - unix = platform.isUnix; - windows = platform.isWindows; - fuchsia = true; - test = false; - - inherit (platform.rust.platform) - arch - os - vendor; - family = platform.rust.platform.target-family; - env = "gnu"; - endian = - if platform.parsed.cpu.significantByte.name == "littleEndian" - then "little" else "big"; - pointer_width = toString platform.parsed.cpu.bits; - debug_assertions = false; - }; - - /* Filters common temp files and build files. */ - # TODO(pkolloch): Substitute with gitignore filter - sourceFilter = name: type: - let - baseName = builtins.baseNameOf (builtins.toString name); - in - ! ( - # Filter out git - baseName == ".gitignore" - || (type == "directory" && baseName == ".git") - - # Filter out build results - || ( - type == "directory" && ( - baseName == "target" - || baseName == "_site" - || baseName == ".sass-cache" - || baseName == ".jekyll-metadata" - || baseName == "build-artifacts" - ) - ) - - # Filter out nix-build result symlinks - || ( - type == "symlink" && lib.hasPrefix "result" baseName - ) - - # Filter out IDE config - || ( - type == "directory" && ( - baseName == ".idea" || baseName == ".vscode" - ) - ) || lib.hasSuffix ".iml" baseName - - # Filter out nix build files - || baseName == "Cargo.nix" - - # Filter out editor backup / swap files. - || lib.hasSuffix "~" baseName - || builtins.match "^\\.sw[a-z]$$" baseName != null - || builtins.match "^\\..*\\.sw[a-z]$$" baseName != null - || lib.hasSuffix ".tmp" baseName - || lib.hasSuffix ".bak" baseName - || baseName == "tests.nix" - ); - - /* Returns a crate which depends on successful test execution - of crate given as the second argument. - - testCrateFlags: list of flags to pass to the test exectuable - testInputs: list of packages that should be available during test execution - */ - crateWithTest = { crate, testCrate, testCrateFlags, testInputs, testPreRun, testPostRun }: - assert builtins.typeOf testCrateFlags == "list"; - assert builtins.typeOf testInputs == "list"; - assert builtins.typeOf testPreRun == "string"; - assert builtins.typeOf testPostRun == "string"; - let - # override the `crate` so that it will build and execute tests instead of - # building the actual lib and bin targets We just have to pass `--test` - # to rustc and it will do the right thing. We execute the tests and copy - # their log and the test executables to $out for later inspection. - test = - let - drv = testCrate.override - ( - _: { - buildTests = true; - release = false; - } - ); - # If the user hasn't set any pre/post commands, we don't want to - # insert empty lines. This means that any existing users of crate2nix - # don't get a spurious rebuild unless they set these explicitly. - testCommand = pkgs.lib.concatStringsSep "\n" - (pkgs.lib.filter (s: s != "") [ - testPreRun - "$f $testCrateFlags 2>&1 | tee -a $out" - testPostRun - ]); - in - pkgs.stdenvNoCC.mkDerivation { - name = "run-tests-${testCrate.name}"; - - inherit (crate) src; - - inherit testCrateFlags; - - buildInputs = testInputs; - - buildPhase = '' - set -e - export RUST_BACKTRACE=1 - - # build outputs - testRoot=target/debug - mkdir -p $testRoot - - # executables of the crate - # we copy to prevent std::env::current_exe() to resolve to a store location - for i in ${crate}/bin/*; do - cp "$i" "$testRoot" - done - chmod +w -R . - - # test harness executables are suffixed with a hash, like cargo does - # this allows to prevent name collision with the main - # executables of the crate - hash=$(basename $out) - for file in ${drv}/tests/*; do - f=$testRoot/$(basename $file)-$hash - cp $file $f - ${testCommand} - done - ''; - }; - in - pkgs.runCommand "${crate.name}-linked" - { - inherit (crate) outputs crateName; - passthru = (crate.passthru or { }) // { - inherit test; - }; - } - (lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) '' - echo tested by ${test} - '' + '' - ${lib.concatMapStringsSep "\n" (output: "ln -s ${crate.${output}} ${"$"}${output}") crate.outputs} - ''); - - /* A restricted overridable version of builtRustCratesWithFeatures. */ - buildRustCrateWithFeatures = - { packageId - , features ? rootFeatures - , crateOverrides ? defaultCrateOverrides - , buildRustCrateForPkgsFunc ? null - , runTests ? false - , testCrateFlags ? [ ] - , testInputs ? [ ] - # Any command to run immediatelly before a test is executed. - , testPreRun ? "" - # Any command run immediatelly after a test is executed. - , testPostRun ? "" - }: - lib.makeOverridable - ( - { features - , crateOverrides - , runTests - , testCrateFlags - , testInputs - , testPreRun - , testPostRun - }: - let - buildRustCrateForPkgsFuncOverriden = - if buildRustCrateForPkgsFunc != null - then buildRustCrateForPkgsFunc - else - ( - if crateOverrides == pkgs.defaultCrateOverrides - then buildRustCrateForPkgs - else - pkgs: (buildRustCrateForPkgs pkgs).override { - defaultCrateOverrides = crateOverrides; - } - ); - builtRustCrates = builtRustCratesWithFeatures { - inherit packageId features; - buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden; - runTests = false; - }; - builtTestRustCrates = builtRustCratesWithFeatures { - inherit packageId features; - buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden; - runTests = true; - }; - drv = builtRustCrates.crates.${packageId}; - testDrv = builtTestRustCrates.crates.${packageId}; - derivation = - if runTests then - crateWithTest - { - crate = drv; - testCrate = testDrv; - inherit testCrateFlags testInputs testPreRun testPostRun; - } - else drv; - in - derivation - ) - { inherit features crateOverrides runTests testCrateFlags testInputs testPreRun testPostRun; }; - - /* Returns an attr set with packageId mapped to the result of buildRustCrateForPkgsFunc - for the corresponding crate. - */ - builtRustCratesWithFeatures = - { packageId - , features - , crateConfigs ? crates - , buildRustCrateForPkgsFunc - , runTests - , makeTarget ? makeDefaultTarget - } @ args: - assert (builtins.isAttrs crateConfigs); - assert (builtins.isString packageId); - assert (builtins.isList features); - assert (builtins.isAttrs (makeTarget stdenv.hostPlatform)); - assert (builtins.isBool runTests); - let - rootPackageId = packageId; - mergedFeatures = mergePackageFeatures - ( - args // { - inherit rootPackageId; - target = makeTarget stdenv.hostPlatform // { test = runTests; }; - } - ); - # Memoize built packages so that reappearing packages are only built once. - builtByPackageIdByPkgs = mkBuiltByPackageIdByPkgs pkgs; - mkBuiltByPackageIdByPkgs = pkgs: - let - self = { - crates = lib.mapAttrs (packageId: value: buildByPackageIdForPkgsImpl self pkgs packageId) crateConfigs; - target = makeTarget stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; - }; - in - self; - buildByPackageIdForPkgsImpl = self: pkgs: packageId: - let - features = mergedFeatures."${packageId}" or [ ]; - crateConfig' = crateConfigs."${packageId}"; - crateConfig = - builtins.removeAttrs crateConfig' [ "resolvedDefaultFeatures" "devDependencies" ]; - devDependencies = - lib.optionals - (runTests && packageId == rootPackageId) - (crateConfig'.devDependencies or [ ]); - dependencies = - dependencyDerivations { - inherit features; - inherit (self) target; - buildByPackageId = depPackageId: - # proc_macro crates must be compiled for the build architecture - if crateConfigs.${depPackageId}.procMacro or false - then self.build.crates.${depPackageId} - else self.crates.${depPackageId}; - dependencies = - (crateConfig.dependencies or [ ]) - ++ devDependencies; - }; - buildDependencies = - dependencyDerivations { - inherit features; - inherit (self.build) target; - buildByPackageId = depPackageId: - self.build.crates.${depPackageId}; - dependencies = crateConfig.buildDependencies or [ ]; - }; - dependenciesWithRenames = - let - buildDeps = filterEnabledDependencies { - inherit features; - inherit (self) target; - dependencies = crateConfig.dependencies or [ ] ++ devDependencies; - }; - hostDeps = filterEnabledDependencies { - inherit features; - inherit (self.build) target; - dependencies = crateConfig.buildDependencies or [ ]; - }; - in - lib.filter (d: d ? "rename") (hostDeps ++ buildDeps); - # Crate renames have the form: - # - # { - # crate_name = [ - # { version = "1.2.3"; rename = "crate_name01"; } - # ]; - # # ... - # } - crateRenames = - let - grouped = - lib.groupBy - (dependency: dependency.name) - dependenciesWithRenames; - versionAndRename = dep: - let - package = crateConfigs."${dep.packageId}"; - in - { inherit (dep) rename; inherit (package) version; }; - in - lib.mapAttrs (name: builtins.map versionAndRename) grouped; - in - buildRustCrateForPkgsFunc pkgs - ( - crateConfig // { - src = crateConfig.src or ( - pkgs.fetchurl rec { - name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; - # https://www.pietroalbini.org/blog/downloading-crates-io/ - # Not rate-limited, CDN URL. - url = "https://static.crates.io/crates/${crateConfig.crateName}/${crateConfig.crateName}-${crateConfig.version}.crate"; - sha256 = - assert (lib.assertMsg (crateConfig ? sha256) "Missing sha256 for ${name}"); - crateConfig.sha256; - } - ); - extraRustcOpts = lib.lists.optional (targetFeatures != [ ]) "-C target-feature=${lib.concatMapStringsSep "," (x: "+${x}") targetFeatures}"; - inherit features dependencies buildDependencies crateRenames release; - } - ); - in - builtByPackageIdByPkgs; - - /* Returns the actual derivations for the given dependencies. */ - dependencyDerivations = - { buildByPackageId - , features - , dependencies - , target - }: - assert (builtins.isList features); - assert (builtins.isList dependencies); - assert (builtins.isAttrs target); - let - enabledDependencies = filterEnabledDependencies { - inherit dependencies features target; - }; - depDerivation = dependency: buildByPackageId dependency.packageId; - in - map depDerivation enabledDependencies; - - /* Returns a sanitized version of val with all values substituted that cannot - be serialized as JSON. - */ - sanitizeForJson = val: - if builtins.isAttrs val - then lib.mapAttrs (n: sanitizeForJson) val - else if builtins.isList val - then builtins.map sanitizeForJson val - else if builtins.isFunction val - then "function" - else val; - - /* Returns various tools to debug a crate. */ - debugCrate = { packageId, target ? makeDefaultTarget stdenv.hostPlatform }: - assert (builtins.isString packageId); - let - debug = rec { - # The built tree as passed to buildRustCrate. - buildTree = buildRustCrateWithFeatures { - buildRustCrateForPkgsFunc = _: lib.id; - inherit packageId; - }; - sanitizedBuildTree = sanitizeForJson buildTree; - dependencyTree = sanitizeForJson - ( - buildRustCrateWithFeatures { - buildRustCrateForPkgsFunc = _: crate: { - "01_crateName" = crate.crateName or false; - "02_features" = crate.features or [ ]; - "03_dependencies" = crate.dependencies or [ ]; - }; - inherit packageId; - } - ); - mergedPackageFeatures = mergePackageFeatures { - features = rootFeatures; - inherit packageId target; - }; - diffedDefaultPackageFeatures = diffDefaultPackageFeatures { - inherit packageId target; - }; - }; - in - { internal = debug; }; - - /* Returns differences between cargo default features and crate2nix default - features. - - This is useful for verifying the feature resolution in crate2nix. - */ - diffDefaultPackageFeatures = - { crateConfigs ? crates - , packageId - , target - }: - assert (builtins.isAttrs crateConfigs); - let - prefixValues = prefix: lib.mapAttrs (n: v: { "${prefix}" = v; }); - mergedFeatures = - prefixValues - "crate2nix" - (mergePackageFeatures { inherit crateConfigs packageId target; features = [ "default" ]; }); - configs = prefixValues "cargo" crateConfigs; - combined = lib.foldAttrs (a: b: a // b) { } [ mergedFeatures configs ]; - onlyInCargo = - builtins.attrNames - (lib.filterAttrs (n: v: !(v ? "crate2nix") && (v ? "cargo")) combined); - onlyInCrate2Nix = - builtins.attrNames - (lib.filterAttrs (n: v: (v ? "crate2nix") && !(v ? "cargo")) combined); - differentFeatures = lib.filterAttrs - ( - n: v: - (v ? "crate2nix") - && (v ? "cargo") - && (v.crate2nix.features or [ ]) != (v."cargo".resolved_default_features or [ ]) - ) - combined; - in - builtins.toJSON { - inherit onlyInCargo onlyInCrate2Nix differentFeatures; - }; - - /* Returns an attrset mapping packageId to the list of enabled features. - - If multiple paths to a dependency enable different features, the - corresponding feature sets are merged. Features in rust are additive. - */ - mergePackageFeatures = - { crateConfigs ? crates - , packageId - , rootPackageId ? packageId - , features ? rootFeatures - , dependencyPath ? [ crates.${packageId}.crateName ] - , featuresByPackageId ? { } - , target - # Adds devDependencies to the crate with rootPackageId. - , runTests ? false - , ... - } @ args: - assert (builtins.isAttrs crateConfigs); - assert (builtins.isString packageId); - assert (builtins.isString rootPackageId); - assert (builtins.isList features); - assert (builtins.isList dependencyPath); - assert (builtins.isAttrs featuresByPackageId); - assert (builtins.isAttrs target); - assert (builtins.isBool runTests); - let - crateConfig = crateConfigs."${packageId}" or (builtins.throw "Package not found: ${packageId}"); - expandedFeatures = expandFeatures (crateConfig.features or { }) features; - enabledFeatures = enableFeatures (crateConfig.dependencies or [ ]) expandedFeatures; - depWithResolvedFeatures = dependency: - let - inherit (dependency) packageId; - features = dependencyFeatures enabledFeatures dependency; - in - { inherit packageId features; }; - resolveDependencies = cache: path: dependencies: - assert (builtins.isAttrs cache); - assert (builtins.isList dependencies); - let - enabledDependencies = filterEnabledDependencies { - inherit dependencies target; - features = enabledFeatures; - }; - directDependencies = map depWithResolvedFeatures enabledDependencies; - foldOverCache = op: lib.foldl op cache directDependencies; - in - foldOverCache - ( - cache: { packageId, features }: - let - cacheFeatures = cache.${packageId} or [ ]; - combinedFeatures = sortedUnique (cacheFeatures ++ features); - in - if cache ? ${packageId} && cache.${packageId} == combinedFeatures - then cache - else - mergePackageFeatures { - features = combinedFeatures; - featuresByPackageId = cache; - inherit crateConfigs packageId target runTests rootPackageId; - } - ); - cacheWithSelf = - let - cacheFeatures = featuresByPackageId.${packageId} or [ ]; - combinedFeatures = sortedUnique (cacheFeatures ++ enabledFeatures); - in - featuresByPackageId // { - "${packageId}" = combinedFeatures; - }; - cacheWithDependencies = - resolveDependencies cacheWithSelf "dep" - ( - crateConfig.dependencies or [ ] - ++ lib.optionals - (runTests && packageId == rootPackageId) - (crateConfig.devDependencies or [ ]) - ); - cacheWithAll = - resolveDependencies - cacheWithDependencies "build" - (crateConfig.buildDependencies or [ ]); - in - cacheWithAll; - - /* Returns the enabled dependencies given the enabled features. */ - filterEnabledDependencies = { dependencies, features, target }: - assert (builtins.isList dependencies); - assert (builtins.isList features); - assert (builtins.isAttrs target); - - lib.filter - ( - dep: - let - targetFunc = dep.target or (features: true); - in - targetFunc { inherit features target; } - && ( - !(dep.optional or false) - || builtins.any (doesFeatureEnableDependency dep) features - ) - ) - dependencies; - - /* Returns whether the given feature should enable the given dependency. */ - doesFeatureEnableDependency = dependency: feature: - let - name = dependency.rename or dependency.name; - prefix = "${name}/"; - len = builtins.stringLength prefix; - startsWithPrefix = builtins.substring 0 len feature == prefix; - in - feature == name || feature == "dep:" + name || startsWithPrefix; - - /* Returns the expanded features for the given inputFeatures by applying the - rules in featureMap. - - featureMap is an attribute set which maps feature names to lists of further - feature names to enable in case this feature is selected. - */ - expandFeatures = featureMap: inputFeatures: - assert (builtins.isAttrs featureMap); - assert (builtins.isList inputFeatures); - let - expandFeaturesNoCycle = oldSeen: inputFeatures: - if inputFeatures != [ ] - then - let - # The feature we're currently expanding. - feature = builtins.head inputFeatures; - # All the features we've seen/expanded so far, including the one - # we're currently processing. - seen = oldSeen // { ${feature} = 1; }; - # Expand the feature but be careful to not re-introduce a feature - # that we've already seen: this can easily cause a cycle, see issue - # #209. - enables = builtins.filter (f: !(seen ? "${f}")) (featureMap."${feature}" or [ ]); - in - [ feature ] ++ (expandFeaturesNoCycle seen (builtins.tail inputFeatures ++ enables)) - # No more features left, nothing to expand to. - else [ ]; - outFeatures = expandFeaturesNoCycle { } inputFeatures; - in - sortedUnique outFeatures; - - /* This function adds optional dependencies as features if they are enabled - indirectly by dependency features. This function mimics Cargo's behavior - described in a note at: - https://doc.rust-lang.org/nightly/cargo/reference/features.html#dependency-features - */ - enableFeatures = dependencies: features: - assert (builtins.isList features); - assert (builtins.isList dependencies); - let - additionalFeatures = lib.concatMap - ( - dependency: - assert (builtins.isAttrs dependency); - let - enabled = builtins.any (doesFeatureEnableDependency dependency) features; - in - if (dependency.optional or false) && enabled - then [ (dependency.rename or dependency.name) ] - else [ ] - ) - dependencies; - in - sortedUnique (features ++ additionalFeatures); - - /* - Returns the actual features for the given dependency. - - features: The features of the crate that refers this dependency. - */ - dependencyFeatures = features: dependency: - assert (builtins.isList features); - assert (builtins.isAttrs dependency); - let - defaultOrNil = - if dependency.usesDefaultFeatures or true - then [ "default" ] - else [ ]; - explicitFeatures = dependency.features or [ ]; - additionalDependencyFeatures = - let - name = dependency.rename or dependency.name; - stripPrefixMatch = prefix: s: - if lib.hasPrefix prefix s - then lib.removePrefix prefix s - else null; - extractFeature = feature: lib.findFirst - (f: f != null) - null - (map (prefix: stripPrefixMatch prefix feature) [ - (name + "/") - (name + "?/") - ]); - dependencyFeatures = lib.filter (f: f != null) (map extractFeature features); - in - dependencyFeatures; - in - defaultOrNil ++ explicitFeatures ++ additionalDependencyFeatures; - - /* Sorts and removes duplicates from a list of strings. */ - sortedUnique = features: - assert (builtins.isList features); - assert (builtins.all builtins.isString features); - let - outFeaturesSet = lib.foldl (set: feature: set // { "${feature}" = 1; }) { } features; - outFeaturesUnique = builtins.attrNames outFeaturesSet; - in - builtins.sort (a: b: a < b) outFeaturesUnique; - - deprecationWarning = message: value: - if strictDeprecation - then builtins.throw "strictDeprecation enabled, aborting: ${message}" - else builtins.trace message value; - - # - # crate2nix/default.nix (excerpt end) - # - }; -} - diff --git a/fun/paroxysm/Cargo.toml b/fun/paroxysm/Cargo.toml deleted file mode 100644 index 4ef2bea4a..000000000 --- a/fun/paroxysm/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -authors = ["eeeeeta "] -edition = "2018" -name = "paroxysm" -version = "0.1.0" - -[dependencies] -chrono = "0.4" -config = "0.9" -crimp = { path = "../../net/crimp" } -env_logger = "0.7" -failure = "0.1" -irc = "0.13" -lazy_static = "1.4" -log = "0.4" -rand = "0.7" -regex = "1.3" -serde = { version = "1.0", features = [ "derive" ] } - -[dependencies.diesel] -features = [ "postgres", "chrono", "r2d2" ] -version = "1.4" - -# Add bogus dependency on any version of pq-sys, so we can force the pkg-config -# flag since pg_config reports an incorrect libdir in pkgs.libpq -# https://github.com/NixOS/nixpkgs/pull/359659#issuecomment-2660995914 -# https://github.com/NixOS/nixpkgs/pull/382380 -# https://github.com/sgrif/pq-sys/issues/75 -[dependencies.pq-sys] -features = [ "pkg-config" ] -version = "*" diff --git a/fun/paroxysm/OWNERS b/fun/paroxysm/OWNERS deleted file mode 100644 index 1120d0dcc..000000000 --- a/fun/paroxysm/OWNERS +++ /dev/null @@ -1 +0,0 @@ -eta diff --git a/fun/paroxysm/README.md b/fun/paroxysm/README.md deleted file mode 100644 index a59553098..000000000 --- a/fun/paroxysm/README.md +++ /dev/null @@ -1,19 +0,0 @@ -paroxysm -======== - -`paroxysm` is a bot for [internet relay chat -(IRC)](https://en.wikipedia.org/wiki/Internet_Relay_Chat) that lets you store -small pieces of information, called *factoids*, and retrieve them later. It's -useful for organising frequently-used information to avoid repeating oneself in -a busy chatroom, as well as making little todo lists or notes to self in a -private chatroom. - -It was directly inspired by the -[LearnDB](https://github.com/crawl/sequell/blob/master/docs/learndb.md) -functionality offered in `##crawl` on chat.freenode.net, and uses similar -syntax. - -## Usage instructions - -Will come soon; the project is very much still in beta, and is subject to -change. diff --git a/fun/paroxysm/default.nix b/fun/paroxysm/default.nix deleted file mode 100644 index 54f59dc47..000000000 --- a/fun/paroxysm/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ pkgs, ... }: - -let - cargoNix = import ./Cargo.nix { - inherit pkgs; - nixpkgs = pkgs.path; - }; -in - -cargoNix.rootCrate.build diff --git a/fun/paroxysm/docker/default.nix b/fun/paroxysm/docker/default.nix deleted file mode 100644 index cb5b2758e..000000000 --- a/fun/paroxysm/docker/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ depot, pkgs, ... }: - -pkgs.dockerTools.buildLayeredImage { - name = "paroxysm"; - contents = [ depot.fun.paroxysm ]; - config.Entrypoint = [ "${depot.fun.paroxysm}/bin/paroxysm" ]; -} diff --git a/fun/paroxysm/migrations/20181209140247_initial/down.sql b/fun/paroxysm/migrations/20181209140247_initial/down.sql deleted file mode 100644 index aa02f4f63..000000000 --- a/fun/paroxysm/migrations/20181209140247_initial/down.sql +++ /dev/null @@ -1,2 +0,0 @@ -DROP TABLE entries; -DROP TABLE keywords; diff --git a/fun/paroxysm/migrations/20181209140247_initial/up.sql b/fun/paroxysm/migrations/20181209140247_initial/up.sql deleted file mode 100644 index e8b52d5a9..000000000 --- a/fun/paroxysm/migrations/20181209140247_initial/up.sql +++ /dev/null @@ -1,15 +0,0 @@ -CREATE TABLE keywords ( - id SERIAL PRIMARY KEY, - name VARCHAR UNIQUE NOT NULL, - chan VARCHAR NOT NULL, - UNIQUE(name, chan) -); - -CREATE TABLE entries ( - id SERIAL PRIMARY KEY, - keyword_id INT NOT NULL REFERENCES keywords ON DELETE CASCADE, - idx INT NOT NULL, - text VARCHAR NOT NULL, - creation_ts TIMESTAMP NOT NULL, - created_by VARCHAR NOT NULL -); diff --git a/fun/paroxysm/migrations/20181218142013_fix_unique/down.sql b/fun/paroxysm/migrations/20181218142013_fix_unique/down.sql deleted file mode 100644 index 291a97c5c..000000000 --- a/fun/paroxysm/migrations/20181218142013_fix_unique/down.sql +++ /dev/null @@ -1 +0,0 @@ --- This file should undo anything in `up.sql` \ No newline at end of file diff --git a/fun/paroxysm/migrations/20181218142013_fix_unique/up.sql b/fun/paroxysm/migrations/20181218142013_fix_unique/up.sql deleted file mode 100644 index 4885ae5ed..000000000 --- a/fun/paroxysm/migrations/20181218142013_fix_unique/up.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE keywords DROP CONSTRAINT IF EXISTS keywords_name_key; diff --git a/fun/paroxysm/src/cfg.rs b/fun/paroxysm/src/cfg.rs deleted file mode 100644 index cfb2e2073..000000000 --- a/fun/paroxysm/src/cfg.rs +++ /dev/null @@ -1,12 +0,0 @@ -use serde::Deserialize; -use std::collections::HashSet; - -#[derive(Deserialize)] -pub struct Config { - pub database_url: String, - pub irc_config_path: String, - #[serde(default)] - pub admins: HashSet, - #[serde(default)] - pub log_filter: Option, -} diff --git a/fun/paroxysm/src/keyword.rs b/fun/paroxysm/src/keyword.rs deleted file mode 100644 index fa40f5347..000000000 --- a/fun/paroxysm/src/keyword.rs +++ /dev/null @@ -1,219 +0,0 @@ -use crate::models::{Entry, Keyword, NewEntry, NewKeyword}; -use diesel::pg::PgConnection; -use diesel::prelude::*; -use failure::{format_err, Error}; -use std::borrow::Cow; - -/// Maximum number of times we'll follow a `see: ` pointer. -const RECURSION_LIMIT: usize = 5; - -pub struct KeywordDetails { - pub keyword: Keyword, - pub entries: Vec, -} - -impl KeywordDetails { - pub fn learn(&mut self, nick: &str, text: &str, dbc: &PgConnection) -> Result { - let now = ::chrono::Utc::now().naive_utc(); - let ins = NewEntry { - keyword_id: self.keyword.id, - idx: (self.entries.len() + 1) as _, - text, - creation_ts: now, - created_by: nick, - }; - let new = { - use crate::schema::entries; - ::diesel::insert_into(entries::table) - .values(ins) - .get_result(dbc)? - }; - self.entries.push(new); - Ok(self.entries.len()) - } - - pub fn process_moves(&mut self, moves: &[(i32, i32)], dbc: &PgConnection) -> Result<(), Error> { - for (oid, new_idx) in moves { - { - use crate::schema::entries::dsl::*; - ::diesel::update(entries.filter(id.eq(oid))) - .set(idx.eq(new_idx)) - .execute(dbc)?; - } - } - self.entries = Self::get_entries(self.keyword.id, dbc)?; - Ok(()) - } - - pub fn swap(&mut self, idx_a: usize, idx_b: usize, dbc: &PgConnection) -> Result<(), Error> { - let mut moves = vec![]; - for ent in self.entries.iter() { - if ent.idx == idx_a as i32 { - moves.push((ent.id, idx_b as i32)); - } - if ent.idx == idx_b as i32 { - moves.push((ent.id, idx_a as i32)); - } - } - if moves.len() != 2 { - Err(format_err!("Invalid swap operation."))?; - } - self.process_moves(&moves, dbc)?; - Ok(()) - } - - pub fn update(&mut self, idx: usize, val: &str, dbc: &PgConnection) -> Result<(), Error> { - let ent = self - .entries - .get_mut(idx.saturating_sub(1)) - .ok_or(format_err!("No such element to update."))?; - { - use crate::schema::entries::dsl::*; - ::diesel::update(entries.filter(id.eq(ent.id))) - .set(text.eq(val)) - .execute(dbc)?; - } - ent.text = val.to_string(); - Ok(()) - } - - pub fn delete(&mut self, idx: usize, dbc: &PgConnection) -> Result<(), Error> { - // step 1: delete the element - { - let ent = self - .entries - .get(idx.saturating_sub(1)) - .ok_or(format_err!("No such element to delete."))?; - { - use crate::schema::entries::dsl::*; - ::diesel::delete(entries.filter(id.eq(ent.id))).execute(dbc)?; - } - } - // step 2: move all the elements in front of it back one - let mut moves = vec![]; - for ent in self.entries.iter() { - if idx > ent.idx as _ { - moves.push((ent.id, ent.idx.saturating_sub(1))); - } - } - self.process_moves(&moves, dbc)?; - Ok(()) - } - - pub fn add_zwsp_to_name(name: &str) -> Option { - let second_index = name.char_indices().nth(1).map(|(i, _)| i)?; - let (start, end) = name.split_at(second_index); - Some(format!("{}​{}", start, end)) - } - - pub fn format_entry(&self, idx: usize) -> Option { - self.format_entry_colours(idx, true) - } - - pub fn format_entry_colours(&self, idx: usize, with_colours: bool) -> Option { - if let Some(ent) = self.entries.get(idx.saturating_sub(1)) { - let gen_clr = if self.keyword.chan == "*" && with_colours { - "\x0307" - } else { - "" - }; - let zwsp_name = Self::add_zwsp_to_name(&self.keyword.name) - .unwrap_or_else(|| self.keyword.name.clone()); - Some(format!( - "{}{}{name}{}[{idx}/{total}]{}: {text} {}[{date}]{}", - if with_colours { "\x02" } else { "" }, - gen_clr, - if with_colours { "\x0f\x0315" } else { "" }, - if with_colours { "\x0f" } else { "" }, - if with_colours { "\x0f\x0314" } else { "" }, - if with_colours { "\x0f" } else { "" }, - name = zwsp_name, - idx = idx, - total = self.entries.len(), - text = ent.text, - date = ent.creation_ts.date() - )) - } else { - None - } - } - - pub fn get_or_create(word: &str, c: &str, dbc: &PgConnection) -> Result { - if let Some(ret) = Self::get(word, c, dbc)? { - Ok(ret) - } else { - Ok(Self::create(word, c, dbc)?) - } - } - - pub fn create(word: &str, c: &str, dbc: &PgConnection) -> Result { - let val = NewKeyword { - name: word, - chan: c, - }; - let ret: Keyword = { - use crate::schema::keywords; - ::diesel::insert_into(keywords::table) - .values(val) - .get_result(dbc)? - }; - Ok(KeywordDetails { - keyword: ret, - entries: vec![], - }) - } - - fn get_entries(kid: i32, dbc: &PgConnection) -> Result, Error> { - let entries: Vec = { - use crate::schema::entries::dsl::*; - entries - .filter(keyword_id.eq(kid)) - .order_by(idx.asc()) - .load(dbc)? - }; - Ok(entries) - } - - fn get_inner<'a, T: Into>>( - word: T, - c: &str, - dbc: &PgConnection, - recursion_count: usize, - ) -> Result, Error> { - let word = word.into(); - let keyword: Option = { - use crate::schema::keywords::dsl::*; - keywords - .filter(name.ilike(word).and(chan.eq(c).or(chan.eq("*")))) - .first(dbc) - .optional()? - }; - if let Some(k) = keyword { - let entries = Self::get_entries(k.id, dbc)?; - if let Some(e0) = entries.get(0) { - if e0.text.starts_with("see: ") { - if recursion_count > RECURSION_LIMIT { - // Oh dear. - Err(format_err!("Halt. You're having a bit too much fun."))? - } - let new_word = e0.text.replace("see: ", ""); - return Self::get_inner(new_word, c, dbc, recursion_count + 1); - } - } - Ok(Some(KeywordDetails { - keyword: k, - entries, - })) - } else { - Ok(None) - } - } - - pub fn get<'a, T: Into>>( - word: T, - c: &str, - dbc: &PgConnection, - ) -> Result, Error> { - Self::get_inner(word, c, dbc, 0) - } -} diff --git a/fun/paroxysm/src/main.rs b/fun/paroxysm/src/main.rs deleted file mode 100644 index 46a215c22..000000000 --- a/fun/paroxysm/src/main.rs +++ /dev/null @@ -1,395 +0,0 @@ -// TODO(tazjin): Upgrade to a Diesel version with public derive -// macros. -#[macro_use] -extern crate diesel; - -use crate::cfg::Config; -use crate::keyword::KeywordDetails; -use diesel::pg::PgConnection; -use diesel::r2d2::{ConnectionManager, Pool}; -use failure::{format_err, Error}; -use irc::client::prelude::*; -use lazy_static::lazy_static; -use log::{debug, info, warn}; -use rand::rngs::ThreadRng; -use rand::{thread_rng, Rng}; -use regex::{Captures, Regex}; -use std::collections::HashMap; -use std::fmt::Display; - -mod cfg; -mod keyword; -mod models; -mod schema; - -lazy_static! { - static ref LEARN_RE: Regex = - Regex::new(r#"^\?\?(?P!)?\s*(?P[^\[:]*):\s*(?P.*)"#).unwrap(); - static ref QUERY_RE: Regex = - Regex::new(r#"^\?\?\s*(?P[^\[:]*)(?P\[[^\]]+\])?"#).unwrap(); - static ref QLAST_RE: Regex = Regex::new(r#"^\?\?\s*(?P[^\[:]*)!"#).unwrap(); - static ref INCREMENT_RE: Regex = - Regex::new(r#"^\?\?(?P!)?\s*(?P[^\[:]*)(?P\+\+|\-\-)"#).unwrap(); - static ref MOVE_RE: Regex = - Regex::new(r#"^\?\?(?P!)?\s*(?P[^\[:]*)(?P\[[^\]]+\])->(?P.*)"#) - .unwrap(); -} - -pub struct App { - client: IrcClient, - pg: Pool>, - rng: ThreadRng, - cfg: Config, - last_msgs: HashMap>, -} - -impl App { - pub fn report_error( - &mut self, - nick: &str, - chan: &str, - msg: T, - ) -> Result<(), Error> { - self.client - .send_notice(nick, format!("[{}] \x0304Error:\x0f {}", chan, msg))?; - Ok(()) - } - - pub fn keyword_from_captures( - &mut self, - learn: &::regex::Captures, - nick: &str, - chan: &str, - ) -> Result { - let db = self.pg.get()?; - debug!("Fetching keyword for captures: {:?}", learn); - let subj = &learn["subj"]; - let learn_chan = if learn.name("gen").is_some() { - "*" - } else { - chan - }; - if !chan.starts_with("#") && learn_chan != "*" { - Err(format_err!("Only general entries may be taught via PM."))?; - } - debug!("Fetching keyword '{}' for chan {}", subj, learn_chan); - let kwd = KeywordDetails::get_or_create(subj, learn_chan, &db)?; - if kwd.keyword.chan == "*" && !self.cfg.admins.contains(nick) { - Err(format_err!( - "Only administrators can create or modify general entries." - ))?; - } - Ok(kwd) - } - - pub fn handle_move( - &mut self, - target: &str, - nick: &str, - chan: &str, - mv: Captures, - ) -> Result<(), Error> { - let db = self.pg.get()?; - let idx = &mv["idx"]; - let idx = match idx[1..(idx.len() - 1)].parse::() { - Ok(i) => i, - Err(e) => Err(format_err!("Could not parse index: {}", e))?, - }; - let new_idx = match mv["new_idx"].parse::() { - Ok(i) => i, - Err(e) => Err(format_err!("Could not parse target index: {}", e))?, - }; - let mut kwd = self.keyword_from_captures(&mv, nick, chan)?; - if new_idx < 0 { - kwd.delete(idx, &db)?; - self.client.send_notice( - target, - format!("\x02{}\x0f: Deleted entry {}.", kwd.keyword.name, idx), - )?; - } else { - kwd.swap(idx, new_idx as _, &db)?; - self.client.send_notice( - target, - format!( - "\x02{}\x0f: Swapped entries {} and {}.", - kwd.keyword.name, idx, new_idx - ), - )?; - } - Ok(()) - } - - pub fn handle_learn( - &mut self, - target: &str, - nick: &str, - chan: &str, - learn: Captures, - ) -> Result<(), Error> { - let db = self.pg.get()?; - let val = &learn["val"]; - let mut kwd = self.keyword_from_captures(&learn, nick, chan)?; - let idx = kwd.learn(nick, val, &db)?; - self.client - .send_notice(target, kwd.format_entry(idx).unwrap())?; - Ok(()) - } - - pub fn handle_insert_last_quote( - &mut self, - target: &str, - nick: &str, - chan: &str, - qlast: Captures, - ) -> Result<(), Error> { - let db = self.pg.get()?; - let nick_to_grab = &qlast["subj"].to_ascii_lowercase(); - let mut kwd = self.keyword_from_captures(&qlast, nick, chan)?; - let chan_lastmsgs = self - .last_msgs - .entry(chan.to_string()) - .or_insert(HashMap::new()); - // Use `nick` here, so things like "grfn: see glittershark" work. - let val = if let Some(last) = chan_lastmsgs.get(nick_to_grab) { - if last.starts_with("\x01ACTION ") { - // Yes, this is inefficient, but it's better than writing some hacky CTCP parsing - // code I guess (also, characters are hard, so just blindly slicing - // seems like a bad idea) - format!( - "* {} {}", - nick_to_grab, - last.replace("\x01ACTION ", "").replace("\x01", "") - ) - } else { - format!("<{}> {}", nick_to_grab, last) - } - } else { - Err(format_err!("I dunno what {} said...", kwd.keyword.name))? - }; - let idx = kwd.learn(nick, &val, &db)?; - self.client - .send_notice(target, kwd.format_entry(idx).unwrap())?; - Ok(()) - } - - pub fn handle_increment( - &mut self, - target: &str, - nick: &str, - chan: &str, - icr: Captures, - ) -> Result<(), Error> { - let db = self.pg.get()?; - let mut kwd = self.keyword_from_captures(&icr, nick, chan)?; - let is_incr = &icr["incrdecr"] == "++"; - let now = chrono::Utc::now().naive_utc().date(); - let mut idx = None; - for (i, ent) in kwd.entries.iter().enumerate() { - if ent.creation_ts.date() == now { - if let Ok(val) = ent.text.parse::() { - let val = if is_incr { val + 1 } else { val - 1 }; - idx = Some((i + 1, val)); - } - } - } - if let Some((i, val)) = idx { - kwd.update(i, &val.to_string(), &db)?; - self.client - .send_notice(target, kwd.format_entry(i).unwrap())?; - } else { - let val = if is_incr { 1 } else { -1 }; - let idx = kwd.learn(nick, &val.to_string(), &db)?; - self.client - .send_notice(target, kwd.format_entry(idx).unwrap())?; - } - Ok(()) - } - - pub fn handle_query( - &mut self, - target: &str, - _nick: &str, - chan: &str, - query: Captures, - ) -> Result<(), Error> { - let db = self.pg.get()?; - let subj = &query["subj"]; - let idx = match query.name("idx") { - Some(i) => { - let i = i.as_str(); - match &i[1..(i.len() - 1)] { - "*" => Some(-1), - x => x.parse::().map(|x| x as i32).ok(), - } - } - None => None, - }; - debug!("Querying {} with idx {:?}", subj, idx); - match KeywordDetails::get(subj, chan, &db)? { - Some(kwd) => { - if let Some(mut idx) = idx { - if idx == -1 { - // 'get all entries' ('*' parses into this) - // step 1: make a blob of all the quotes - let mut data_to_upload = String::new(); - for i in 0..kwd.entries.len() { - data_to_upload - .push_str(&kwd.format_entry_colours(i + 1, false).unwrap()); - data_to_upload.push('\n'); - } - // step 2: attempt to POST it to eta's pastebin - // TODO(eta): make configurable - let response = crimp::Request::put("https://eta.st/lx/upload") - .user_agent("paroxysm/0.0.2 crimp/0.2")? - .header("Linx-Expiry", "7200")? // 2 hours - .body("text/plain", data_to_upload.as_bytes()) - .timeout(std::time::Duration::from_secs(2))? - .send()? - .as_string()?; - // step 3: tell the world about it - if response.status != 200 { - Err(format_err!( - "upload returned {}: {}", - response.status, - response.body - ))? - } - self.client.send_notice( - target, - format!( - "\x02{}\x0f: uploaded {} quotes to \x02\x0311{}\x0f (will expire in \x0224\x0f hours)", - subj, - kwd.entries.len(), - response.body - ) - )?; - } else { - if idx == 0 { - idx = 1; - } - if let Some(ent) = kwd.format_entry(idx as _) { - self.client.send_notice(target, ent)?; - } else { - let pluralised = if kwd.entries.len() == 1 { - "entry" - } else { - "entries" - }; - self.client.send_notice( - target, - format!( - "\x02{}\x0f: only has \x02\x0304{}\x0f {}", - subj, - kwd.entries.len(), - pluralised - ), - )?; - } - } - } else { - let entry = if kwd.entries.len() < 2 { - 1 // because [1, 1) does not a range make - } else { - self.rng.gen_range(1, kwd.entries.len()) - }; - if let Some(ent) = kwd.format_entry(entry) { - self.client.send_notice(target, ent)?; - } else { - self.client - .send_notice(target, format!("\x02{}\x0f: no entries yet", subj))?; - } - } - } - None => { - // If someone just posts "??????????", don't spam the channel with - // an error message (but do allow joke entries to appear if set). - if !subj.chars().all(|c| c == '?' || c == ' ') { - self.client - .send_notice(target, format!("\x02{}\x0f: never heard of it", subj))?; - } - } - } - Ok(()) - } - - pub fn handle_privmsg(&mut self, from: &str, chan: &str, msg: &str) -> Result<(), Error> { - let nick = from.split("!").next().ok_or(format_err!( - "Received PRIVMSG from a source without nickname (failed to split n!u@h)" - ))?; - let target = if chan.starts_with("#") { chan } else { nick }; - debug!("[{}] <{}> {}", chan, nick, msg); - if let Some(learn) = LEARN_RE.captures(msg) { - self.handle_learn(target, nick, chan, learn)?; - } else if let Some(qlast) = QLAST_RE.captures(msg) { - self.handle_insert_last_quote(target, nick, chan, qlast)?; - } else if let Some(mv) = MOVE_RE.captures(msg) { - self.handle_move(target, nick, chan, mv)?; - } else if let Some(icr) = INCREMENT_RE.captures(msg) { - self.handle_increment(target, nick, chan, icr)?; - } else if let Some(query) = QUERY_RE.captures(msg) { - self.handle_query(target, nick, chan, query)?; - } else { - let chan_lastmsgs = self - .last_msgs - .entry(chan.to_string()) - .or_insert(HashMap::new()); - chan_lastmsgs.insert(nick.to_string().to_ascii_lowercase(), msg.to_string()); - } - Ok(()) - } - - pub fn handle_msg(&mut self, m: Message) -> Result<(), Error> { - match m.command { - Command::PRIVMSG(channel, message) => { - if let Some(src) = m.prefix { - if let Err(e) = self.handle_privmsg(&src, &channel, &message) { - warn!("error handling command in {} (src {}): {}", channel, src, e); - if let Some(nick) = src.split("!").next() { - self.report_error(nick, &channel, e)?; - } - } - } - } - Command::INVITE(nick, channel) => { - if self.cfg.admins.contains(&nick) { - info!("Joining {} after admin invite", channel); - self.client.send_join(channel)?; - } - } - _ => {} - } - Ok(()) - } -} - -fn main() -> Result<(), Error> { - println!("[+] loading configuration"); - let default_log_filter = "paroxysm=info".to_string(); - let mut settings = config::Config::default(); - settings.merge(config::Environment::with_prefix("PARX"))?; - let cfg: Config = settings.try_into()?; - let env = env_logger::Env::new() - .default_filter_or(cfg.log_filter.clone().unwrap_or(default_log_filter)); - env_logger::init_from_env(env); - info!("paroxysm starting up"); - info!("connecting to database at {}", cfg.database_url); - let pg = Pool::new(ConnectionManager::new(&cfg.database_url))?; - info!("connecting to IRC using config {}", cfg.irc_config_path); - let client = IrcClient::new(&cfg.irc_config_path)?; - client.identify()?; - let st = client.stream(); - let mut app = App { - client, - pg, - cfg, - rng: thread_rng(), - last_msgs: HashMap::new(), - }; - info!("running!"); - st.for_each_incoming(|m| { - if let Err(e) = app.handle_msg(m) { - warn!("Error processing message: {}", e); - } - })?; - Ok(()) -} diff --git a/fun/paroxysm/src/models.rs b/fun/paroxysm/src/models.rs deleted file mode 100644 index 721efbbb2..000000000 --- a/fun/paroxysm/src/models.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::schema::{entries, keywords}; -use chrono::NaiveDateTime; - -#[derive(Queryable)] -pub struct Keyword { - pub id: i32, - pub name: String, - pub chan: String, -} - -#[derive(Queryable)] -pub struct Entry { - pub id: i32, - pub keyword_id: i32, - pub idx: i32, - pub text: String, - pub creation_ts: NaiveDateTime, - pub created_by: String, -} - -#[derive(Insertable)] -#[table_name = "keywords"] -pub struct NewKeyword<'a> { - pub name: &'a str, - pub chan: &'a str, -} - -#[derive(Insertable)] -#[table_name = "entries"] -pub struct NewEntry<'a> { - pub keyword_id: i32, - pub idx: i32, - pub text: &'a str, - pub creation_ts: NaiveDateTime, - pub created_by: &'a str, -} diff --git a/fun/paroxysm/src/schema.rs b/fun/paroxysm/src/schema.rs deleted file mode 100644 index ef4044531..000000000 --- a/fun/paroxysm/src/schema.rs +++ /dev/null @@ -1,18 +0,0 @@ -table! { - entries (id) { - id -> Int4, - keyword_id -> Int4, - idx -> Int4, - text -> Varchar, - creation_ts -> Timestamp, - created_by -> Varchar, - } -} - -table! { - keywords (id) { - id -> Int4, - name -> Varchar, - chan -> Varchar, - } -} diff --git a/fun/quinistry/.gitignore b/fun/quinistry/.gitignore deleted file mode 100644 index 622119552..000000000 --- a/fun/quinistry/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.idea/ -quinistry \ No newline at end of file diff --git a/fun/quinistry/README.md b/fun/quinistry/README.md deleted file mode 100644 index de197a219..000000000 --- a/fun/quinistry/README.md +++ /dev/null @@ -1,63 +0,0 @@ -Quinistry -========= - -*A simple Docker registry quine.* - -## What? - -This is an example project for a from-scratch implementation of an HTTP server compatible with the [Docker Registry V2][] -protocol. - -It serves a single image called `quinistry:latest` which is a Docker image that runs quinistry itself, therefore it is a -sort of Docker registry [quine][]. - -The official documentation does not contain enough information to actually implement this protocol (which I assume is -intentional), but a bit of trial&error lead there anyways. I've added comments to parts of the code to clear up things -that may be helpful to other developers in the future. - -## Example - -``` -# Run quinistry: -vincent@urdhva ~/go/src/github.com/tazjin/quinistry (git)-[master] % ./quinistry -2017/03/16 14:11:56 Starting quinistry - -# Pull the quinistry image from itself: -vincent@urdhva ~ % docker pull localhost:8080/quinistry -Using default tag: latest -latest: Pulling from quinistry -7bf1a8b18466: Already exists -Digest: sha256:d5cd4490901ef04b4e28e4ccc03a1d25fe3461200cf4d7166aab86fcd495e22e -Status: Downloaded newer image for localhost:8080/quinistry:latest - -# Quinistry will log: -2017/03/16 14:14:03 Acknowleding V2 API: GET /v2/ -2017/03/16 14:14:03 Serving manifest: GET /v2/quinistry/manifests/latest -2017/03/16 14:14:03 Serving config: GET /v2/quinistry/blobs/sha256:fbb165c48849de16017aa398aa9bb08fd1c00eaa7c150b6c2af37312913db279 - -# Run the downloaded image: -vincent@urdhva ~ % docker run -p 8090:8080 localhost:8080/quinistry -2017/03/16 13:15:18 Starting quinistry - -# And download it again from itself: -vincent@urdhva ~ % docker pull localhost:8090/quinistry -Using default tag: latest -latest: Pulling from quinistry -7bf1a8b18466: Already exists -Digest: sha256:11141d95ddce0bac9ffa32ab1e8bc94748ed923e87762c68858dc41d11a46d3f -Status: Downloaded newer image for localhost:8090/quinistry:latest -``` - -## Building - -Quinistry creates a Docker image that only contains a statically linked `main` binary. As this package makes use of -`net/http`, Go will (by default) link against `libc` for DNS resolution and create a dynamic binary instead. - -To disable this, `build` the project with `-tags netgo`: - -``` -go build -tags netgo -``` - -[Docker Registry V2]: https://docs.docker.com/registry/spec/api/ -[quine]: https://en.wikipedia.org/wiki/Quine_(computing) \ No newline at end of file diff --git a/fun/quinistry/const.go b/fun/quinistry/const.go deleted file mode 100644 index 173fa9efc..000000000 --- a/fun/quinistry/const.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -// HTTP content types - -const ImageConfigMediaType string = "application/vnd.docker.container.image.v1+json" -const ManifestMediaType string = "application/vnd.docker.distribution.manifest.v2+json" -const LayerMediaType string = "application/vnd.docker.image.rootfs.diff.tar.gzip" - -// HTTP header names - -const ContentType string = "Content-Type" -const DigestHeader string = "Docker-Content-Digest" diff --git a/fun/quinistry/default.nix b/fun/quinistry/default.nix deleted file mode 100644 index b12c5e6f0..000000000 --- a/fun/quinistry/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ depot, ... }: - -depot.nix.buildGo.program { - name = "quinistry"; - srcs = [ - ./const.go - ./image.go - ./main.go - ./types.go - ]; -} diff --git a/fun/quinistry/image.go b/fun/quinistry/image.go deleted file mode 100644 index 3daeac34d..000000000 --- a/fun/quinistry/image.go +++ /dev/null @@ -1,150 +0,0 @@ -// The code in this file creates a Docker image layer containing the binary of the -// application itself. - -package main - -import ( - "archive/tar" - "bytes" - "compress/gzip" - "crypto/sha256" - "encoding/json" - "fmt" - "io/ioutil" - "log" - "os" - "time" -) - -// This function creates a Docker-image digest (i.e. SHA256 hash with -// algorithm-specification prefix) -func Digest(b []byte) string { - hash := sha256.New() - hash.Write(b) - - return fmt.Sprintf("sha256:%x", hash.Sum(nil)) -} - -func GetImageOfCurrentExecutable() Image { - binary := getCurrentBinary() - tarArchive := createTarArchive(&map[string][]byte{ - "/main": binary, - }) - - configJson, configElem := createConfig([]string{Digest(tarArchive)}) - compressed := gzipArchive("Quinistry image", tarArchive) - manifest := createManifest(&configElem, &compressed) - manifestJson, _ := json.Marshal(manifest) - - return Image{ - Layer: compressed, - LayerDigest: Digest(compressed), - Manifest: manifestJson, - ManifestDigest: Digest(manifestJson), - Config: configJson, - ConfigDigest: Digest(configJson), - } - -} - -func getCurrentBinary() []byte { - path, _ := os.Executable() - file, _ := ioutil.ReadFile(path) - return file -} - -func createTarArchive(files *map[string][]byte) []byte { - buf := new(bytes.Buffer) - w := tar.NewWriter(buf) - - for name, file := range *files { - hdr := &tar.Header{ - Name: name, - // Everything is executable \o/ - Mode: 0755, - Size: int64(len(file)), - } - w.WriteHeader(hdr) - w.Write(file) - } - - if err := w.Close(); err != nil { - log.Fatalln(err) - os.Exit(1) - } - - return buf.Bytes() -} - -func gzipArchive(name string, archive []byte) []byte { - buf := new(bytes.Buffer) - w := gzip.NewWriter(buf) - w.Name = name - w.Write(archive) - - if err := w.Close(); err != nil { - log.Fatalln(err) - os.Exit(1) - } - - return buf.Bytes() -} - -func createConfig(layerDigests []string) (configJson []byte, elem Element) { - now := time.Now() - - imageConfig := &ImageConfig{ - Cmd: []string{"/main"}, - Env: []string{"PATH=/"}, - } - - rootFs := RootFs{ - DiffIds: layerDigests, - Type: "layers", - } - - history := []History{ - { - Created: now, - CreatedBy: "Quinistry magic", - }, - } - - config := Config{ - Created: now, - Author: "tazjin", - Architecture: "amd64", - Os: "linux", - Config: imageConfig, - RootFs: rootFs, - History: history, - } - - configJson, _ = json.Marshal(config) - - elem = Element{ - MediaType: ImageConfigMediaType, - Size: len(configJson), - Digest: Digest(configJson), - } - - return -} - -func createManifest(config *Element, layer *[]byte) Manifest { - layers := []Element{ - { - MediaType: LayerMediaType, - Size: len(*layer), - // Layers must contain the digest of the *gzipped* layer. - Digest: Digest(*layer), - }, - } - - return Manifest{ - SchemaVersion: 2, - MediaType: ManifestMediaType, - Config: *config, - Layers: layers, - } -} diff --git a/fun/quinistry/k8s/child.yaml b/fun/quinistry/k8s/child.yaml deleted file mode 100644 index aa2e31826..000000000 --- a/fun/quinistry/k8s/child.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# This is a child quinistry, running via an image served off the parent. ---- -apiVersion: extensions/v1beta1 -kind: DaemonSet -metadata: - name: quinistry-gen2 - labels: - k8s-app: quinistry - quinistry/role: child - quinistry/generation: '2' -spec: - template: - metadata: - labels: - k8s-app: quinistry - quinistry/role: child - quinistry/generation: '2' - spec: - containers: - - name: quinistry - # Bootstrap via Docker Hub (or any other registry) - image: localhost:5000/quinistry - ports: - - name: registry - containerPort: 8080 - # Incremented hostPort, - hostPort: 5001 diff --git a/fun/quinistry/k8s/parent.yaml b/fun/quinistry/k8s/parent.yaml deleted file mode 100644 index 0db2fe300..000000000 --- a/fun/quinistry/k8s/parent.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# This is a bootstrapped Quinistry DaemonSet. The initial image -# comes from Docker Hub ---- -apiVersion: extensions/v1beta1 -kind: DaemonSet -metadata: - name: quinistry - labels: - k8s-app: quinistry - quinistry/role: parent - quinistry/generation: '1' -spec: - template: - metadata: - labels: - k8s-app: quinistry - quinistry/role: parent - quinistry/generation: '1' - spec: - containers: - - name: quinistry - # Bootstrap via Docker Hub (or any other registry) - image: tazjin/quinistry - ports: - - name: registry - containerPort: 8080 - hostPort: 5000 diff --git a/fun/quinistry/main.go b/fun/quinistry/main.go deleted file mode 100644 index 50b47418d..000000000 --- a/fun/quinistry/main.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" -) - -func main() { - log.Println("Starting quinistry") - - image := GetImageOfCurrentExecutable() - - layerUri := fmt.Sprintf("/v2/quinistry/blobs/%s", image.LayerDigest) - configUri := fmt.Sprintf("/v2/quinistry/blobs/%s", image.ConfigDigest) - - log.Fatal(http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Acknowledge that we speak V2 - if r.RequestURI == "/v2/" { - logRequest("Acknowleding V2 API", r) - fmt.Fprintln(w) - return - } - - // Serve manifest - if r.RequestURI == "/v2/quinistry/manifests/latest" { - logRequest("Serving manifest", r) - w.Header().Set(ContentType, ManifestMediaType) - w.Header().Add(DigestHeader, image.ManifestDigest) - w.Write(image.Manifest) - return - } - - // Serve actual image layer - if r.RequestURI == layerUri { - logRequest("Serving image layer blob", r) - w.Header().Add(DigestHeader, image.LayerDigest) - w.Write(image.Layer) - return - } - - // Serve image config - if r.RequestURI == configUri { - logRequest("Serving config", r) - w.Header().Set("Content-Type", ImageConfigMediaType) - w.Header().Set(DigestHeader, image.ConfigDigest) - w.Write(image.Config) - return - } - - log.Printf("Unhandled request: %v\n", *r) - }))) -} - -func logRequest(msg string, r *http.Request) { - log.Printf("%s: %s %s\n", msg, r.Method, r.RequestURI) -} diff --git a/fun/quinistry/types.go b/fun/quinistry/types.go deleted file mode 100644 index 498cbac2f..000000000 --- a/fun/quinistry/types.go +++ /dev/null @@ -1,79 +0,0 @@ -package main - -import "time" - -// This type represents the rootfs-key of the Docker image config. -// It specifies the digest (i.e. usually SHA256 hash) of the tar'ed, but NOT -// compressed image layers. -type RootFs struct { - // The digests of the non-compressed FS layers. - DiffIds []string `json:"diff_ids"` - - // Type should always be set to "layers" - Type string `json:"type"` -} - -// This type represents an entry in the Docker image config's history key. -// Every history element "belongs" to a filesystem layer. -type History struct { - Created time.Time `json:"created"` - CreatedBy string `json:"created_by"` -} - -// This type represents runtime-configuration for the Docker image. -// A lot of possible keys are omitted here, see: -// https://github.com/docker/docker/blob/master/image/spec/v1.2.md#image-json-description -type ImageConfig struct { - Cmd []string - Env []string -} - -// This type represents the Docker image configuration -type Config struct { - Created time.Time `json:"created"` - Author string `json:"author"` - - // Architecture should be "amd64" - Architecture string `json:"architecture"` - - // OS should be "linux" - Os string `json:"os"` - - // Configuration can be set to 'nil', in which case all options have to be - // supplied at container launch time. - Config *ImageConfig `json:"config"` - - // Filesystem layers and history elements have to be in the same order. - RootFs RootFs `json:"rootfs"` - History []History `json:"history"` -} - -// This type represents any manifest -type Element struct { - MediaType string `json:"mediaType"` - Size int `json:"size"` - Digest string `json:"digest"` -} - -// This type represents a Docker image manifest as used by the registry -// protocol V2. -type Manifest struct { - SchemaVersion int `json:"schemaVersion"` // Must be 2 - MediaType string `json:"mediaType"` // Use ManifestMediaType const - Config Element `json:"config"` - Layers []Element `json:"layers"` -} - -// A really "dumb" representation of an image, with its data blob and related -// metadata. -// Note: This is not a registry API type. -type Image struct { - Layer []byte - LayerDigest string - - Manifest []byte - ManifestDigest string - - Config []byte - ConfigDigest string -} diff --git a/fun/tvl-ebooks/OWNERS b/fun/tvl-ebooks/OWNERS deleted file mode 100644 index a58e6540a..000000000 --- a/fun/tvl-ebooks/OWNERS +++ /dev/null @@ -1 +0,0 @@ -ben diff --git a/fun/tvl-ebooks/default.nix b/fun/tvl-ebooks/default.nix deleted file mode 100644 index 68e61c252..000000000 --- a/fun/tvl-ebooks/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ pkgs, ... }: - -pkgs.buildGoModule { - name = "tvl-ebooks"; - vendorHash = "sha256:1p7bazh2vbhvvm559bcvfff9s4yy4q9jmklxr3sfp97inwpv6hzy"; - src = ./.; -} diff --git a/fun/tvl-ebooks/ebook-client/main.go b/fun/tvl-ebooks/ebook-client/main.go deleted file mode 100644 index 7954184dd..000000000 --- a/fun/tvl-ebooks/ebook-client/main.go +++ /dev/null @@ -1,170 +0,0 @@ -package main - -import ( - "crypto/tls" - "encoding/json" - "flag" - "fmt" - "log" - "net" - "sync" - "time" - - "github.com/go-redis/redis" - "gopkg.in/irc.v3" -) - -var messageBeat chan bool -var firstMessage chan bool -var client *irc.Client -var safeLock sync.Mutex - -func main() { - nick := flag.String("nick", "NONE", "the ircnick you want") - from := flag.String("ip", "[::1]", "src address") - flag.Parse() - - localAddrDialier := &net.Dialer{ - LocalAddr: &net.TCPAddr{ - IP: net.ParseIP(*from), - Port: 0, - }, - } - - conn, err := tls.DialWithDialer(localAddrDialier, "tcp", "chat.freenode.net:6697", &tls.Config{}) - if err != nil { - log.Fatalln(err) - } - - messageBeat = make(chan bool) - firstMessage = make(chan bool, 10) - go ircKeepalive() - - redisc := redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("127.0.0.1:%d", 6379), - Password: "", // no password set - DB: 0, // use default DB - }) - - go func() { - for { - time.Sleep(time.Second) - r := redisc.Ping() - if r.Err() != nil { - redisc = redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("127.0.0.1:%d", 6379), - Password: "", // no password set - DB: 0, // use default DB - }) - } - redisc.Set(fmt.Sprintf("alive-%s", *nick), "yes", time.Second*5) - } - }() - - if *nick == "NONE" { - log.Fatalf("You must set a nick") - } - - go func() { - <-firstMessage - for { - psub := redisc.Subscribe(fmt.Sprintf("irc-%s", *nick)) - - for { - msg, err := psub.ReceiveMessage() - if err != nil { - break - } - client.WriteMessage(&irc.Message{ - Command: "PRIVMSG", - Params: []string{ - "##tvl-ebooks", - msg.Payload, - }, - }) - } - time.Sleep(time.Second * 10) - } - - }() - - go func() { - <-firstMessage - for { - psub := redisc.Subscribe(fmt.Sprintf("raw-irc-%s", *nick)) - - for { - msg, err := psub.ReceiveMessage() - if err != nil { - break - } - im := irc.Message{} - err = json.Unmarshal([]byte(msg.Payload), &im) - if err == nil { - client.WriteMessage(&im) - } - } - time.Sleep(time.Second * 10) - } - - }() - - seenMsgBefore := false - config := irc.ClientConfig{ - Nick: *nick, - User: *nick, - Name: fmt.Sprintf("%s Ebooks", *nick), - Handler: irc.HandlerFunc(func(c *irc.Client, m *irc.Message) { - b, _ := json.Marshal(m) - log.Printf("%#v", string(b)) - - messageBeat <- true - - if !seenMsgBefore { - firstMessage <- true - seenMsgBefore = true - } - res := redisc.Publish("ebook", string(b)) - if res.Err() != nil { - log.Printf("Publish error! %#v", err) - } - if m.Command == "001" { - // 001 is a welcome event, so we join channels there - c.Write("JOIN ##tvl-ebooks") - } - // else if m.Command == "PRIVMSG" && c.FromChannel(m) { - // // // Create a handler on all messages. - // // c.WriteMessage(&irc.Message{ - // // Command: "PRIVMSG", - // // Params: []string{ - // // m.Params[0], - // // m.Trailing(), - // // }, - // // }) - // } - }), - } - - // Create the client - client = irc.NewClient(conn, config) - err = client.Run() - if err != nil { - log.Fatalln(err) - } -} - -func ircKeepalive() { - tt := time.NewTimer(time.Second) - lastPing := time.Now() - for { - select { - case <-tt.C: - if time.Since(lastPing) > time.Minute*5 { - log.Fatalf("It's been too long since the last IRC message, blowing up") - } - break - case <-messageBeat: - lastPing = time.Now() - } - } -} diff --git a/fun/tvl-ebooks/go.mod b/fun/tvl-ebooks/go.mod deleted file mode 100644 index 154fbf821..000000000 --- a/fun/tvl-ebooks/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/benjojo/tvl-ebooks - -go 1.14 - -require ( - github.com/go-redis/redis v6.15.9+incompatible - gopkg.in/irc.v3 v3.1.3 -) diff --git a/fun/tvl-ebooks/go.sum b/fun/tvl-ebooks/go.sum deleted file mode 100644 index bd3ff8761..000000000 --- a/fun/tvl-ebooks/go.sum +++ /dev/null @@ -1,11 +0,0 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= -github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/irc.v3 v3.1.3 h1:yeTiJ365882L8h4AnBKYfesD92y5R5ZhGiylu9DfcPY= -gopkg.in/irc.v3 v3.1.3/go.mod h1:shO2gz8+PVeS+4E6GAny88Z0YVVQSxQghdrMVGQsR9s= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/fun/tvl-ebooks/irc-ingest/main.go b/fun/tvl-ebooks/irc-ingest/main.go deleted file mode 100644 index bbd607405..000000000 --- a/fun/tvl-ebooks/irc-ingest/main.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "crypto/tls" - "encoding/json" - "fmt" - "log" - "os" - "time" - - "github.com/go-redis/redis" - "gopkg.in/irc.v3" -) - -var messageBeat chan bool - -func main() { - conn, err := tls.Dial("tcp", "bnc.irccloud.com:6697", nil) - if err != nil { - log.Fatalln(err) - } - - messageBeat = make(chan bool) - go ircKeepalive() - - redisc := redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("127.0.0.1:%d", 6379), - Password: "", // no password set - DB: 0, // use default DB - }) - - go func() { - for { - time.Sleep(time.Second) - r := redisc.Ping() - if r.Err() != nil { - redisc = redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("127.0.0.1:%d", 6379), - Password: "", // no password set - DB: 0, // use default DB - }) - } - } - }() - - config := irc.ClientConfig{ - Nick: "Benjojo", - Pass: os.Getenv("IRCCLOUD"), - User: "Benjojo", - Name: "Ben Cox", - Handler: irc.HandlerFunc(func(c *irc.Client, m *irc.Message) { - b, _ := json.Marshal(m) - // log.Printf("%#v", string(b)) - - messageBeat <- true - res := redisc.Publish("irccloud", string(b)) - if res.Err() != nil { - log.Printf("Publish error! %#v", err) - } - // if m.Command == "001" { - // // 001 is a welcome event, so we join channels there - // // c.Write("JOIN #bot-test-chan") - // } else if m.Command == "PRIVMSG" && c.FromChannel(m) { - // // // Create a handler on all messages. - // // c.WriteMessage(&irc.Message{ - // // Command: "PRIVMSG", - // // Params: []string{ - // // m.Params[0], - // // m.Trailing(), - // // }, - // // }) - // } - }), - } - - // Create the client - client := irc.NewClient(conn, config) - err = client.Run() - if err != nil { - log.Fatalln(err) - } -} - -func ircKeepalive() { - tt := time.NewTimer(time.Second) - lastPing := time.Now() - for { - select { - case <-tt.C: - if time.Since(lastPing) > time.Minute*5 { - log.Fatalf("It's been too long since the last IRC message, blowing up") - } - break - case <-messageBeat: - lastPing = time.Now() - } - } - -} diff --git a/fun/tvl-ebooks/make-v6/main.go b/fun/tvl-ebooks/make-v6/main.go deleted file mode 100644 index 6d4d0047b..000000000 --- a/fun/tvl-ebooks/make-v6/main.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "crypto/rand" - "log" - "net" -) - -func main() { - // 2a0c:2f07:29:9999:6564:5298:8413:4652 - ip := net.ParseIP("2a0c:2f07:29::") - - rand.Read(ip[6:]) - - if ip[7] > 0xaa { - ip[4] = 0x03 - ip[5] = 0x84 - if ip[7] > 0xdd { - ip[4] = 0x08 - ip[5] = 0x64 - } - } - - log.Printf("%s\n", ip) - // -} diff --git a/fun/tvl-ebooks/mkov-engine/main.go b/fun/tvl-ebooks/mkov-engine/main.go deleted file mode 100644 index ba4863414..000000000 --- a/fun/tvl-ebooks/mkov-engine/main.go +++ /dev/null @@ -1,246 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "log" - "math/rand" - "strconv" - "strings" - "time" - - "github.com/go-redis/redis" -) - -type incomingIRC struct { - Command string `json:"Command"` - Host string `json:"Host"` - Name string `json:"Name"` - Params []string `json:"Params"` - User string `json:"User"` -} - -var suppressionUsernames map[string]bool -var noMkov map[string]bool - -func main() { - redisc := redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("127.0.0.1:%d", 6379), - Password: "", // no password set - DB: 0, // use default DB - }) - - fireaway := make(chan incomingIRC, 10) - suppressionUsernames = make(map[string]bool) - - suppressionList := redisc.HGetAll("suppressionList") - suppressionListA, _ := suppressionList.Result() - - suppressionListMap, _ := stringMaptoIntMap(suppressionListA) - for v, _ := range suppressionListMap { - suppressionUsernames[v] = true - suppressionUsernames[strings.ToLower(v)] = true - } - - noMkov = make(map[string]bool) - - noMkovRedis := redisc.HGetAll("nomkov") - noMkovRedisA, _ := noMkovRedis.Result() - - noMkovMap, _ := stringMaptoIntMap(noMkovRedisA) - for v, _ := range noMkovMap { - noMkov[v] = true - noMkov[strings.ToLower(v)] = true - } - - go func() { - for { - irccloudFeed := redisc.Subscribe("irccloud") - for { - msg, err := irccloudFeed.ReceiveMessage() - if err != nil { - break - } - imsg := incomingIRC{} - err = json.Unmarshal([]byte(msg.Payload), &imsg) - if err != nil { - log.Printf("Json decoding error from irccloud feed %s", err) - continue - } - - if imsg.Command == "PRIVMSG" { - if len(imsg.Params) == 2 { - if imsg.Params[0] == "##tvl" || imsg.Params[0] == "##tvlbot" { - fireaway <- imsg - } - } - } - } - time.Sleep(time.Second) - } - }() - - for msg := range fireaway { - // Learn - learnFromMessage(msg, redisc) - msg2 := generateMesasge(msg, redisc) - - // Check if we have a active log in for that user - ttl := redisc.TTL("alive-" + msg.Name + "-eb") - ttld, err := ttl.Result() - if err == nil { - redisc.Publish("irc-"+msg.Name+"-eb", msg2) - if ttld == 0 || ttld.Seconds() == -2 { - redisc.Publish("irc-tvlebooks-eb", "<"+fmt.Sprintf("%s.%s", string(msg.Name[0]), msg.Name[1:])+"-eb> "+msg2) - } - } else { - redisc.Publish("irc-tvlebooks-eb", "<"+fmt.Sprintf("%s.%s", string(msg.Name[0]), msg.Name[1:])+"-eb> "+msg2) - } - } -} - -func generateMesasge(msg incomingIRC, redisc *redis.Client) string { - text := msg.Params[1] - username := strings.ToLower(msg.Name) - suppressionUsernames[username] = true - suppressionUsernames[username+":"] = true - suppressionUsernames[msg.Name] = true - suppressionUsernames[msg.Name+":"] = true - redisc.HIncrBy("suppressionList", msg.Name, 1) - - text = strings.ToLower(text) - text = strings.Replace(text, ",", "", -1) - text = strings.Replace(text, ",", "", -1) - text = strings.Replace(text, ".", "", -1) - text = strings.Replace(text, "!", "", -1) - text = strings.Replace(text, "?", "", -1) - - words := strings.Split(text, " ") - lastWord := propwords(msg.Name, words[0], redisc) - - if noMkov[username] { - lastWord = blockoutWord(lastWord) - words[0] = blockoutWord(words[0]) - } - - lastWord = filterHighlights(lastWord) - - if lastWord == "_END_" { - if noMkov[username] { - return blockoutWord(words[0]) - } - return words[0] - } - outputMsg := words[0] + " " + lastWord + " " - - for { - lastWord = propwords(username, lastWord, redisc) - if lastWord == "" || lastWord == "_END_" { - return outputMsg - } - - if noMkov[username] { - lastWord = blockoutWord(lastWord) - } - - lastWord = filterHighlights(lastWord) - - outputMsg += lastWord + " " - if len(outputMsg) > 100 { - return outputMsg - } - } -} - -// filterHighlights: tries to prevent highlights by checking against -// a map called suppressionUsernames -func filterHighlights(in string) string { - for username := range suppressionUsernames { - if strings.Contains(in, username) { - if len(in) < 2 { - in = fmt.Sprintf("%s.%s", string(in[0]), in[1:]) - return in - } - } - } - return in -} - -func blockoutWord(in string) string { - block := "" - for i := 0; i < len(in); i++ { - block += "█" - } - return block -} - -func propwords(username string, start string, redisc *redis.Client) string { - userHash := redisc.HGetAll(fmt.Sprintf("%s-%s", username, start)) - userHashMap, err := userHash.Result() - if err != nil { - genericHash := redisc.HGetAll(fmt.Sprintf("generic-%s", start)) - userHashMap, err = genericHash.Result() - } - - userIntHashMap, totalVectors := stringMaptoIntMap(userHashMap) - if totalVectors == 0 { - return "" - } - targetRand := rand.Intn(totalVectors) - progresRand := 0 - - for k, v := range userIntHashMap { - progresRand += v - if targetRand > progresRand { - return k - } - } - - for k, _ := range userIntHashMap { - return k - } - - return "" -} - -func stringMaptoIntMap(in map[string]string) (outMap map[string]int, total int) { - outMap = make(map[string]int) - - for k, v := range in { - i, err := strconv.ParseInt(v, 10, 64) - if err != nil { - continue - } - total += int(i) - outMap[k] = int(i) - } - - return outMap, total -} - -func learnFromMessage(msg incomingIRC, redisc *redis.Client) { - text := msg.Params[1] - - text = strings.ToLower(text) - text = strings.Replace(text, ",", "", -1) - text = strings.Replace(text, ",", "", -1) - text = strings.Replace(text, ".", "", -1) - text = strings.Replace(text, "!", "", -1) - text = strings.Replace(text, "?", "", -1) - - words := strings.Split(text, " ") - username := msg.Name - - for k, word := range words { - // HINCRBY myhash field 1 - nextWord := "_END_" - if len(words)-1 != k { - nextWord = words[k+1] - } - - if !noMkov[username] { - redisc.HIncrBy(fmt.Sprintf("%s-%s", username, word), nextWord, 1) - } - redisc.HIncrBy(fmt.Sprintf("generic-%s", word), nextWord, 1) - } -} diff --git a/fun/tvl-ebooks/parse-logs/main.go b/fun/tvl-ebooks/parse-logs/main.go deleted file mode 100644 index a2d0d20ee..000000000 --- a/fun/tvl-ebooks/parse-logs/main.go +++ /dev/null @@ -1,174 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "log" - "math/rand" - "os" - "regexp" - "strconv" - "strings" - - "github.com/go-redis/redis" -) - -type incomingIRC struct { - Command string `json:"Command"` - Host string `json:"Host"` - Name string `json:"Name"` - Params []string `json:"Params"` - User string `json:"User"` -} - -var quicklogMatch = regexp.MustCompile(`<(\w+)> (.+)`) - -func main() { - redisc := redis.NewClient(&redis.Options{ - Addr: fmt.Sprintf("127.0.0.1:%d", 6379), - Password: "", // no password set - DB: 0, // use default DB - }) - - fireaway := make(chan incomingIRC, 10) - go func() { - f, err := os.Open("tvl.txt") - if err != nil { - log.Printf("aaa %v", err) - os.Exit(0) - } - - bio := bufio.NewReader(f) - for { - line, _, err := bio.ReadLine() - if err != nil { - break - } - - sline := string(line) - - offset := strings.Index(sline, "]") - - notime := sline[offset+1:] - - if quicklogMatch.MatchString(notime) { - bits := quicklogMatch.FindAllStringSubmatch(notime, -1) - if len(bits) != 0 { - if len(bits[0]) != 0 { - a := make([]string, 2) - a[1] = bits[0][2] - ic := incomingIRC{ - Name: bits[0][1], - Params: a, - } - log.Printf("aa %#v", ic) - - fireaway <- ic - } - } - } - - } - - }() - - for msg := range fireaway { - // Learn - learnFromMessage(msg, redisc) - // os.Exit(0) - } -} - -func generateMesasge(msg incomingIRC, redisc *redis.Client) string { - text := msg.Params[1] - username := msg.Name - - text = strings.ToLower(text) - text = strings.Replace(text, ",", "", -1) - text = strings.Replace(text, ",", "", -1) - text = strings.Replace(text, ".", "", -1) - text = strings.Replace(text, "!", "", -1) - text = strings.Replace(text, "?", "", -1) - - words := strings.Split(text, " ") - lastWord := propwords(username, words[0], redisc) - outputMsg := words[0] + " " + lastWord + " " - - for { - lastWord = propwords(username, words[0], redisc) - if lastWord == "" || lastWord == "_END_" { - return outputMsg - } - - outputMsg += lastWord + " " - if len(outputMsg) > 100 { - return outputMsg - } - } -} - -func propwords(username string, start string, redisc *redis.Client) string { - userHash := redisc.HGetAll(fmt.Sprintf("%s-%s", username, start)) - userHashMap, err := userHash.Result() - if err != nil { - genericHash := redisc.HGetAll(fmt.Sprintf("generic-%s", start)) - userHashMap, err = genericHash.Result() - } - - userIntHashMap, totalVectors := stringMaptoIntMap(userHashMap) - targetRand := rand.Intn(totalVectors) - progresRand := 0 - - for k, v := range userIntHashMap { - progresRand += v - if targetRand > progresRand { - return k - } - } - - for k, _ := range userIntHashMap { - return k - } - - return "" -} - -func stringMaptoIntMap(in map[string]string) (outMap map[string]int, total int) { - outMap = make(map[string]int) - - for k, v := range in { - i, err := strconv.ParseInt(v, 10, 64) - if err != nil { - continue - } - total += int(i) - outMap[k] = int(i) - } - - return outMap, total -} - -func learnFromMessage(msg incomingIRC, redisc *redis.Client) { - text := msg.Params[1] - - text = strings.ToLower(text) - text = strings.Replace(text, ",", "", -1) - text = strings.Replace(text, ",", "", -1) - text = strings.Replace(text, ".", "", -1) - text = strings.Replace(text, "!", "", -1) - text = strings.Replace(text, "?", "", -1) - - words := strings.Split(text, " ") - username := msg.Name - - for k, word := range words { - // HINCRBY myhash field 1 - nextWord := "_END_" - if len(words)-1 != k { - nextWord = words[k+1] - } - - redisc.HIncrBy(fmt.Sprintf("%s-%s", username, word), nextWord, 1) - redisc.HIncrBy(fmt.Sprintf("generic-%s", word), nextWord, 1) - } -} diff --git a/fun/uggc/default.nix b/fun/uggc/default.nix deleted file mode 100644 index 980ad16bc..000000000 --- a/fun/uggc/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.third_party) gopkgs; - - uggc = depot.nix.buildGo.program { - name = "uggc"; - srcs = [ - ./main.go - ]; - deps = [ - gopkgs."github.com".pkg.browser.gopkg - ]; - }; -in -uggc.overrideAttrs (old: { - buildCommand = old.buildCommand + '' - install -D ${./uggc.desktop} $out/share/applications/uggc.desktop - sed "s|@out@|$out|g" -i $out/share/applications/uggc.desktop - ''; -}) diff --git a/fun/uggc/main.go b/fun/uggc/main.go deleted file mode 100644 index 94f8cf092..000000000 --- a/fun/uggc/main.go +++ /dev/null @@ -1,38 +0,0 @@ -package main - -import ( - "fmt" - "os" - "strings" - - "github.com/pkg/browser" -) - -func rot13(r rune) rune { - if 'a' <= r && r <= 'm' { - return r + ('n' - 'a') - } else if 'n' <= r && r <= 'z' { - return r - ('n' - 'a') - } - if 'A' <= r && r <= 'M' { - return r + ('N' - 'A') - } else if 'N' <= r && r <= 'Z' { - return r - ('N' - 'A') - } - return r -} - -func main() { - if len(os.Args) == 0 { - fmt.Println("usage: uggc [rot13-encoded URL]") - return - } - urlText := strings.Join(os.Args[1:], " ") - corrected := strings.Map(rot13, urlText) - - err := browser.OpenURL(corrected) - - if err != nil { - fmt.Println("could not launch browser:", err) - } -} diff --git a/fun/uggc/uggc.desktop b/fun/uggc/uggc.desktop deleted file mode 100644 index c4eeff7f5..000000000 --- a/fun/uggc/uggc.desktop +++ /dev/null @@ -1,7 +0,0 @@ -[Desktop Entry] -Type=Application -Name=Rot13 URL Handler -Exec=@out@/bin/uggc -StartupNotify=false -MimeType=x-scheme-handler/uggc; -MimeType=x-scheme-handler/uggcf; diff --git a/fun/uggc/uggc.reg b/fun/uggc/uggc.reg deleted file mode 100644 index bfb8e1952..000000000 --- a/fun/uggc/uggc.reg +++ /dev/null @@ -1,23 +0,0 @@ -Windows Registry Editor Version 5.00 - -[HKEY_CLASSES_ROOT\uggc] -"URL Protocol"="" -@="URL:Rot13 HTTP URL Protocol" - -[HKEY_CLASSES_ROOT\uggcf] -"URL Protocol"="" -@="URL:Rot13 HTTPS URL Protocol" - -[HKEY_CLASSES_ROOT\uggc\shell] - -[HKEY_CLASSES_ROOT\uggcf\shell] - -[HKEY_CLASSES_ROOT\uggc\shell\open] - -[HKEY_CLASSES_ROOT\uggcf\shell\open] - -[HKEY_CLASSES_ROOT\uggc\shell\open\command] -@="\"C:\\Program Files\\uggc\\uggc.exe\" \"%1\"" - -[HKEY_CLASSES_ROOT\uggcf\shell\open\command] -@="\"C:\\Program Files\\uggc\\uggc.exe\" \"%1\"" diff --git a/fun/watchblob/README.md b/fun/watchblob/README.md deleted file mode 100644 index 712c96cd9..000000000 --- a/fun/watchblob/README.md +++ /dev/null @@ -1,35 +0,0 @@ -Watchblob - WatchGuard VPN on Linux -=================================== - -This tiny helper tool makes it possible to use WatchGuard / Firebox / <> VPNs that use multi-factor authentication on Linux. - -Rather than using OpenVPN's built-in dynamic challenge/response protocol, WatchGuard -has opted for a separate implementation negotiating credentials outside of the -OpenVPN protocol, which makes it impossible to start those connections solely by -using the `openvpn` CLI and configuration files. - -What this application does has been reverse-engineered from the "WatchGuard Mobile VPN -with SSL" application on OS X. - -I've published a [blog post](https://www.tazj.in/en/1486830338) describing the process -and what is actually going on in this protocol. - -## Installation - -Make sure you have Go installed and `GOPATH` configured, then simply -`go get github.com/tazjin/watchblob/...`. - -## Usage - -Right now the usage is very simple. Make sure you have the correct OpenVPN client -config ready (this is normally supplied by the WatchGuard UI) simply run: - -``` -watchblob vpnserver.somedomain.org username p4ssw0rd -``` - -The server responds with a challenge which is displayed to the user, wait until you -receive the SMS code or whatever and enter it. `watchblob` then completes the -credential negotiation and you may proceed to log in with OpenVPN using your username -and *the OTP token* (**not** your password) as credentials. diff --git a/fun/watchblob/default.nix b/fun/watchblob/default.nix deleted file mode 100644 index dc32e4d1c..000000000 --- a/fun/watchblob/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ depot, ... }: - -depot.nix.buildGo.program { - name = "watchblob"; - srcs = [ - ./main.go - ./urls.go - ]; - - deps = with depot.third_party; [ - gopkgs."golang.org".x.crypto.ssh.terminal.gopkg - ]; -} diff --git a/fun/watchblob/main.go b/fun/watchblob/main.go deleted file mode 100644 index a7ab65d3d..000000000 --- a/fun/watchblob/main.go +++ /dev/null @@ -1,108 +0,0 @@ -package main - -import ( - "bufio" - "encoding/xml" - "fmt" - "golang.org/x/crypto/ssh/terminal" - "net/http" - "os" - "strings" - "syscall" -) - -// The XML response returned by the WatchGuard server -type Resp struct { - Action string `xml:"action"` - LogonStatus int `xml:"logon_status"` - LogonId int `xml:"logon_id"` - Error string `xml:"errStr"` - Challenge string `xml:"chaStr"` -} - -func main() { - args := os.Args[1:] - - if len(args) != 1 { - fmt.Fprintln(os.Stderr, "Usage: watchblob ") - os.Exit(1) - } - - host := args[0] - - username, password, err := readCredentials() - if err != nil { - fmt.Fprintf(os.Stderr, "Could not read credentials: %v\n", err) - } - - fmt.Printf("Requesting challenge from %s as user %s\n", host, username) - challenge, err := triggerChallengeResponse(&host, &username, &password) - - if err != nil || challenge.LogonStatus != 4 { - fmt.Fprintln(os.Stderr, "Did not receive challenge from server") - fmt.Fprintf(os.Stderr, "Response: %v\nError: %v\n", challenge, err) - os.Exit(1) - } - - token := getToken(&challenge) - err = logon(&host, &challenge, &token) - - if err != nil { - fmt.Fprintf(os.Stderr, "Logon failed: %v\n", err) - os.Exit(1) - } - - fmt.Printf("Login succeeded, you may now (quickly) authenticate OpenVPN with %s as your password\n", token) -} - -func readCredentials() (string, string, error) { - fmt.Printf("Username: ") - reader := bufio.NewReader(os.Stdin) - username, err := reader.ReadString('\n') - - fmt.Printf("Password: ") - password, err := terminal.ReadPassword(syscall.Stdin) - fmt.Println() - - // If an error occured, I don't care about which one it is. - return strings.TrimSpace(username), strings.TrimSpace(string(password)), err -} - -func triggerChallengeResponse(host *string, username *string, password *string) (r Resp, err error) { - return request(templateUrl(host, templateChallengeTriggerUri(username, password))) -} - -func getToken(challenge *Resp) string { - fmt.Println(challenge.Challenge) - - reader := bufio.NewReader(os.Stdin) - token, _ := reader.ReadString('\n') - - return strings.TrimSpace(token) -} - -func logon(host *string, challenge *Resp, token *string) (err error) { - resp, err := request(templateUrl(host, templateResponseUri(challenge.LogonId, token))) - if err != nil { - return - } - - if resp.LogonStatus != 1 { - err = fmt.Errorf("Challenge/response authentication failed: %v", resp) - } - - return -} - -func request(url string) (r Resp, err error) { - resp, err := http.Get(url) - if err != nil { - return - } - - defer resp.Body.Close() - decoder := xml.NewDecoder(resp.Body) - - err = decoder.Decode(&r) - return -} diff --git a/fun/watchblob/main_test.go b/fun/watchblob/main_test.go deleted file mode 100644 index 1af52d0cd..000000000 --- a/fun/watchblob/main_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package main - -import ( - "encoding/xml" - "reflect" - "testing" -) - -func TestUnmarshalChallengeRespones(t *testing.T) { - var testXml string = ` - - - sslvpn_logon - 4 - - - RADIUS - - - 441 - Enter Your 6 Digit Passcode -` - - var r Resp - xml.Unmarshal([]byte(testXml), &r) - - expected := Resp{ - Action: "sslvpn_logon", - LogonStatus: 4, - LogonId: 441, - Challenge: "Enter Your 6 Digit Passcode ", - } - - assertEqual(t, expected, r) -} - -func TestUnmarshalLoginError(t *testing.T) { - var testXml string = ` - - - sslvpn_logon - 2 - - - RADIUS - - - 501 -` - - var r Resp - xml.Unmarshal([]byte(testXml), &r) - - expected := Resp{ - Action: "sslvpn_logon", - LogonStatus: 2, - Error: "501", - } - - assertEqual(t, expected, r) -} - -func TestUnmarshalLoginSuccess(t *testing.T) { - var testXml string = ` - - - sslvpn_logon - 1 - - - RADIUS - - - -` - var r Resp - xml.Unmarshal([]byte(testXml), &r) - - expected := Resp{ - Action: "sslvpn_logon", - LogonStatus: 1, - } - - assertEqual(t, expected, r) -} - -func assertEqual(t *testing.T, expected interface{}, result interface{}) { - if !reflect.DeepEqual(expected, result) { - t.Errorf( - "Unmarshaled values did not match.\nExpected: %v\nResult: %v\n", - expected, result, - ) - - t.Fail() - } -} diff --git a/fun/watchblob/urls.go b/fun/watchblob/urls.go deleted file mode 100644 index 37f65e0fa..000000000 --- a/fun/watchblob/urls.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "fmt" - "net/url" - "strconv" -) - -const urlFormat string = "https://%s%s" -const uriFormat = "/?%s" - -func templateChallengeTriggerUri(username *string, password *string) string { - v := url.Values{} - v.Set("action", "sslvpn_logon") - v.Set("style", "fw_logon_progress.xsl") - v.Set("fw_logon_type", "logon") - v.Set("fw_domain", "Firebox-DB") - v.Set("fw_username", *username) - v.Set("fw_password", *password) - - return fmt.Sprintf(uriFormat, v.Encode()) -} - -func templateResponseUri(logonId int, token *string) string { - v := url.Values{} - v.Set("action", "sslvpn_logon") - v.Set("style", "fw_logon_progress.xsl") - v.Set("fw_logon_type", "response") - v.Set("response", *token) - v.Set("fw_logon_id", strconv.Itoa(logonId)) - - return fmt.Sprintf(uriFormat, v.Encode()) -} - -func templateUrl(baseUrl *string, uri string) string { - return fmt.Sprintf(urlFormat, *baseUrl, uri) -} diff --git a/fun/wcl/default.nix b/fun/wcl/default.nix deleted file mode 100644 index e4d9804c8..000000000 --- a/fun/wcl/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ depot, ... }: - -depot.nix.buildLisp.program { - name = "wc"; - - srcs = [ - ./wc.lisp - ]; - - deps = with depot.third_party.lisp; [ - unix-opts - iterate - ]; -} diff --git a/fun/wcl/wc.lisp b/fun/wcl/wc.lisp deleted file mode 100644 index 83c7e8c4f..000000000 --- a/fun/wcl/wc.lisp +++ /dev/null @@ -1,34 +0,0 @@ -(defpackage wc - (:use #:cl #:iterate) - (:export :main)) -(in-package :wc) -(declaim (optimize (speed 3) (safety 0))) - -(defun main () - (let ((filename (cadr (opts:argv))) - (space (char-code #\Space)) - (newline (char-code #\Newline))) - (with-open-file (file-stream filename :element-type '(unsigned-byte 8)) - (iter - (for byte in-stream file-stream using #'read-byte) - (for previous-byte previous byte) - (for is-newline = (eql newline byte)) - - ;; Count each byte - (sum 1 into bytes) - - ;; Count every newline - (counting is-newline into newlines) - - ;; Count every "word", unless the preceding character already - ;; was a space or we are at the beginning of the file. - (when (or (eql space previous-byte) - (eql newline previous-byte) - (not previous-byte)) - (next-iteration)) - - (counting (or is-newline (eql space byte)) - into words) - - (declare (fixnum bytes newlines words)) - (finally (format t " ~A ~A ~A ~A~%" newlines words bytes filename)))))) diff --git a/fun/🕰️/OWNERS b/fun/🕰️/OWNERS deleted file mode 100644 index 2e9580706..000000000 --- a/fun/🕰️/OWNERS +++ /dev/null @@ -1 +0,0 @@ -sterni diff --git a/fun/🕰️/bin.lisp b/fun/🕰️/bin.lisp deleted file mode 100644 index 1f5a2b2e0..000000000 --- a/fun/🕰️/bin.lisp +++ /dev/null @@ -1,91 +0,0 @@ -(defpackage 🕰️.bin - (:shadow :describe) - (:use :cl :opts) - (:import-from :uiop :quit) - (:import-from :local-time - :now :timestamp-subtimezone :+utc-zone+ - :*default-timezone* :define-timezone) - (:import-from :klatre :format-dottime-offset) - (:import-from :🕰️ :⌚) - (:export :🚂)) - -(in-package :🕰️.bin) -(declaim (optimize (safety 3))) - -(opts:define-opts - (:name :help - :description "Print this help text" - :short #\h - :long "help") - (:name :dot-time - :description "Use pseudo dot-time format (implies -u)" - :short #\d - :long "dot-time") - (:name :utc - :description "Display time in UTC instead of local time" - :short #\u - :long "utc") - (:name :no-newline - :description "Don't print a trailing newline" - :short #\n - :long "no-newline")) - -(defun make-slash-terminated (str) - (if (eq (char str (1- (length str))) #\/) - str - (concatenate 'string str "/"))) - -; TODO(sterni): upstream this into local-time -(defun setup-default-timezone () - (let* ((tz (remove #\: (uiop:getenv "TZ") :count 1)) - (tz-dir (uiop:getenv "TZDIR")) - (tz-file (if (and tz tz-dir) - (merge-pathnames - (pathname tz) - (pathname (make-slash-terminated tz-dir))) - (pathname "/etc/localtime")))) - (handler-case - (define-timezone *default-timezone* tz-file :load t) - (t () (setf *default-timezone* +utc-zone+))))) - - -(defun 🚂 () - (let ((ts (now))) - (multiple-value-bind (options free-args) - (handler-case (opts:get-opts) - ; only handle subset of conditions that can happen here - (opts:unknown-option (c) - (format t "error: unknown option ~s~%" (opts:option c)) - (quit 100))) - - ; check if we have any free args we don't know what to do with - (when (> (length free-args) 0) - (write-string "error: unexpected command line argument(s): ") - (loop for arg in free-args - do (progn (write-string arg) (write-char #\space))) - (write-char #\newline) - (quit 100)) - - ; print help and exit - (when (getf options :help) - (opts:describe :usage-of "🕰️") - (quit 0)) - - ; reinit *default-timezone* as it is cached from compilation - (setup-default-timezone) - ; dot-time implies UTC, naturally - (when (getf options :dot-time) - (setf (getf options :utc) t)) - ; print clock face - (format t "~A" (⌚ ts (if (getf options :utc) - local-time:+utc-zone+ - local-time:*default-timezone*))) - ; render dot-time offset if necessary - (when (getf options :dot-time) - (multiple-value-bind (offset-secs _dst _name) - (timestamp-subtimezone ts local-time:*default-timezone*) - (write-string - (format-dottime-offset (round (/ offset-secs 3600)))))) - ; write newline if necessary - (when (not (getf options :no-newline)) - (write-char #\newline))))) diff --git a/fun/🕰️/default.nix b/fun/🕰️/default.nix deleted file mode 100644 index 2b1a94640..000000000 --- a/fun/🕰️/default.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.nix) - buildLisp - ; - - lib = buildLisp.library { - name = "lib🕰️"; - deps = [ - depot.third_party.lisp.local-time - ]; - - srcs = [ - ./lib.lisp - ]; - }; - - bin = buildLisp.program { - name = "🕰️"; - deps = [ - depot.third_party.lisp.unix-opts - depot.lisp.klatre - { - default = buildLisp.bundled "asdf"; - sbcl = buildLisp.bundled "uiop"; - } - lib - ]; - - srcs = [ - ./bin.lisp - ]; - - main = "🕰️.bin:🚂"; - - brokenOn = [ - "ecl" # refuses to create non-ASCII paths even on POSIX… - ]; - }; -in -bin // { - inherit lib; -} diff --git a/fun/🕰️/lib.lisp b/fun/🕰️/lib.lisp deleted file mode 100644 index d23db0337..000000000 --- a/fun/🕰️/lib.lisp +++ /dev/null @@ -1,32 +0,0 @@ -(defpackage 🕰️ - (:use :cl) - (:import-from :local-time - :timestamp-subtimezone :*default-timezone* :sec-of) - (:export :⌚)) - -(in-package :🕰️) -(declaim (optimize (safety 3))) - -(defparameter *clock-emojis* - (vector #\🕛 #\🕧 ; 00:00 - 00:30 - #\🕐 #\🕜 ; 01:00 - 01:30 - #\🕑 #\🕝 ; 00:00 - 00:30 - #\🕒 #\🕞 ; 00:00 - 00:30 - #\🕓 #\🕟 ; 00:00 - 00:30 - #\🕔 #\🕠 ; 00:00 - 00:30 - #\🕕 #\🕡 ; 00:00 - 00:30 - #\🕖 #\🕢 ; 00:00 - 00:30 - #\🕗 #\🕣 ; 00:00 - 00:30 - #\🕘 #\🕤 ; 00:00 - 00:30 - #\🕙 #\🕥 ; 00:00 - 00:30 - #\🕚 #\🕦)) ; 11:00 - 11:30 - -(defun ⌚ (timestamp &optional (tz *default-timezone*)) - "Convert a LOCAL-TIME:TIMESTAMP into the nearest Unicode clock face. - Use TZ (which defaults to LOCAL-TIME:*DEFAULT-TIMEZONE*) to determine - the UTC offset to factor when determining the local clock face." - (let* ((offset (multiple-value-bind (offset-secs _dst _name) - (timestamp-subtimezone timestamp tz) - offset-secs)) - (secs (+ (sec-of timestamp) offset))) - (elt *clock-emojis* (mod (round (/ secs 1800)) 24)))) diff --git a/lisp/dns/README.md b/lisp/dns/README.md deleted file mode 100644 index c95d2e9a6..000000000 --- a/lisp/dns/README.md +++ /dev/null @@ -1,75 +0,0 @@ -dns -=== - -This library is a DNS-over-HTTPS client for Common Lisp. - -The ambition is to transform it into a fully-featured DNS resolver -instead of piggy-backing on the HTTPS implementation, but ... -baby-steps! - -Note that there is no Common Lisp HTTP client that fully supports the -HTTP2 protocol at the moment, so you can not expect this library to -provide equivalent performance to a native DNS resolver (yet). - -## API - -The API is kept as simple as it can be. - -### Types - -The types of this library are implemented as several structs that -support binary (de-)serialisation via [lisp-binary][]. - -The existing structs are as follows and directly implement the -corresponding definitions from [RFC 1035][]: - -* `dns-header` -* `dns-question` -* `dns-rr` -* `dns-message` - -All relevant field accessors for these structs are exported and can be -used to inspect query results. - -### Functions - -All lookup functions are of the type `(function (string &key doh-url) -(dns-message))` and signal a `dns:doh-error` condition for -unsuccessful requests. - -If `:doh-url` is unspecified, Google's public DNS-over-HTTPS servers -at [dns.google][https://dns.google] will be used. - -Currently implemented lookup functions: - -* `lookup-a` -* `lookup-mx` -* `lookup-txt` - -## Example usage - -```lisp -DNS> (dns-message-answer (lookup-a "git.tazj.in.")) -#(#S(DNS-RR - :NAME #S(QNAME :START-AT 29 :NAMES #(12)) - :TYPE A - :CLASS 1 - :TTL 286 - :RDLENGTH 4 - :RDATA #(34 98 120 189))) -``` - -## TODO - -Various things in this library are currently broken because I only -implemented it to work for my blog setup, but these things will be -ironed out. - -Most importantly, the following needs to be fixed: - -* Each qname *fragment* needs to track its offset, not each qname. -* The RDATA for a TXT record can have multiple counted strings. -* qnames should be canonicalised after parsing. - -[lisp-binary]: https://github.com/j3pic/lisp-binary -[RFC 1035]: https://tools.ietf.org/html/rfc1035 diff --git a/lisp/dns/client.lisp b/lisp/dns/client.lisp deleted file mode 100644 index cee7bceb5..000000000 --- a/lisp/dns/client.lisp +++ /dev/null @@ -1,85 +0,0 @@ -;; Implementation of a DoH-client, see RFC 8484 (DNS Queries over -;; HTTPS (DoH)) - -(in-package #:dns) - -(defvar *doh-base-url* "https://dns.google/resolve" - "Base URL of the service providing DNS-over-HTTP(S). Defaults to the - Google-hosted API.") - -(define-condition doh-error (error) - ((query-name :initarg :query-name - :reader doh-error-query-name - :type string) - (query-type :initarg :query-type - :reader doh-error-query-type - :type string) - (doh-url :initarg :doh-url - :reader doh-error-doh-url - :type string) - (status-code :initarg :status-code - :reader doh-error-status-code - :type integer) - (response-body :initarg :response-body - :reader doh-error-response-body - :type (or nil (vector (unsigned-byte 8)) string))) - - (:report (lambda (condition stream) - (let ((url (doh-error-doh-url condition)) - (status (doh-error-status-code condition)) - (body (doh-error-response-body condition))) - (format stream "DoH service at '~A' responded with non-success (~A): ~%~%~A" - url status body))))) - -(defun lookup-generic (name type doh-url) - (multiple-value-bind (body status) - (drakma:http-request doh-url - :decode-content t - ;; TODO(tazjin): Figure out why 'want-stream' doesn't work - :parameters `(("type" . ,type) - ("name" . ,name) - ("ct" . "application/dns-message"))) - (if (= 200 status) - (dns-message-answer - (read-binary 'dns-message (flexi-streams:make-in-memory-input-stream body))) - - (restart-case (error 'doh-error - :query-name name - :query-type type - :doh-url doh-url - :status-code status - :response-body body) - (call-with-other-name (new-name) - :interactive (lambda () (list (the string (read)))) - :test (lambda (c) (typep c 'doh-error)) - (lookup-generic new-name type doh-url)) - - (call-with-other-type (new-type) - :interactive (lambda () (list (the string (read)))) - :test (lambda (c) (typep c 'doh-error)) - (lookup-generic name new-type doh-url)) - - (call-with-other-url (new-url) - :interactive (lambda () (list (the string (read)))) - :test (lambda (c) (typep c 'doh-error)) - (lookup-generic name type new-url)))))) - -(defun lookup-a (name &key (doh-url *doh-base-url*)) - "Look up the A records at NAME." - (lookup-generic name "A" doh-url)) - -(defun lookup-txt (name &key (doh-url *doh-base-url*)) - "Look up the TXT records at NAME." - (lookup-generic name "TXT" doh-url)) - -(defun lookup-mx (name &key (doh-url *doh-base-url*)) - "Look up the MX records at NAME." - (lookup-generic name "MX" doh-url)) - -(defun lookup-cname (name &key (doh-url *doh-base-url*)) - "Look up the CNAME records at NAME." - (lookup-generic name "CNAME" doh-url)) - -(defun lookup-ns (name &key (doh-url *doh-base-url*)) - "Look up the NS records at NAME." - (lookup-generic name "NS" doh-url)) diff --git a/lisp/dns/default.nix b/lisp/dns/default.nix deleted file mode 100644 index cb2445b46..000000000 --- a/lisp/dns/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ depot, ... }: - -depot.nix.buildLisp.library { - name = "dns"; - - deps = with depot.third_party.lisp; [ - drakma - lisp-binary - iterate - ]; - - srcs = [ - ./package.lisp - ./message.lisp - ./client.lisp - ]; - - brokenOn = [ - "ecl" # dynamic cffi - ]; -} diff --git a/lisp/dns/message.lisp b/lisp/dns/message.lisp deleted file mode 100644 index 46243ac8d..000000000 --- a/lisp/dns/message.lisp +++ /dev/null @@ -1,407 +0,0 @@ -(in-package :dns) - -;; 3.3. Standard RRs - -;; The following RR definitions are expected to occur, at least -;; potentially, in all classes. In particular, NS, SOA, CNAME, and PTR -;; will be used in all classes, and have the same format in all classes. -;; Because their RDATA format is known, all domain names in the RDATA -;; section of these RRs may be compressed. - -;; is a domain name represented as a series of labels, and -;; terminated by a label with zero length. is a single -;; length octet followed by that number of characters. -;; is treated as binary information, and can be up to 256 characters in -;; length (including the length octet). - - -;; 3.3.11. NS RDATA format - -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; / NSDNAME / -;; / / -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - -;; where: - -;; NSDNAME A which specifies a host which should be -;; authoritative for the specified class and domain. - -;; NS records cause both the usual additional section processing to locate -;; a type A record, and, when used in a referral, a special search of the -;; zone in which they reside for glue information. - -;; The NS RR states that the named host should be expected to have a zone -;; starting at owner name of the specified class. Note that the class may -;; not indicate the protocol family which should be used to communicate -;; with the host, although it is typically a strong hint. For example, -;; hosts which are name servers for either Internet (IN) or Hesiod (HS) -;; class information are normally queried using IN class protocols. - -;; 3.3.12. PTR RDATA format - -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; / PTRDNAME / -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - -;; where: - -;; PTRDNAME A which points to some location in the -;; domain name space. - -;; PTR records cause no additional section processing. These RRs are used -;; in special domains to point to some other location in the domain space. -;; These records are simple data, and don't imply any special processing -;; similar to that performed by CNAME, which identifies aliases. See the -;; description of the IN-ADDR.ARPA domain for an example. - -;; 3.3.13. SOA RDATA format - -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; / MNAME / -;; / / -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; / RNAME / -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | SERIAL | -;; | | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | REFRESH | -;; | | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | RETRY | -;; | | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | EXPIRE | -;; | | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; | MINIMUM | -;; | | -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - -;; where: - -;; MNAME The of the name server that was the -;; original or primary source of data for this zone. - -;; RNAME A which specifies the mailbox of the -;; person responsible for this zone. - -;; SERIAL The unsigned 32 bit version number of the original copy -;; of the zone. Zone transfers preserve this value. This -;; value wraps and should be compared using sequence space -;; arithmetic. - -;; REFRESH A 32 bit time interval before the zone should be -;; refreshed. - -;; RETRY A 32 bit time interval that should elapse before a -;; failed refresh should be retried. - -;; EXPIRE A 32 bit time value that specifies the upper limit on -;; the time interval that can elapse before the zone is no -;; longer authoritative. - -;; MINIMUM The unsigned 32 bit minimum TTL field that should be -;; exported with any RR from this zone. - -;; SOA records cause no additional section processing. - -;; All times are in units of seconds. - -;; Most of these fields are pertinent only for name server maintenance -;; operations. However, MINIMUM is used in all query operations that -;; retrieve RRs from a zone. Whenever a RR is sent in a response to a -;; query, the TTL field is set to the maximum of the TTL field from the RR -;; and the MINIMUM field in the appropriate SOA. Thus MINIMUM is a lower -;; bound on the TTL field for all RRs in a zone. Note that this use of -;; MINIMUM should occur when the RRs are copied into the response and not -;; when the zone is loaded from a master file or via a zone transfer. The -;; reason for this provison is to allow future dynamic update facilities to -;; change the SOA RR with known semantics. - - -;; 3.3.14. TXT RDATA format - -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ -;; / TXT-DATA / -;; +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - -;; where: - -;; TXT-DATA - -;; TXT RRs are used to hold descriptive text. The semantics of the text -;; depends on the domain where it is found. - -(defbinary dns-header (:byte-order :big-endian) - ;; A 16 bit identifier assigned by the program that - ;; generates any kind of query. This identifier is copied - ;; the corresponding reply and can be used by the requester - ;; to match up replies to outstanding queries. - (id 0 :type 16) - - ;; A one bit field that specifies whether this message is a - ;; query (0), or a response (1). - (qr 0 :type 1) - - ;; A four bit field that specifies kind of query in this - ;; message. This value is set by the originator of a query - ;; and copied into the response. The values are: - ;; - ;; 0 a standard query (QUERY) - ;; 1 an inverse query (IQUERY) - ;; 2 a server status request (STATUS) - ;; 3-15 reserved for future use - (opcode 0 :type 4) - - ;; Authoritative Answer - this bit is valid in responses, - ;; and specifies that the responding name server is an - ;; authority for the domain name in question section. - (aa nil :type 1) - - ;; TrunCation - specifies that this message was truncated - ;; due to length greater than that permitted on the - ;; transmission channel. - (tc nil :type 1) - - ;; Recursion Desired - this bit may be set in a query and - ;; is copied into the response. If RD is set, it directs - ;; the name server to pursue the query recursively. - ;; Recursive query support is optional. - (rd nil :type 1) - - ;; Recursion Available - this be is set or cleared in a - ;; response, and denotes whether recursive query support is - ;; available in the name server. - (ra nil :type 1) - - ;; Reserved for future use. Must be zero in all queries and - ;; responses. - (z 0 :type 3) - - ;; Response code - this 4 bit field is set as part of - ;; responses. The values have the following - ;; interpretation: - ;; 0 No error condition - ;; 1 Format error - The name server was - ;; unable to interpret the query. - ;; 2 Server failure - The name server was - ;; unable to process this query due to a - ;; problem with the name server. - ;; 3 Name Error - Meaningful only for - ;; responses from an authoritative name - ;; server, this code signifies that the - ;; domain name referenced in the query does - ;; not exist. - ;; 4 Not Implemented - The name server does - ;; not support the requested kind of query. - ;; 5 Refused - The name server refuses to - ;; perform the specified operation for - ;; policy reasons. For example, a name - ;; server may not wish to provide the - ;; information to the particular requester, - ;; or a name server may not wish to perform - ;; a particular operation (e.g., zone - ;; transfer) for particular data. - ;; 6-15 Reserved for future use. - (rcode 0 :type 4) - - ;; an unsigned 16 bit integer specifying the number of - ;; entries in the question section. - (qdcount 0 :type 16) - - ;; an unsigned 16 bit integer specifying the number of - ;; resource records in the answer section. - (ancount 0 :type 16) - - ;; an unsigned 16 bit integer specifying the number of name - ;; server resource records in the authority records - ;; section. - (nscount 0 :type 16) - - ;; an unsigned 16 bit integer specifying the number of - ;; resource records in the additional records section. - (arcount 0 :type 16)) - - -;; Representation of DNS QNAMEs. -;; -;; A QNAME can be either made up entirely of labels, which is -;; basically a list of strings, or be terminated with a pointer to an -;; offset within the original message. - -(deftype qname-field () - '(or - ;; pointer - (unsigned-byte 14) - ;; label - string)) - -(defstruct qname - (start-at 0 :type (unsigned-byte 14)) - (names #() :type (vector qname-field))) - -;; Domain names in questions and resource records are represented as a -;; sequence of labels, where each label consists of a length octet -;; followed by that number of octets. -;; -;; The domain name terminates with the zero length octet for the null -;; label of the root. Note that this field may be an odd number of -;; octets; no padding is used. -(declaim (ftype (function (stream) (values qname integer)) read-qname)) -(defun read-qname (stream) - "Reads a DNS QNAME from STREAM." - - (let ((start-at (file-position stream))) - (iter (for byte next (read-byte stream)) - ;; Each fragment is collected into this byte vector pre-allocated - ;; with the correct size. - (for fragment = (make-array byte :element-type '(unsigned-byte 8) - :fill-pointer 0)) - - ;; If the bit sequence (1 1) is encountered at the beginning of - ;; the fragment, a qname pointer is being read. - (let ((byte-copy byte)) - (when (equal #b11 (lisp-binary/integer:pop-bits 2 8 byte-copy)) - (let ((next (read-byte stream))) - (lisp-binary/integer:push-bits byte-copy 8 next) - (collect next into fragments result-type vector) - (sum 2 into size) - (finish)))) - - ;; Total size is needed, count for each iteration byte, plus its - ;; own value. - (sum (+ 1 byte) into size) - (until (equal byte 0)) - - ;; On each iteration, this will interpret the current byte as an - ;; unsigned integer and read from STREAM an equivalent amount of - ;; times to assemble the current fragment. - ;; - ;; Advancing the stream like this also ensures that the next - ;; iteration occurs on a new fragment or the final terminating - ;; byte. - (dotimes (_ byte (collect (babel:octets-to-string fragment) - into fragments result-type vector)) - (vector-push (read-byte stream) fragment)) - - (finally (return (values (make-qname :start-at start-at - :names fragments) - size)))))) - -(declaim (ftype (function (stream qname)) write-qname)) -(defun write-qname (stream qname) - "Write a DNS qname to STREAM." - - ;; Write each fragment starting with its (byte-) length, followed by - ;; the bytes. - (iter (for fragment in-vector (qname-names qname)) - (for bytes = (babel:string-to-octets fragment)) - (write-byte (length bytes) stream) - (iter (for byte in-vector bytes) - (write-byte byte stream))) - - ;; Always finish off the serialisation with a null-byte! - (write-byte 0 stream)) - -(define-enum dns-type 2 - (:byte-order :big-endian) - - ;; http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml - (A 1) - (NS 2) - (CNAME 5) - (SOA 6) - (PTR 12) - (MX 15) - (TXT 16) - (SRV 33) - (AAAA 28) - - ;; ANY typically wants SOA, MX, NS and MX - (ANY 255)) - -(defbinary dns-question (:byte-order :big-endian :export t) - ;; a domain name represented - (qname "" :type (custom :lisp-type qname - :reader #'read-qname - :writer #'write-qname)) - - ;; a two octet code which specifies the type of the query. - (qtype 0 :type dns-type) - - ;; a two octet code that specifies the class of the query. For - ;; example, the QCLASS field is IN for the Internet. - (qclass 0 :type 16)) - -(defbinary dns-rr (:byte-order :big-endian :export t) - (name nil :type (custom :lisp-type qname - :reader #'read-qname - :writer #'write-qname)) - - ;; two octets containing one of the RR type codes. This field - ;; specifies the meaning of the data in the RDATA field. - (type 0 :type dns-type) - - ;; two octets which specify the class of the data in the RDATA - ;; field. - (class 0 :type 16) - - ;; a 32 bit unsigned integer that specifies the time interval (in - ;; seconds) that the resource record may be cached before it should - ;; be discarded. Zero values are interpreted to mean that the RR - ;; can only be used for the transaction in progress, and should not - ;; be cached. - (ttl 0 :type 32) - - ;; an unsigned 16 bit integer that specifies the length in octets - ;; of the RDATA field. - (rdlength 0 :type 16) - - ;; a variable length string of octets that describes the resource. - ;; The format of this information varies according to the TYPE and - ;; CLASS of the resource record. For example, the if the TYPE is A - ;; and the CLASS is IN, the RDATA field is a 4 octet ARPA Internet - ;; address. - (rdata #() :type (eval (case type - ;; A 32-bit internet address in its - ;; canonical representation of 4 integers. - ((A) '(simple-array (unsigned-byte 8) (4))) - - ;; TODO(tazjin): Deal with multiple strings in single RRDATA - ;; One or more s. - ((TXT) '(counted-string 1)) - - ;; A which specifies the - ;; canonical or primary name for the - ;; owner. The owner name is an alias. - ((CNAME) '(custom - :lisp-type qname - :reader #'read-qname - :writer #'write-qname)) - - ;; A which specifies a host - ;; which should be authoritative for the - ;; specified class and domain. - ((NS) '(custom - :lisp-type qname - :reader #'read-qname - :writer #'write-qname)) - (otherwise `(simple-array (unsigned-byte 8) (,rdlength))))))) - -(defbinary dns-message (:byte-order :big-endian :export t) - (header nil :type dns-header) - - ;; the question for the name server - (question #() :type (simple-array dns-question ((dns-header-qdcount header)))) - - ;; ;; RRs answering the question - ;; (answer #() :type (simple-array (unsigned-byte 8) (16))) - (answer #() :type (simple-array dns-rr ((dns-header-ancount header)))) - - ;; ;; ;; RRs pointing toward an authority - (authority #() :type (simple-array dns-rr ((dns-header-nscount header)))) - - ;; ;; RRs holding additional information - (additional #() :type (simple-array dns-rr ((dns-header-arcount header))))) diff --git a/lisp/dns/package.lisp b/lisp/dns/package.lisp deleted file mode 100644 index 2b8bfaa8b..000000000 --- a/lisp/dns/package.lisp +++ /dev/null @@ -1,11 +0,0 @@ -(defpackage #:dns - (:documentation "Simple DNS resolver in Common Lisp") - (:use #:cl #:iterate #:lisp-binary) - (:export - ;; Individual lookup functions - #:lookup-txt #:lookup-mx #:lookup-cname #:lookup-a #:lookup-ns - - ;; Useful accessors - #:dns-message-header #:dns-message-answer #:dns-message-question - #:dns-rr-name #:dns-rr-type #:dns-rr-ttl #:dns-rr-rdata - #:dns-question-qname #:dns-question-qtype)) diff --git a/lisp/klatre/OWNERS b/lisp/klatre/OWNERS deleted file mode 100644 index b381c4e66..000000000 --- a/lisp/klatre/OWNERS +++ /dev/null @@ -1 +0,0 @@ -aspen diff --git a/lisp/klatre/default.nix b/lisp/klatre/default.nix deleted file mode 100644 index 2c7bb6490..000000000 --- a/lisp/klatre/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ depot, ... }: - -depot.nix.buildLisp.library { - name = "klatre"; - - deps = with depot.third_party.lisp; [ - local-time - ]; - - srcs = [ - ./package.lisp - ./klatre.lisp - ]; -} diff --git a/lisp/klatre/klatre.lisp b/lisp/klatre/klatre.lisp deleted file mode 100644 index 79c725975..000000000 --- a/lisp/klatre/klatre.lisp +++ /dev/null @@ -1,119 +0,0 @@ -(in-package #:klatre) -(declaim (optimize (safety 3))) - -(defmacro comment (&rest _) - (declare (ignore _))) - -(defun posp (n) (> n 0)) - -;;; Sequence utilities - -(defun slice (vector start end) - (make-array (- end start) - :element-type (array-element-type vector) - :displaced-to vector - :displaced-index-offset start)) - -(defun chunk-vector (size vector &key start end sharedp) - (check-type size (integer 1)) - (loop - with slicer = (if sharedp #'slice #'subseq) - and low = (or start 0) - and high = (or end (length vector)) - for s from low below high by size - for e from (+ low size) by size - collect (funcall slicer vector s (min e high)))) - -(defun chunk-list/unbounded (size list) - (loop - for front = list then next - for next = (nthcdr size front) - collect (ldiff front next) - while next)) - -(defun chunk-list/bounded (size list upper-limit) - (loop - for front = list then next - for next = (nthcdr (min size upper-limit) front) - collect (ldiff front next) - do (decf upper-limit size) - while (and next (plusp upper-limit)))) - -(defun chunk-list (size list &key (start 0) end) - "Returns successive chunks of list of size SIZE, starting at START and ending -at END." - (declare (inline chunk-list/bounded chunk-list/unbounded)) - (check-type size (integer 1)) - (let ((list (nthcdr start list))) - (when list - (if end - (chunk-list/bounded size list (- end start)) - (chunk-list/unbounded size list))))) - -(defun mapconcat (func lst sep) - "Apply FUNC to each element of LST, and concat the results as strings, -separated by SEP." - (check-type lst cons) - (check-type sep (simple-array character (*))) - (let ((vs (make-array 0 - :element-type 'character - :fill-pointer 0 - :adjustable t)) - (lsep (length sep))) - (mapcar #'(lambda (str) - (let ((nstr (the (simple-array character (*)) - (funcall func str)))) - (dotimes (j (length nstr) j) - (vector-push-extend (char nstr (the fixnum j)) vs)) - (dotimes (k lsep k) - (vector-push-extend (char sep (the fixnum k)) vs)))) - lst) - vs)) - -;;; -;;; String handling -;;; - -(defparameter dottime-format - '((:year 4) #\- (:month 2) #\- (:day 2) - #\T - (:hour 2) #\· (:min 2)) - "`:LOCAL-TIME' format specifier for dottime") - -(defun format-dottime (timestamp &optional (offset 0)) - "Return TIMESTAMP formatted as dottime, with a specified offset or +00" - (check-type timestamp local-time:timestamp) - (concatenate 'string - (local-time:format-timestring nil timestamp - :format dottime-format - :timezone local-time:+utc-zone+) - (format-dottime-offset offset))) - -(defun format-dottime-offset (offset) - "Render OFFSET in hours in the format specified by dottime." - (check-type offset integer) - (concatenate 'string - ; render sign manually since format prints it after padding - (if (>= offset 0) "+" "-") - (format nil "~2,'0D" (abs offset)))) - -(comment - (format-dottime (local-time:now)) - (format-dottime (local-time:now) 2)) - -(defun try-parse-integer (str) - "Attempt to parse STR as an integer, returning nil if it is invalid." - (check-type str string) - (handler-case (parse-integer str) - (#+sbcl sb-int:simple-parse-error - #-sbcl parse-error (_) (declare (ignore _)) nil))) - -;;; -;;; Function utilities -;;; - -(defun partial (f &rest args) - "Return a function that calls F with ARGS prepended to any remaining - arguments" - (lambda (&rest more-args) - (apply f (append args more-args)))) diff --git a/lisp/klatre/package.lisp b/lisp/klatre/package.lisp deleted file mode 100644 index 41174bbb3..000000000 --- a/lisp/klatre/package.lisp +++ /dev/null @@ -1,16 +0,0 @@ -(defpackage #:klatre - (:documentation "Grab-bag utility library for Common Lisp") - (:use #:cl) - (:export - ;; Miscellanious utilities - #:comment #:posp - - ;; Sequence functions - #:chunk-list #:mapconcat - - ;; String handling - #:+dottime-format+ #:format-dottime - #:try-parse-integer #:format-dottime-offset - - ;; Function utilities - #:partial)) diff --git a/net/alcoholic_jwt/.gitignore b/net/alcoholic_jwt/.gitignore deleted file mode 100644 index 143b1ca01..000000000 --- a/net/alcoholic_jwt/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ - -/target/ -**/*.rs.bk -Cargo.lock diff --git a/net/alcoholic_jwt/Cargo.lock b/net/alcoholic_jwt/Cargo.lock deleted file mode 100644 index 4ca139e25..000000000 --- a/net/alcoholic_jwt/Cargo.lock +++ /dev/null @@ -1,196 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "alcoholic_jwt" -version = "4091.0.0" -dependencies = [ - "base64", - "openssl", - "serde", - "serde_derive", - "serde_json", -] - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "cc" -version = "1.0.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "libc" -version = "0.2.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl" -version = "0.10.59" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-sys" -version = "0.9.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "serde" -version = "1.0.192" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.192" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "syn" -version = "2.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" diff --git a/net/alcoholic_jwt/Cargo.toml b/net/alcoholic_jwt/Cargo.toml deleted file mode 100644 index b5135d14d..000000000 --- a/net/alcoholic_jwt/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "alcoholic_jwt" -description = "Library for validation of RS256 JWTs" -version = "4091.0.0" -authors = ["Vincent Ambo "] -keywords = ["jwt", "token", "jwks"] -categories = ["authentication"] -license = "GPL-3.0-or-later" -homepage = "https://code.tvl.fyi/about/net/alcoholic_jwt" -repository = "https://code.tvl.fyi/depot.git:/net/alcoholic_jwt.git" - -[dependencies] -base64 = "0.13" -openssl = "0.10" -serde = "1.0" -serde_derive = "1.0" -serde_json = "1.0" diff --git a/net/alcoholic_jwt/LICENSE b/net/alcoholic_jwt/LICENSE deleted file mode 100644 index 94a9ed024..000000000 --- a/net/alcoholic_jwt/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/net/alcoholic_jwt/README.md b/net/alcoholic_jwt/README.md deleted file mode 100644 index c6da0ab8d..000000000 --- a/net/alcoholic_jwt/README.md +++ /dev/null @@ -1,72 +0,0 @@ -alcoholic_jwt -============= - -This is a library for **validation** of **RS256** JWTs using keys from -a JWKS. Nothing more, nothing less. - -RS256 is the most commonly used asymmetric signature mechanism for -JWTs, encountered in for example [Google][]'s or [Aprila][]'s APIs. - -The name of the library stems from the potential side-effects of -trying to use the other Rust libraries that are made for similar -purposes. - -## Usage overview - -You are retrieving JWTs from some authentication provider that uses -`RS256` signatures and provides its public keys in [JWKS][] format. - -Example for a token that provides the key ID used for signing in the -[`kid` claim][]: - -```rust -extern crate alcoholic_jwt; - -use alcoholic_jwt::{JWKS, Validation, validate, token_kid}; - -// The function implied here would usually perform an HTTP-GET -// on the JWKS-URL for an authentication provider and deserialize -// the result into the `alcoholic_jwt::JWKS`-struct. -let jwks: JWKS = jwks_fetching_function(); - -let token: String = some_token_fetching_function(); - -// Several types of built-in validations are provided: -let validations = vec![ - Validation::Issuer("auth.test.aprila.no".into()), - Validation::SubjectPresent, -]; - -// If a JWKS contains multiple keys, the correct KID first -// needs to be fetched from the token headers. -let kid = token_kid(&token) - .expect("Failed to decode token headers") - .expect("No 'kid' claim present in token"); - -let jwk = jwks.find(&kid).expect("Specified key not found in set"); - -validate(token, jwk, validations).expect("Token validation has failed!"); -``` - -## Under the hood - -This library aims to only use trustworthy off-the-shelf components to -do the work. Cryptographic operations are provided by the `openssl` -crate, JSON-serialisation is provided by `serde_json`. - -## Contributing - -This project is developed in the [TVL monorepo][depot]. To work on it, -you can either use a local clone of the entire repository or clone -just the `alcoholic_jwt` subtree: - - https://code.tvl.fyi/depot.git:/net/alcoholic_jwt.git - -Please follow the TVL [contribution guidelines][contributing]. - -[Google]: https://www.google.com/ -[Aprila]: https://www.aprila.no/ -[JWKS]: https://tools.ietf.org/html/rfc7517 -[`kid` claim]: https://tools.ietf.org/html/rfc7515#section-4.1.4 -[depot]: https://code.tvl.fyi/ -[contributing]: https://code.tvl.fyi/about/docs/CONTRIBUTING.md diff --git a/net/alcoholic_jwt/default.nix b/net/alcoholic_jwt/default.nix deleted file mode 100644 index aa1df10c8..000000000 --- a/net/alcoholic_jwt/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ depot, pkgs, ... }: - -depot.third_party.naersk.buildPackage { - src = ./.; - buildInputs = with pkgs; [ - openssl - pkg-config - ]; -} diff --git a/net/alcoholic_jwt/src/lib.rs b/net/alcoholic_jwt/src/lib.rs deleted file mode 100644 index 4a3ece8af..000000000 --- a/net/alcoholic_jwt/src/lib.rs +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright (C) 2019-2022 The TVL Community -// -// alcoholic_jwt is free software: you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! Implements a library for for **validation** of **RS256** JWTs -//! using keys from a JWKS. Nothing more, nothing less. -//! -//! The name of the library stems from the potential side-effects of -//! trying to use the other Rust libraries that are made for similar -//! purposes. -//! -//! This library is specifically aimed at developers that consume -//! tokens from services which provide their RSA public keys in -//! [JWKS][] format. -//! -//! ## Usage example (token with `kid`-claim) -//! -//! ```rust -//! # extern crate serde_json; -//! extern crate alcoholic_jwt; -//! -//! use alcoholic_jwt::{JWKS, Validation, validate, token_kid}; -//! -//! # fn some_token_fetching_function() -> &'static str { -//! # "eyJraWQiOiI4ckRxOFB3MEZaY2FvWFdURVZRbzcrVGYyWXpTTDFmQnhOS1BDZWJhYWk0PSIsImFsZyI6IlJTMjU2IiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoLnRlc3QuYXByaWxhLm5vIiwiaWF0IjoxNTM2MDUwNjkzLCJleHAiOjE1MzYwNTQyOTMsInN1YiI6IjQyIiwiZXh0Ijoic21va2V0ZXN0IiwicHJ2IjoiYXJpc3RpIiwic2NwIjoicHJvY2VzcyJ9.gOLsv98109qLkmRK6Dn7WWRHLW7o8W78WZcWvFZoxPLzVO0qvRXXRLYc9h5chpfvcWreLZ4f1cOdvxv31_qnCRSQQPOeQ7r7hj_sPEDzhKjk-q2aoNHaGGJg1vabI--9EFkFsGQfoS7UbMMssS44dgR68XEnKtjn0Vys-Vzbvz_CBSCH6yQhRLik2SU2jR2L7BoFvh4LGZ6EKoQWzm8Z-CHXLGLUs4Hp5aPhF46dGzgAzwlPFW4t9G4DciX1uB4vv1XnfTc5wqJch6ltjKMde1GZwLR757a8dJSBcmGWze3UNE2YH_VLD7NCwH2kkqr3gh8rn7lWKG4AUIYPxsw9CB" -//! # } -//! -//! # fn jwks_fetching_function() -> JWKS { -//! # let jwks_json = "{\"keys\":[{\"kty\":\"RSA\",\"alg\":\"RS256\",\"use\":\"sig\",\"kid\":\"8rDq8Pw0FZcaoXWTEVQo7+Tf2YzSL1fBxNKPCebaai4=\",\"n\":\"l4UTgk1zr-8C8utt0E57DtBV6qqAPWzVRrIuQS2j0_hp2CviaNl5XzGRDnB8gwk0Hx95YOhJupAe6RNq5ok3fDdxL7DLvppJNRLz3Ag9CsmDLcbXgNEQys33fBJaPw1v3GcaFC4tisU5p-o1f5RfWwvwdBtdBfGiwT1GRvbc5sFx6M4iYjg9uv1lNKW60PqSJW4iDYrfqzZmB0zF1SJ0BL_rnQZ1Wi_UkFmNe9arM8W9tI9T3Ie59HITFuyVSTCt6qQEtSfa1e5PiBaVuV3qoFI2jPBiVZQ6LPGBWEDyz4QtrHLdECPPoTF30NN6TSVwwlRbCuUUrdNdXdjYe2dMFQ\",\"e\":\"DhaD5zC7mzaDvHO192wKT_9sfsVmdy8w8T8C9VG17_b1jG2srd3cmc6Ycw-0blDf53Wrpi9-KGZXKHX6_uIuJK249WhkP7N1SHrTJxO0sUJ8AhK482PLF09Qtu6cUfJqY1X1y1S2vACJZItU4Vjr3YAfiVGQXeA8frAf7Sm4O1CBStCyg6yCcIbGojII0jfh2vSB-GD9ok1F69Nmk-R-bClyqMCV_Oq-5a0gqClVS8pDyGYMgKTww2RHgZaFSUcG13KeLMQsG2UOB2OjSC8FkOXK00NBlAjU3d0Vv-IamaLIszO7FQBY3Oh0uxNOvIE9ofQyCOpB-xIK6V9CTTphxw\"}]}"; -//! # serde_json::from_str(jwks_json).unwrap() -//! # } -//! # -//! // The function implied here would usually perform an HTTP-GET -//! // on the JWKS-URL for an authentication provider and deserialize -//! // the result into the `alcoholic_jwt::JWKS`-struct. -//! let jwks: JWKS = jwks_fetching_function(); -//! -//! let token = some_token_fetching_function(); -//! -//! // Several types of built-in validations are provided: -//! let validations = vec![ -//! Validation::Issuer("auth.test.aprila.no".into()), -//! Validation::SubjectPresent, -//! ]; -//! -//! // If a JWKS contains multiple keys, the correct KID first -//! // needs to be fetched from the token headers. -//! let kid = token_kid(&token) -//! .expect("Failed to decode token headers") -//! .expect("No 'kid' claim present in token"); -//! -//! let jwk = jwks.find(&kid).expect("Specified key not found in set"); -//! -//! validate(token, jwk, validations).expect("Token validation has failed!"); -//! ``` -//! -//! [JWKS]: https://tools.ietf.org/html/rfc7517 - -#[macro_use] -extern crate serde_derive; - -extern crate base64; -extern crate openssl; -extern crate serde; -extern crate serde_json; - -use base64::{Config, DecodeError, URL_SAFE_NO_PAD}; -use openssl::bn::BigNum; -use openssl::error::ErrorStack; -use openssl::hash::MessageDigest; -use openssl::pkey::{PKey, Public}; -use openssl::rsa::Rsa; -use openssl::sign::Verifier; -use serde::de::DeserializeOwned; -use serde_json::Value; -use std::error::Error; -use std::fmt::{self, Display}; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -#[cfg(test)] -mod tests; - -/// URL-safe character set without padding that allows trailing bits, -/// which appear in some JWT implementations. -/// -/// Note: The functions on `base64::Config` are not marked `const`, -/// and the constructors are not exported, which is why this is -/// implemented as a function. -fn jwt_forgiving() -> Config { - URL_SAFE_NO_PAD.decode_allow_trailing_bits(true) -} - -/// JWT algorithm used. The only supported algorithm is currently -/// RS256. -#[derive(Clone, Deserialize, Debug)] -enum KeyAlgorithm { - RS256, -} - -/// Type of key contained in a JWT. The only supported key type is -/// currently RSA. -#[derive(Clone, Deserialize, Debug)] -enum KeyType { - RSA, -} - -/// Representation of a single JSON Web Key. See [RFC -/// 7517](https://tools.ietf.org/html/rfc7517#section-4). -#[allow(dead_code)] // kty & alg only constrain deserialisation, but aren't used -#[derive(Clone, Debug, Deserialize)] -pub struct JWK { - kty: KeyType, - alg: Option, - kid: Option, - - // Shared modulus - n: String, - - // Public key exponent - e: String, -} - -/// Representation of a set of JSON Web Keys. See [RFC -/// 7517](https://tools.ietf.org/html/rfc7517#section-5). -#[derive(Clone, Debug, Deserialize)] -pub struct JWKS { - // This is a vector instead of some kind of map-like structure - // because key IDs are in fact optional. - // - // Technically having multiple keys with the same KID would not - // violate the JWKS-definition either, but behaviour in that case - // is unspecified. - keys: Vec, -} - -impl JWKS { - /// Attempt to find a JWK by its key ID. - pub fn find(&self, kid: &str) -> Option<&JWK> { - self.keys.iter().find(|jwk| jwk.kid == Some(kid.into())) - } -} - -/// Representation of an undecoded JSON Web Token. See [RFC -/// 7519](https://tools.ietf.org/html/rfc7519). -struct JWT<'a>(&'a str); - -/// Representation of a decoded and validated JSON Web Token. -/// -/// Specific claim fields are only decoded internally in the library -/// for validation purposes, while it is generally up to the consumer -/// of the validated JWT what structure they would like to impose. -pub struct ValidJWT { - /// JOSE header of the JSON Web Token. Certain fields are - /// guaranteed to be present in this header, consult section 5 of - /// RFC7519 for more information. - pub headers: Value, - - /// Claims (i.e. primary data) contained in the JSON Web Token. - /// While there are several registered and recommended headers - /// (consult section 4.1 of RFC7519), the presence of no field is - /// guaranteed in these. - pub claims: Value, -} - -/// Possible token claim validations. This enumeration only covers -/// common use-cases, for other types of validations the user is -/// encouraged to inspect the claim set manually. -pub enum Validation { - /// Validate that the issuer ("iss") claim matches a specified - /// value. - Issuer(String), - - /// Validate that the audience ("aud") claim matches a specified - /// value. - Audience(String), - - /// Validate that a subject value is present. - SubjectPresent, - - /// Validate that the expiry time of the token ("exp"-claim) has - /// not yet been reached. - NotExpired, -} - -/// Possible results of a token validation. -#[derive(Debug)] -pub enum ValidationError { - /// Invalid number of token components (not a JWT?) - InvalidComponents, - - /// Token segments had invalid base64-encoding. - InvalidBase64(DecodeError), - - /// Decoding of the provided JWK failed. - InvalidJWK, - - /// Signature validation failed, i.e. because of a non-matching - /// public key. - InvalidSignature, - - /// An OpenSSL operation failed along the way at a point at which - /// a more specific error variant could not be constructed. - OpenSSL(ErrorStack), - - /// JSON decoding into a provided type failed. - JSON(serde_json::Error), - - /// One or more claim validations failed. This variant contains - /// human-readable validation errors. - InvalidClaims(Vec<&'static str>), -} - -impl Error for ValidationError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - ValidationError::InvalidBase64(e) => Some(e), - ValidationError::OpenSSL(e) => Some(e), - ValidationError::JSON(e) => Some(e), - ValidationError::InvalidComponents - | ValidationError::InvalidJWK - | ValidationError::InvalidSignature - | ValidationError::InvalidClaims(_) => None, - } - } -} - -impl Display for ValidationError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ValidationError::InvalidComponents => { - f.write_str("Invalid number of token components in JWT") - } - ValidationError::InvalidBase64(_) => f.write_str("Invalid Base64 encoding in JWT"), - ValidationError::InvalidJWK => f.write_str("JWK decoding failed"), - ValidationError::InvalidSignature => f.write_str("JWT signature validation failed"), - ValidationError::OpenSSL(e) => write!(f, "SSL error: {}", e), - ValidationError::JSON(e) => write!(f, "JSON error: {}", e), - ValidationError::InvalidClaims(errs) => { - write!(f, "Invalid claims: {}", errs.join(", ")) - } - } - } -} - -type JWTResult = Result; - -impl From for ValidationError { - fn from(err: ErrorStack) -> Self { - ValidationError::OpenSSL(err) - } -} - -impl From for ValidationError { - fn from(err: serde_json::Error) -> Self { - ValidationError::JSON(err) - } -} - -impl From for ValidationError { - fn from(err: DecodeError) -> Self { - ValidationError::InvalidBase64(err) - } -} - -/// Attempt to extract the `kid`-claim out of a JWT's header claims. -/// -/// This function is normally used when a token provider has multiple -/// public keys in rotation at the same time that could all still have -/// valid tokens issued under them. -/// -/// This is only safe if the key set containing the currently allowed -/// key IDs is fetched from a trusted source. -pub fn token_kid(token: &str) -> JWTResult> { - // Fetch the header component of the JWT by splitting it out and - // dismissing the rest. - let parts: Vec<&str> = token.splitn(2, '.').collect(); - if parts.len() != 2 { - return Err(ValidationError::InvalidComponents); - } - - // Decode only the first part of the token into a specialised - // representation: - #[derive(Deserialize)] - struct KidOnly { - kid: Option, - } - - let kid_only: KidOnly = deserialize_part(parts[0])?; - - Ok(kid_only.kid) -} - -/// Validate the signature of a JSON Web Token and optionally apply -/// claim validations. Signatures are always verified before claims, -/// and if a signature verification passes *all* claim validations are -/// run and returned. -/// -/// If validation succeeds a representation of the token is returned -/// that contains the header and claims as simple JSON values. -/// -/// It is the user's task to ensure that the correct JWK is passed in -/// for validation. -pub fn validate(token: &str, jwk: &JWK, validations: Vec) -> JWTResult { - let jwt = JWT(token); - let public_key = public_key_from_jwk(&jwk)?; - validate_jwt_signature(&jwt, public_key)?; - - // Split out all three parts of the JWT this time, deserialising - // the first and second as appropriate. - let parts: Vec<&str> = jwt.0.splitn(3, '.').collect(); - if parts.len() != 3 { - // This is unlikely considering that validation has already - // been performed at this point, but better safe than sorry. - return Err(ValidationError::InvalidComponents); - } - - // Perform claim validations before constructing the valid token: - let partial_claims = deserialize_part(parts[1])?; - validate_claims(partial_claims, validations)?; - - let headers = deserialize_part(parts[0])?; - let claims = deserialize_part(parts[1])?; - let valid_jwt = ValidJWT { headers, claims }; - - Ok(valid_jwt) -} - -// Internal implementation -// -// The functions in the following section are not part of the public -// API of this library. - -/// Decode a single key fragment (base64-url encoded integer) to an -/// OpenSSL BigNum. -fn decode_fragment(fragment: &str) -> JWTResult { - let bytes = base64::decode_config(fragment, jwt_forgiving()) - .map_err(|_| ValidationError::InvalidJWK)?; - - BigNum::from_slice(&bytes).map_err(Into::into) -} - -/// Decode an RSA public key from a JWK by constructing it directly -/// from the public RSA key fragments. -fn public_key_from_jwk(jwk: &JWK) -> JWTResult> { - let jwk_n = decode_fragment(&jwk.n)?; - let jwk_e = decode_fragment(&jwk.e)?; - Rsa::from_public_components(jwk_n, jwk_e).map_err(Into::into) -} - -/// Decode a base64-URL encoded string and deserialise the resulting -/// JSON. -fn deserialize_part(part: &str) -> JWTResult { - let json = base64::decode_config(part, jwt_forgiving())?; - serde_json::from_slice(&json).map_err(Into::into) -} - -/// Validate the signature on a JWT using a provided public key. -/// -/// A JWT is made up of three components (headers, claims, signature) -/// - only the first two are part of the signed data. -fn validate_jwt_signature(jwt: &JWT, key: Rsa) -> JWTResult<()> { - let key = PKey::from_rsa(key)?; - let mut verifier = Verifier::new(MessageDigest::sha256(), &key)?; - - // Split the token from the back to a maximum of two elements. - // There are technically three components using the same separator - // ('.'), but we are interested in the first two together and - // splitting them is unnecessary. - let token_parts: Vec<&str> = jwt.0.rsplitn(2, '.').collect(); - if token_parts.len() != 2 { - return Err(ValidationError::InvalidComponents); - } - - // Second element of the vector will be the signed payload. - let data = token_parts[1]; - - // First element of the vector will be the (encoded) signature. - let sig_b64 = token_parts[0]; - let sig = base64::decode_config(sig_b64, jwt_forgiving())?; - - // Verify signature by inserting the payload data and checking it - // against the decoded signature. - verifier.update(data.as_bytes())?; - - match verifier.verify(&sig)? { - true => Ok(()), - false => Err(ValidationError::InvalidSignature), - } -} - -/// Internal helper enum for PartialClaims that supports single or -/// multiple audiences -#[derive(Deserialize)] -#[serde(untagged)] -enum Audience { - Single(String), - Multi(Vec), -} - -/// Internal helper struct for claims that are relevant for claim -/// validations. -#[derive(Deserialize)] -struct PartialClaims { - aud: Option, - iss: Option, - sub: Option, - exp: Option, -} - -/// Apply a single validation to the claim set of a token. -fn apply_validation(claims: &PartialClaims, validation: Validation) -> Result<(), &'static str> { - match validation { - // Validate that an 'iss' claim is present and matches the - // supplied value. - Validation::Issuer(iss) => match claims.iss { - None => Err("'iss' claim is missing"), - Some(ref claim) => { - if *claim == iss { - Ok(()) - } else { - Err("'iss' claim does not match") - } - } - }, - - // Validate that an 'aud' claim is present and matches the - // supplied value. - Validation::Audience(aud) => match claims.aud { - None => Err("'aud' claim is missing"), - Some(Audience::Single(ref claim)) => { - if *claim == aud { - Ok(()) - } else { - Err("'aud' claim does not match") - } - } - Some(Audience::Multi(ref claims)) => { - if claims.contains(&aud) { - Ok(()) - } else { - Err("'aud' claim does not match") - } - } - }, - - Validation::SubjectPresent => match claims.sub { - Some(_) => Ok(()), - None => Err("'sub' claim is missing"), - }, - - Validation::NotExpired => match claims.exp { - None => Err("'exp' claim is missing"), - Some(exp) => { - // Determine the current timestamp in seconds since - // the UNIX epoch. - let now = SystemTime::now() - .duration_since(UNIX_EPOCH) - // this is an unrecoverable, critical error. There - // aren't many ways this can occur, other than - // system time being set into the far future or - // this library being used in some sort of future - // museum. - .expect("system time is likely incorrect"); - - // Convert the expiry time (which is also in epoch - // seconds) to a duration. - let exp_duration = Duration::from_secs(exp); - - // The token has not expired if the expiry duration is - // larger than (i.e. in the future from) the current - // time. - if exp_duration > now { - Ok(()) - } else { - Err("token has expired") - } - } - }, - } -} - -/// Apply all requested validations to a partial claim set. -fn validate_claims(claims: PartialClaims, validations: Vec) -> JWTResult<()> { - let validation_errors: Vec<_> = validations - .into_iter() - .map(|v| apply_validation(&claims, v)) - .filter_map(|result| match result { - Ok(_) => None, - Err(err) => Some(err), - }) - .collect(); - - if validation_errors.is_empty() { - Ok(()) - } else { - Err(ValidationError::InvalidClaims(validation_errors)) - } -} diff --git a/net/alcoholic_jwt/src/tests.rs b/net/alcoholic_jwt/src/tests.rs deleted file mode 100644 index c264bb5a1..000000000 --- a/net/alcoholic_jwt/src/tests.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (C) 2019-2022 The TVL Community -// -// alcoholic_jwt is free software: you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -use super::*; - -#[test] -fn test_fragment_decoding() { - let fragment = "ngRRjNbXgPW29oNtF0JgsyyfTwPyEL0u_X16s453X2AOc33XGFxVKLEQ7R_TiMenaKcr-tPifYqgps_deyi0XOr4I3SOdOMtAVKDZJCANe--CANOHZb-meIfjKhCHisvT90fm5Apd6qPRVsXsZ7A8pmClZHKM5fwZUkBv8NsPLm2Xy2sGOZIiwP_7z8m3j0abUzniPQsx2b3xcWimB9vRtshFHN1KgPUf1ALQ5xzLfJnlFkCxC7kmOxKC7_NpQ4kJR_DKzKFV_r3HxTqf-jddHcXIrrMcLQXCSyeLQtLaz7whQ4F-EfL42z4XgwPr4ji3sct2gWL13EqlbE5DDxLKQ"; - let bignum = decode_fragment(fragment).expect("Failed to decode fragment"); - - let expected = "19947781743618558124649689124245117083485690334420160711273532766920651190711502679542723943527557680293732686428091794139998732541701457212387600480039297092835433997837314251024513773285252960725418984381935183495143908023024822433135775773958512751261112853383693442999603704969543668619221464654540065497665889289271044207667765128672709218996183649696030570183970367596949687544839066873508106034650634722970893169823917299050098551447676778961773465887890052852528696684907153295689693676910831376066659456592813140662563597179711588277621736656871685099184755908108451080261403193680966083938080206832839445289"; - assert_eq!( - expected, - format!("{}", bignum), - "Decoded fragment should match " - ); -} - -#[test] -fn test_decode_find_jwks() { - let json = "{\"keys\":[{\"kty\":\"RSA\",\"alg\":\"RS256\",\"use\":\"sig\",\"kid\":\"mUjI\\/rIMLLtung35BKZfdbrqtlEAAYJ4JX\\/SKvnLxJc=\",\"n\":\"ngRRjNbXgPW29oNtF0JgsyyfTwPyEL0u_X16s453X2AOc33XGFxVKLEQ7R_TiMenaKcr-tPifYqgps_deyi0XOr4I3SOdOMtAVKDZJCANe--CANOHZb-meIfjKhCHisvT90fm5Apd6qPRVsXsZ7A8pmClZHKM5fwZUkBv8NsPLm2Xy2sGOZIiwP_7z8m3j0abUzniPQsx2b3xcWimB9vRtshFHN1KgPUf1ALQ5xzLfJnlFkCxC7kmOxKC7_NpQ4kJR_DKzKFV_r3HxTqf-jddHcXIrrMcLQXCSyeLQtLaz7whQ4F-EfL42z4XgwPr4ji3sct2gWL13EqlbE5DDxLKQ\",\"e\":\"GK7oLCDbNPAF59LhvyseqcG04hDnPs58qGYolr_HHmaR4lulWJ90ozx6e4Ut363yKG2p9vwvivR5UIC-aLPtqT2qr-OtjhBFzUFVaMGZ6mPCvMKk0AgMYdOHvWTgBSqQtNJTvl1yYLnhcWyoE2fLQhoEbY9qUyCBCEOScXOZRDpnmBtz5I8q5yYMV6a920J24T_IYbxHgkGcEU2SGg-b1cOMD7Rja7vCfV---CQ2pR4leQ0jufzudDoe7z3mziJm-Ihcdrz2Ujy5kPEMdz6R55prJ-ENKrkD_X4u5aSlSRaetwmHS3oAVkjr1JwUNbqnpM-kOqieqHEp8LUmez-Znw\"}]}"; - let jwks: JWKS = serde_json::from_str(json).expect("Failed to decode JWKS"); - let jwk = jwks - .find("mUjI/rIMLLtung35BKZfdbrqtlEAAYJ4JX/SKvnLxJc=") - .expect("Failed to find required JWK"); - - public_key_from_jwk(&jwk).expect("Failed to construct public key from JWK"); -} - -#[test] -fn test_token_kid() { - let jwt = "eyJraWQiOiI4ckRxOFB3MEZaY2FvWFdURVZRbzcrVGYyWXpTTDFmQnhOS1BDZWJhYWk0PSIsImFsZyI6IlJTMjU2IiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoLnRlc3QuYXByaWxhLm5vIiwiaWF0IjoxNTM2MDUwNjkzLCJleHAiOjE1MzYwNTQyOTMsInN1YiI6IjQyIiwiZXh0Ijoic21va2V0ZXN0IiwicHJ2IjoiYXJpc3RpIiwic2NwIjoicHJvY2VzcyJ9.gOLsv98109qLkmRK6Dn7WWRHLW7o8W78WZcWvFZoxPLzVO0qvRXXRLYc9h5chpfvcWreLZ4f1cOdvxv31_qnCRSQQPOeQ7r7hj_sPEDzhKjk-q2aoNHaGGJg1vabI--9EFkFsGQfoS7UbMMssS44dgR68XEnKtjn0Vys-Vzbvz_CBSCH6yQhRLik2SU2jR2L7BoFvh4LGZ6EKoQWzm8Z-CHXLGLUs4Hp5aPhF46dGzgAzwlPFW4t9G4DciX1uB4vv1XnfTc5wqJch6ltjKMde1GZwLR757a8dJSBcmGWze3UNE2YH_VLD7NCwH2kkqr3gh8rn7lWKG4AUIYPxsw9CB"; - - let kid = token_kid(&jwt).expect("Failed to extract token KID"); - assert_eq!( - Some("8rDq8Pw0FZcaoXWTEVQo7+Tf2YzSL1fBxNKPCebaai4=".into()), - kid, - "Extracted KID did not match expected KID" - ); -} - -#[test] -fn test_validate_jwt() { - let jwks_json = "{\"keys\":[{\"kty\":\"RSA\",\"alg\":\"RS256\",\"use\":\"sig\",\"kid\":\"8rDq8Pw0FZcaoXWTEVQo7+Tf2YzSL1fBxNKPCebaai4=\",\"n\":\"l4UTgk1zr-8C8utt0E57DtBV6qqAPWzVRrIuQS2j0_hp2CviaNl5XzGRDnB8gwk0Hx95YOhJupAe6RNq5ok3fDdxL7DLvppJNRLz3Ag9CsmDLcbXgNEQys33fBJaPw1v3GcaFC4tisU5p-o1f5RfWwvwdBtdBfGiwT1GRvbc5sFx6M4iYjg9uv1lNKW60PqSJW4iDYrfqzZmB0zF1SJ0BL_rnQZ1Wi_UkFmNe9arM8W9tI9T3Ie59HITFuyVSTCt6qQEtSfa1e5PiBaVuV3qoFI2jPBiVZQ6LPGBWEDyz4QtrHLdECPPoTF30NN6TSVwwlRbCuUUrdNdXdjYe2dMFQ\",\"e\":\"DhaD5zC7mzaDvHO192wKT_9sfsVmdy8w8T8C9VG17_b1jG2srd3cmc6Ycw-0blDf53Wrpi9-KGZXKHX6_uIuJK249WhkP7N1SHrTJxO0sUJ8AhK482PLF09Qtu6cUfJqY1X1y1S2vACJZItU4Vjr3YAfiVGQXeA8frAf7Sm4O1CBStCyg6yCcIbGojII0jfh2vSB-GD9ok1F69Nmk-R-bClyqMCV_Oq-5a0gqClVS8pDyGYMgKTww2RHgZaFSUcG13KeLMQsG2UOB2OjSC8FkOXK00NBlAjU3d0Vv-IamaLIszO7FQBY3Oh0uxNOvIE9ofQyCOpB-xIK6V9CTTphxw\"}]}"; - - let jwks: JWKS = serde_json::from_str(jwks_json).expect("Failed to decode JWKS"); - - let jwk = jwks - .find("8rDq8Pw0FZcaoXWTEVQo7+Tf2YzSL1fBxNKPCebaai4=") - .expect("Failed to find required JWK"); - - let pkey = public_key_from_jwk(&jwk).expect("Failed to construct public key"); - - let jwt = JWT("eyJraWQiOiI4ckRxOFB3MEZaY2FvWFdURVZRbzcrVGYyWXpTTDFmQnhOS1BDZWJhYWk0PSIsImFsZyI6IlJTMjU2IiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoLnRlc3QuYXByaWxhLm5vIiwiaWF0IjoxNTM2MDUwNjkzLCJleHAiOjE1MzYwNTQyOTMsInN1YiI6IjQyIiwiZXh0Ijoic21va2V0ZXN0IiwicHJ2IjoiYXJpc3RpIiwic2NwIjoicHJvY2VzcyJ9.gOLsv98109qLkmRK6Dn7WWRHLW7o8W78WZcWvFZoxPLzVO0qvRXXRLYc9h5chpfvcWreLZ4f1cOdvxv31_qnCRSQQPOeQ7r7hj_sPEDzhKjk-q2aoNHaGGJg1vabI--9EFkFsGQfoS7UbMMssS44dgR68XEnKtjn0Vys-Vzbvz_CBSCH6yQhRLik2SU2jR2L7BoFvh4LGZ6EKoQWzm8Z-CHXLGLUs4Hp5aPhF46dGzgAzwlPFW4t9G4DciX1uB4vv1XnfTc5wqJch6ltjKMde1GZwLR757a8dJSBcmGWze3UNE2YH_VLD7NCwH2kkqr3gh8rn7lWKG4AUIYPxsw9CB".into()); - - validate_jwt_signature(&jwt, pkey).expect("Validation failed unexpectedly"); -} diff --git a/net/crimp/.gitignore b/net/crimp/.gitignore deleted file mode 100644 index 693699042..000000000 --- a/net/crimp/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target -**/*.rs.bk -Cargo.lock diff --git a/net/crimp/Cargo.lock b/net/crimp/Cargo.lock deleted file mode 100644 index 74a5a2c47..000000000 --- a/net/crimp/Cargo.lock +++ /dev/null @@ -1,259 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "cc" -version = "1.0.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" - -[[package]] -name = "crimp" -version = "4087.0.0" -dependencies = [ - "curl", - "serde", - "serde_json", -] - -[[package]] -name = "curl" -version = "0.4.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "windows-sys", -] - -[[package]] -name = "curl-sys" -version = "0.4.72+curl-8.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys", -] - -[[package]] -name = "itoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libz-sys" -version = "1.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "proc-macro2" -version = "1.0.78" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "serde" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "socket2" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "syn" -version = "2.0.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" diff --git a/net/crimp/Cargo.toml b/net/crimp/Cargo.toml deleted file mode 100644 index 1e529cfad..000000000 --- a/net/crimp/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "crimp" -description = "Higher-level Rust API for cURL bindings" -version = "4087.0.0" -authors = ["Vincent Ambo "] -keywords = [ "http", "curl" ] -categories = [ "api-bindings" ] -license = "GPL-3.0-or-later" -homepage = "https://code.tvl.fyi/about/net/crimp" -repository = "https://code.tvl.fyi/depot.git:/net/crimp.git" - - -[features] -default = [ "json" ] -json = [ "serde", "serde_json"] - -[dependencies] -curl = "0.4" -serde = { version = "1.0", optional = true } -serde_json = { version = "1.0", optional = true } diff --git a/net/crimp/LICENSE b/net/crimp/LICENSE deleted file mode 100644 index 94a9ed024..000000000 --- a/net/crimp/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/net/crimp/README.md b/net/crimp/README.md deleted file mode 100644 index 65a9d4293..000000000 --- a/net/crimp/README.md +++ /dev/null @@ -1,26 +0,0 @@ -crimp -===== - -[![](https://img.shields.io/crates/v/crimp.svg)](https://crates.io/crates/crimp) -[![](https://docs.rs/crimp/badge.svg)](https://docs.rs/crimp) - -Crimp is an HTTP client interface on top of the [Rust bindings][] to -cURL. - -The documentation for this crate is primarily in the [module -documentation][] - -------- - -This project is developed in the [TVL monorepo][depot]. To work on it, -you can either use a local clone of the entire repository or clone -just the `crimp` subtree: - - https://code.tvl.fyi/depot.git:/net/crimp.git - -Please follow the TVL [contribution guidelines][contributing]. - -[Rust bindings]: https://docs.rs/curl -[module documentation]: https://docs.rs/crimp -[depot]: https://code.tvl.fyi/ -[contributing]: https://code.tvl.fyi/about/docs/CONTRIBUTING.md diff --git a/net/crimp/default.nix b/net/crimp/default.nix deleted file mode 100644 index aa1df10c8..000000000 --- a/net/crimp/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ depot, pkgs, ... }: - -depot.third_party.naersk.buildPackage { - src = ./.; - buildInputs = with pkgs; [ - openssl - pkg-config - ]; -} diff --git a/net/crimp/src/lib.rs b/net/crimp/src/lib.rs deleted file mode 100644 index 7dfd261ee..000000000 --- a/net/crimp/src/lib.rs +++ /dev/null @@ -1,546 +0,0 @@ -// crimp - Higher-level Rust cURL API -// -// Copyright (C) 2019 Vincent Ambo -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! # crimp -//! -//! This library provides a simplified API over the [cURL Rust -//! bindings][] that resemble that of higher-level libraries such as -//! [reqwest][]. All calls are synchronous. -//! -//! `crimp` is intended to be used in situations where HTTP client -//! functionality is desired without adding a significant number of -//! dependencies or sacrificing too much usability. -//! -//! Using `crimp` to make HTTP requests is done using a simple -//! builder-pattern style API. For example, to make a `GET`-request -//! and print the result to `stdout`: -//! -//! ```rust -//! use crimp::Request; -//! -//! let response = Request::get("http://httpbin.org/get") -//! .user_agent("crimp test suite") -//! .unwrap() -//! .send() -//! .unwrap() -//! .as_string() -//! .unwrap(); -//! -//! println!("Status: {}\nBody: {}", response.status, response.body); -//! # assert_eq!(response.status, 200); -//! ``` -//! -//! If a feature from the underlying cURL library is missing, the -//! `Request::raw` method can be used as an escape hatch to deal with -//! the handle directly. Should you find yourself doing this, please -//! [file an issue][]. -//! -//! `crimp` does not currently expose functionality for re-using a -//! cURL Easy handle, meaning that keep-alive of HTTP connections and -//! the like is not supported. -//! -//! ## Cargo features -//! -//! All optional features are enabled by default. -//! -//! * `json`: Adds `Request::json` and `Response::as_json` methods which can be used for convenient -//! serialisation of request/response bodies using `serde_json`. This feature adds a dependency on -//! the `serde` and `serde_json` crates. -//! -//! ## Initialisation -//! -//! It is recommended to call the underlying `curl::init` method -//! (re-exported as `crimp::init`) when launching your application to -//! initialise the cURL library. This is not required, but will -//! otherwise occur the first time a request is made. -//! -//! [cURL Rust bindings]: https://docs.rs/curl -//! [reqwest]: https://docs.rs/reqwest -//! [file an issue]: https://github.com/tazjin/crimp/issues - -extern crate curl; - -#[cfg(feature = "json")] -extern crate serde; -#[cfg(feature = "json")] -extern crate serde_json; - -pub use curl::init; - -use curl::easy::{Auth, Easy, Form, List, ReadError, Transfer, WriteError}; -use std::collections::HashMap; -use std::io::Write; -use std::path::Path; -use std::string::{FromUtf8Error, ToString}; -use std::time::Duration; - -#[cfg(feature = "json")] -use serde::de::DeserializeOwned; -#[cfg(feature = "json")] -use serde::Serialize; - -#[cfg(test)] -mod tests; - -/// HTTP method to use for the request. -enum Method { - Get, - Post, - Put, - Patch, - Delete, -} - -/// Certificate types for client-certificate key pairs. -pub enum CertType { - P12, - PEM, - DER, -} - -/// Builder structure for an HTTP request. -/// -/// This is the primary API-type in `crimp`. After creating a new -/// request its parameters are modified using the various builder -/// methods until it is consumed by `send()`. -pub struct Request<'a> { - url: &'a str, - method: Method, - handle: Easy, - headers: List, - body: Body<'a>, -} - -enum Body<'a> { - NoBody, - Form(Form), - - Bytes { - content_type: &'a str, - data: &'a [u8], - }, - - #[cfg(feature = "json")] - Json(Vec), -} - -/// HTTP responses structure containing response data and headers. -/// -/// By default the `send()` function of the `Request` structure will -/// return a `Response>`. Convenience helpers exist for -/// decoding a string via `Response::as_string` or to a -/// `serde`-compatible type with `Response::as_json` (if the -/// `json`-feature is enabled). -#[derive(Debug, PartialEq)] -pub struct Response { - /// HTTP status code of the response. - pub status: u32, - - /// HTTP headers returned from the remote. - pub headers: HashMap, - - /// Body data from the HTTP response. - pub body: T, -} - -impl<'a> Request<'a> { - /// Initiate an HTTP request with the given method and URL. - fn new(method: Method, url: &'a str) -> Self { - Request { - url, - method, - handle: Easy::new(), - headers: List::new(), - body: Body::NoBody, - } - } - - /// Initiate a GET request with the given URL. - pub fn get(url: &'a str) -> Self { - Request::new(Method::Get, url) - } - - /// Initiate a POST request with the given URL. - pub fn post(url: &'a str) -> Self { - Request::new(Method::Post, url) - } - - /// Initiate a PUT request with the given URL. - pub fn put(url: &'a str) -> Self { - Request::new(Method::Put, url) - } - - /// Initiate a PATCH request with the given URL. - pub fn patch(url: &'a str) -> Self { - Request::new(Method::Patch, url) - } - - /// Initiate a DELETE request with the given URL. - pub fn delete(url: &'a str) -> Self { - Request::new(Method::Delete, url) - } - - /// Add an HTTP header to a request. - pub fn header(mut self, k: &str, v: &str) -> Result { - self.headers.append(&format!("{}: {}", k, v))?; - Ok(self) - } - - /// Set the `User-Agent` for this request. By default this will be - /// set to cURL's standard user agent. - pub fn user_agent(mut self, agent: &str) -> Result { - self.handle.useragent(agent)?; - Ok(self) - } - - /// Set the `Authorization` header to a `Bearer` value with the - /// supplied token. - pub fn bearer_auth(mut self, token: &str) -> Result { - self.headers - .append(&format!("Authorization: Bearer {}", token))?; - Ok(self) - } - - /// Set the `Authorization` header to a basic authentication value - /// from the supplied username and password. - pub fn basic_auth(mut self, username: &str, password: &str) -> Result { - let mut auth = Auth::new(); - auth.basic(true); - self.handle.username(username)?; - self.handle.password(password)?; - self.handle.http_auth(&auth)?; - Ok(self) - } - - /// Configure a TLS client certificate on the request. - /// - /// Depending on whether the certificate file contains the private - /// key or not, calling `tls_client_key` may be required in - /// addition. - /// - /// Consult the documentation for the `ssl_cert` and `ssl_key` - /// functions in `curl::easy::Easy2` for details on supported - /// formats and defaults. - pub fn tls_client_cert>( - mut self, - cert_type: CertType, - cert: P, - ) -> Result { - self.handle.ssl_cert(cert)?; - self.handle.ssl_cert_type(match cert_type { - CertType::P12 => "P12", - CertType::PEM => "PEM", - CertType::DER => "DER", - })?; - - Ok(self) - } - - /// Configure a TLS client certificate key on the request. - /// - /// Note that this does **not** need to be called again for - /// PKCS12-encoded key pairs which are set via `tls_client_cert`. - /// - /// Currently only PEM-encoded key files are supported. - pub fn tls_client_key>(mut self, key: P) -> Result { - self.handle.ssl_key(key)?; - Ok(self) - } - - /// Configure an encryption password for a TLS client certificate - /// key on the request. - /// - /// This is required in case of an encrypted private key that - /// should be used. - pub fn tls_key_password(mut self, password: &str) -> Result { - self.handle.key_password(password)?; - Ok(self) - } - - /// Configure a timeout for the request after which the request - /// will be aborted. - pub fn timeout(mut self, timeout: Duration) -> Result { - self.handle.timeout(timeout)?; - Ok(self) - } - - /// Set custom configuration on the cURL `Easy` handle. - /// - /// This function can be considered an "escape-hatch" from the - /// high-level API which lets users access the internal - /// `curl::easy::Easy` handle and configure options on it - /// directly. - /// - /// ``` - /// # use crimp::Request; - /// let response = Request::get("https://httpbin.org/get") - /// .with_handle(|mut handle| handle.referer("Example-Referer")) - /// .unwrap() - /// .send() - /// .unwrap(); - /// # - /// # assert!(response.is_success()); - /// ``` - pub fn with_handle(mut self, function: F) -> Result - where - F: FnOnce(&mut Easy) -> Result<(), curl::Error>, - { - function(&mut self.handle)?; - Ok(self) - } - - /// Add a byte-array body to a request using the specified - /// `Content-Type`. - pub fn body(mut self, content_type: &'a str, data: &'a [u8]) -> Self { - self.body = Body::Bytes { data, content_type }; - self - } - - /// Add a form-encoded body to a request using the `curl::Form` - /// type. - /// - /// ```rust - /// # extern crate curl; - /// # extern crate serde_json; - /// # use crimp::*; - /// # use serde_json::{Value, json}; - /// use curl::easy::Form; - /// - /// let mut form = Form::new(); - /// form.part("some-name") - /// .contents("some-data".as_bytes()) - /// .add() - /// .unwrap(); - /// - /// let response = Request::post("https://httpbin.org/post") - /// .user_agent("crimp test suite") - /// .unwrap() - /// .form(form) - /// .send() - /// .unwrap(); - /// # - /// # assert_eq!(200, response.status, "form POST should succeed"); - /// # assert_eq!( - /// # response.as_json::().unwrap().body.get("form").unwrap(), - /// # &json!({"some-name": "some-data"}), - /// # "posted form data should match", - /// # ); - /// ``` - /// - /// See the documentation of `curl::easy::Form` for details on how - /// to construct a form body. - pub fn form(mut self, form: Form) -> Self { - self.body = Body::Form(form); - self - } - - /// Add a JSON-encoded body from a serializable type. - #[cfg(feature = "json")] - pub fn json(mut self, body: &T) -> Result { - let json = serde_json::to_vec(body)?; - self.body = Body::Json(json); - Ok(self) - } - - /// Send the HTTP request and return a response structure - /// containing the raw body. - pub fn send(mut self) -> Result>, curl::Error> { - // Configure request basics: - self.handle.url(self.url)?; - - match self.method { - Method::Get => self.handle.get(true)?, - Method::Post => self.handle.post(true)?, - Method::Put => self.handle.upload(true)?, - Method::Patch => self.handle.custom_request("PATCH")?, - Method::Delete => self.handle.custom_request("DELETE")?, - } - - // Create structures in which to store the response data: - let mut headers = HashMap::new(); - let mut body = vec![]; - - // Submit a form value to cURL if it is set and proceed - // pretending that there is no body, as the handling of this - // type of body happens under-the-hood. - if let Body::Form(form) = self.body { - self.handle.httppost(form)?; - self.body = Body::NoBody; - } - - // Optionally set content type if a body payload is configured - // and configure the expected body size (or form payload). - match self.body { - Body::Bytes { content_type, data } => { - match self.method { - Method::Put => self.handle.in_filesize(data.len() as u64)?, - // TODO(sterni): this may still be wrong for some request types? - _ => self.handle.post_field_size(data.len() as u64)?, - }; - - self.headers - .append(&format!("Content-Type: {}", content_type))?; - } - - #[cfg(feature = "json")] - Body::Json(ref data) => { - match self.method { - Method::Put => self.handle.in_filesize(data.len() as u64)?, - // TODO(sterni): this may still be wrong for some request types? - _ => self.handle.post_field_size(data.len() as u64)?, - }; - self.headers.append("Content-Type: application/json")?; - } - - // Do not set content-type header at all if there is no - // body, or if the form handler was invoked above. - _ => (), - }; - - // Configure headers on the request: - self.handle.http_headers(self.headers)?; - - { - // Take a scoped transfer from the Easy handle. This makes it - // possible to write data into the above local buffers without - // fighting the borrow-checker: - let mut transfer = self.handle.transfer(); - - // Write the payload if it exists: - match self.body { - Body::Bytes { data, .. } => chunked_read_function(&mut transfer, data)?, - - #[cfg(feature = "json")] - Body::Json(ref json) => chunked_read_function(&mut transfer, json)?, - - // Do nothing if there is no body or if the body is a - // form. - _ => (), - }; - - // Read one header per invocation. Request processing is - // terminated if any header is malformed: - transfer.header_function(|header| { - // Headers are expected to be valid UTF-8 data. If they - // are not, the conversion is lossy. - // - // Technically it is legal for HTTP requests to use - // different encodings, but we don't interface with such - // services for hygienic reasons. - let header = String::from_utf8_lossy(header); - let split = header.splitn(2, ':').collect::>(); - - // "Malformed" headers are skipped. In most cases this - // will only be the HTTP version statement. - if split.len() != 2 { - return true; - } - - headers.insert(split[0].trim().to_string(), split[1].trim().to_string()); - true - })?; - - // Read the body to the allocated buffer. - transfer.write_function(|data| { - let len = data.len(); - body.write_all(data) - .map(|_| len) - .map_err(|_| WriteError::Pause) - })?; - - transfer.perform()?; - } - - Ok(Response { - status: self.handle.response_code()?, - headers, - body, - }) - } -} - -/// Provide a data chunk potentially larger than cURL's initial write -/// buffer to the data reading callback by tracking the offset off -/// already written data. -/// -/// As we manually set the expected upload size, cURL will call the -/// read callback repeatedly until it has all the data it needs. -fn chunked_read_function<'easy, 'data>( - transfer: &mut Transfer<'easy, 'data>, - data: &'data [u8], -) -> Result<(), curl::Error> { - let mut data = data; - - transfer.read_function(move |mut into| { - let written = into.write(data).map_err(|_| ReadError::Abort)?; - - data = &data[written..]; - - Ok(written) - }) -} - -impl Response { - /// Check whether the status code of this HTTP response is a - /// success (i.e. in the 200-299 range). - pub fn is_success(&self) -> bool { - self.status >= 200 && self.status < 300 - } - - /// Check whether a request succeeded using `Request::is_success` - /// and let users provide a closure that creates a custom error - /// from the request if it did not. - /// - /// This function exists for convenience to avoid having to write - /// repetitive `if !response.is_success() { ... }` blocks. - pub fn error_for_status(self, closure: F) -> Result - where - F: FnOnce(Self) -> E, - { - if !self.is_success() { - return Err(closure(self)); - } - - Ok(self) - } -} - -impl Response> { - /// Attempt to parse the HTTP response body as a UTF-8 encoded - /// string. - pub fn as_string(self) -> Result, FromUtf8Error> { - let body = String::from_utf8(self.body)?; - - Ok(Response { - body, - status: self.status, - headers: self.headers, - }) - } - - /// Attempt to deserialize the HTTP response body from JSON. - #[cfg(feature = "json")] - pub fn as_json(self) -> Result, serde_json::Error> { - let deserialized = serde_json::from_slice(&self.body)?; - - Ok(Response { - body: deserialized, - status: self.status, - headers: self.headers, - }) - } -} diff --git a/net/crimp/src/tests.rs b/net/crimp/src/tests.rs deleted file mode 100644 index e8e9223ce..000000000 --- a/net/crimp/src/tests.rs +++ /dev/null @@ -1,185 +0,0 @@ -// All tests expect an httpbin instance to be available at -// `http://localhost:4662`. -// -// This is easily spun up using Docker by running: -// -// docker run --rm -p 4662:80 kennethreitz/httpbin - -use super::*; -use serde_json::{json, Value}; - -// These tests check whether the correct HTTP method is used in the -// requests. - -#[test] -fn test_http_get() { - let resp = Request::get("http://127.0.0.1:4662/get") - .send() - .expect("failed to send request"); - - assert!(resp.is_success(), "request should have succeeded"); -} - -#[test] -fn test_http_delete() { - let resp = Request::delete("http://127.0.0.1:4662/delete") - .send() - .expect("failed to send request"); - - assert_eq!(200, resp.status, "response status should be 200 OK"); -} - -#[test] -fn test_http_put() { - let resp = Request::put("http://127.0.0.1:4662/put") - .send() - .expect("failed to send request"); - - assert_eq!(200, resp.status, "response status should be 200 OK"); -} - -#[test] -fn test_http_patch() { - let resp = Request::patch("http://127.0.0.1:4662/patch") - .send() - .expect("failed to send request"); - - assert_eq!(200, resp.status, "response status should be 200 OK"); -} - -// These tests perform various requests with different body payloads -// and verify that those were received correctly by the remote side. - -#[test] -fn test_http_post() { - let body = "test body"; - let response = Request::post("http://127.0.0.1:4662/post") - .user_agent("crimp test suite") - .expect("failed to set user-agent") - .timeout(Duration::from_secs(5)) - .expect("failed to set request timeout") - .body("text/plain", &body.as_bytes()) - .send() - .expect("failed to send request") - .as_json::() - .expect("failed to deserialize response"); - - let data = response.body; - - assert_eq!(200, response.status, "response status should be 200 OK"); - - assert_eq!( - data.get("data").unwrap(), - &json!("test body"), - "test body should have been POSTed" - ); - - assert_eq!( - data.get("headers").unwrap().get("Content-Type").unwrap(), - &json!("text/plain"), - "Content-Type should be `text/plain`", - ); -} - -#[cfg(feature = "json")] -#[test] -fn test_http_post_json() { - let body = json!({ - "purpose": "testing!" - }); - - let response = Request::post("http://127.0.0.1:4662/post") - .user_agent("crimp test suite") - .expect("failed to set user-agent") - .timeout(Duration::from_secs(5)) - .expect("failed to set request timeout") - .json(&body) - .expect("request serialization failed") - .send() - .expect("failed to send request") - .as_json::() - .expect("failed to deserialize response"); - - let data = response.body; - - assert_eq!(200, response.status, "response status should be 200 OK"); - - assert_eq!( - data.get("json").unwrap(), - &body, - "test body should have been POSTed" - ); - - assert_eq!( - data.get("headers").unwrap().get("Content-Type").unwrap(), - &json!("application/json"), - "Content-Type should be `application/json`", - ); -} - -// Tests for different authentication methods that are supported -// out-of-the-box: - -#[test] -fn test_bearer_auth() { - let response = Request::get("http://127.0.0.1:4662/bearer") - .bearer_auth("some-token") - .expect("failed to set auth header") - .send() - .expect("failed to send request"); - - assert!(response.is_success(), "authorized request should succeed"); -} - -#[test] -fn test_basic_auth() { - let request = Request::get("http://127.0.0.1:4662/basic-auth/alan_watts/oneness"); - - let response = request - .basic_auth("alan_watts", "oneness") - .expect("failed to set auth header") - .send() - .expect("failed to send request"); - - assert!(response.is_success(), "authorized request should succeed"); -} - -#[test] -fn test_large_body() { - // By default cURL buffers seem to be 2^16 bytes in size. The test - // size is therefore 2^16+1. - const BODY_SIZE: usize = 65537; - - let resp = Request::post("http://127.0.0.1:4662/post") - .body("application/octet-stream", &[0; BODY_SIZE]) - .send() - .expect("sending request") - .as_json::() - .expect("JSON deserialisation"); - - // httpbin returns the uploaded data as a string in the `data` - // field. - let data = resp.body.get("data").unwrap().as_str().unwrap(); - - assert_eq!( - BODY_SIZE, - data.len(), - "uploaded data length should be correct" - ); -} - -// Tests for various other features. - -#[test] -fn test_error_for_status() { - let response = Request::get("http://127.0.0.1:4662/patch") - .send() - .expect("failed to send request") - .error_for_status(|resp| format!("Response error code: {}", resp.status)); - - assert_eq!( - Err("Response error code: 405".into()), - response, - "returned error should be converted into Result::Err" - ); -} diff --git a/net/stomp_erl/.gitignore b/net/stomp_erl/.gitignore deleted file mode 100644 index 8e46d5a07..000000000 --- a/net/stomp_erl/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -.eunit -deps -*.o -*.beam -*.plt -erl_crash.dump -ebin -rel/example_project -.concrete/DEV_MODE -.rebar diff --git a/net/stomp_erl/Makefile b/net/stomp_erl/Makefile deleted file mode 100644 index b3bc54673..000000000 --- a/net/stomp_erl/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -PROJECT = stomp -PROJECT_DESCRIPTION = STOMP client for Erlang -PROJECT_VERSION = 0.1.0 - -# Whitespace to be used when creating files from templates. -SP = 4 - -include erlang.mk diff --git a/net/stomp_erl/README.md b/net/stomp_erl/README.md deleted file mode 100644 index 21c95a11a..000000000 --- a/net/stomp_erl/README.md +++ /dev/null @@ -1,78 +0,0 @@ -STOMP on Erlang -=============== - -`stomp.erl` is a simple Erlang client for the [STOMP protocol][] in version 1.2. - -Currently only subscribing to queues is supported. - -It provides an application called `stomp` which takes configuration of the form: - -```erlang -[{stomp, #{host => "stomp-server.somedomain.sexy", % required - port => 61613, % optional - login => <<"someuser">>, % optional - passcode => <<"hunter2>>, % optional - }}]. -``` - -## Types - -The following types are used in `stomp.erl`, you can include them from -`stomp.hrl`: - -```erlang -%% Client ack modes, refer to the STOMP protocol documentation --type ack_mode() :: client | client_individual | auto. - -%% Subscriptions are enumerated from 0 --type sub_id() :: integer(). - -%% Message IDs (for acknowledgements) are simple strings. They are -%% extracted from the 'ack' field of the header in client or client-individual -%% mode, and from the 'message-id' field in auto mode. --type message_id() :: binary(). - -%% A STOMP message as received from a queue subscription --record(stomp_msg, { headers :: #{ binary() => binary() }, - body :: binary() }. --type stomp_msg() :: #stomp_msg{}. -``` - -Once the application starts it will register a process under the name -`stomp_worker` and expose the following API: - -## Subscribing to a queue - -```erlang -%% Subscribe to a destination, receive the subscription ID --spec subscribe(binary(), % Destination (e.g. <<"/queue/lizards">>) - ack_mode(), % Client-acknowledgement mode - -> {ok, sub_id()}. -``` - -This synchronous call subscribes to a message queue. The `stomp_worker` will -link itself to the caller and forward received messages as -`{msg, sub_id(), stomp_msg()}`. - -Depending on the acknowledgement mode specified on connecting, the subscriber -may have to acknowledge receival of messages. - -## Acknowledging messages - -```erlang -%% Acknowledge a message ID. -%% This is not required in auto mode. In client mode it will acknowledge the -%% received messages up to the ID specified. In client-individual mode every -%% single message has to be acknowledged. --spec ack(sub_id(), message_id()) -> ok. - -%% Explicitly "unacknowledge" a message --spec nack(sub_id(), message_id()) -> ok. -``` - -Both of these calls are asynchronous and will return immediately. Note that in -the case of the `stomp_worker` crashing before a message acknowledgement is -handled, the message *may* be delivered again. Your consumer needs to be able to -handle this. - -[STOMP protocol]: https://stomp.github.io/stomp-specification-1.2.html diff --git a/net/stomp_erl/include/stomp.hrl b/net/stomp_erl/include/stomp.hrl deleted file mode 100644 index 30c933b56..000000000 --- a/net/stomp_erl/include/stomp.hrl +++ /dev/null @@ -1,22 +0,0 @@ -%% Client ack modes, refer to the STOMP protocol documentation --type ack_mode() :: client | client_individual | auto. - -%% Subscriptions are enumerated from 0 --type sub_id() :: integer(). - -%% Message IDs (for acknowledgements) are simple strings. They are -%% extracted from the 'ack' field of the header in client or client-individual -%% mode, and from the 'message-id' field in auto mode. --type message_id() :: binary(). - -%% A destination can be a queue, or something else. -%% Example: <<"/queue/lizards">> --type destination() :: binary(). - -%% A STOMP message as received from a queue subscription --record(stomp_msg, { headers :: #{ binary() => binary() }, - body :: binary() }). --type stomp_msg() :: #stomp_msg{}. - -%% STOMP frame components --type headers() :: #{binary() => binary()}. diff --git a/net/stomp_erl/src/stomp.app.src b/net/stomp_erl/src/stomp.app.src deleted file mode 100644 index baf0e271d..000000000 --- a/net/stomp_erl/src/stomp.app.src +++ /dev/null @@ -1,7 +0,0 @@ -{application, stomp, [{description, "STOMP client for Erlang"}, - {vsn, "0.1.0"}, - {modules, [stomp_app, stomp_sup, stomp_worker]}, - {registered, [stomp_worker]}, - {env, []}, - {applications, [kernel, stdlib]}, - {mod, {stomp_app, []}}]}. diff --git a/net/stomp_erl/src/stomp_app.erl b/net/stomp_erl/src/stomp_app.erl deleted file mode 100644 index 2ba3e69f9..000000000 --- a/net/stomp_erl/src/stomp_app.erl +++ /dev/null @@ -1,11 +0,0 @@ --module(stomp_app). --behaviour(application). - --export([start/2]). --export([stop/1]). - -start(_Type, _Args) -> - stomp_sup:start_link(). - -stop(_State) -> - ok. diff --git a/net/stomp_erl/src/stomp_sup.erl b/net/stomp_erl/src/stomp_sup.erl deleted file mode 100644 index 3a298bc9b..000000000 --- a/net/stomp_erl/src/stomp_sup.erl +++ /dev/null @@ -1,22 +0,0 @@ --module(stomp_sup). --behaviour(supervisor). - --export([start_link/0]). --export([init/1]). - -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -init([]) -> - Procs = [stomp_spec()], - {ok, {{one_for_one, 1, 5}, Procs}}. - -%% Private - -stomp_spec() -> - #{id => stomp_proc, - start => {stomp_worker, start_link, []}, - restart => permanent, - shutdown => 5000, - type => worker, - module => [stomp_worker]}. diff --git a/net/stomp_erl/src/stomp_worker.erl b/net/stomp_erl/src/stomp_worker.erl deleted file mode 100644 index 80981d37a..000000000 --- a/net/stomp_erl/src/stomp_worker.erl +++ /dev/null @@ -1,193 +0,0 @@ --module(stomp_worker). --behaviour(gen_server). - -%% API. --export([start_link/0]). - -%% gen_server. --export([init/1]). --export([handle_call/3]). --export([handle_cast/2]). --export([handle_info/2]). --export([terminate/2]). --export([code_change/3]). - -%% Testing --compile(export_all). - --include("stomp.hrl"). - -%% State of a stomp_worker --record(state, {connection :: port(), - next_sub :: sub_id(), - subscriptions :: #{ destination() => sub_id() }, - subscribers :: #{ destination() => pid() } - }). --type state() :: #state{}. - -%% API implementation - --spec start_link() -> {ok, pid()}. -start_link() -> - {ok, Pid} = gen_server:start_link(?MODULE, [], []), - register(?MODULE, Pid), - {ok, Pid}. - -%% gen_server implementation - --spec init(any()) -> {ok, state()}. -init(_Args) -> - %% Fetch configuration from app config - {ok, Host} = application:get_env(stomp, host), - Port = application:get_env(stomp, port, 61613), - Login = application:get_env(stomp, login), - Pass = application:get_env(stomp, passcode), - - %% Catch exit signals from linked processes (subscribers dying) - process_flag(trap_exit, true), - - %% Establish connection - {ok, Conn} = connect(Host, Port, Login, Pass), - - {ok, #state{connection = Conn, - next_sub = 0, - subscriptions = #{}, - subscribers = #{}}}. - -%% Handle subscription calls -handle_call({subscribe, Dest, Ack}, From, State) -> - %% Subscribe to new destination - SubId = State#state.next_sub, - ok = subscribe(State#state.connection, SubId, Dest, Ack), - - %% Add subscription and subscriber to state - Subscriptions = maps:put(SubId, Dest, State#state.subscriptions), - Subscribers = maps:put(SubId, From, State#state.subscribers), - NextSub = SubId + 1, - NewState = State#state{subscriptions = Subscriptions, - subscribers = Subscribers, - next_sub = NextSub }, - - {reply, {ok, SubId}, NewState}; -handle_call(_Req, _From, State) -> - {reply, ignored, State}. - -handle_info({tcp, Conn, Frame}, State) when Conn =:= State#state.connection -> - handle_frame(Frame, State); -handle_info(_Msg, State) -> - {noreply, State}. - -%% Unused gen_server callbacks - -handle_cast(_Msg, State) -> - {noreply, State}. - -terminate(_Reason, _State) -> - ok. - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -%% Private functions - --spec connect(list(), integer(), any(), any()) -> {ok, port()}. -connect(Host, Port, Login, Pass) -> - %% STOMP CONNECT frame - Connect = connect_frame(Host, Login, Pass), - - %% TODO: Configurable buffer size - %% Frames larger than the user-level buffer will be truncated, so it should - %% never be smaller than the largest expected messages. - {ok, Socket} = gen_tcp:connect(Host, Port, [binary, - {packet, line}, - {line_delimiter, $\0}, - {buffer, 262144}]), - - ok = gen_tcp:send(Socket, Connect), - {ok, Socket}. - --spec subscribe(port(), sub_id(), destination(), ack_mode()) -> ok. -subscribe(Socket, Id, Queue, Ack) -> - {ok, SubscribeFrame} = subscribe_frame(Id, Queue, Ack), - gen_tcp:send(Socket, SubscribeFrame). - -%%% Parsing STOMP frames - -handle_frame(<<"MESSAGE", "\n", _Frame/binary>>, State) -> - {noreply, State}; -handle_frame(Frame, State) -> - io:format("Received unknown frame ~p", [Frame]), - {noreply, State}. - - -%% Parse out headers into a map --spec parse_headers(binary()) -> headers(). -parse_headers(HeadersBin) -> - Headers = binary:split(HeadersBin, <<"\n">>, [global]), - ToPairs = fun(H, M) -> [K,V | []] = binary:split(H, <<":">>), - maps:put(K, V, M) - end, - {ok, lists:mapfoldl(ToPairs, #{}, Headers)}. - -%%% Making STOMP protocol frames - -%% Format a header --spec format_header({binary(), binary()}) -> binary(). -format_header({Key, Val}) -> - <>. - -%% Build a single STOMP frame --spec make_frame(binary(), - headers(), - binary()) - -> {ok, iolist()}. -make_frame(Command, HeaderMap, Body) -> - Headers = lists:map(fun format_header/1, maps:to_list(HeaderMap)), - Frame = [Command, <<"\n">>, Headers, <<"\n">>, Body, <<0>>], - {ok, Frame}. - -%%% Default frames - --spec connect_frame(list(), any(), any()) -> iolist(). -connect_frame(Host, {ok, Login}, {ok, Pass}) -> - make_frame(<<"CONNECT">>, - #{<<"accept-version">> => <<"1.2">>, - <<"host">> => Host, - <<"login">> => Login, - <<"passcode">> => Pass, - <<"heart-beat">> => <<"0,5000">>}, - []); -connect_frame(Host, _Login, _Pass) -> - make_frame(<<"CONNECT">>, - #{<<"accept-version">> => <<"1.2">>, - <<"host">> => Host, - %% Expect a server heartbeat every 5 seconds, let the server - %% expect one every 10. We don't actually check this and just - %% echo server heartbeats. - %% TODO: For now the server is told not to expect replies due to - %% a weird behaviour. - <<"heart-beat">> => <<"0,5000">>}, - []). - - --spec subscribe_frame(sub_id(), destination(), ack_mode()) -> iolist(). -subscribe_frame(Id, Queue, Ack) -> - make_frame(<<"SUBSCRIBE">>, - #{<<"id">> => integer_to_binary(Id), - <<"destination">> => Queue, - <<"ack">> => ack_mode_to_binary(Ack)}, - []). - --spec ack_mode_to_binary(ack_mode()) -> binary(). -ack_mode_to_binary(AckMode) -> - case AckMode of - auto -> <<"auto">>; - client -> <<"client">>; - client_individual -> <<"client-individual">> - end. - -%% -spec ack_frame(binary()) -> iolist(). -%% ack_frame(MessageID) -> -%% make_frame(<<"ACK">>, -%% [{"id", MessageID}], -%% []). diff --git a/nix/OWNERS b/nix/OWNERS index a64022791..557709b72 100644 --- a/nix/OWNERS +++ b/nix/OWNERS @@ -1 +1 @@ -Profpatsch +raitobezarius diff --git a/nix/buildLisp/README.md b/nix/buildLisp/README.md deleted file mode 100644 index 0d1e46983..000000000 --- a/nix/buildLisp/README.md +++ /dev/null @@ -1,254 +0,0 @@ -buildLisp.nix -============= - -This is a build system for Common Lisp, written in Nix. - -It aims to offer an alternative to ASDF for users who live in a -Nix-based ecosystem. This offers several advantages over ASDF: - -* Simpler (almost logic-less) package definitions -* Easy linking of native dependencies (from Nix) -* Composability with Nix tooling for other languages -* Effective, per-system caching strategies -* Easy overriding of dependencies and whatnot -* Convenient support for multiple Common Lisp implementations -* ... and more! - -The project is still in its early stages and some important -restrictions should be highlighted: - -* Extending `buildLisp` with support for a custom implementation - currently requires some knowledge of internals and may not be - considered stable yet. -* Parallel compilation is not possible: Since buildLisp doesn't encode - dependencies between components (i. e. source files) like ASDF, - it must compile source files in sequence to avoid errors due to - undefined symbols. - -## Usage - -`buildLisp` exposes four different functions: - -* `buildLisp.library`: Builds a collection of Lisp files into a library. - - | parameter | type | use | required? | - |-----------|--------------|-------------------------------|-----------| - | `name` | `string` | Name of the library | yes | - | `srcs` | `list` | List of paths to source files | yes | - | `deps` | `list` | List of dependencies | no | - | `native` | `list` | List of native dependencies | no | - | `test` | see "Tests" | Specification for test suite | no | - | `implementation` | see "Implementations" | Common Lisp implementation to use | no | - - The output of invoking this is a directory containing a FASL file - that is the concatenated result of all compiled sources. - -* `buildLisp.program`: Builds an executable program out of Lisp files. - - | parameter | type | use | required? | - |-----------|--------------|-------------------------------|-----------| - | `name` | `string` | Name of the program | yes | - | `srcs` | `list` | List of paths to source files | yes | - | `deps` | `list` | List of dependencies | no | - | `native` | `list` | List of native dependencies | no | - | `main` | `string` | Entrypoint function | no | - | `test` | see "Tests" | Specification for test suite | no | - | `implementation` | see "Implementations" | Common Lisp implementation to use | no | - - The `main` parameter should be the name of a function and defaults - to `${name}:main` (i.e. the *exported* `main` function of the - package named after the program). - - The output of invoking this is a directory containing a - `bin/${name}`. - -* `buildLisp.bundled`: Creates a virtual dependency on a built-in library. - - Certain libraries ship with Lisp implementations, for example - UIOP/ASDF are commonly included but many implementations also ship - internals (such as SBCLs various `sb-*` libraries). - - This function takes a single string argument that is the name of a - built-in library and returns a "package" that simply requires this - library. - -## Tests - -Both `buildLisp.library` and `buildLisp.program` take an optional argument -`tests`, which has the following supported fields: - - | parameter | type | use | required? | - |--------------|--------------|-------------------------------|-----------| - | `name` | `string` | Name of the test suite | no | - | `expression` | `string` | Lisp expression to run tests | yes | - | `srcs` | `list` | List of paths to source files | no | - | `native` | `list` | List of native dependencies | no | - -the `expression` parameter should be a Lisp expression and will be evaluated -after loading all sources and dependencies (including library/program -dependencies). It must return a non-`NIL` value if the test suite has passed. - -## Example - -Using buildLisp could look like this: - -```nix -{ buildLisp, lispPkgs }: - -let libExample = buildLisp.library { - name = "lib-example"; - srcs = [ ./lib.lisp ]; - - deps = with lispPkgs; [ - (buildLisp.bundled "sb-posix") - iterate - cl-ppcre - ]; -}; -in buildLisp.program { - name = "example"; - deps = [ libExample ]; - srcs = [ ./main.lisp ]; - tests = { - deps = [ lispPkgs.fiveam ]; - srcs = [ ./tests.lisp ]; - expression = "(fiveam:run!)"; - }; -} -``` - -## Development REPLs - -`buildLisp` builds loadable variants of both `program` and `library` derivations -(usually FASL files). Therefore it can provide a convenient way to obtain an -instance of any implementation preloaded with `buildLisp`-derivations. This -is especially useful to use as a host for Sly or SLIME. - -* `buildLisp.sbcl.lispWith`, `buildLisp.ccl.lispWith`, ...: - Creates a wrapper script preloading a Lisp implementation with various dependencies. - - This function takes a single argument which is a list of Lisp - libraries programs or programs. The desired Lisp implementation - will load all given derivations and all their dependencies on - startup. - - The shortcut `buildLisp.sbclWith` for `buildLisp.sbcl.lispWith` is also provided. - -* `repl` passthru attribute: `derivation.repl` is provided as a shortcut - for `buildLisp.${implementationName}.lispWith [ derivation ]`. - `derivation.ccl.repl`, `derivation.sbcl.repl` etc. work as well, of course - (see also "Implementations" section). - -## Implementations - -Both `buildLisp.library` and `buildLisp.program` allow specifying a different -Common Lisp implementation than the default one (which is SBCL). When an -implementation is passed, `buildLisp` makes sure all dependencies are built -with that implementation as well since build artifacts from different -implementation will be incompatible with each other. - -The argument taken by `implementation` is a special attribute set which -describes how to do certain tasks for a given implementation, like building -or loading a library. In case you want to use a custom implementation -description, the precise structure needed is documented in `buildLisp`'s -source code for now. `buildLisp` also exposes the following already -working implementation sets: - -* `buildLisp.sbcl`: [SBCL][sbcl], our default implementation - -* `buildLisp.ccl`: [CCL][ccl], similar to SBCL, but with very good macOS support - -* `buildLisp.ecl`: [ECL][ecl] setup to produce statically linked binaries and - libraries. Note that its runtime library is LGPL, so [extra conditions][lgpl-static] - must be fulfilled when distributing binaries produced this way. - -* Support for ABCL is planned. - -For every of these “known” implementations, `buildLisp` will create a `passthru` -attribute named like the implementation which points to a variant of the derivation -built with said implementation. Say we have a derivation, `myDrv`, built using SBCL: -While `myDrv` and `myDrv.sbcl` are built using SBCL, `myDrv.ecl`, `myDrv.ccl` etc. -build the derivation and all its dependencies using ECL and CCL respectively. - -This is useful to test portability of your derivation, but is also used internally -to speed up the “normalization” of the dependency graph. Thus it is important to -make sure that your custom implementation's name doesn't clash with one of the -“known” ones. - -## Handling Implementation Specifics - -When targeting multiple Common Lisp implementation, it is often necessary to -handle differing interfaces for OS interaction or to make use of special -implementation features. For this reason, `buildLisp` allows specifying -dependencies and source files for specific implementations only. This can -be utilized by having an attribute set in the list for the `deps` or `srcs` -argument: `buildLisp` will pick the value of the attribute named like the -used implementation or `default` and ignore the set completely if both -are missing. - -```nix -{ buildLisp, lispPkgs }: - -buildLisp.library { - name = "mylib"; - - srcs = [ - # These are included always of course - ./package.lisp - ./portable-lib.lisp - - # Choose right impl-* file - { - sbcl = ./impl-sbcl.lisp; - ccl = ./impl-ccl.lisp; - ecl = ./impl-ecl.lisp; - } - - # We can also use this to inject extra files - { ecl = ./extra-ecl-optimizations.lisp; } - ]; - - deps = [ - # Use SBCL's special bundled package, flexi-streams otherwise - { - sbcl = buildLisp.bundled "sb-rotate-byte"; - default = lispPkgs.flexi-streams; - } - ]; -} -``` - -Additionally a `brokenOn` parameter is accepted which takes a list of -implementation names on which the derivation is not expected to work. -This only influences `meta.ci.targets` which is read by depot's CI to -check which variants (see "Implementations") of the derivation to -build, so it may not be useful outside of depot. - -## Influencing the Lisp Runtime - -Lisp implementations which create an executable by dumping an image -usually parse a few implementation-specific command line options on -executable startup that influence runtime settings related to things -like GC. `buildLisp` generates a wrapper which makes sure that this -never interferes with the argument parsing implemented in the actual -application, but sometimes it is useful to run an executable with -special settings. To allow this, the content of `NIX_BUILDLISP_LISP_ARGS` -is passed to the lisp implementation. - -For example, you can make the underlying SBCL print its version for -any executable built with `buildLisp` (and SBCL) like this: - -```console -$ env NIX_BUILDLISP_LISP_ARGS="--version" ./result/bin/🕰️ -SBCL 2.1.2.nixos -``` - -In practice you'd probably want to specify options like -`--dynamic-space-size` or `--tls-limit` (try passing `--help` for a -full list). Naturally, these options are completely different for -different implementations. - -[sbcl]: http://www.sbcl.org/ -[ccl]: https://ccl.clozure.com/ -[ecl]: https://common-lisp.net/project/ecl/ -[lgpl-static]: https://www.gnu.org/licenses/gpl-faq.en.html#LGPLStaticVsDynamic diff --git a/nix/buildLisp/default.nix b/nix/buildLisp/default.nix deleted file mode 100644 index 0d68a2818..000000000 --- a/nix/buildLisp/default.nix +++ /dev/null @@ -1,778 +0,0 @@ -# buildLisp provides Nix functions to build Common Lisp packages, -# targeting SBCL. -# -# buildLisp is designed to enforce conventions and do away with the -# free-for-all of existing Lisp build systems. - -{ pkgs ? import { }, ... }: - -let - inherit (builtins) map elemAt match filter; - inherit (pkgs) lib runCommand makeWrapper writeText writeShellScriptBin sbcl ecl-static ccl; - inherit (pkgs.stdenv) targetPlatform; - - # - # Internal helper definitions - # - - defaultImplementation = impls.sbcl; - - # Many Common Lisp implementations (like ECL and CCL) will occasionally drop - # you into an interactive debugger even when executing something as a script. - # In nix builds we don't want such a situation: Any error should make the - # script exit non-zero. Luckily the ANSI standard specifies *debugger-hook* - # which is invoked before the debugger letting us just do that. - disableDebugger = writeText "disable-debugger.lisp" '' - (setf *debugger-hook* - (lambda (error hook) - (declare (ignore hook)) - (format *error-output* "~%Unhandled error: ~a~%" error) - #+ccl (quit 1) - #+ecl (ext:quit 1))) - ''; - - # Process a list of arbitrary values which also contains “implementation - # filter sets” which describe conditonal inclusion of elements depending - # on the CL implementation used. Elements are processed in the following - # manner: - # - # * Paths, strings, derivations are left as is - # * A non-derivation attribute set is processed like this: - # 1. If it has an attribute equal to impl.name, replace with its value. - # 2. Alternatively use the value of the "default" attribute. - # 3. In all other cases delete the element from the list. - # - # This can be used to express dependencies or source files which are specific - # to certain implementations: - # - # srcs = [ - # # mixable with unconditional entries - # ./package.lisp - # - # # implementation specific source files - # { - # ccl = ./impl-ccl.lisp; - # sbcl = ./impl-sbcl.lisp; - # ecl = ./impl-ecl.lisp; - # } - # ]; - # - # deps = [ - # # this dependency is ignored if impl.name != "sbcl" - # { sbcl = buildLisp.bundled "sb-posix"; } - # - # # only special casing for a single implementation - # { - # sbcl = buildLisp.bundled "uiop"; - # default = buildLisp.bundled "asdf"; - # } - # ]; - implFilter = impl: xs: - let - isFilterSet = x: builtins.isAttrs x && !(lib.isDerivation x); - in - builtins.map - ( - x: if isFilterSet x then x.${impl.name} or x.default else x - ) - (builtins.filter - ( - x: !(isFilterSet x) || x ? ${impl.name} || x ? default - ) - xs); - - # Generates lisp code which instructs the given lisp implementation to load - # all the given dependencies. - genLoadLispGeneric = impl: deps: - lib.concatStringsSep "\n" - (map (lib: "(load \"${lib}/${lib.lispName}.${impl.faslExt}\")") - (allDeps impl deps)); - - # 'genTestLispGeneric' generates a Lisp file that loads all sources and deps - # and executes expression for a given implementation description. - genTestLispGeneric = impl: { name, srcs, deps, expression }: writeText "${name}.lisp" '' - ;; Dependencies - ${impl.genLoadLisp deps} - - ;; Sources - ${lib.concatStringsSep "\n" (map (src: "(load \"${src}\")") srcs)} - - ;; Test expression - (unless ${expression} - (exit :code 1)) - ''; - - # 'dependsOn' determines whether Lisp library 'b' depends on 'a'. - dependsOn = a: b: builtins.elem a b.lispDeps; - - # 'allDeps' flattens the list of dependencies (and their - # dependencies) into one ordered list of unique deps which - # all use the given implementation. - allDeps = impl: deps: - let - # The override _should_ propagate itself recursively, as every derivation - # would only expose its actually used dependencies. Use implementation - # attribute created by withExtras if present, override in all other cases - # (mainly bundled). - deps' = builtins.map - (dep: dep."${impl.name}" or (dep.overrideLisp (_: { - implementation = impl; - }))) - deps; - in - (lib.toposort dependsOn (lib.unique ( - lib.flatten (deps' ++ (map (d: d.lispDeps) deps')) - ))).result; - - # 'allNative' extracts all native dependencies of a dependency list - # to ensure that library load paths are set correctly during all - # compilations and program assembly. - allNative = native: deps: lib.unique ( - lib.flatten (native ++ (map (d: d.lispNativeDeps) deps)) - ); - - # Add an `overrideLisp` attribute to a function result that works - # similar to `overrideAttrs`, but is used specifically for the - # arguments passed to Lisp builders. - makeOverridable = f: orig: (f orig) // { - overrideLisp = new: makeOverridable f (orig // (new orig)); - }; - - # This is a wrapper arround 'makeOverridable' which performs its - # function, but also adds a the following additional attributes to the - # resulting derivation, namely a repl attribute which builds a `lispWith` - # derivation for the current implementation and additional attributes for - # every all implementations. So `drv.sbcl` would build the derivation - # with SBCL regardless of what was specified in the initial arguments. - withExtras = f: args: - let - drv = (makeOverridable f) args; - in - lib.fix (self: - drv.overrideLisp - (old: - let - implementation = old.implementation or defaultImplementation; - brokenOn = old.brokenOn or [ ]; - targets = lib.subtractLists (brokenOn ++ [ implementation.name ]) - (builtins.attrNames impls); - in - { - passthru = (old.passthru or { }) // { - repl = implementation.lispWith [ self ]; - - # meta is done via passthru to minimize rebuilds caused by overriding - meta = (old.passthru.meta or { }) // { - ci = (old.passthru.meta.ci or { }) // { - inherit targets; - }; - }; - } // builtins.listToAttrs (builtins.map - (impl: { - inherit (impl) name; - value = self.overrideLisp (_: { - implementation = impl; - }); - }) - (builtins.attrValues impls)); - }) // { - overrideLisp = new: withExtras f (args // new args); - }); - - # 'testSuite' builds a Common Lisp test suite that loads all of srcs and deps, - # and then executes expression to check its result - testSuite = { name, expression, srcs, deps ? [ ], native ? [ ], implementation }: - let - lispDeps = allDeps implementation (implFilter implementation deps); - lispNativeDeps = allNative native lispDeps; - filteredSrcs = implFilter implementation srcs; - in - runCommand name - { - LD_LIBRARY_PATH = lib.makeLibraryPath lispNativeDeps; - LANG = "C.UTF-8"; - } '' - echo "Running test suite ${name}" - - ${implementation.runScript} ${ - implementation.genTestLisp { - inherit name expression; - srcs = filteredSrcs; - deps = lispDeps; - } - } | tee $out - - echo "Test suite ${name} succeeded" - ''; - - # 'impls' is an attribute set of attribute sets which describe how to do common - # tasks when building for different Common Lisp implementations. Each - # implementation set has the following members: - # - # Required members: - # - # - runScript :: string - # Describes how to invoke the implementation from the shell, so it runs a - # lisp file as a script and exits. - # - faslExt :: string - # File extension of the implementations loadable (FASL) files. - # Implementations are free to generate native object files, but with the way - # buildLisp works it is required that we can also 'load' libraries, so - # (additionally) building a FASL or equivalent is required. - # - genLoadLisp :: [ dependency ] -> string - # Returns lisp code to 'load' the given dependencies. 'genLoadLispGeneric' - # should work for most dependencies. - # - genCompileLisp :: { name, srcs, deps } -> file - # Builds a lisp file which instructs the implementation to build a library - # from the given source files when executed. After running at least - # the file "$out/${name}.${impls.${implementation}.faslExt}" should have - # been created. - # - genDumpLisp :: { name, main, deps } -> file - # Builds a lisp file which instructs the implementation to build an - # executable which runs 'main' (and exits) where 'main' is available from - # 'deps'. The executable should be created as "$out/bin/${name}", usually - # by dumping the lisp image with the replaced toplevel function replaced. - # - wrapProgram :: boolean - # Whether to wrap the resulting binary / image with a wrapper script setting - # `LD_LIBRARY_PATH`. - # - genTestLisp :: { name, srcs, deps, expression } -> file - # Builds a lisp file which loads the given 'deps' and 'srcs' files and - # then evaluates 'expression'. Depending on whether 'expression' returns - # true or false, the script must exit with a zero or non-zero exit code. - # 'genTestLispGeneric' will work for most implementations. - # - lispWith :: [ dependency ] -> drv - # Builds a script (or dumped image) which when executed loads (or has - # loaded) all given dependencies. When built this should create an executable - # at "$out/bin/${implementation}". - # - # Optional members: - # - # - bundled :: string -> library - # Allows giving an implementation specific builder for a bundled library. - # This function is used as a replacement for the internal defaultBundled - # function and only needs to support one implementation. The returned derivation - # must behave like one built by 'library' (in particular have the same files - # available in "$out" and the same 'passthru' attributes), but may be built - # completely differently. - impls = lib.mapAttrs (name: v: { inherit name; } // v) { - sbcl = { - runScript = "${sbcl}/bin/sbcl --script"; - faslExt = "fasl"; - - # 'genLoadLisp' generates Lisp code that instructs SBCL to load all - # the provided Lisp libraries. - genLoadLisp = genLoadLispGeneric impls.sbcl; - - # 'genCompileLisp' generates a Lisp file that instructs SBCL to - # compile the provided list of Lisp source files to "$out/${name}.fasl". - genCompileLisp = { name, srcs, deps }: writeText "sbcl-compile.lisp" '' - ;; This file compiles the specified sources into the Nix build - ;; directory, creating one FASL file for each source. - (require 'sb-posix) - - ${impls.sbcl.genLoadLisp deps} - - (defun nix-compile-lisp (srcfile) - (let ((outfile (make-pathname :type "fasl" - :directory (or (sb-posix:getenv "NIX_BUILD_TOP") - (error "not running in a Nix build")) - :name (substitute #\- #\/ srcfile)))) - (multiple-value-bind (out-truename _warnings-p failure-p) - (compile-file srcfile :output-file outfile) - (if failure-p (sb-posix:exit 1) - (progn - ;; For the case of multiple files belonging to the same - ;; library being compiled, load them in order: - (load out-truename) - - ;; Return pathname as a string for cat-ting it later - (namestring out-truename)))))) - - (let ((*compile-verbose* t) - (catted-fasl (make-pathname :type "fasl" - :directory (or (sb-posix:getenv "out") - (error "not running in a Nix build")) - :name "${name}"))) - - (with-open-file (file catted-fasl - :direction :output - :if-does-not-exist :create) - - ;; SBCL's FASL files can just be bundled together using cat - (sb-ext:run-program "cat" - (mapcar #'nix-compile-lisp - ;; These forms were inserted by the Nix build: - '(${ - lib.concatMapStringsSep "\n" (src: "\"${src}\"") srcs - })) - :output file :search t))) - ''; - - # 'genDumpLisp' generates a Lisp file that instructs SBCL to dump - # the currently loaded image as an executable to $out/bin/$name. - # - # TODO(tazjin): Compression is currently unsupported because the - # SBCL in nixpkgs is, by default, not compiled with zlib support. - genDumpLisp = { name, main, deps }: writeText "sbcl-dump.lisp" '' - (require 'sb-posix) - - ${impls.sbcl.genLoadLisp deps} - - (let* ((bindir (concatenate 'string (sb-posix:getenv "out") "/bin")) - (outpath (make-pathname :name "${name}" - :directory bindir))) - - ;; Tell UIOP that argv[0] will refer to running image, not the lisp impl - (when (find-package :uiop) - (eval `(setq ,(find-symbol "*IMAGE-DUMPED-P*" :uiop) :executable))) - - (save-lisp-and-die outpath - :executable t - :toplevel - (lambda () - ;; Filter out everything prior to the `--` we - ;; insert in the wrapper to prevent SBCL from - ;; parsing arguments at startup - (setf sb-ext:*posix-argv* - (delete "--" sb-ext:*posix-argv* - :test #'string= :count 1)) - (${main})) - :purify t)) - ''; - - wrapProgram = true; - - genTestLisp = genTestLispGeneric impls.sbcl; - - lispWith = deps: - let lispDeps = filter (d: !d.lispBinary) (allDeps impls.sbcl deps); - in writeShellScriptBin "sbcl" '' - export LD_LIBRARY_PATH="${lib.makeLibraryPath (allNative [] lispDeps)}" - export LANG="C.UTF-8" - exec ${sbcl}/bin/sbcl ${ - lib.optionalString (deps != []) - "--load ${writeText "load.lisp" (impls.sbcl.genLoadLisp lispDeps)}" - } $@ - ''; - }; - ecl = { - runScript = "${ecl-static}/bin/ecl --load ${disableDebugger} --shell"; - faslExt = "fasc"; - genLoadLisp = genLoadLispGeneric impls.ecl; - genCompileLisp = { name, srcs, deps }: writeText "ecl-compile.lisp" '' - ;; This seems to be required to bring make the 'c' package available - ;; early, otherwise ECL tends to fail with a read failure… - (ext:install-c-compiler) - - ;; Load dependencies - ${impls.ecl.genLoadLisp deps} - - (defun getenv-or-fail (var) - (or (ext:getenv var) - (error (format nil "Missing expected environment variable ~A" var)))) - - (defun nix-compile-file (srcfile &key native) - "Compile the given srcfile into a compilation unit in :out-dir using - a unique name based on srcfile as the filename which is returned after - compilation. If :native is true, create an native object file, - otherwise a byte-compile fasc file is built and immediately loaded." - - (let* ((unique-name (substitute #\_ #\/ srcfile)) - (out-file (make-pathname :type (if native "o" "fasc") - :directory (getenv-or-fail "NIX_BUILD_TOP") - :name unique-name))) - (multiple-value-bind (out-truename _warnings-p failure-p) - (compile-file srcfile :system-p native - :load (not native) - :output-file out-file - :verbose t :print t) - (if failure-p (ext:quit 1) out-truename)))) - - (let* ((out-dir (getenv-or-fail "out")) - (nix-build-dir (getenv-or-fail "NIX_BUILD_TOP")) - (srcs - ;; These forms are inserted by the Nix build - '(${lib.concatMapStringsSep "\n" (src: "\"${src}\"") srcs}))) - - ;; First, we'll byte compile loadable FASL files and load them - ;; immediately. Since we are using a statically linked ECL, there's - ;; no way to load native objects, so we rely on byte compilation - ;; for all our loading — which is crucial in compilation of course. - (ext:install-bytecodes-compiler) - - ;; ECL's bytecode FASLs can just be concatenated to create a bundle - ;; at least since a recent bugfix which we apply as a patch. - ;; See also: https://gitlab.com/embeddable-common-lisp/ecl/-/issues/649 - (let ((bundle-out (make-pathname :type "fasc" :name "${name}" - :directory out-dir))) - - (with-open-file (fasc-stream bundle-out :direction :output) - (ext:run-program "cat" - (mapcar (lambda (f) - (namestring - (nix-compile-file f :native nil))) - srcs) - :output fasc-stream))) - - (ext:install-c-compiler) - - ;; Build a (natively compiled) static archive (.a) file. We want to - ;; use this for (statically) linking an executable later. The bytecode - ;; dance is only required because we can't load such archives. - (c:build-static-library - (make-pathname :type "a" :name "${name}" :directory out-dir) - :lisp-files (mapcar (lambda (x) - (nix-compile-file x :native t)) - srcs))) - ''; - genDumpLisp = { name, main, deps }: writeText "ecl-dump.lisp" '' - (defun getenv-or-fail (var) - (or (ext:getenv var) - (error (format nil "Missing expected environment variable ~A" var)))) - - ${impls.ecl.genLoadLisp deps} - - ;; makes a 'c' package available that can link executables - (ext:install-c-compiler) - - (c:build-program - (merge-pathnames (make-pathname :directory '(:relative "bin") - :name "${name}") - (truename (getenv-or-fail "out"))) - :epilogue-code `(progn - ;; UIOP doesn't understand ECL, so we need to make it - ;; aware that we are a proper executable, causing it - ;; to handle argument parsing and such properly. Since - ;; this needs to work even when we're not using UIOP, - ;; we need to do some compile-time acrobatics. - ,(when (find-package :uiop) - `(setf ,(find-symbol "*IMAGE-DUMPED-P*" :uiop) :executable)) - ;; Run the actual application… - (${main}) - ;; … and exit. - (ext:quit)) - ;; ECL can't remember these from its own build… - :ld-flags '("-static") - :lisp-files - ;; The following forms are inserted by the Nix build - '(${ - lib.concatMapStrings (dep: '' - "${dep}/${dep.lispName}.a" - '') (allDeps impls.ecl deps) - })) - ''; - - wrapProgram = false; - - genTestLisp = genTestLispGeneric impls.ecl; - - lispWith = deps: - let lispDeps = filter (d: !d.lispBinary) (allDeps impls.ecl deps); - in writeShellScriptBin "ecl" '' - exec ${ecl-static}/bin/ecl ${ - lib.optionalString (deps != []) - "--load ${writeText "load.lisp" (impls.ecl.genLoadLisp lispDeps)}" - } $@ - ''; - - bundled = name: runCommand "${name}-cllib" - { - passthru = { - lispName = name; - lispNativeDeps = [ ]; - lispDeps = [ ]; - lispBinary = false; - repl = impls.ecl.lispWith [ (impls.ecl.bundled name) ]; - }; - } '' - mkdir -p "$out" - ln -s "${ecl-static}/lib/ecl-${ecl-static.version}/${name}.${impls.ecl.faslExt}" -t "$out" - ln -s "${ecl-static}/lib/ecl-${ecl-static.version}/lib${name}.a" "$out/${name}.a" - ''; - }; - ccl = { - # Relatively bespoke wrapper script necessary to make CCL just™ execute - # a lisp file as a script. - runScript = pkgs.writers.writeBash "ccl" '' - # don't print intro message etc. - args=("--quiet") - - # makes CCL crash on error instead of entering the debugger - args+=("--load" "${disableDebugger}") - - # load files from command line in order - for f in "$@"; do - args+=("--load" "$f") - done - - # Exit if everything was processed successfully - args+=("--eval" "(quit)") - - exec ${ccl}/bin/ccl ''${args[@]} - ''; - - # See https://ccl.clozure.com/docs/ccl.html#building-definitions - faslExt = - if targetPlatform.isPower && targetPlatform.is32bit then "pfsl" - else if targetPlatform.isPower && targetPlatform.is64bit then "p64fsl" - else if targetPlatform.isx86_64 && targetPlatform.isLinux then "lx64fsl" - else if targetPlatform.isx86_32 && targetPlatform.isLinux then "lx32fsl" - else if targetPlatform.isAarch32 && targetPlatform.isLinux then "lafsl" - else if targetPlatform.isx86_32 && targetPlatform.isDarwin then "dx32fsl" - else if targetPlatform.isx86_64 && targetPlatform.isDarwin then "dx64fsl" - else if targetPlatform.isx86_64 && targetPlatform.isDarwin then "dx64fsl" - else if targetPlatform.isx86_32 && targetPlatform.isFreeBSD then "fx32fsl" - else if targetPlatform.isx86_64 && targetPlatform.isFreeBSD then "fx64fsl" - else if targetPlatform.isx86_32 && targetPlatform.isWindows then "wx32fsl" - else if targetPlatform.isx86_64 && targetPlatform.isWindows then "wx64fsl" - else builtins.throw "Don't know what FASLs are called for this platform: " - + pkgs.stdenv.targetPlatform.system; - - genLoadLisp = genLoadLispGeneric impls.ccl; - - genCompileLisp = { name, srcs, deps }: writeText "ccl-compile.lisp" '' - ${impls.ccl.genLoadLisp deps} - - (defun getenv-or-fail (var) - (or (getenv var) - (error (format nil "Missing expected environment variable ~A" var)))) - - (defun nix-compile-file (srcfile) - "Trivial wrapper around COMPILE-FILE which causes CCL to exit if - compilation fails and LOADs the compiled file on success." - (let ((output (make-pathname :name (substitute #\_ #\/ srcfile) - :type "${impls.ccl.faslExt}" - :directory (getenv-or-fail "NIX_BUILD_TOP")))) - (multiple-value-bind (out-truename _warnings-p failure-p) - (compile-file srcfile :output-file output :print t :verbose t) - (declare (ignore _warnings-p)) - (if failure-p (quit 1) - (progn (load out-truename) out-truename))))) - - (fasl-concatenate (make-pathname :name "${name}" :type "${impls.ccl.faslExt}" - :directory (getenv-or-fail "out")) - (mapcar #'nix-compile-file - ;; These forms where inserted by the Nix build - '(${ - lib.concatMapStrings (src: '' - "${src}" - '') srcs - }))) - ''; - - genDumpLisp = { name, main, deps }: writeText "ccl-dump.lisp" '' - ${impls.ccl.genLoadLisp deps} - - (let* ((out (or (getenv "out") (error "Not running in a Nix build"))) - (bindir (concatenate 'string out "/bin/")) - (executable (make-pathname :directory bindir :name "${name}"))) - - ;; Tell UIOP that argv[0] will refer to running image, not the lisp impl - (when (find-package :uiop) - (eval `(setf ,(find-symbol "*IMAGE-DUMPED-P*" :uiop) :executable))) - - (save-application executable - :purify t - :error-handler :quit - :toplevel-function - (lambda () - ;; Filter out everything prior to the `--` we - ;; insert in the wrapper to prevent SBCL from - ;; parsing arguments at startup - (setf ccl:*command-line-argument-list* - (delete "--" ccl:*command-line-argument-list* - :test #'string= :count 1)) - (${main})) - :mode #o755 - ;; TODO(sterni): use :native t on macOS - :prepend-kernel t)) - ''; - - wrapProgram = true; - - genTestLisp = genTestLispGeneric impls.ccl; - - lispWith = deps: - let lispDeps = filter (d: !d.lispBinary) (allDeps impls.ccl deps); - in writeShellScriptBin "ccl" '' - export LD_LIBRARY_PATH="${lib.makeLibraryPath (allNative [] lispDeps)}" - exec ${ccl}/bin/ccl ${ - lib.optionalString (deps != []) - "--load ${writeText "load.lisp" (impls.ccl.genLoadLisp lispDeps)}" - } "$@" - ''; - }; - }; - - # - # Public API functions - # - - # 'library' builds a list of Common Lisp files into an implementation - # specific library format, usually a single FASL file, which can then be - # loaded and built into an executable via 'program'. - library = - { name - , implementation ? defaultImplementation - , brokenOn ? [ ] # TODO(sterni): make this a warning - , srcs - , deps ? [ ] - , native ? [ ] - , tests ? null - , passthru ? { } - }: - let - filteredDeps = implFilter implementation deps; - filteredSrcs = implFilter implementation srcs; - lispNativeDeps = (allNative native filteredDeps); - lispDeps = allDeps implementation filteredDeps; - testDrv = - if ! isNull tests - then - testSuite - { - name = tests.name or "${name}-test"; - srcs = filteredSrcs ++ (tests.srcs or [ ]); - deps = filteredDeps ++ (tests.deps or [ ]); - expression = tests.expression; - inherit implementation; - } - else null; - in - lib.fix (self: runCommand "${name}-cllib" - { - LD_LIBRARY_PATH = lib.makeLibraryPath lispNativeDeps; - LANG = "C.UTF-8"; - passthru = passthru // { - inherit lispNativeDeps lispDeps; - lispName = name; - lispBinary = false; - tests = testDrv; - }; - } '' - ${if ! isNull testDrv - then "echo 'Test ${testDrv} succeeded'" - else "echo 'No tests run'"} - - mkdir $out - - ${implementation.runScript} ${ - implementation.genCompileLisp { - srcs = filteredSrcs; - inherit name; - deps = lispDeps; - } - } - ''); - - # 'program' creates an executable, usually containing a dumped image of the - # specified sources and dependencies. - program = - { name - , implementation ? defaultImplementation - , brokenOn ? [ ] # TODO(sterni): make this a warning - , main ? "${name}:main" - , srcs - , deps ? [ ] - , native ? [ ] - , tests ? null - , passthru ? { } - }: - let - filteredSrcs = implFilter implementation srcs; - filteredDeps = implFilter implementation deps; - lispDeps = allDeps implementation filteredDeps; - libPath = lib.makeLibraryPath (allNative native lispDeps); - # overriding is used internally to propagate the implementation to use - selfLib = (makeOverridable library) { - inherit name native brokenOn; - deps = lispDeps; - srcs = filteredSrcs; - }; - testDrv = - if ! isNull tests - then - testSuite - { - name = tests.name or "${name}-test"; - srcs = - ( - # testSuite does run implFilter as well - filteredSrcs ++ (tests.srcs or [ ]) - ); - deps = filteredDeps ++ (tests.deps or [ ]); - expression = tests.expression; - inherit implementation; - } - else null; - in - lib.fix (self: runCommand "${name}" - { - nativeBuildInputs = [ makeWrapper ]; - LD_LIBRARY_PATH = libPath; - LANG = "C.UTF-8"; - passthru = passthru // { - lispName = name; - lispDeps = [ selfLib ]; - lispNativeDeps = native; - lispBinary = true; - tests = testDrv; - }; - } - ('' - ${if ! isNull testDrv - then "echo 'Test ${testDrv} succeeded'" - else ""} - mkdir -p $out/bin - - ${implementation.runScript} ${ - implementation.genDumpLisp { - inherit name main; - deps = ([ selfLib ] ++ lispDeps); - } - } - '' + lib.optionalString implementation.wrapProgram '' - wrapProgram $out/bin/${name} \ - --prefix LD_LIBRARY_PATH : "${libPath}" \ - --add-flags "\$NIX_BUILDLISP_LISP_ARGS --" - '')); - - # 'bundled' creates a "library" which makes a built-in package available, - # such as any of SBCL's sb-* packages or ASDF. By default this is done - # by calling 'require', but implementations are free to provide their - # own specific bundled function. - bundled = name: - let - # TODO(sterni): allow overriding args to underlying 'library' (e. g. srcs) - defaultBundled = implementation: name: library { - inherit name implementation; - srcs = lib.singleton (builtins.toFile "${name}.lisp" "(require '${name})"); - }; - - bundled' = - { implementation ? defaultImplementation - , name - }: - implementation.bundled or (defaultBundled implementation) name; - - in - (makeOverridable bundled') { - inherit name; - }; - -in -{ - library = withExtras library; - program = withExtras program; - inherit bundled; - - # 'sbclWith' creates an image with the specified libraries / - # programs loaded in SBCL. - sbclWith = impls.sbcl.lispWith; - - inherit (impls) - sbcl - ecl - ccl - ; -} diff --git a/nix/buildLisp/example/default.nix b/nix/buildLisp/example/default.nix deleted file mode 100644 index 6add2676f..000000000 --- a/nix/buildLisp/example/default.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.nix) buildLisp; - - # Example Lisp library. - # - # Currently the `name` attribute is only used for the derivation - # itself, it has no practical implications. - libExample = buildLisp.library { - name = "lib-example"; - srcs = [ - ./lib.lisp - ]; - }; - - # Example Lisp program. - # - # This builds & writes an executable for a program using the library - # above to disk. - # - # By default, buildLisp.program expects the entry point to be - # `$name:main`. This can be overridden by configuring the `main` - # attribute. -in -buildLisp.program { - name = "example"; - deps = [ libExample ]; - - srcs = [ - ./main.lisp - ]; -} diff --git a/nix/buildLisp/example/lib.lisp b/nix/buildLisp/example/lib.lisp deleted file mode 100644 index e557de4ae..000000000 --- a/nix/buildLisp/example/lib.lisp +++ /dev/null @@ -1,6 +0,0 @@ -(defpackage lib-example - (:use :cl) - (:export :who)) -(in-package :lib-example) - -(defun who () "edef") diff --git a/nix/buildLisp/example/main.lisp b/nix/buildLisp/example/main.lisp deleted file mode 100644 index a29390cf4..000000000 --- a/nix/buildLisp/example/main.lisp +++ /dev/null @@ -1,7 +0,0 @@ -(defpackage example - (:use :cl :lib-example) - (:export :main)) -(in-package :example) - -(defun main () - (format t "i <3 ~A~%" (who))) diff --git a/nix/buildLisp/tests/argv0.nix b/nix/buildLisp/tests/argv0.nix deleted file mode 100644 index ca5f2b974..000000000 --- a/nix/buildLisp/tests/argv0.nix +++ /dev/null @@ -1,58 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - # Trivial test program that outputs argv[0] and exits - prog = - depot.nix.buildLisp.program { - name = "argv0-test"; - - srcs = [ - (pkgs.writeText "argv0-test.lisp" '' - (defpackage :argv0-test (:use :common-lisp :uiop) (:export :main)) - (in-package :argv0-test) - - (defun main () - (format t "~A~%" (uiop:argv0))) - '') - ]; - - deps = [ - { - sbcl = depot.nix.buildLisp.bundled "uiop"; - default = depot.nix.buildLisp.bundled "asdf"; - } - ]; - }; - - # Extract verify argv[0] output for given buildLisp program - checkImplementation = prog: - pkgs.runCommand "check-argv0" { } '' - set -eux - - checkInvocation() { - invocation="$1" - test "$invocation" = "$("$invocation")" - } - - checkInvocation "${prog}/bin/argv0-test" - - cd ${prog} - checkInvocation "./bin/argv0-test" - - cd bin - checkInvocation ./argv0-test - - set +x - - touch "$out" - ''; - - inherit (prog.meta.ci) targets; -in - -(checkImplementation prog).overrideAttrs (_: { - # Wire up a subtarget all (active) non-default implementations - passthru = lib.genAttrs targets (name: checkImplementation prog.${name}); - - meta.ci = { inherit targets; }; -}) diff --git a/nix/dependency-analyzer/examples/ci-targets.nix b/nix/dependency-analyzer/examples/ci-targets.nix deleted file mode 100644 index 597abd410..000000000 --- a/nix/dependency-analyzer/examples/ci-targets.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ depot, lib, ... }: - -( - depot.nix.dependency-analyzer.knownDependencyGraph - "depot" - depot.ci.targets -).overrideAttrs (old: { - # Causes an infinite recursion via ci.targets otherwise - meta = lib.recursiveUpdate (old.meta or { }) { - ci.skip = true; - }; -}) diff --git a/nix/dependency-analyzer/examples/lisp.nix b/nix/dependency-analyzer/examples/lisp.nix deleted file mode 100644 index 775eb9ab5..000000000 --- a/nix/dependency-analyzer/examples/lisp.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ depot, lib, ... }: - -depot.nix.dependency-analyzer.knownDependencyGraph "3p-lisp" ( - builtins.filter lib.isDerivation (builtins.attrValues depot.third_party.lisp) -) diff --git a/nix/dependency-analyzer/tests/default.nix b/nix/dependency-analyzer/tests/default.nix deleted file mode 100644 index 79ac127e9..000000000 --- a/nix/dependency-analyzer/tests/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ depot, lib, ... }: - -let - inherit (depot.nix.runTestsuite) - runTestsuite - assertEq - it - ; - - inherit (depot.nix.dependency-analyzer) - plainDrvDepMap - drvsToPaths - ; - - knownDrvs = drvsToPaths ( - builtins.filter lib.isDerivation (builtins.attrValues depot.third_party.lisp) - ); - exampleMap = plainDrvDepMap knownDrvs; - - # These will be needed to index into the attribute set which can't have context - # in the attribute names. - knownDrvsNoContext = builtins.map builtins.unsafeDiscardStringContext knownDrvs; -in - -runTestsuite "dependency-analyzer" [ - (it "checks plainDrvDepMap properties" [ - (assertEq "all known drvs are marked known" - (builtins.all (drv: exampleMap.${drv}.known) knownDrvsNoContext) - true) - (assertEq "no unknown drv is marked known" - (builtins.all (entry: !entry.known) ( - builtins.attrValues (builtins.removeAttrs exampleMap knownDrvsNoContext) - )) - true) - ]) -] diff --git a/nix/drvSeqL/default.nix b/nix/drvSeqL/default.nix deleted file mode 100644 index 6437e1a04..000000000 --- a/nix/drvSeqL/default.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - - inherit (depot.nix.yants) - defun - list - drv - ; - - /* Realize drvDeps, then return drvOut if that succeds. - * This can be used to make drvOut depend on the - * build success of all drvDeps without making each drvDep - * a dependency of drvOut. - * => drvOut is not rebuilt if drvDep changes - */ - drvSeqL = defun [ (list drv) drv drv ] - (drvDeps: drvOut: - let - drvOutOutputs = drvOut.outputs or [ "out" ]; - in - pkgs.runCommandLocal drvOut.name - { - # we inherit all attributes in order to replicate - # the original derivation as much as possible - outputs = drvOutOutputs; - passthru = drvOut.drvAttrs; - # depend on drvDeps (by putting it in builder context) - inherit drvDeps; - } - # the outputs of the original derivation are replicated - # by creating a symlink to the old output path - (lib.concatMapStrings - (output: '' - target=${lib.escapeShellArg drvOut.${output}} - # if the target is already a symlink, follow it until it’s not; - # this is done to prevent too many dereferences - target=$(readlink -e "$target") - # link to the output - ln -s "$target" "${"$"}${output}" - '') - drvOutOutputs)); - -in -{ - __functor = _: drvSeqL; -} diff --git a/nix/emptyDerivation/OWNERS b/nix/emptyDerivation/OWNERS deleted file mode 100644 index a64022791..000000000 --- a/nix/emptyDerivation/OWNERS +++ /dev/null @@ -1 +0,0 @@ -Profpatsch diff --git a/nix/emptyDerivation/default.nix b/nix/emptyDerivation/default.nix deleted file mode 100644 index f808aa228..000000000 --- a/nix/emptyDerivation/default.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ depot, pkgs, localSystem, ... }: - -let - emptyDerivation = import ./emptyDerivation.nix { - inherit pkgs; - inherit (pkgs) stdenv; - inherit (depot.nix) getBins; - system = localSystem; - }; - - tests = import ./tests.nix { - inherit emptyDerivation; - inherit pkgs; - inherit (depot.nix) writeExecline getBins; - inherit (depot.nix.runTestsuite) runTestsuite it assertEq; - }; - -in -{ - __functor = _: emptyDerivation; - inherit tests; -} diff --git a/nix/emptyDerivation/emptyDerivation.nix b/nix/emptyDerivation/emptyDerivation.nix deleted file mode 100644 index d7de7ccfb..000000000 --- a/nix/emptyDerivation/emptyDerivation.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ stdenv, system, pkgs, getBins }: - -# The empty derivation. All it does is touch $out. -# Basically the unit value for derivations. -# -# In addition to simple test situations which require -# a derivation, we set __functor, so you can call it -# as a function and pass an attrset. The set you pass -# is `//`-merged with the attrset before calling derivation, -# so you can use this to add more fields. - -let - bins = getBins pkgs.s6-portable-utils [ "s6-touch" ] - // getBins pkgs.execline [ "importas" "exec" ]; - - emptiness = { - name = "empty-derivation"; - inherit system; - - builder = bins.exec; - args = [ - bins.importas - "out" - "out" - bins.s6-touch - "$out" - ]; - }; - -in -(derivation emptiness) // { - # This allows us to call the empty derivation - # like a function and override fields/add new fields. - __functor = _: overrides: - derivation (emptiness // overrides); -} diff --git a/nix/emptyDerivation/tests.nix b/nix/emptyDerivation/tests.nix deleted file mode 100644 index a73842882..000000000 --- a/nix/emptyDerivation/tests.nix +++ /dev/null @@ -1,40 +0,0 @@ -{ emptyDerivation, getBins, pkgs, writeExecline, runTestsuite, it, assertEq }: - -let - bins = getBins pkgs.s6-portable-utils [ "s6-echo" ]; - - empty = it "is just an empty path" [ - (assertEq "path empty" - (builtins.readFile emptyDerivation) - "") - ]; - - fooOut = emptyDerivation { - builder = writeExecline "foo-builder" { } [ - "importas" - "out" - "out" - "redirfd" - "-w" - "1" - "$out" - bins.s6-echo - "-n" - "foo" - ]; - }; - - overrideBuilder = it "can override the builder" [ - (assertEq "output is foo" - (builtins.readFile fooOut) - "foo") - (assertEq "can add new drv variables" - (emptyDerivation { foo = "bar"; }).foo - "bar") - ]; - -in -runTestsuite "emptyDerivation" [ - empty - overrideBuilder -] diff --git a/nix/netstring/attrsToKeyValList.nix b/nix/netstring/attrsToKeyValList.nix deleted file mode 100644 index c854b5695..000000000 --- a/nix/netstring/attrsToKeyValList.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ depot, lib, ... }: - -# Convert an attrset of strings to a list of key/value netstring pairs. -# A good minimally viable json replacement if all you need is to iterate. -# You can use e.g. `forstdin -Ed '' item` in execline to split the items -# and then get the key and value via `multidefine -d '' $item { key value }` -# -# Example: -# { foo = "bar"; x = "abc"; } -# => "12:3:foo,3:bar,,10:1:x,3:abc,," -# -# Example with runExecline: -# nix.runExecline "test" { -# stdin = nix.netstring.attrsToKeyValList { -# foo = "bar"; -# x = "abc"; -# }; -# } [ -# "forstdin" "-Ed" "" "item" -# "multidefine" "-d" "" "$item" [ "key" "value" ] -# "${pkgs.coreutils}/bin/echo" "\${key} -> \${value}" -# ] - -# will print: -# foo -> bar -# x -> abc -attrs: -lib.concatStrings - (lib.mapAttrsToList - (k: v: depot.nix.netstring.fromString - (depot.nix.netstring.fromString k - + depot.nix.netstring.fromString v)) - attrs) diff --git a/nix/netstring/fromString.nix b/nix/netstring/fromString.nix deleted file mode 100644 index dcd688a8b..000000000 --- a/nix/netstring/fromString.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ ... }: -# convert any nix string into a netstring -# (prefixed by its length) according to https://en.wikipedia.org/wiki/Netstring -# -# Examples: -# netstring.fromString "foo" -# => "3:foo," -# netstring.fromString "" -# => "0:," -s: "${toString (builtins.stringLength s)}:${s}," diff --git a/nix/nint/OWNERS b/nix/nint/OWNERS index 2e9580706..557709b72 100644 --- a/nix/nint/OWNERS +++ b/nix/nint/OWNERS @@ -1 +1 @@ -sterni +raitobezarius diff --git a/nix/nix-1p/README.md b/nix/nix-1p/README.md deleted file mode 100644 index 309eddb51..000000000 --- a/nix/nix-1p/README.md +++ /dev/null @@ -1,648 +0,0 @@ -> [!TIP] -> Are you interested in hacking on Nix projects for a week, together -> with other Nix users? Do you have time at the end of August? Great, -> come join us at [Volga Sprint](https://volgasprint.org/)! - -Nix - A One Pager -================= - -[Nix](https://nixos.org/nix/), the package manager, is built on and with Nix, -the language. This page serves as a fast intro to most of the (small) language. - -Unless otherwise specified, the word "Nix" refers only to the language below. - -Please file an issue if something in here confuses you or you think something -important is missing. - -If you have Nix installed, you can try the examples below by running `nix repl` -and entering code snippets there. - - -**Table of Contents** - -- [Overview](#overview) -- [Language constructs](#language-constructs) - - [Primitives / literals](#primitives--literals) - - [Operators](#operators) - - [`//` (merge) operator](#-merge-operator) - - [Variable bindings](#variable-bindings) - - [Functions](#functions) - - [Multiple arguments (currying)](#multiple-arguments-currying) - - [Multiple arguments (attribute sets)](#multiple-arguments-attribute-sets) - - [`if ... then ... else ...`](#if--then--else-) - - [`inherit` keyword](#inherit-keyword) - - [`with` statements](#with-statements) - - [`import` / `NIX_PATH` / ``](#import--nix_path--entry) - - [`or` expressions](#or-expressions) -- [Standard libraries](#standard-libraries) - - [`builtins`](#builtins) - - [`pkgs.lib`](#pkgslib) - - [`pkgs` itself](#pkgs-itself) -- [Derivations](#derivations) -- [Nix Idioms](#nix-idioms) - - [File lambdas](#file-lambdas) - - [`callPackage`](#callpackage) - - [Overrides / Overlays](#overrides--overlays) - - - - -# Overview - -Nix is: - -* **purely functional**. It has no concept of sequential steps being executed, - any dependency between operations is established by depending on *data* from - previous operations. - - Any valid piece of Nix code is an *expression* that returns a value. - - Evaluating a Nix expression *yields a single data structure*, it does not - execute a sequence of operations. - - Every Nix file evaluates to a *single expression*. -* **lazy**. It will only evaluate expressions when their result is actually - requested. - - For example, the builtin function `throw` causes evaluation to stop. - Entering the following expression works fine however, because we never - actually ask for the part of the structure that causes the `throw`. - - ```nix - let attrs = { a = 15; b = builtins.throw "Oh no!"; }; - in "The value of 'a' is ${toString attrs.a}" - ``` -* **purpose-built**. Nix only exists to be the language for Nix, the package - manager. While people have occasionally used it for other use-cases, it is - explicitly not a general-purpose language. - -# Language constructs - -This section describes the language constructs in Nix. It is a small language -and most of these should be self-explanatory. - -## Primitives / literals - -Nix has a handful of data types which can be represented literally in source -code, similar to many other languages. - -```nix -# numbers -42 -1.72394 - -# strings & paths -"hello" -./some-file.json - -# strings support interpolation -"Hello ${name}" - -# multi-line strings (common prefix whitespace is dropped) -'' -first line -second line -'' - -# lists (note: no commas!) -[ 1 2 3 ] - -# attribute sets (field access with dot syntax) -{ a = 15; b = "something else"; } - -# recursive attribute sets (fields can reference each other) -rec { a = 15; b = a * 2; } -``` - -## Operators - -Nix has several operators, most of which are unsurprising: - -| Syntax | Description | -|---------------------------|-----------------------------------------------------------------------------| -| `+`, `-`, `*`, `/` | Numerical operations | -| `+` | String concatenation | -| `++` | List concatenation | -| `==` | Equality | -| `>`, `>=`, `<`, `<=` | Ordering comparators | -| `&&` | Logical `AND` | -| || | Logical `OR` | -| `e1 -> e2` | Logical implication (i.e. !e1 || e2) | -| `!` | Boolean negation | -| `set.attr` | Access attribute `attr` in attribute set `set` | -| `set ? attribute` | Test whether attribute set contains an attribute | -| `left // right` | Merge `left` & `right` attribute sets, with the right set taking precedence | - - -### `//` (merge) operator - -The `//`-operator is used pervasively in Nix code. You should familiarise -yourself with it, as it is likely also the least familiar one. - -It merges the left and right attribute sets given to it: - -```nix -{ a = 1; } // { b = 2; } - -# yields { a = 1; b = 2; } -``` - -Values from the right side take precedence: - -```nix -{ a = "left"; } // { a = "right"; } - -# yields { a = "right"; } -``` - -The merge operator does *not* recursively merge attribute sets; - -```nix -{ a = { b = 1; }; } // { a = { c = 2; }; } - -# yields { a = { c = 2; }; } -``` - -Helper functions for recursive merging exist in the [`lib` library](#pkgslib). - -## Variable bindings - -Bindings in Nix are introduced locally via `let` expressions, which make some -variables available within a given scope. - -For example: - -```nix -let - a = 15; - b = 2; -in a * b - -# yields 30 -``` - -Variables are immutable. This means that after defining what `a` or `b` are, you -can not *modify* their value in the scope in which they are available. - -You can nest `let`-expressions to shadow variables. - -Variables are *not* available outside of the scope of the `let` expression. -There are no global variables. - -## Functions - -All functions in Nix are anonymous lambdas. This means that they are treated -just like data. Giving them names is accomplished by assigning them to -variables, or setting them as values in an attribute set (more on that below). - -``` -# simple function -# declaration is simply the argument followed by a colon -name: "Hello ${name}" -``` - -### Multiple arguments (currying) - -Technically any Nix function can only accept **one argument**. Sometimes -however, a function needs multiple arguments. This is achieved in Nix via -[currying][], which means to create a function with one argument, that returns a -function with another argument, that returns ... and so on. - -For example: - -```nix -name: age: "${name} is ${toString age} years old" -``` - -An additional benefit of this approach is that you can pass one parameter to a -curried function, and receive back a function that you can re-use (similar to -partial application): - -```nix -let - multiply = a: b: a * b; - doubleIt = multiply 2; # at this point we have passed in the value for 'a' and - # receive back another function that still expects 'b' -in - doubleIt 15 - -# yields 30 -``` - -### Multiple arguments (attribute sets) - -Another way of specifying multiple arguments to a function in Nix is to make it -accept an attribute set, which enables multiple other features: - -```nix -{ name, age }: "${name} is ${toString age} years old" -``` - -Using this method, we gain the ability to specify default arguments (so that -callers can omit them): - -```nix -{ name, age ? 42 }: "${name} is ${toString age} years old" - -``` - -Or in practice: - -```nix -let greeter = { name, age ? 42 }: "${name} is ${toString age} years old"; -in greeter { name = "Slartibartfast"; } - -# yields "Slartibartfast is 42 years old" -# (note: Slartibartfast is actually /significantly/ older) -``` - -Additionally we can introduce an ellipsis using `...`, meaning that we can -accept an attribute set as our input that contains more variables than are -needed for the function. - -```nix -let greeter = { name, age, ... }: "${name} is ${toString age} years old"; - person = { - name = "Slartibartfast"; - age = 42; - # the 'email' attribute is not expected by the 'greeter' function ... - email = "slartibartfast@magrath.ea"; - }; -in greeter person # ... but the call works due to the ellipsis. -``` - -Nix also supports binding the whole set of passed in attributes to a -parameter using the `@` syntax: - -```nix -let func = { name, age, ... }@args: builtins.attrNames args; -in func { - name = "Slartibartfast"; - age = 42; - email = "slartibartfast@magrath.ea"; -} - -# yields: [ "age" "email" "name" ] -``` - -**Warning:** Combining the `@` syntax with default arguments can lead -to surprising behaviour, as the passed attributes are bound verbatim. -This means that defaulted arguments are not included in the bound -attribute set: - -```nix -({ a ? 1, b }@args: args.a) { b = 1; } -# throws: error: attribute 'a' missing - -({ a ? 1, b }@args: args.a) { b = 1; a = 2; } -# => 2 -``` - -## `if ... then ... else ...` - -Nix has simple conditional support. Note that `if` is an **expression** in Nix, -which means that both branches must be specified. - -```nix -if someCondition -then "it was true" -else "it was false" -``` - -## `inherit` keyword - -The `inherit` keyword is used in attribute sets or `let` bindings to "inherit" -variables from the parent scope. - -In short, a statement like `inherit foo;` expands to `foo = foo;`. - -Consider this example: - -```nix -let - name = "Slartibartfast"; - # ... other variables -in { - name = name; # set the attribute set key 'name' to the value of the 'name' var - # ... other attributes -} -``` - -The `name = name;` line can be replaced with `inherit name;`: - -```nix -let - name = "Slartibartfast"; - # ... other variables -in { - inherit name; - # ... other attributes -} -``` - -This is often convenient, especially because inherit supports multiple variables -at the same time as well as "inheritance" from other attribute sets: - -```nix -{ - inherit name age; # equivalent to `name = name; age = age;` - inherit (otherAttrs) email; # equivalent to `email = otherAttrs.email`; -} -``` - -## `with` statements - -The `with` statement "imports" all attributes from an attribute set into -variables of the same name: - -```nix -let attrs = { a = 15; b = 2; }; -in with attrs; a + b # 'a' and 'b' become variables in the scope following 'with' -``` - -The scope of a `with`-"block" is the expression immediately following the -semicolon, i.e.: - -```nix -let attrs = { /* some attributes */ }; -in with attrs; (/* this is the scope of the `with` */) -``` - -## `import` / `NIX_PATH` / `` - -Nix files can import each other by using the builtin `import` function and a -literal path: - -```nix -# assuming there is a file lib.nix with some useful functions -let myLib = import ./lib.nix; -in myLib.usefulFunction 42 -``` - -The `import` function will read and evaluate the file, and return its Nix value. - -Nix files often begin with a function header to pass parameters into the rest of -the file, so you will often see imports of the form `import ./some-file { ... }`. - -Nix has a concept of a `NIX_PATH` (similar to the standard `PATH` environment -variable) which contains named aliases for file paths containing Nix -expressions. - -In a standard Nix installation, several [channels][] will be present (for -example `nixpkgs` or `nixos-unstable`) on the `NIX_PATH`. - -`NIX_PATH` entries can be accessed using the `` syntax, which simply -evaluates to their file path: - -```nix - -# might yield something like `/home/tazjin/.nix-defexpr/channels/nixpkgs` -``` - -This is commonly used to import from channels: - -```nix -let pkgs = import {}; -in pkgs.something -``` - -## `or` expressions - -Nix has a keyword called `or` which can be used to access a value from an -attribute set while providing a fallback to a default value. - -The syntax is simple: - -```nix -# Access an existing attribute -let set = { a = 42; }; -in set.a or 23 -``` - -Since the attribute `a` exists, this will return `42`. - - -```nix -# ... or fall back to a default if there is no such key -let set = { }; -in set.a or 23 -``` - -Since the attribute `a` does not exist, this will fall back to returning the -default value `23`. - -Note that `or` expressions also work for nested attribute set access. - -# Standard libraries - -Yes, libraries, plural. - -Nix has three major things that could be considered its standard library and -while there's a lot of debate to be had about this point, you still need to know -all three. - -## `builtins` - -Nix comes with several functions that are baked into the language. These work -regardless of which other Nix code you may or may not have imported. - -Most of these functions are implemented in the Nix interpreter itself, which -means that they are rather fast when compared to some of the equivalents which -are implemented in Nix itself. - -The Nix manual has [a section listing all `builtins`][builtins] and their usage. - -Examples of builtins that you will commonly encounter include, but are not -limited to: - -* `derivation` (see [Derivations](#derivations)) -* `toJSON` / `fromJSON` -* `toString` -* `toPath` / `fromPath` - -The builtins also include several functions that have the (spooky) ability to -break Nix' evaluation purity. No functions written in Nix itself can do this. - -Examples of those include: - -* `fetchGit` which can fetch a git-repository using the environment's default - git/ssh configuration -* `fetchTarball` which can fetch & extract archives without having to specify - hashes - -Read through the manual linked above to get the full overview. - -## `pkgs.lib` - -The Nix package set, commonly referred to by Nixers simply as [nixpkgs][], -contains a child attribute set called `lib` which provides a large number of -useful functions. - -The canonical definition of these functions is [their source code][lib-src]. I -wrote a tool ([nixdoc][]) in 2018 which generates manual entries for these -functions, however not all of the files are included as of July 2019. - -See the [Nixpkgs manual entry on `lib`][lib-manual] for the documentation. - -These functions include various utilities for dealing with the data types in Nix -(lists, attribute sets, strings etc.) and it is useful to at least skim through -them to familiarise yourself with what is available. - -```nix -{ pkgs ? import {} }: - -with pkgs.lib; # bring contents pkgs.lib into scope - -strings.toUpper "hello" - -# yields "HELLO" -``` - -## `pkgs` itself - -The Nix package set itself does not just contain packages, but also many useful -functions which you might run into while creating new Nix packages. - -One particular subset of these that stands out are the [trivial builders][], -which provide utilities for writing text files or shell scripts, running shell -commands and capturing their output and so on. - -```nix -{ pkgs ? import {} }: - -pkgs.writeText "hello.txt" "Hello dear reader!" - -# yields a derivation which creates a text file with the above content -``` - -# Derivations - -When a Nix expression is evaluated it may yield one or more *derivations*. -Derivations describe a single build action that, when run, places one or more -outputs (whether they be files or folders) in the Nix store. - -The builtin function `derivation` is responsible for creating derivations at a -lower level. Usually when Nix users create derivations they will use the -higher-level functions such as [stdenv.mkDerivation][smkd]. - -Please see the manual [on derivations][drv-manual] for more information, as the -general build logic is out of scope for this document. - -# Nix Idioms - -There are several idioms in Nix which are not technically part of the language -specification, but will commonly be encountered in the wild. - -This section is an (incomplete) list of them. - -## File lambdas - -It is customary to start every file with a function header that receives the -files dependencies, instead of importing them directly in the file. - -Sticking to this pattern lets users of your code easily change out, for example, -the specific version of `nixpkgs` that is used. - -A common file header pattern would look like this: - -```nix -{ pkgs ? import {} }: - -# ... 'pkgs' is then used in the code -``` - -In some sense, you might consider the function header of a file to be its "API". - -## `callPackage` - -Building on the previous pattern, there is a custom in nixpkgs of specifying the -dependencies of your file explicitly instead of accepting the entire package -set. - -For example, a file containing build instructions for a tool that needs the -standard build environment and `libsvg` might start like this: - -```nix -# my-funky-program.nix -{ stdenv, libsvg }: - -stdenv.mkDerivation { ... } -``` - -Any time a file follows this header pattern it is probably meant to be imported -using a special function called `callPackage` which is part of the top-level -package set (as well as certain subsets, such as `haskellPackages`). - -```nix -{ pkgs ? import {} }: - -let my-funky-program = pkgs.callPackage ./my-funky-program.nix {}; -in # ... something happens with my-funky-program -``` - -The `callPackage` function looks at the expected arguments (via -`builtins.functionArgs`) and passes the appropriate keys from the set in which -it is defined as the values for each corresponding argument. - -## Overrides / Overlays - -One of the most powerful features of Nix is that the representation of all build -instructions as data means that they can easily be *overridden* to get a -different result. - -For example, assuming there is a package `someProgram` which is built without -our favourite configuration flag (`--mimic-threaten-tag`) we might override it -like this: - -```nix -someProgram.overrideAttrs(old: { - configureFlags = old.configureFlags or [] ++ ["--mimic-threaten-tag"]; -}) -``` - -This pattern has a variety of applications of varying complexity. The top-level -package set itself can have an `overlays` argument passed to it which may add -new packages to the imported set. - -Note the use of the `or` operator to default to an empty list if the -original flags do not include `configureFlags`. This is required in -case a package does not set any flags by itself. - -Since this can change in a package over time, it is useful to guard -against it using `or`. - -For a slightly more advanced example, assume that we want to import `` -but have the modification above be reflected in the imported package set: - -```nix -let - overlay = (final: prev: { - someProgram = prev.someProgram.overrideAttrs(old: { - configureFlags = old.configureFlags or [] ++ ["--mimic-threaten-tag"]; - }); - }); -in import { overlays = [ overlay ]; } -``` - -The overlay function receives two arguments, `final` and `prev`. `final` is -the [fixed point][fp] of the overlay's evaluation, i.e. the package set -*including* the new packages and `prev` is the "original" package set. - -See the Nix manual sections [on overrides][] and [on overlays][] for more -details (note: the convention has moved away from using `self` in favor of -`final`, and `prev` instead of `super`, but the documentation has not been -updated to reflect this). - -[currying]: https://en.wikipedia.org/wiki/Currying -[builtins]: https://nixos.org/manual/nix/stable/language/builtins -[nixpkgs]: https://github.com/NixOS/nixpkgs -[lib-src]: https://github.com/NixOS/nixpkgs/tree/master/lib -[nixdoc]: https://github.com/tazjin/nixdoc -[lib-manual]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library -[channels]: https://nixos.org/manual/nix/stable/command-ref/files/channels -[trivial builders]: https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/trivial-builders/default.nix -[smkd]: https://nixos.org/manual/nixpkgs/stable/#chap-stdenv -[drv-manual]: https://nixos.org/manual/nix/stable/language/derivations -[fp]: https://github.com/NixOS/nixpkgs/blob/master/lib/fixed-points.nix -[on overrides]: https://nixos.org/manual/nixpkgs/stable/#chap-overrides -[on overlays]: https://nixos.org/manual/nixpkgs/stable/#chap-overlays diff --git a/nix/nix-1p/default.nix b/nix/nix-1p/default.nix deleted file mode 100644 index 6cc71b954..000000000 --- a/nix/nix-1p/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -# The canonical source location of nix-1p is //nix/nix-1p in the TVL -# depot: https://code.tvl.fyi/about/nix/nix-1p -# -# This file configures TVL CI to mirror the subtree to GitHub. -{ depot ? { }, pkgs ? import { }, ... }: - -(pkgs.runCommandLocal "nix-1p" { } '' - mkdir $out - cp ${./README.md} $out/README.md -'').overrideAttrs (_: { - meta.ci.extraSteps.github = depot.tools.releases.filteredGitPush { - filter = ":/nix/nix-1p"; - remote = "git@github.com:tazjin/nix-1p.git"; - ref = "refs/heads/master"; - }; -}) diff --git a/nix/sparseTree/OWNERS b/nix/sparseTree/OWNERS index 2e9580706..557709b72 100644 --- a/nix/sparseTree/OWNERS +++ b/nix/sparseTree/OWNERS @@ -1 +1 @@ -sterni +raitobezarius diff --git a/nix/tailscale/default.nix b/nix/tailscale/default.nix deleted file mode 100644 index 363f717db..000000000 --- a/nix/tailscale/default.nix +++ /dev/null @@ -1,31 +0,0 @@ -# This file defines a Nix helper function to create Tailscale ACL files. -# -# https://tailscale.com/kb/1018/install-acls - -{ depot, pkgs, ... }: - -with depot.nix.yants; - -let - inherit (builtins) toFile toJSON; - - acl = struct "acl" { - Action = enum [ "accept" "reject" ]; - Users = list string; - Ports = list string; - }; - - acls = list entry; - - aclConfig = struct "aclConfig" { - # Static group mappings from group names to lists of users - Groups = option (attrs (list string)); - - # Hostname aliases to use in place of IPs - Hosts = option (attrs string); - - # Actual ACL entries - ACLs = list acl; - }; -in -config: pkgs.writeText "tailscale-acl.json" (toJSON (aclConfig config)) diff --git a/nix/utils/OWNERS b/nix/utils/OWNERS index 2e9580706..557709b72 100644 --- a/nix/utils/OWNERS +++ b/nix/utils/OWNERS @@ -1 +1 @@ -sterni +raitobezarius diff --git a/ops/glesys/.gitignore b/ops/glesys/.gitignore deleted file mode 100644 index de8e8f12e..000000000 --- a/ops/glesys/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.terraform* -terraform.tfstate* -.envrc diff --git a/ops/glesys/README.md b/ops/glesys/README.md deleted file mode 100644 index 00f61a936..000000000 --- a/ops/glesys/README.md +++ /dev/null @@ -1,20 +0,0 @@ -Terraform for GleSYS -====================== - -This contains the Terraform configuration for deploying TVL's -infrastructure at [GleSYS](https://glesys.com). This includes object -storage (e.g. for backups and Terraform state) and DNS. - -Secrets are needed for applying this. The encrypted file -`//ops/secrets/tf-glesys.age` contains `export` calls which should be -sourced, for example via `direnv`, by users with the appropriate -credentials. - -An example `direnv` configuration used by tazjin is this: - -``` -# //ops/secrets/.envrc -source_up -eval $(age --decrypt -i ~/.ssh/id_ed25519 $(git rev-parse --show-toplevel)/ops/secrets/tf-glesys.age) -watch_file $(git rev-parse --show-toplevel)/secrets/tf-glesys.age -``` diff --git a/ops/glesys/default.nix b/ops/glesys/default.nix deleted file mode 100644 index e511e1f6b..000000000 --- a/ops/glesys/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ depot, lib, pkgs, ... }: - -depot.nix.readTree.drvTargets rec { - # Provide a Terraform wrapper with the right provider installed. - terraform = pkgs.terraform.withPlugins (_: [ - depot.third_party.terraform-provider-glesys - ]); - - validate = depot.tools.checks.validateTerraform { - inherit terraform; - name = "glesys"; - src = lib.cleanSource ./.; - env.GLESYS_TOKEN = "ci-dummy"; - }; -} diff --git a/ops/glesys/dns-nixery-dev.tf b/ops/glesys/dns-nixery-dev.tf deleted file mode 100644 index 13d5f39ab..000000000 --- a/ops/glesys/dns-nixery-dev.tf +++ /dev/null @@ -1,44 +0,0 @@ -# DNS configuration for nixery.dev -# -# TODO(tazjin): Figure out what to do with //ops/dns for this. I'd -# like to keep zonefiles in case we move providers again, but maybe -# generate something from them. Not sure yet. - -resource "glesys_dnsdomain" "nixery_dev" { - name = "nixery.dev" -} - -resource "glesys_dnsdomain_record" "nixery_dev_apex_A" { - domain = glesys_dnsdomain.nixery_dev.id - host = "@" - type = "A" - data = var.bugry_ipv4 -} - -resource "glesys_dnsdomain_record" "nixery_dev_apex_AAAA" { - domain = glesys_dnsdomain.nixery_dev.id - host = "@" - type = "AAAA" - data = var.bugry_ipv6 -} - -resource "glesys_dnsdomain_record" "nixery_dev_NS1" { - domain = glesys_dnsdomain.nixery_dev.id - host = "@" - type = "NS" - data = "ns1.namesystem.se." -} - -resource "glesys_dnsdomain_record" "nixery_dev_NS2" { - domain = glesys_dnsdomain.nixery_dev.id - host = "@" - type = "NS" - data = "ns2.namesystem.se." -} - -resource "glesys_dnsdomain_record" "nixery_dev_NS3" { - domain = glesys_dnsdomain.nixery_dev.id - host = "@" - type = "NS" - data = "ns3.namesystem.se." -} diff --git a/ops/glesys/dns-tvix-dev.tf b/ops/glesys/dns-tvix-dev.tf deleted file mode 100644 index d6c56077d..000000000 --- a/ops/glesys/dns-tvix-dev.tf +++ /dev/null @@ -1,54 +0,0 @@ -# DNS configuration for tvix.dev - -resource "glesys_dnsdomain" "tvix_dev" { - name = "tvix.dev" -} - -resource "glesys_dnsdomain_record" "tvix_dev_apex_A" { - domain = glesys_dnsdomain.tvix_dev.id - host = "@" - type = "A" - data = var.bugry_ipv4 -} - -resource "glesys_dnsdomain_record" "tvix_dev_apex_AAAA" { - domain = glesys_dnsdomain.tvix_dev.id - host = "@" - type = "AAAA" - data = var.bugry_ipv6 -} - -resource "glesys_dnsdomain_record" "tvix_dev_bolt_CNAME" { - domain = glesys_dnsdomain.tvix_dev.id - host = "bolt" - type = "CNAME" - data = "bugry.tvl.fyi." -} - -resource "glesys_dnsdomain_record" "tvix_dev_docs_CNAME" { - domain = glesys_dnsdomain.tvix_dev.id - host = "docs" - type = "CNAME" - data = "bugry.tvl.fyi." -} - -resource "glesys_dnsdomain_record" "tvix_dev_NS1" { - domain = glesys_dnsdomain.tvix_dev.id - host = "@" - type = "NS" - data = "ns1.namesystem.se." -} - -resource "glesys_dnsdomain_record" "tvix_dev_NS2" { - domain = glesys_dnsdomain.tvix_dev.id - host = "@" - type = "NS" - data = "ns2.namesystem.se." -} - -resource "glesys_dnsdomain_record" "tvix_dev_NS3" { - domain = glesys_dnsdomain.tvix_dev.id - host = "@" - type = "NS" - data = "ns3.namesystem.se." -} diff --git a/ops/glesys/dns-tvl-fyi.tf b/ops/glesys/dns-tvl-fyi.tf deleted file mode 100644 index 837f40aed..000000000 --- a/ops/glesys/dns-tvl-fyi.tf +++ /dev/null @@ -1,156 +0,0 @@ -# DNS configuration for tvl.fyi - -resource "glesys_dnsdomain" "tvl_fyi" { - name = "tvl.fyi" -} - -resource "glesys_dnsdomain_record" "tvl_fyi_NS1" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "NS" - data = "ns1.namesystem.se." -} - -resource "glesys_dnsdomain_record" "tvl_fyi_NS2" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "NS" - data = "ns2.namesystem.se." -} - -resource "glesys_dnsdomain_record" "tvl_fyi_NS3" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "NS" - data = "ns3.namesystem.se." -} - -resource "glesys_dnsdomain_record" "tvl_fyi_apex_A" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "A" - data = var.bugry_ipv4 -} - -resource "glesys_dnsdomain_record" "tvl_fyi_apex_AAAA" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "AAAA" - data = var.bugry_ipv6 -} - -resource "glesys_dnsdomain_record" "tvl_fyi_nevsky_A" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "nevsky" - type = "A" - data = var.nevsky_ipv4 -} - -resource "glesys_dnsdomain_record" "tvl_fyi_nevsky_AAAA" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "nevsky" - type = "AAAA" - data = var.nevsky_ipv6 -} - -resource "glesys_dnsdomain_record" "tvl_fyi_bugry_A" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "bugry" - type = "A" - data = var.bugry_ipv4 -} - -resource "glesys_dnsdomain_record" "tvl_fyi_bugry_AAAA" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "bugry" - type = "AAAA" - data = var.bugry_ipv6 -} - -# Explicit records for all services running on nevsky -resource "glesys_dnsdomain_record" "tvl_fyi_nevsky_services" { - domain = glesys_dnsdomain.tvl_fyi.id - type = "CNAME" - data = "nevsky.tvl.fyi." - host = each.key - for_each = toset(local.nevsky_services) -} - -# Explicit records for all services running on bugry -resource "glesys_dnsdomain_record" "tvl_fyi_bugry_services" { - domain = glesys_dnsdomain.tvl_fyi.id - type = "CNAME" - data = "bugry.tvl.fyi." - host = each.key - for_each = toset(local.bugry_services) -} - -resource "glesys_dnsdomain_record" "tvl_fyi_net_CNAME" { - domain = glesys_dnsdomain.tvl_fyi.id - type = "CNAME" - data = "sanduny.tvl.su." - host = "net" -} - -# Binary cache round-robin setup (experimental; only on .fyi) - -resource "glesys_dnsdomain_record" "cache_tvl_fyi_A" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "cache" - type = "A" - data = each.key - for_each = toset([var.nevsky_ipv4]) -} - -resource "glesys_dnsdomain_record" "cache_tvl_fyi_AAAA" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "cache" - type = "AAAA" - data = each.key - for_each = toset([var.nevsky_ipv6]) -} - -# Builderball cache records - -resource "glesys_dnsdomain_record" "tvl_fyi_cache_nevsky_CNAME" { - domain = glesys_dnsdomain.tvl_fyi.id - type = "CNAME" - data = "nevsky.tvl.fyi." - host = "nevsky.cache" -} - -# Google Domains mail forwarding configuration (no sending) -resource "glesys_dnsdomain_record" "tvl_fyi_MX_5" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "MX" - data = "5 gmr-smtp-in.l.google.com." -} - -resource "glesys_dnsdomain_record" "tvl_fyi_MX_10" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "MX" - data = "10 alt1.gmr-smtp-in.l.google.com." -} - -resource "glesys_dnsdomain_record" "tvl_fyi_MX_20" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "MX" - data = "20 alt2.gmr-smtp-in.l.google.com." -} - -resource "glesys_dnsdomain_record" "tvl_fyi_MX_30" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "MX" - data = "30 alt3.aspmx.l.google.com." -} - -resource "glesys_dnsdomain_record" "tvl_fyi_MX_40" { - domain = glesys_dnsdomain.tvl_fyi.id - host = "@" - type = "MX" - data = "40 alt4.gmr-smtp-in.l.google.com." -} diff --git a/ops/glesys/dns-tvl-su.tf b/ops/glesys/dns-tvl-su.tf deleted file mode 100644 index df5685893..000000000 --- a/ops/glesys/dns-tvl-su.tf +++ /dev/null @@ -1,139 +0,0 @@ -# DNS configuration for tvl.su - -resource "glesys_dnsdomain" "tvl_su" { - name = "tvl.su" -} - -resource "glesys_dnsdomain_record" "tvl_su_NS1" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "NS" - data = "ns1.namesystem.se." -} - -resource "glesys_dnsdomain_record" "tvl_su_NS2" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "NS" - data = "ns2.namesystem.se." -} - -resource "glesys_dnsdomain_record" "tvl_su_NS3" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "NS" - data = "ns3.namesystem.se." -} - -resource "glesys_dnsdomain_record" "tvl_su_apex_A" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "A" - data = var.bugry_ipv4 -} - -resource "glesys_dnsdomain_record" "tvl_su_apex_AAAA" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "AAAA" - data = var.bugry_ipv6 -} - -resource "glesys_dnsdomain_record" "tvl_su_sanduny_A" { - domain = glesys_dnsdomain.tvl_su.id - host = "sanduny" - type = "A" - data = var.sanduny_ipv4 -} - -resource "glesys_dnsdomain_record" "tvl_su_sanduny_AAAA" { - domain = glesys_dnsdomain.tvl_su.id - host = "sanduny" - type = "AAAA" - data = var.sanduny_ipv6 -} - -resource "glesys_dnsdomain_record" "cache_tvl_su_nevsky_CNAME" { - domain = glesys_dnsdomain.tvl_su.id - host = "cache" - type = "CNAME" - data = "nevsky.tvl.fyi." -} - -# Explicit records for all services running on nevsky -resource "glesys_dnsdomain_record" "tvl_su_nevsky_services" { - domain = glesys_dnsdomain.tvl_su.id - type = "CNAME" - data = "nevsky.tvl.fyi." - host = each.key - for_each = toset(local.nevsky_services) -} - -# Explicit records for all services running on bugry -resource "glesys_dnsdomain_record" "tvl_su_bugry_services" { - domain = glesys_dnsdomain.tvl_su.id - type = "CNAME" - data = "bugry.tvl.fyi." - host = each.key - for_each = toset(local.bugry_services) -} - -# historical tvixbolt.tvl.su record, redirects to bolt.tvix.dev -resource "glesys_dnsdomain_record" "tvix_su_tvixbolt_CNAME" { - domain = glesys_dnsdomain.tvl_su.id - host = "tvixbolt" - type = "CNAME" - data = "nevsky.tvl.fyi." -} - -resource "glesys_dnsdomain_record" "tvl_su_inbox_CNAME" { - domain = glesys_dnsdomain.tvl_su.id - type = "CNAME" - data = "sanduny.tvl.su." - host = "inbox.tvl.su." -} - -resource "glesys_dnsdomain_record" "tvl_su_TXT_google_site" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "TXT" - data = "google-site-verification=3ksTBzFK3lZlzD3ddBfpaHs9qasfAiYBmvbW2T_ejH4" -} - -# Yandex 360 setup - -resource "glesys_dnsdomain_record" "tvl_su_TXT_yandex" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "TXT" - data = "yandex-verification: b99c43b7838949dc" -} - -resource "glesys_dnsdomain_record" "tvl_su_MX_yandex" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "MX" - data = "10 mx.yandex.net." -} - -resource "glesys_dnsdomain_record" "tvl_su_TXT_yandex_spf" { - domain = glesys_dnsdomain.tvl_su.id - host = "@" - type = "TXT" - data = "v=spf1 redirect=_spf.yandex.net" - -} - -resource "glesys_dnsdomain_record" "tvl_su_TXT_yandex_dkim" { - domain = glesys_dnsdomain.tvl_su.id - host = "mail._domainkey" - type = "TXT" - data = "v=DKIM1; k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaRdWF8BtCHlTTQN8O+E5Qn27FVIpUEAdk1uq2vdIKh1Un/3NfdWtxStcS1Mf0iEprt1Fb4zgWOkDlPi+hH/UZqiC9QNeNqEBGMB9kgJyfsUt6cDCIVGvn8PT9JcZW1jxSziOj8nUWB4noqbaVcQNqNbwtaHPm3aifwKwScxVO7wIDAQAB" -} - -resource "glesys_dnsdomain_record" "tvl_su_CNAME_yandex_mail" { - domain = glesys_dnsdomain.tvl_su.id - host = "mail" - type = "CNAME" - data = "domain.mail.yandex.net." -} diff --git a/ops/glesys/main.tf b/ops/glesys/main.tf deleted file mode 100644 index 3c566376b..000000000 --- a/ops/glesys/main.tf +++ /dev/null @@ -1,105 +0,0 @@ -# Configure TVL resources hosted with GleSYS. -# -# Most importantly: -# - all of our DNS -# - object storage (e.g. backups) - -terraform { - required_providers { - glesys = { - source = "depot/glesys" - } - } - - backend "s3" { - endpoints = { - s3 = "https://objects.dc-sto1.glesys.net" - } - bucket = "tvl-state" - key = "terraform/tvl-glesys" - region = "glesys" - - skip_credentials_validation = true - skip_region_validation = true - skip_metadata_api_check = true - skip_requesting_account_id = true - skip_s3_checksum = true - } -} - -provider "glesys" { - userid = "cl26117" # generated by GleSYS -} - -resource "glesys_objectstorage_instance" "tvl-backups" { - description = "tvl-backups" - datacenter = "dc-sto1" -} - -resource "glesys_objectstorage_instance" "tvl-state" { - description = "tvl-state" - datacenter = "dc-sto1" -} - -resource "glesys_objectstorage_credential" "terraform-state" { - instanceid = glesys_objectstorage_instance.tvl-state.id - description = "key for terraform state" -} - -resource "glesys_objectstorage_credential" "litestream" { - instanceid = glesys_objectstorage_instance.tvl-state.id - description = "key for litestream" -} - -variable "nevsky_ipv4" { - type = string - default = "188.225.81.75" -} - -variable "nevsky_ipv6" { - type = string - default = "2a03:6f00:2:514b:0:feed:edef:beef" -} - -variable "bugry_ipv4" { - type = string - default = "91.199.149.239" -} - -variable "bugry_ipv6" { - type = string - default = "2a03:6f00:2:514b:5bc7:95ef:0:2" -} - -variable "sanduny_ipv4" { - type = string - default = "85.119.82.231" -} - -variable "sanduny_ipv6" { - type = string - default = "2001:ba8:1f1:f109::feed:edef:beef" -} - -locals { - # Hostnames of all public services on nevsky - nevsky_services = [ - "auth", - "b", - "cl", - "code", - "cs", - "deploys", # TODO: unsupported (b/437) - "grep", - "status", - ] - - # Hostnames of all public services on bugry - bugry_services = [ - "at", - "atward", - "signup", - "static", - "todo", - ] -} diff --git a/ops/journaldriver/.gitignore b/ops/journaldriver/.gitignore deleted file mode 100644 index 29e65519b..000000000 --- a/ops/journaldriver/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -result -/target -**/*.rs.bk diff --git a/ops/journaldriver/Cargo.lock b/ops/journaldriver/Cargo.lock deleted file mode 100644 index eaf87cc52..000000000 --- a/ops/journaldriver/Cargo.lock +++ /dev/null @@ -1,626 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "build-env" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e068f31938f954b695423ecaf756179597627d0828c0d3e48c0a722a8b23cf9e" - -[[package]] -name = "cc" -version = "1.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "crimp" -version = "4087.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ead2c83f7d1f9b8e5a6f7a25985d0d1759ccd2cd72abb1eee2db65d05e12b39" -dependencies = [ - "curl", - "serde", - "serde_json", -] - -[[package]] -name = "cstr-argument" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bd9c8e659a473bce955ae5c35b116af38af11a7acb0b480e01f3ed348aeb40" -dependencies = [ - "cfg-if", - "memchr", -] - -[[package]] -name = "curl" -version = "0.4.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "curl-sys" -version = "0.4.74+curl-8.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8af10b986114528fcdc4b63b6f5f021b7057618411046a4de2ba0f0149a097bf" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys 0.52.0", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "is-terminal" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "journaldriver" -version = "5656.0.0" -dependencies = [ - "anyhow", - "crimp", - "env_logger", - "lazy_static", - "log", - "medallion", - "pkg-config", - "serde", - "serde_json", - "systemd", - "time", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[package]] -name = "libsystemd-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d28ad38d7bee81aabd41201ee7d36df8d7f76aa0a455c77d5c365c4669b4b4b6" -dependencies = [ - "build-env", - "libc", - "pkg-config", -] - -[[package]] -name = "libz-sys" -version = "1.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "medallion" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b83c0c3277d722b53a6eb24e3c1321172f85b715cc7405add8ffd1f2f06288" -dependencies = [ - "anyhow", - "base64", - "openssl", - "serde", - "serde_json", - "time", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "openssl" -version = "0.10.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "serde" -version = "1.0.209" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.209" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.127" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "syn" -version = "2.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "systemd" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95085b9c6eedbcf0b828302a3483a84bdbf772158e586b787092112008fd1f" -dependencies = [ - "cstr-argument", - "foreign-types 0.5.0", - "libc", - "libsystemd-sys", - "log", - "utf8-cstr", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "utf8-cstr" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55bcbb425141152b10d5693095950b51c3745d019363fc2929ffd8f61449b628" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/ops/journaldriver/Cargo.toml b/ops/journaldriver/Cargo.toml deleted file mode 100644 index 65510d870..000000000 --- a/ops/journaldriver/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "journaldriver" -version = "5656.0.0" -authors = ["Vincent Ambo "] -license = "GPL-3.0-or-later" -edition = "2021" - -[dependencies] -anyhow = "1.0" -crimp = "4087.0" -env_logger = "0.10" -lazy_static = "1.4" -log = "0.4" -medallion = "2.5" -serde = { version = "1.0", features = [ "derive" ] } -serde_json = "1.0" -systemd = "0.5" -time = { version = "0.3", features = [ "serde-well-known", "macros" ]} - -[build-dependencies] -pkg-config = "0.3" diff --git a/ops/journaldriver/README.md b/ops/journaldriver/README.md deleted file mode 100644 index 4dc9de0f6..000000000 --- a/ops/journaldriver/README.md +++ /dev/null @@ -1,152 +0,0 @@ -journaldriver -============= - -This is a small daemon used to forward logs from `journald` (systemd's -logging service) to [Stackdriver Logging][]. - -Many existing log services are written in inefficient dynamic -languages with error-prone "cover every possible use-case" -configuration. `journaldriver` instead aims to fit a specific use-case -very well, instead of covering every possible logging setup. - -`journaldriver` can be run on GCP-instances with no additional -configuration as authentication tokens are retrieved from the -[metadata server][]. - - -**Table of Contents** - -- [Features](#features) -- [Usage on Google Cloud Platform](#usage-on-google-cloud-platform) -- [Usage outside of Google Cloud Platform](#usage-outside-of-google-cloud-platform) -- [Log levels / severities / priorities](#log-levels--severities--priorities) -- [NixOS module](#nixos-module) -- [Stackdriver Error Reporting](#stackdriver-error-reporting) - - - -# Features - -* `journaldriver` persists the last forwarded position in the journal - and will resume forwarding at the same position after a restart -* `journaldriver` will recognise log entries in JSON format and - forward them appropriately to make structured log entries available - in Stackdriver -* `journaldriver` can be used outside of GCP by configuring static - credentials -* `journaldriver` will recognise journald's log priority levels and - convert them into equivalent Stackdriver log severity levels - -# Usage on Google Cloud Platform - -`journaldriver` does not require any configuration when running on GCP -instances. - -1. Install `journaldriver` on the instance from which you wish to - forward logs. - -2. Ensure that the instance has the appropriate permissions to write - to Stackdriver. Google continously changes how IAM is implemented - on GCP, so you will have to refer to [Google's documentation][]. - - By default instances have the required permissions if Stackdriver - Logging support is enabled in the project. - -3. Start `journaldriver`, for example via `systemd`. - -# Usage outside of Google Cloud Platform - -When running outside of GCP, the following extra steps need to be -performed: - -1. Create a Google Cloud Platform service account with the "Log - Writer" role and download its private key in JSON-format. -2. When starting `journaldriver`, configure the following environment - variables: - - * `GOOGLE_CLOUD_PROJECT`: Name of the GCP project to which logs - should be written. - * `GOOGLE_APPLICATION_CREDENTIALS`: Filesystem path to the - JSON-file containing the service account's private key. - * `LOG_STREAM`: Name of the target log stream in Stackdriver Logging. - This will be automatically created if it does not yet exist. - * `LOG_NAME`: Name of the target log to write to. This defaults to - `journaldriver` if unset, but it is recommended to - for - example - set it to the machine hostname. - -# Log levels / severities / priorities - -`journaldriver` recognises [journald's priorities][] and converts them -into [equivalent severities][] in Stackdriver. Both sets of values -correspond to standard `syslog` priorities. - -The easiest way to emit log messages with priorites from an -application is to use [priority prefixes][], which are compatible with -structured log messages. - -For example, to emit a simple warning message (structured and -unstructured): - -``` -$ echo '<4>{"fnord":true, "msg":"structured log (warning)"}' | systemd-cat -$ echo '<4>unstructured log (warning)' | systemd-cat -``` - -# NixOS module - -The NixOS package repository [contains a module][] for setting up -`journaldriver` on NixOS machines. NixOS by default uses `systemd` for -service management and `journald` for logging, which means that log -output from most services will be captured automatically. - -On a GCP instance the only required option is this: - -```nix -services.journaldriver.enable = true; -``` - -When running outside of GCP, the configuration looks as follows: - -```nix -services.journaldriver = { - enable = true; - logStream = "prod-environment"; - logName = "hostname"; - googleCloudProject = "gcp-project-name"; - applicationCredentials = keyFile; -}; -``` - -**Note**: The `journaldriver`-module is included in stable releases of -NixOS since NixOS 18.09. - -# Stackdriver Error Reporting - -The [Stackdriver Error Reporting][] service of Google's monitoring -toolbox supports automatically detecting and correlating errors from -log entries. - -To use this functionality log messages must be logged in the expected -[log format][]. - -*Note*: Reporting errors from non-GCP instances requires that the -`LOG_STREAM` environment variable is set to the special value -`global`. - -This value changes the monitored resource descriptor from a log stream -to the project-global stream. Due to a limitation in Stackdriver Error -Reporting, this is the only way to correctly ingest errors from -non-GCP machines. Please see [issue #4][] for more information about -this. - -[Stackdriver Logging]: https://cloud.google.com/logging/ -[metadata server]: https://cloud.google.com/compute/docs/storing-retrieving-metadata -[Google's documentation]: https://cloud.google.com/logging/docs/access-control -[NixOS]: https://nixos.org/ -[contains a module]: https://github.com/NixOS/nixpkgs/pull/42134 -[journald's priorities]: http://0pointer.de/public/systemd-man/sd-daemon.html -[equivalent severities]: https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#logseverity -[priority prefixes]: http://0pointer.de/public/systemd-man/sd-daemon.html -[Stackdriver Error Reporting]: https://cloud.google.com/error-reporting/ -[log format]: https://cloud.google.com/error-reporting/docs/formatting-error-messages -[issue #4]: https://github.com/tazjin/journaldriver/issues/4 diff --git a/ops/journaldriver/build.rs b/ops/journaldriver/build.rs deleted file mode 100644 index 79eb1001b..000000000 --- a/ops/journaldriver/build.rs +++ /dev/null @@ -1,5 +0,0 @@ -extern crate pkg_config; - -fn main() { - pkg_config::probe_library("libsystemd").expect("Could not probe libsystemd"); -} diff --git a/ops/journaldriver/default.nix b/ops/journaldriver/default.nix deleted file mode 100644 index 2a3836c35..000000000 --- a/ops/journaldriver/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ depot, pkgs, ... }: - -depot.third_party.naersk.buildPackage { - src = ./.; - - buildInputs = with pkgs; [ - pkg-config - openssl - systemd.dev - ]; -} diff --git a/ops/journaldriver/src/main.rs b/ops/journaldriver/src/main.rs deleted file mode 100644 index 4c404e607..000000000 --- a/ops/journaldriver/src/main.rs +++ /dev/null @@ -1,638 +0,0 @@ -// Copyright (C) 2018 Vincent Ambo -// -// journaldriver is free software: you can redistribute it and/or -// modify it under the terms of the GNU General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! This file implements journaldriver, a small application that -//! forwards logs from journald (systemd's log facility) to -//! Stackdriver Logging. -//! -//! Log entries are read continously from journald and are forwarded -//! to Stackdriver in batches. -//! -//! Stackdriver Logging has a concept of monitored resources. In the -//! simplest case this monitored resource will be the GCE instance on -//! which journaldriver is running. -//! -//! Information about the instance, the project and required security -//! credentials are retrieved from Google's metadata instance on GCP. -//! -//! To run journaldriver on non-GCP machines, users must specify the -//! `GOOGLE_APPLICATION_CREDENTIALS`, `GOOGLE_CLOUD_PROJECT` and -//! `LOG_NAME` environment variables. - -use anyhow::{bail, Context, Result}; -use lazy_static::lazy_static; -use log::{debug, error, info, trace}; -use serde::{Deserialize, Serialize}; -use serde_json::{from_str, json, Value}; -use std::convert::TryInto; -use std::fs::{self, rename, File}; -use std::io::{self, ErrorKind, Read, Write}; -use std::path::PathBuf; -use std::time::{Duration, Instant}; -use std::{env, mem, process}; -use systemd::journal::{Journal, JournalFiles, JournalRecord, JournalSeek}; - -#[cfg(test)] -mod tests; - -const LOGGING_SERVICE: &str = "https://logging.googleapis.com/google.logging.v2.LoggingServiceV2"; -const ENTRIES_WRITE_URL: &str = "https://logging.googleapis.com/v2/entries:write"; -const METADATA_TOKEN_URL: &str = - "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token"; -const METADATA_ID_URL: &str = "http://metadata.google.internal/computeMetadata/v1/instance/id"; -const METADATA_ZONE_URL: &str = "http://metadata.google.internal/computeMetadata/v1/instance/zone"; -const METADATA_PROJECT_URL: &str = - "http://metadata.google.internal/computeMetadata/v1/project/project-id"; - -/// Representation of static service account credentials for GCP. -#[derive(Debug, Deserialize)] -struct Credentials { - /// PEM encoded private key - private_key: String, - - /// `kid` of this private key - private_key_id: String, - - /// "email" address of the service account - client_email: String, -} - -lazy_static! { - /// ID of the GCP project to which to send logs. - static ref PROJECT_ID: String = get_project_id(); - - /// Name of the log to write to (this should only be manually - /// configured if not running on GCP): - static ref LOG_NAME: String = env::var("LOG_NAME") - .unwrap_or("journaldriver".into()); - - /// Service account credentials (if configured) - static ref SERVICE_ACCOUNT_CREDENTIALS: Option = - env::var("GOOGLE_APPLICATION_CREDENTIALS").ok() - .and_then(|path| File::open(path).ok()) - .and_then(|file| serde_json::from_reader(file).ok()); - - /// Descriptor of the currently monitored instance. Refer to the - /// documentation of `determine_monitored_resource` for more - /// information. - static ref MONITORED_RESOURCE: Value = determine_monitored_resource(); - - /// Path to the directory in which journaldriver should persist - /// its cursor state. - static ref CURSOR_DIR: PathBuf = env::var("CURSOR_POSITION_DIR") - .unwrap_or("/var/lib/journaldriver".into()) - .into(); - - /// Path to the cursor position file itself. - static ref CURSOR_FILE: PathBuf = { - let mut path = CURSOR_DIR.clone(); - path.push("cursor.pos"); - path - }; - - /// Path to the temporary file used for cursor position writes. - static ref CURSOR_TMP_FILE: PathBuf = { - let mut path = CURSOR_DIR.clone(); - path.push("cursor.tmp"); - path - }; -} - -/// Convenience helper for retrieving values from the metadata server. -fn get_metadata(url: &str) -> Result { - let response = crimp::Request::get(url) - .header("Metadata-Flavor", "Google")? - .timeout(std::time::Duration::from_secs(5))? - .send()? - .as_string()?; - - if !response.is_success() { - bail!( - "Error response ({}) from metadata server: {}", - response.status, - response.body - ); - } - - Ok(response.body.trim().to_owned()) -} - -/// Convenience helper for determining the project ID. -fn get_project_id() -> String { - env::var("GOOGLE_CLOUD_PROJECT") - .or_else(|_| get_metadata(METADATA_PROJECT_URL)) - .expect("Could not determine project ID") -} - -/// Determines the monitored resource descriptor used in Stackdriver -/// logs. On GCP this will be set to the instance ID as returned by -/// the metadata server. -/// -/// On non-GCP machines the value is determined by using the -/// `GOOGLE_CLOUD_PROJECT` and `LOG_STREAM` environment variables. -/// -/// [issue #4]: https://github.com/tazjin/journaldriver/issues/4 -fn determine_monitored_resource() -> Value { - if let Ok(log) = env::var("LOG_STREAM") { - // The special value `global` is recognised as a log stream name that - // results in a `global`-type resource descriptor. This is useful in - // cases where Stackdriver Error Reporting is intended to be used on - // a non-GCE instance. See [issue #4][] for details. - if log == "global" { - return json!({ - "type": "global", - "labels": { - "project_id": PROJECT_ID.as_str(), - } - }); - } - - json!({ - "type": "logging_log", - "labels": { - "project_id": PROJECT_ID.as_str(), - "name": log, - } - }) - } else { - let instance_id = get_metadata(METADATA_ID_URL).expect("Could not determine instance ID"); - - let zone = get_metadata(METADATA_ZONE_URL).expect("Could not determine instance zone"); - - json!({ - "type": "gce_instance", - "labels": { - "project_id": PROJECT_ID.as_str(), - "instance_id": instance_id, - "zone": zone, - } - }) - } -} - -/// Represents the response returned by the metadata server's token -/// endpoint. The token is normally valid for an hour. -#[derive(Deserialize)] -struct TokenResponse { - expires_in: u64, - access_token: String, -} - -/// Struct used to store a token together with a sensible -/// representation of when it expires. -struct Token { - token: String, - fetched_at: Instant, - expires: Duration, -} - -impl Token { - /// Does this token need to be renewed? - fn is_expired(&self) -> bool { - self.fetched_at.elapsed() > self.expires - } -} - -/// Retrieves a token from the GCP metadata service. Retrieving these -/// tokens requires no additional authentication. -fn get_metadata_token() -> Result { - let body = get_metadata(METADATA_TOKEN_URL)?; - let token: TokenResponse = from_str(&body)?; - - debug!("Fetched new token from metadata service"); - - Ok(Token { - fetched_at: Instant::now(), - expires: Duration::from_secs(token.expires_in / 2), - token: token.access_token, - }) -} - -/// Signs a token using static client credentials configured for a -/// service account. This service account must have been given the -/// `Log Writer` role in Google Cloud IAM. -/// -/// The process for creating and signing these tokens is described -/// here: -/// -/// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth -fn sign_service_account_token(credentials: &Credentials) -> Result { - use medallion::{Algorithm, Header, Payload}; - - let iat = time::OffsetDateTime::now_utc(); - let exp = iat + time::Duration::seconds(3600); - - let header = Header { - alg: Algorithm::RS256, - headers: Some(json!({ - "kid": credentials.private_key_id, - })), - }; - - let payload: Payload<()> = Payload { - iss: Some(credentials.client_email.clone()), - sub: Some(credentials.client_email.clone()), - aud: Some(LOGGING_SERVICE.to_string()), - iat: Some(iat.unix_timestamp().try_into().unwrap()), - exp: Some(exp.unix_timestamp().try_into().unwrap()), - ..Default::default() - }; - - let token = medallion::Token::new(header, payload) - .sign(credentials.private_key.as_bytes()) - .context("Signing service account token failed")?; - - debug!("Signed new service account token"); - - Ok(Token { - token, - fetched_at: Instant::now(), - expires: Duration::from_secs(3000), - }) -} - -/// Retrieve the authentication token either by using static client -/// credentials, or by talking to the metadata server. -/// -/// Which behaviour is used is controlled by the environment variable -/// `GOOGLE_APPLICATION_CREDENTIALS`, which should be configured to -/// point at a JSON private key file if service account authentication -/// is to be used. -fn get_token() -> Result { - if let Some(credentials) = SERVICE_ACCOUNT_CREDENTIALS.as_ref() { - sign_service_account_token(credentials) - } else { - get_metadata_token() - } -} - -/// This structure represents the different types of payloads -/// supported by journaldriver. -/// -/// Currently log entries can either contain plain text messages or -/// structured payloads in JSON-format. -#[derive(Debug, Serialize, PartialEq)] -#[serde(untagged)] -enum Payload { - TextPayload { - #[serde(rename = "textPayload")] - text_payload: String, - }, - JsonPayload { - #[serde(rename = "jsonPayload")] - json_payload: Value, - }, -} - -/// Attempt to parse a log message as JSON and return it as a -/// structured payload. If parsing fails, return the entry in plain -/// text format. -fn message_to_payload(message: Option) -> Payload { - match message { - None => Payload::TextPayload { - text_payload: "empty log entry".into(), - }, - Some(text_payload) => { - // Attempt to deserialize the text payload as a generic - // JSON value. - if let Ok(json_payload) = serde_json::from_str::(&text_payload) { - // If JSON-parsing succeeded on the payload, check - // whether we parsed an object (Stackdriver does not - // expect other types of JSON payload) and return it - // in that case. - if json_payload.is_object() { - return Payload::JsonPayload { json_payload }; - } - } - - Payload::TextPayload { text_payload } - } - } -} - -/// Attempt to parse journald's microsecond timestamps into a UTC -/// timestamp. -/// -/// Parse errors are dismissed and returned as empty options: There -/// simply aren't any useful fallback mechanisms other than defaulting -/// to ingestion time for journaldriver's use-case. -fn parse_microseconds(input: String) -> Option { - if input.len() != 16 { - return None; - } - - let micros: i128 = input.parse().ok()?; - let nanos: i128 = micros * 1000; - - time::OffsetDateTime::from_unix_timestamp_nanos(nanos).ok() -} - -/// Converts a journald log message priority to a -/// Stackdriver-compatible severity number. -/// -/// Both Stackdriver and journald specify equivalent -/// severities/priorities. Conveniently, the names are the same. -/// Inconveniently, the numbers are not. -/// -/// For more information on the journald priorities, consult these -/// man-pages: -/// -/// * systemd.journal-fields(7) (section 'PRIORITY') -/// * sd-daemon(3) -/// * systemd.exec(5) (section 'SyslogLevelPrefix') -/// -/// Note that priorities can be logged by applications via the prefix -/// concept described in these man pages, without interfering with -/// structured JSON-payloads. -/// -/// For more information on the Stackdriver severity levels, please -/// consult Google's documentation: -/// -/// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity -/// -/// Any unknown priority values result in no severity being set. -fn priority_to_severity(priority: String) -> Option { - match priority.as_ref() { - "0" => Some(800), // emerg - "1" => Some(700), // alert - "2" => Some(600), // crit - "3" => Some(500), // err - "4" => Some(400), // warning - "5" => Some(300), // notice - "6" => Some(200), // info - "7" => Some(100), // debug - _ => None, - } -} - -/// This structure represents a log entry in the format expected by -/// the Stackdriver API. -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct LogEntry { - labels: Value, - - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(with = "time::serde::rfc3339::option")] - timestamp: Option, - - #[serde(flatten)] - payload: Payload, - - // https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity - #[serde(skip_serializing_if = "Option::is_none")] - severity: Option, -} - -impl From for LogEntry { - // Converts from the fields contained in a journald record to the - // representation required by Stackdriver Logging. - // - // The fields are documented in systemd.journal-fields(7). - fn from(mut record: JournalRecord) -> LogEntry { - // The message field is technically just a convention, but - // journald seems to default to it when ingesting unit - // output. - let payload = message_to_payload(record.remove("MESSAGE")); - - // Presumably this is always set, but who can be sure - // about anything in this world. - let hostname = record.remove("_HOSTNAME"); - - // The unit is seemingly missing on kernel entries, but - // present on all others. - let unit = record.remove("_SYSTEMD_UNIT"); - - // The source timestamp (if present) is specified in - // microseconds since epoch. - // - // If it is not present or can not be parsed, journaldriver - // will not send a timestamp for the log entry and it will - // default to the ingestion time. - let timestamp = record - .remove("_SOURCE_REALTIME_TIMESTAMP") - .and_then(parse_microseconds); - - // Journald uses syslogd's concept of priority. No idea if this is - // always present, but it's optional in the Stackdriver API, so we just - // omit it if we can't find or parse it. - let severity = record.remove("PRIORITY").and_then(priority_to_severity); - - LogEntry { - payload, - timestamp, - labels: json!({ - "host": hostname, - "unit": unit.unwrap_or_else(|| "syslog".into()), - }), - severity, - } - } -} - -/// Attempt to read from the journal. If no new entry is present, -/// await the next one up to the specified timeout. -fn receive_next_record(timeout: Duration, journal: &mut Journal) -> Result> { - let next_record = journal.next_record()?; - if next_record.is_some() { - return Ok(next_record); - } - - Ok(journal.await_next_record(Some(timeout))?) -} - -/// This function starts a double-looped, blocking receiver. It will -/// buffer messages for half a second before flushing them to -/// Stackdriver. -fn receiver_loop(mut journal: Journal) -> Result<()> { - let mut token = get_token()?; - - let mut buf: Vec = Vec::new(); - let iteration = Duration::from_millis(500); - - loop { - trace!("Beginning outer iteration"); - let now = Instant::now(); - - loop { - if now.elapsed() > iteration { - break; - } - - if let Ok(Some(entry)) = receive_next_record(iteration, &mut journal) { - trace!("Received a new entry"); - buf.push(entry.into()); - } - } - - if !buf.is_empty() { - let to_flush = mem::replace(&mut buf, Vec::new()); - flush(&mut token, to_flush, journal.cursor()?)?; - } - - trace!("Done outer iteration"); - } -} - -/// Writes the current cursor into `/var/journaldriver/cursor.pos`. To -/// avoid issues with journaldriver being terminated while the cursor -/// is still being written, this will first write the cursor into a -/// temporary file and then move it. -fn persist_cursor(cursor: String) -> Result<()> { - // This code exists to aid in tracking down if there are other - // causes of issue #2 than what has already been taken care of. - // - // One theory is that journald (or the Rust library to interface - // with it) may occasionally return empty cursor strings. If this - // is ever the case, we would like to know about it. - if cursor.is_empty() { - error!("Received empty journald cursor position, refusing to persist!"); - error!("Please report this message at https://github.com/tazjin/journaldriver/issues/2"); - return Ok(()); - } - - let mut file = File::create(&*CURSOR_TMP_FILE).context("Failed to create cursor file")?; - - write!(file, "{}", cursor).context("Failed to write cursor file")?; - - rename(&*CURSOR_TMP_FILE, &*CURSOR_FILE) - .context("Failed to move cursor file") - .map_err(Into::into) -} - -/// Flushes all drained records to Stackdriver. Any Stackdriver -/// message can at most contain 1000 log entries which means they are -/// chunked up here. -/// -/// In some cases large payloads seem to cause errors in Stackdriver - -/// the chunks are therefore made smaller here. -/// -/// If flushing is successful the last cursor position will be -/// persisted to disk. -fn flush(token: &mut Token, entries: Vec, cursor: String) -> Result<()> { - if token.is_expired() { - debug!("Refreshing Google metadata access token"); - let new_token = get_token()?; - *token = new_token; - } - - for chunk in entries.chunks(750) { - let request = prepare_request(chunk); - if let Err(write_error) = write_entries(token, request) { - error!("Failed to write {} entries: {}", chunk.len(), write_error) - } else { - debug!("Wrote {} entries to Stackdriver", chunk.len()) - } - } - - persist_cursor(cursor) -} - -/// Convert a slice of log entries into the format expected by -/// Stackdriver. This format is documented here: -/// -/// https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/write -fn prepare_request(entries: &[LogEntry]) -> Value { - json!({ - "logName": format!("projects/{}/logs/{}", PROJECT_ID.as_str(), LOG_NAME.as_str()), - "resource": &*MONITORED_RESOURCE, - "entries": entries, - "partialSuccess": true - }) -} - -/// Perform the log entry insertion in Stackdriver Logging. -fn write_entries(token: &Token, request: Value) -> Result<()> { - let response = crimp::Request::post(ENTRIES_WRITE_URL) - .json(&request)? - .header("Authorization", format!("Bearer {}", token.token).as_str())? - // The timeout values are set relatively high, not because of - // an expectation of Stackdriver being slow but just to - // eventually force an error in case of network troubles. - // Presumably no request in a functioning environment will - // ever hit these limits. - .timeout(std::time::Duration::from_secs(5))? - .send()?; - - if !response.is_success() { - let status = response.status; - let body = response - .as_string() - .map(|r| r.body) - .unwrap_or_else(|_| "no valid response body".to_owned()); - - bail!("Writing to Stackdriver failed({}): {}", status, body); - } - - Ok(()) -} - -/// Attempt to read the initial cursor position from the configured -/// file. If there is no initial cursor position set, read from the -/// tail of the log. -/// -/// The only "acceptable" error when reading the cursor position is -/// the cursor position file not existing, other errors are fatal -/// because they indicate a misconfiguration of journaldriver. -fn initial_cursor() -> Result { - let read_result: io::Result = (|| { - let mut contents = String::new(); - let mut file = File::open(&*CURSOR_FILE)?; - file.read_to_string(&mut contents)?; - Ok(contents.trim().into()) - })(); - - match read_result { - Ok(cursor) => Ok(JournalSeek::Cursor { cursor }), - Err(ref err) if err.kind() == ErrorKind::NotFound => { - info!("No previous cursor position, reading from journal tail"); - Ok(JournalSeek::Tail) - } - Err(err) => (Err(err).context("Could not read cursor position"))?, - } -} - -fn main() { - env_logger::init(); - - // The directory in which cursor positions are persisted should - // have been created: - if !CURSOR_DIR.exists() { - error!("Cursor directory at '{:?}' does not exist", *CURSOR_DIR); - process::exit(1); - } - - let cursor_position_dir = CURSOR_FILE - .parent() - .expect("Invalid cursor position file path"); - - fs::create_dir_all(cursor_position_dir) - .expect("Could not create directory to store cursor position in"); - - let mut journal = - Journal::open(JournalFiles::All, false, true).expect("Failed to open systemd journal"); - - let seek_position = initial_cursor().expect("Failed to determine initial cursor position"); - - match journal.seek(seek_position) { - Ok(cursor) => info!("Opened journal at cursor '{}'", cursor), - Err(err) => { - error!("Failed to set initial journal position: {}", err); - process::exit(1) - } - } - - receiver_loop(journal).expect("log receiver encountered an unexpected error"); -} diff --git a/ops/journaldriver/src/tests.rs b/ops/journaldriver/src/tests.rs deleted file mode 100644 index 6f5045d6a..000000000 --- a/ops/journaldriver/src/tests.rs +++ /dev/null @@ -1,131 +0,0 @@ -use super::*; -use serde_json::to_string; -use time::macros::datetime; - -#[test] -fn test_text_entry_serialization() { - let entry = LogEntry { - labels: Value::Null, - timestamp: None, - payload: Payload::TextPayload { - text_payload: "test entry".into(), - }, - severity: None, - }; - - let expected = "{\"labels\":null,\"textPayload\":\"test entry\"}"; - let result = to_string(&entry).expect("serialization failed"); - - assert_eq!( - expected, result, - "Plain text payload should serialize correctly" - ) -} - -#[test] -fn test_timestamped_entry_serialization() { - let entry = LogEntry { - labels: Value::Null, - timestamp: Some(datetime!(1952-10-07 12:00:00 UTC)), - payload: Payload::TextPayload { - text_payload: "test entry".into(), - }, - severity: None, - }; - - let expected = - "{\"labels\":null,\"timestamp\":\"1952-10-07T12:00:00Z\",\"textPayload\":\"test entry\"}"; - let result = to_string(&entry).expect("serialization failed"); - - assert_eq!( - expected, result, - "Plain text payload should serialize correctly" - ) -} - -#[test] -fn test_json_entry_serialization() { - let entry = LogEntry { - labels: Value::Null, - timestamp: None, - payload: Payload::JsonPayload { - json_payload: json!({ - "message": "JSON test" - }), - }, - severity: None, - }; - - let expected = "{\"labels\":null,\"jsonPayload\":{\"message\":\"JSON test\"}}"; - let result = to_string(&entry).expect("serialization failed"); - - assert_eq!(expected, result, "JSON payload should serialize correctly") -} - -#[test] -fn test_plain_text_payload() { - let message = "plain text payload".into(); - let payload = message_to_payload(Some(message)); - let expected = Payload::TextPayload { - text_payload: "plain text payload".into(), - }; - - assert_eq!( - expected, payload, - "Plain text payload should be detected correctly" - ); -} - -#[test] -fn test_empty_payload() { - let payload = message_to_payload(None); - let expected = Payload::TextPayload { - text_payload: "empty log entry".into(), - }; - - assert_eq!( - expected, payload, - "Empty payload should be handled correctly" - ); -} - -#[test] -fn test_json_payload() { - let message = "{\"someKey\":\"someValue\", \"otherKey\": 42}".into(); - let payload = message_to_payload(Some(message)); - let expected = Payload::JsonPayload { - json_payload: json!({ - "someKey": "someValue", - "otherKey": 42 - }), - }; - - assert_eq!( - expected, payload, - "JSON payload should be detected correctly" - ); -} - -#[test] -fn test_json_no_object() { - // This message can be parsed as valid JSON, but it is not an - // object - it should be returned as a plain-text payload. - let message = "42".into(); - let payload = message_to_payload(Some(message)); - let expected = Payload::TextPayload { - text_payload: "42".into(), - }; - - assert_eq!( - expected, payload, - "Non-object JSON payload should be plain text" - ); -} - -#[test] -fn test_parse_microseconds() { - let input: String = "1529175149291187".into(); - let expected: time::OffsetDateTime = datetime!(2018-06-16 18:52:29.291187 UTC); - - assert_eq!(Some(expected), parse_microseconds(input)); -} diff --git a/ops/machines/all-systems.nix b/ops/machines/all-systems.nix index c8a325a1c..289c2d88f 100644 --- a/ops/machines/all-systems.nix +++ b/ops/machines/all-systems.nix @@ -1,28 +1,6 @@ { depot, ... }: (with depot.ops.machines; [ - sanduny - bugry - nevsky -]) ++ - -(with depot.users.tazjin.nixos; [ - camden - frog - tverskoy - zamalek -]) ++ - -(with depot.users.aspen.system.system; [ - yeren - mugwump - ogopogo - lusca -]) ++ - -(with depot.users.wpcarro.nixos; [ - ava - kyoko - marcus - tarasco + meta01 + public01 ]) diff --git a/ops/machines/bugry/default.nix b/ops/machines/bugry/default.nix deleted file mode 100644 index 5815d4348..000000000 --- a/ops/machines/bugry/default.nix +++ /dev/null @@ -1,205 +0,0 @@ -{ depot, lib, pkgs, ... }: # readTree options -{ config, ... }: # passed by module system - -let - mod = name: depot.path.origSrc + ("/ops/modules/" + name); -in -{ - imports = [ - (mod "atward.nix") - (mod "depot-replica.nix") - (mod "known-hosts.nix") - (mod "nixery.nix") - (mod "tvl-cache.nix") - (mod "tvl-users.nix") - (mod "www/atward.tvl.fyi.nix") - (mod "www/nixery.dev.nix") - (mod "www/self-redirect.nix") - (mod "www/signup.tvl.fyi.nix") - (mod "www/static.tvl.fyi.nix") - (mod "www/todo.tvl.fyi.nix") - (mod "www/tvix.dev.nix") - (mod "www/tvl.fyi.nix") - (mod "www/tvl.su.nix") - (mod "www/wigglydonke.rs.nix") - - (depot.third_party.agenix.src + "/modules/age.nix") - ]; - - hardware.cpu.intel.updateMicrocode = true; - - boot = { - tmp.useTmpfs = true; - kernelModules = [ "kvm-intel" ]; - supportedFilesystems = [ "zfs" ]; - kernelParams = [ - "ip=91.199.149.239::91.199.149.1:255.255.255.0:bugry:enp6s0:none" - ]; - - initrd = { - availableKernelModules = [ "uhci_hcd" "ehci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" "e1000e" ]; - - # initrd SSH for disk unlocking - network = { - enable = true; - ssh = { - enable = true; - port = 2222; - authorizedKeys = - depot.users.tazjin.keys.all - ++ depot.users.lukegb.keys.all - ++ depot.users.sterni.keys.all; - - hostKeys = [ - /etc/secrets/initrd_host_ed25519_key - ]; - }; - - # this will launch the zfs password prompt on login and kill the - # other prompt - postCommands = '' - echo "zfs load-key -a && killall zfs" >> /root/.profile - ''; - }; - }; - - kernel.sysctl = { - "net.ipv4.tcp_congestion_control" = "bbr"; - }; - - loader.grub = { - enable = true; - device = "/dev/disk/by-id/wwn-0x5002538ec0ae4c93"; - }; - - zfs.requestEncryptionCredentials = true; - }; - - fileSystems = { - "/" = { - device = "tank/root"; - fsType = "zfs"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/70AC-4B48"; - fsType = "vfat"; - }; - - "/nix" = { - device = "tank/nix"; - fsType = "zfs"; - }; - - "/home" = { - device = "tank/home"; - fsType = "zfs"; - }; - }; - - age.secrets = { - wg-privkey.file = depot.ops.secrets."wg-bugry.age"; - }; - - networking = { - hostName = "bugry"; - domain = "tvl.fyi"; - hostId = "8425e349"; - useDHCP = false; - - interfaces.enp6s0.ipv4.addresses = [{ - address = "91.199.149.239"; - prefixLength = 24; - }]; - - defaultGateway = "91.199.149.1"; - - wireguard.interfaces.wg-nevsky = { - ips = [ "2a03:6f00:2:514b:5bc7:95ef:0:2/96" ]; - privateKeyFile = "/run/agenix/wg-privkey"; - - peers = [{ - publicKey = "gLyIY+R/YG9S8W8jtqE6pEV6MTyzeUX/PalL6iyvu3g="; # nevsky - endpoint = "188.225.81.75:51820"; - persistentKeepalive = 25; - allowedIPs = [ "::/0" ]; - }]; - - allowedIPsAsRoutes = false; # used as default v6 gateway below - }; - - defaultGateway6.address = "2a03:6f00:2:514b:5bc7:95ef::1"; - defaultGateway6.interface = "wg-nevsky"; - - nameservers = [ - "8.8.8.8" - "8.8.4.4" - ]; - - firewall.allowedTCPPorts = [ 22 80 443 ]; - }; - - # Generate an immutable /etc/resolv.conf from the nameserver settings - # above (otherwise DHCP overwrites it): - environment.etc."resolv.conf" = with lib; { - source = pkgs.writeText "resolv.conf" '' - ${concatStringsSep "\n" (map (ns: "nameserver ${ns}") config.networking.nameservers)} - options edns0 - ''; - }; - - services.openssh = { - enable = true; - settings = { - PasswordAuthentication = false; - KbdInteractiveAuthentication = false; - }; - }; - - services.fail2ban.enable = true; - - programs.mtr.enable = true; - programs.mosh.enable = true; - - time.timeZone = "UTC"; - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - - # Join TVL Tailscale network at net.tvl.fyi - services.tailscale = { - enable = true; - useRoutingFeatures = "both"; - }; - - security.sudo.extraRules = [ - { - groups = [ "wheel" ]; - commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }]; - } - ]; - - zramSwap.enable = true; - - tvl.cache.enable = true; - tvl.cache.builderball = true; - - services.depot = - { - nixery.enable = true; - - # Allow Gerrit to replicate depot to /var/lib/depot - replica.enable = true; - - # Run atward, the search engine redirection thing. - atward.enable = true; - - automatic-gc = { - enable = true; - interval = "1 hour"; - diskThreshold = 50; # GiB (10% of disk) - maxFreed = 150; # GiB - preserveGenerations = "14d"; - }; - }; - - system.stateVersion = "24.11"; -} diff --git a/ops/machines/nevsky/default.nix b/ops/machines/nevsky/default.nix deleted file mode 100644 index 983f4bcb8..000000000 --- a/ops/machines/nevsky/default.nix +++ /dev/null @@ -1,560 +0,0 @@ -{ depot, lib, pkgs, ... }: # readTree options -{ config, ... }: # passed by module system - -let - mod = name: depot.path.origSrc + ("/ops/modules/" + name); -in -{ - imports = [ - (depot.third_party.agenix.src + "/modules/age.nix") - (mod "builderball.nix") - (mod "cgit.nix") - (mod "cheddar.nix") - (mod "clbot.nix") - (mod "gerrit-autosubmit.nix") - (mod "harmonia.nix") - (mod "irccat.nix") - (mod "josh.nix") - (mod "known-hosts.nix") - (mod "livegrep.nix") - (mod "monitoring.nix") - (mod "monorepo-gerrit.nix") - (mod "owothia.nix") - (mod "panettone.nix") - (mod "paroxysm.nix") - (mod "restic.nix") - (mod "smtprelay.nix") - (mod "teleirc.nix") - (mod "tvl-buildkite.nix") - (mod "tvl-slapd/default.nix") - (mod "tvl-users.nix") - (mod "www/auth.tvl.fyi.nix") - (mod "www/b.tvl.fyi.nix") - (mod "www/cache.tvl.fyi.nix") - (mod "www/cache.tvl.su.nix") - (mod "www/cl.tvl.fyi.nix") - (mod "www/code.tvl.fyi.nix") - (mod "www/cs.tvl.fyi.nix") - (mod "www/grep.tvl.fyi.nix") - (mod "www/self-cache.tvl.fyi.nix") - (mod "www/self-redirect.nix") - (mod "www/status.tvl.su.nix") - ]; - - hardware.cpu.amd.updateMicrocode = true; - hardware.enableRedistributableFirmware = true; - powerManagement.cpuFreqGovernor = "performance"; - - boot = { - tmp.useTmpfs = true; - kernelModules = [ "kvm-amd" ]; - supportedFilesystems = [ "zfs" ]; - kernelParams = [ - "ip=188.225.81.75::188.225.81.1:255.255.255.0:nevsky:enp1s0f0np0:none" - ]; - - initrd = { - availableKernelModules = [ "nvme" "xhci_pci" "usbhid" "ice" ]; - - # initrd SSH for disk unlocking - network = { - enable = true; - ssh = { - enable = true; - port = 2222; - authorizedKeys = - depot.users.tazjin.keys.all - ++ depot.users.lukegb.keys.all - ++ depot.users.sterni.keys.all; - - hostKeys = [ - /etc/secrets/initrd_host_ed25519_key - ]; - }; - - # this will launch the zfs password prompt on login and kill the - # other prompt - postCommands = '' - echo "zfs load-key -a && killall zfs" >> /root/.profile - ''; - }; - }; - - kernel.sysctl = { - "net.ipv4.tcp_congestion_control" = "bbr"; - }; - - loader.systemd-boot.enable = true; - loader.efi.canTouchEfiVariables = true; - zfs.requestEncryptionCredentials = true; - }; - - fileSystems = { - "/" = { - device = "tank/root"; - fsType = "zfs"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/CCB4-8821"; - fsType = "vfat"; - }; - - "/nix" = { - device = "tank/nix"; - fsType = "zfs"; - }; - - "/home" = { - device = "tank/home"; - fsType = "zfs"; - }; - - "/depot" = { - device = "tank/depot"; - fsType = "zfs"; - }; - }; - - age.secrets = - let - secretFile = name: depot.ops.secrets."${name}.age"; - in - { - clbot.file = secretFile "clbot"; - gerrit-autosubmit.file = secretFile "gerrit-autosubmit"; - grafana.file = secretFile "grafana"; - irccat.file = secretFile "irccat"; - keycloak-db.file = secretFile "keycloak-db"; - owothia.file = secretFile "owothia"; - panettone.file = secretFile "panettone"; - smtprelay.file = secretFile "smtprelay"; - teleirc.file = secretFile "teleirc"; - wg-privkey.file = depot.ops.secrets."wg-nevsky.age"; - - nix-cache-priv = { - file = secretFile "nix-cache-priv"; - mode = "0440"; - group = "harmonia"; - }; - - # Not actually a secret - nix-cache-pub = { - file = secretFile "nix-cache-pub"; - mode = "0444"; - }; - - buildkite-agent-token = { - file = secretFile "buildkite-agent-token"; - mode = "0440"; - group = "buildkite-agents"; - }; - - buildkite-graphql-token = { - file = secretFile "buildkite-graphql-token"; - mode = "0440"; - group = "buildkite-agents"; - }; - - buildkite-besadii-config = { - file = secretFile "besadii"; - mode = "0440"; - group = "buildkite-agents"; - }; - - buildkite-private-key = { - file = secretFile "buildkite-ssh-private-key"; - mode = "0440"; - group = "buildkite-agents"; - }; - - gerrit-besadii-config = { - file = secretFile "besadii"; - owner = "git"; - }; - - gerrit-secrets = { - file = secretFile "gerrit-secrets"; - path = "/var/lib/gerrit/etc/secure.config"; - owner = "git"; - mode = "0400"; - }; - - clbot-ssh = { - file = secretFile "clbot-ssh"; - owner = "clbot"; - }; - - depot-replica-key = { - file = secretFile "depot-replica-key"; - mode = "0500"; - owner = "git"; - group = "git"; - path = "/var/lib/git/.ssh/id_ed25519"; - }; - }; - - networking = { - hostName = "nevsky"; - domain = "tvl.fyi"; - hostId = "0117d088"; - useDHCP = false; - - interfaces.enp1s0f0np0.ipv4.addresses = [{ - address = "188.225.81.75"; - prefixLength = 24; - }]; - - defaultGateway = "188.225.81.1"; - - interfaces.enp1s0f0np0.ipv6.addresses = [{ - address = "2a03:6f00:2:514b:0:feed:edef:beef"; - prefixLength = 64; - }]; - - defaultGateway6 = { - address = "2a03:6f00:2:514b::1"; - interface = "enp1s0f0np0"; - }; - - wireguard.interfaces.wg-bugry = { - ips = [ "2a03:6f00:2:514b:5bc7:95ef::1/96" ]; - privateKeyFile = "/run/agenix/wg-privkey"; - listenPort = 51820; - - postSetup = '' - ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s '2a03:6f00:2:514b:5bc7:95ef::1/96' -o enp1s0f0np0 -j MASQUERADE - ip -6 neigh add proxy 2a03:6f00:2:514b:5bc7:95ef:0:2 dev enp1s0f0np0 - ''; - - postShutdown = '' - ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s '2a03:6f00:2:514b:5bc7:95ef::1/96' -o enp1s0f0np0 -j MASQUERADE - ip -6 neigh del proxy 2a03:6f00:2:514b:5bc7:95ef:0:2 dev enp1s0f0np0 - ''; - - peers = [{ - publicKey = "+vFeWLH99aaypitw7x1J8IypoTrva28LItb1v2VjOAg="; # bugry - allowedIPs = [ "2a03:6f00:2:514b:5bc7:95ef::/96" ]; - }]; - - allowedIPsAsRoutes = true; - }; - - nameservers = [ - "8.8.8.8" - "8.8.4.4" - ]; - - firewall.allowedTCPPorts = [ 22 80 443 29418 ]; - firewall.allowedUDPPorts = [ 51820 ]; - }; - - # Generate an immutable /etc/resolv.conf from the nameserver settings - # above (otherwise DHCP overwrites it): - environment.etc."resolv.conf" = with lib; { - source = pkgs.writeText "resolv.conf" '' - ${concatStringsSep "\n" (map (ns: "nameserver ${ns}") config.networking.nameservers)} - options edns0 - ''; - }; - - services.openssh = { - enable = true; - settings = { - PasswordAuthentication = false; - KbdInteractiveAuthentication = false; - }; - }; - - services.fail2ban.enable = true; - - programs.mtr.enable = true; - programs.mosh.enable = true; - - time.timeZone = "UTC"; - nixpkgs.hostPlatform = "x86_64-linux"; - - services.fwupd.enable = true; - - services.postgresql = { - enable = true; - enableTCPIP = true; - package = pkgs.postgresql_16; - - authentication = lib.mkForce '' - local all all trust - host all all 127.0.0.1/32 password - host all all ::1/128 password - hostnossl all all 127.0.0.1/32 password - hostnossl all all ::1/128 password - ''; - - ensureDatabases = [ - "panettone" - ]; - - ensureUsers = [{ - name = "panettone"; - ensureDBOwnership = true; - }]; - }; - - # Join TVL Tailscale network at net.tvl.fyi - services.tailscale = { - enable = true; - useRoutingFeatures = "both"; - }; - - services.depot = { - # Run a Harmonia binary cache. - # - # TODO(tazjin): switch to upstream module after fix for Nix 2.3 - harmonia = { - enable = true; - signKeyPaths = [ (config.age.secretsDir + "/nix-cache-priv") ]; - settings.bind = "127.0.0.1:6443"; - settings.priority = 50; - }; - - builderball.enable = true; - - # Run Markdown/code renderer - cheddar.enable = true; - - # Run a livegrep code search instance - livegrep.enable = true; - - # Automatically collect garbage from the Nix store. - automatic-gc = { - enable = true; - interval = "1 hour"; - diskThreshold = 200; # GiB - maxFreed = 420; # GiB - preserveGenerations = "60d"; - }; - - # Run cgit & josh to serve git - cgit = { - enable = true; - user = "git"; # run as the same user as gerrit - }; - - josh.enable = true; - - # Run a handful of Buildkite agents to support parallel builds. - buildkite = { - enable = true; - agentCount = 24; - largeSlots = 6; - }; - - # Run the Panettone issue tracker - panettone = { - enable = true; - dbUser = "panettone"; - dbName = "panettone"; - irccatChannel = "#tvl"; - }; - - # Run the first cursed bot (quote bot) - paroxysm.enable = true; - - # make our channel more owo - owothia = { - enable = true; - ircServer = "localhost"; - ircPort = config.services.znc.config.Listener.l.Port; - }; - - # Run irccat to forward messages to IRC - irccat = { - enable = true; - config = { - tcp.listen = ":4722"; # "ircc" - irc = { - server = "localhost:${toString config.services.znc.config.Listener.l.Port}"; - tls = false; - nick = "tvlbot"; - # Note: irccat means 'ident' where it says 'realname', so - # this is critical for connecting to ZNC. - realname = "tvlbot"; - channels = [ - "#tvl" - ]; - }; - }; - }; - - # Start the Gerrit->IRC bot - clbot = { - enable = true; - channels = { - "#tvl" = { }; - "#tvix-dev" = { - only_display = "tvix,nix-compat,third_party,third-party,3p"; - }; - }; - - # See //fun/clbot for details. - flags = { - gerrit_host = "cl.tvl.fyi:29418"; - gerrit_ssh_auth_username = "clbot"; - gerrit_ssh_auth_key = config.age.secretsDir + "/clbot-ssh"; - - irc_server = "localhost:${toString config.services.znc.config.Listener.l.Port}"; - irc_user = "tvlbot"; - irc_nick = "tvlbot"; - - notify_branches = "canon,refs/meta/config"; - notify_repo = "depot"; - - # This secret is read from an environment variable, which is - # populated by a systemd EnvironmentFile. - irc_pass = "$CLBOT_PASS"; - }; - }; - - # Start a local SMTP relay to Gmail (used by gerrit) - smtprelay = { - enable = true; - args = { - listen = ":2525"; - remote_host = "smtp.gmail.com:587"; - remote_auth = "plain"; - remote_user = "tvlbot@tazj.in"; - }; - }; - - # Run the Telegram<>IRC bridge for Volga Sprint. - teleirc.enable = true; - - # Configure backups to GleSYS - restic = { - enable = true; - paths = [ - "/var/backup/postgresql" - "/var/lib/grafana" - "/var/lib/znc" - ]; - }; - - # Run autosubmit bot for Gerrit - gerrit-autosubmit.enable = true; - }; - - # Start a ZNC instance which bounces for tvlbot and owothia. - services.znc = { - enable = true; - useLegacyConfig = false; - config = { - LoadModule = [ - "webadmin" - "adminlog" - ]; - - User.admin = { - Admin = true; - Pass.password = { - Method = "sha256"; - Hash = "bb00aa8239de484c2925b1c3f6a196fb7612633f001daa9b674f83abe7e1103f"; - Salt = "TiB0Ochb1CrtpMTl;2;j"; - }; - }; - - Listener.l = { - Host = "localhost"; - Port = 2627; # bncr - SSL = false; - }; - - Listener.tailscale = { - Host = "100.64.0.11"; - Port = 2627; # bncr - SSL = false; - }; - }; - }; - - services.keycloak = { - enable = true; - - settings = { - http-port = 5925; # kycl - hostname = "auth.tvl.fyi"; - http-relative-path = "/auth"; - proxy-headers = "xforwarded"; - http-enabled = true; - }; - - database = { - type = "postgresql"; - passwordFile = config.age.secretsDir + "/keycloak-db"; - createLocally = false; - }; - }; - - services.postgresqlBackup = { - enable = true; - databases = [ - "keycloak" - "panettone" - "tvldb" - ]; - }; - - # Use TVL cache locally through the proxy; for cross-builder substitution. - tvl.cache.enable = true; - tvl.cache.builderball = true; - - # Disable background git gc system-wide, as it has a tendency to break CI. - environment.etc."gitconfig".source = pkgs.writeText "gitconfig" '' - [gc] - autoDetach = false - ''; - - security.sudo.extraRules = [{ - groups = [ "wheel" ]; - commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }]; - }]; - - users = { - # Set up a user & group for git shenanigans - groups.git = { }; - users.git = { - group = "git"; - isSystemUser = true; - createHome = true; - home = "/var/lib/git"; - }; - }; - - zramSwap.enable = true; - - environment.systemPackages = (with pkgs; [ - bat - bb - curl - direnv - emacs-nox - fd - git - htop - hyperfine - jq - nano - nix-diff - nix-top - nvd - ripgrep - screen - tig - tree - unzip - vim - watchexec - zfs - zfstools - ]); - - system.stateVersion = "24.11"; -} diff --git a/ops/machines/sanduny/default.nix b/ops/machines/sanduny/default.nix deleted file mode 100644 index af2dfb02a..000000000 --- a/ops/machines/sanduny/default.nix +++ /dev/null @@ -1,138 +0,0 @@ -# sanduny.tvl.su -# -# This is a VPS hosted with Bitfolk, intended to additionally serve -# some of our public services like cgit, josh and the websites. -# -# In case of whitby going down, sanduny will keep depot available. - -_: # ignore readTree options - -{ config, depot, lib, pkgs, ... }: - -let - mod = name: depot.path.origSrc + ("/ops/modules/" + name); -in -{ - imports = [ - (mod "cgit.nix") - (mod "depot-inbox.nix") - (mod "depot-replica.nix") - (mod "journaldriver.nix") - (mod "known-hosts.nix") - (mod "tvl-cache.nix") - (mod "tvl-headscale.nix") - (mod "tvl-users.nix") - (mod "www/inbox.tvl.su.nix") - (mod "www/self-redirect.nix") - (mod "www/volgasprint.org.nix") - ]; - - networking = { - hostName = "sanduny"; - domain = "tvl.su"; - useDHCP = false; - - interfaces.eth0 = { - ipv4.addresses = lib.singleton { - address = "85.119.82.231"; - prefixLength = 21; - }; - - ipv6.addresses = lib.singleton { - address = "2001:ba8:1f1:f109::feed:edef:beef"; - prefixLength = 64; - }; - }; - - defaultGateway = "85.119.80.1"; - defaultGateway6.address = "2001:ba8:1f1:f109::1"; - - firewall.allowedTCPPorts = [ 22 80 443 ]; - - # https://bitfolk.com/customer_information.html#toc_2_DNS - nameservers = [ - "85.119.80.232" - "85.119.80.233" - "2001:ba8:1f1:f205::53" - "2001:ba8:1f1:f206::53" - ]; - }; - - security.sudo.wheelNeedsPassword = false; - - environment.systemPackages = with pkgs; [ - emacs-nox - vim - curl - unzip - htop - ]; - - programs.mtr.enable = true; - - services.openssh.enable = true; - services.fail2ban.enable = true; - - # Run tailscale for the TVL net.tvl.fyi network. - # tailscale up --login-server https://net.tvl.fyi --accept-dns=false --advertise-exit-node - services.tailscale = { - enable = true; - useRoutingFeatures = "server"; # for exit-node usage - }; - - # Automatically collect garbage from the Nix store. - services.depot.automatic-gc = { - enable = true; - interval = "1 hour"; - diskThreshold = 2; # GiB - maxFreed = 5; # GiB - preserveGenerations = "90d"; - }; - - # Allow Gerrit to replicate depot to /var/lib/depot - services.depot.replica.enable = true; - - # Run git serving tools locally ... - services.depot.cgit = { - enable = true; - repo = "/var/lib/depot"; - }; - - # Serve public-inbox ... - services.depot.inbox.enable = true; - - time.timeZone = "UTC"; - - # GRUB does not actually need to be installed on disk; Bitfolk have - # their own way of booting systems as long as config is in place. - boot.loader.grub.device = "nodev"; - boot.loader.grub.enable = true; - boot.initrd.availableKernelModules = [ "xen_blkfront" ]; - - hardware.cpu.intel.updateMicrocode = true; - - fileSystems = { - "/" = { - device = "/dev/disk/by-uuid/aabc3638-43ca-45f3-af89-c451e8448e92"; - fsType = "ext4"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/75aa99d5-fed7-4c5c-8570-7745f6cff9f5"; - fsType = "ext3"; - }; - - "/nix" = { - device = "/dev/disk/by-uuid/d1721678-c294-482b-b72e-3b15f2c56c63"; - fsType = "ext4"; - }; - }; - - tvl.cache.enable = true; - - swapDevices = lib.singleton { - device = "/dev/disk/by-uuid/df4ad9da-0a06-4c27-93e5-5d44e4750e55"; - }; - - system.stateVersion = "22.05"; # Did you read the comment? -} diff --git a/ops/modules/cgit.nix b/ops/modules/cgit.nix deleted file mode 100644 index fc3f17158..000000000 --- a/ops/modules/cgit.nix +++ /dev/null @@ -1,55 +0,0 @@ -# Configuration for running the TVL cgit instance using thttpd. -{ config, depot, lib, pkgs, ... }: - -let - cfg = config.services.depot.cgit; - - userConfig = - if builtins.isNull cfg.user then { - DynamicUser = true; - } else { - User = cfg.user; - Group = cfg.user; - }; -in -{ - options.services.depot.cgit = with lib; { - enable = mkEnableOption "Run cgit web interface for depot"; - - port = mkOption { - description = "Port on which cgit should listen"; - type = types.int; - default = 2448; - }; - - repo = mkOption { - description = "Path to depot's .git folder on the machine"; - type = types.str; - default = "/var/lib/gerrit/git/depot.git/"; - }; - - user = mkOption { - description = '' - User to use for the cgit service. It is expected that this is - also the name of the user's primary group. - ''; - - type = with types; nullOr str; - default = null; - }; - }; - - config = lib.mkIf cfg.enable { - systemd.services.cgit = { - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - Restart = "on-failure"; - - ExecStart = depot.web.cgit-tvl.override { - inherit (cfg) port repo; - }; - } // userConfig; - }; - }; -} diff --git a/ops/modules/cheddar.nix b/ops/modules/cheddar.nix deleted file mode 100644 index 8c3036978..000000000 --- a/ops/modules/cheddar.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ depot, config, pkgs, lib, ... }: - -let - cfg = config.services.depot.cheddar; - description = "cheddar - markdown/highlighting server"; -in -{ - options.services.depot.cheddar = with lib; { - enable = mkEnableOption description; - port = mkOption { - description = "Port on which cheddar should listen"; - type = types.int; - default = 4238; - }; - }; - - config = lib.mkIf cfg.enable { - systemd.services.cheddar-server = { - inherit description; - wantedBy = [ "multi-user.target" ]; - script = "${depot.tools.cheddar}/bin/cheddar --listen 0.0.0.0:${toString cfg.port} --sourcegraph-server"; - - serviceConfig = { - DynamicUser = true; - Restart = "always"; - }; - }; - }; -} diff --git a/ops/modules/default-imports.nix b/ops/modules/default-imports.nix index 11514a437..01a378ad0 100644 --- a/ops/modules/default-imports.nix +++ b/ops/modules/default-imports.nix @@ -9,6 +9,5 @@ imports = [ ./automatic-gc.nix ./auto-deploy.nix - ./tvl-cache.nix ]; } diff --git a/ops/modules/depot-inbox.nix b/ops/modules/depot-inbox.nix deleted file mode 100644 index 14fc646a9..000000000 --- a/ops/modules/depot-inbox.nix +++ /dev/null @@ -1,148 +0,0 @@ -# public-inbox configuration for depot@tvl.su -# -# The account itself is a Yandex 360 account in the tvl.su organisation, which -# is accessed via IMAP. Yandex takes care of spam filtering for us, so there is -# no particular SpamAssassin or other configuration. -{ config, depot, lib, pkgs, ... }: - -let - cfg = config.services.depot.inbox; - - imapConfig = pkgs.writeText "offlineimaprc" '' - [general] - accounts = depot - - [Account depot] - localrepository = Local - remoterepository = Remote - - [Repository Local] - type = Maildir - localfolders = /var/lib/public-inbox/depot-imap - - [Repository Remote] - type = IMAP - ssl = yes - sslcacertfile = /etc/ssl/certs/ca-bundle.crt - remotehost = imap.yandex.ru - remoteuser = depot@tvl.su - remotepassfile = /var/run/agenix/depot-inbox-imap - ''; -in -{ - options.services.depot.inbox = with lib; { - enable = mkEnableOption "Enable public-inbox for depot@tvl.su"; - - depotPath = mkOption { - description = "path to local depot replica"; - type = types.str; - default = "/var/lib/depot"; - }; - }; - - config = lib.mkIf cfg.enable { - # Having nginx *and* other services use ACME certificates for the - # same hostname is unsupported in NixOS without resorting to doing - # all ACME configuration manually. - # - # To work around this, we duplicate the TLS certificate used by - # nginx to a location that is readable by public-inbox daemons. - systemd.services.inbox-cert-sync = { - startAt = "daily"; - - script = '' - ${pkgs.coreutils}/bin/install -D -g ${config.users.groups."public-inbox".name} -m 0440 \ - /var/lib/acme/inbox.tvl.su/fullchain.pem /var/lib/public-inbox/tls/fullchain.pem - - ${pkgs.coreutils}/bin/install -D -g ${config.users.groups."public-inbox".name} -m 0440 \ - /var/lib/acme/inbox.tvl.su/key.pem /var/lib/public-inbox/tls/key.pem - ''; - }; - - services.public-inbox = { - enable = true; - - http.enable = true; - http.port = 8053; - - imap = { - enable = true; - port = 993; - cert = "/var/lib/public-inbox/tls/fullchain.pem"; - key = "/var/lib/public-inbox/tls/key.pem"; - }; - - nntp = { - enable = true; - port = 563; - cert = "/var/lib/public-inbox/tls/fullchain.pem"; - key = "/var/lib/public-inbox/tls/key.pem"; - }; - - inboxes.depot = rec { - address = [ - "depot@tvl.su" # primary address - "depot@tazj.in" # legacy address - ]; - - description = "TVL depot development (mail to depot@tvl.su)"; - coderepo = [ "depot" ]; - url = "https://inbox.tvl.su/depot"; - - watch = [ - "maildir:/var/lib/public-inbox/depot-imap/INBOX/" - ]; - - newsgroup = "su.tvl.depot"; - }; - - settings.coderepo.depot = { - dir = cfg.depotPath; - cgitUrl = "https://code.tvl.fyi"; - }; - - settings.publicinbox = { - wwwlisting = "all"; - nntpserver = [ "inbox.tvl.su" ]; - imapserver = [ "inbox.tvl.su" ]; - - depot.obfuscate = true; - noObfuscate = [ - "tvl.su" - "tvl.fyi" - ]; - }; - }; - - networking.firewall.allowedTCPPorts = [ - 993 # imap - 563 # nntp - ]; - - age.secrets.depot-inbox-imap = { - file = depot.ops.secrets."depot-inbox-imap.age"; - mode = "0440"; - group = config.users.groups."public-inbox".name; - }; - - systemd.services.offlineimap-depot = { - description = "download mail for depot@tvl.su"; - wantedBy = [ "multi-user.target" ]; - startAt = "minutely"; - - script = '' - mkdir -p /var/lib/public-inbox/depot-imap - ${pkgs.offlineimap}/bin/offlineimap -c ${imapConfig} - ''; - - serviceConfig = { - Type = "oneshot"; - - # Run in the same user context as public-inbox itself to avoid - # permissions trouble. - User = config.users.users."public-inbox".name; - Group = config.users.groups."public-inbox".name; - }; - }; - }; -} diff --git a/ops/modules/depot-replica.nix b/ops/modules/depot-replica.nix deleted file mode 100644 index b71f10409..000000000 --- a/ops/modules/depot-replica.nix +++ /dev/null @@ -1,45 +0,0 @@ -# Configuration for receiving a depot replica from Gerrit's -# replication plugin. -# -# This only prepares the user and folder for receiving the replica, -# but Gerrit configuration still needs to be modified in addition. -{ config, depot, lib, pkgs, ... }: - -let - cfg = config.services.depot.replica; -in -{ - options.services.depot.replica = with lib; { - enable = mkEnableOption "Receive depot git replica from Gerrit"; - - key = mkOption { - description = "Public key to use for replication"; - type = types.str; - default = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFFab9O1xaQ1TCyn+CxmXHexdlLzURREG+UR3Qdi3BvH"; - }; - - path = mkOption { - description = "Replication destination path (will be created)"; - type = types.str; - default = "/var/lib/depot"; - }; - }; - - config = lib.mkIf cfg.enable { - users.groups.depot = { }; - - users.users.depot = { - group = "depot"; - isSystemUser = true; - createHome = true; - home = cfg.path; - homeMode = "755"; # everyone can read depot - openssh.authorizedKeys.keys = lib.singleton cfg.key; - shell = pkgs.bashInteractive; # gerrit needs to run shell commands - }; - - environment.systemPackages = [ - pkgs.git - ]; - }; -} diff --git a/ops/modules/journaldriver.nix b/ops/modules/journaldriver.nix deleted file mode 100644 index 0d6b0bcc7..000000000 --- a/ops/modules/journaldriver.nix +++ /dev/null @@ -1,26 +0,0 @@ -# Configures journaldriver to forward to the tvl-fyi GCP project from -# TVL machines. -{ config, depot, lib, pkgs, ... }: - -{ - imports = [ - (depot.third_party.agenix.src + "/modules/age.nix") - ]; - - age.secrets.journaldriver.file = depot.ops.secrets."journaldriver.age"; - - services.journaldriver = { - enable = true; - googleCloudProject = "tvl-fyi"; - logStream = config.networking.hostName; - }; - - # Override the systemd service defined in the nixpkgs module to use - # the credentials provided by agenix. - systemd.services.journaldriver = { - serviceConfig = { - LoadCredential = "journaldriver.json:/run/agenix/journaldriver"; - ExecStart = lib.mkForce "${pkgs.coreutils}/bin/env GOOGLE_APPLICATION_CREDENTIALS=\"\${CREDENTIALS_DIRECTORY}/journaldriver.json\" ${depot.ops.journaldriver}/bin/journaldriver"; - }; - }; -} diff --git a/ops/modules/known-hosts.nix b/ops/modules/known-hosts.nix index 93f0ca75e..7943d7399 100644 --- a/ops/modules/known-hosts.nix +++ b/ops/modules/known-hosts.nix @@ -3,21 +3,6 @@ { programs.ssh.knownHosts = { - sanduny = { - hostNames = [ "sanduny.tvl.su" ]; - publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOag0XhylaTVhmT6HB8EN2Fv5Ymrc4ZfypOXONUkykTX"; - }; - - bugry = { - hostNames = [ "bugry.tvl.fyi" ]; - publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGqG6sITyJ/UsQ/RtYqmmMvTT4r4sppadoQIz5SvA+5J"; - }; - - nevsky = { - hostNames = [ "nevsky.tvl.fyi" ]; - publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHQe7M+G8Id3ZD7j+I07TCUV1o12q1vpsOXHRlcPSEfa"; - }; - github = { hostNames = [ "github.com" ]; publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl"; diff --git a/ops/modules/nixery.nix b/ops/modules/nixery.nix deleted file mode 100644 index 72de24ab5..000000000 --- a/ops/modules/nixery.nix +++ /dev/null @@ -1,44 +0,0 @@ -# NixOS module to run Nixery, currently with local-storage as the -# backend for storing/serving image layers. -{ depot, config, lib, pkgs, ... }: - -let - cfg = config.services.depot.nixery; - description = "Nixery - container images on-demand"; - nixpkgsSrc = depot.third_party.sources.nixpkgs; - storagePath = "/var/lib/nixery/${nixpkgsSrc.rev}"; -in -{ - options.services.depot.nixery = { - enable = lib.mkEnableOption description; - - port = lib.mkOption { - type = lib.types.int; - default = 45243; # "image" - description = "Port on which Nixery should listen"; - }; - }; - - config = lib.mkIf cfg.enable { - systemd.services.nixery = { - inherit description; - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - DynamicUser = true; - StateDirectory = "nixery"; - Restart = "always"; - ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${storagePath}"; - ExecStart = "${depot.tools.nixery.nixery}/bin/server"; - }; - - environment = { - PORT = toString cfg.port; - NIXERY_PKGS_PATH = nixpkgsSrc.outPath; - NIXERY_STORAGE_BACKEND = "filesystem"; - NIX_TIMEOUT = "60"; # seconds - STORAGE_PATH = storagePath; - }; - }; - }; -} diff --git a/ops/modules/panettone.nix b/ops/modules/panettone.nix deleted file mode 100644 index e23dd028a..000000000 --- a/ops/modules/panettone.nix +++ /dev/null @@ -1,119 +0,0 @@ -{ depot, config, lib, pkgs, ... }: - -let - cfg = config.services.depot.panettone; -in -{ - options.services.depot.panettone = with lib; { - enable = mkEnableOption "Panettone issue tracker"; - - port = mkOption { - description = "Port on which Panettone should listen"; - type = types.int; - default = 7268; - }; - - dbHost = mkOption { - description = "Postgresql host to connect to for Panettone"; - type = types.str; - default = "localhost"; - }; - - dbName = mkOption { - description = "Name of the database for Panettone"; - type = types.str; - default = "panettone"; - }; - - dbUser = mkOption { - description = "Name of the database user for Panettone"; - type = types.str; - default = "panettone"; - }; - - secretsFile = mkOption { - description = '' - Path to a file containing secrets, in the format accepted - by systemd's EnvironmentFile - ''; - type = types.str; - default = config.age.secretsDir + "/panettone"; - }; - - irccatHost = mkOption { - description = "Hostname for the irccat instance"; - type = types.str; - default = "localhost"; - }; - - irccatPort = mkOption { - description = "Port for the irccat instance"; - type = types.int; - default = 4722; - }; - - irccatChannel = mkOption { - description = "IRC channels to post to via irccat"; - type = types.str; - }; - }; - - config = lib.mkIf cfg.enable { - assertions = [{ - assertion = - cfg.dbHost != "localhost" || config.services.postgresql.enable; - message = "Panettone requires a postgresql database"; - } - { - assertion = - cfg.dbHost != "localhost" || config.services.postgresql.enableTCPIP; - message = "Panettone can only connect to the postgresql database over TCP"; - } - { - assertion = - cfg.dbHost != "localhost" || (lib.any - (user: user.name == cfg.dbUser) - config.services.postgresql.ensureUsers); - message = "Panettone requires a database user"; - } - { - assertion = - cfg.dbHost != "localhost" || (lib.any - (db: db == cfg.dbName) - config.services.postgresql.ensureDatabases); - message = "Panettone requires a database"; - }]; - - systemd.services.panettone = { - wantedBy = [ "multi-user.target" ]; - script = "${depot.web.panettone}/bin/panettone"; - - serviceConfig = { - DynamicUser = true; - Restart = "always"; - EnvironmentFile = cfg.secretsFile; - }; - - environment = { - PANETTONE_PORT = toString cfg.port; - PGHOST = "localhost"; - PGUSER = cfg.dbUser; - PGDATABASE = cfg.dbName; - IRCCATHOST = cfg.irccatHost; - IRCCATPORT = toString cfg.irccatPort; - ISSUECHANNEL = cfg.irccatChannel; - }; - }; - - systemd.services.panettone-fixer = { - description = "Restart panettone regularly to work around b/225"; - wantedBy = [ "multi-user.target" ]; - script = "${pkgs.systemd}/bin/systemctl restart panettone"; - serviceConfig.Type = "oneshot"; - - # We don't exactly know how frequently this occurs, but - # _probably_ not more than hourly. - startAt = "hourly"; - }; - }; -} diff --git a/ops/modules/tvl-slapd/default.nix b/ops/modules/tvl-slapd/default.nix deleted file mode 100644 index c08cd30f1..000000000 --- a/ops/modules/tvl-slapd/default.nix +++ /dev/null @@ -1,81 +0,0 @@ -# Configures an OpenLDAP instance for TVL -# -# TODO(tazjin): Configure ldaps:// -{ depot, lib, pkgs, ... }: - -with depot.nix.yants; - -let - user = struct { - username = string; - email = string; - password = string; - displayName = option string; - }; - - toLdif = defun [ user string ] (u: '' - dn: cn=${u.username},ou=users,dc=tvl,dc=fyi - objectClass: organizationalPerson - objectClass: inetOrgPerson - sn: ${u.username} - cn: ${u.username} - displayName: ${u.displayName or u.username} - mail: ${u.email} - userPassword: ${u.password} - ''); - - inherit (depot.ops) users; - -in -{ - services.openldap = { - enable = true; - - settings.children = { - "olcDatabase={1}mdb".attrs = { - objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; - olcDatabase = "{1}mdb"; - olcDbDirectory = "/var/lib/openldap/db"; - olcSuffix = "dc=tvl,dc=fyi"; - olcAccess = "to * by * read"; - olcRootDN = "cn=admin,dc=tvl,dc=fyi"; - olcRootPW = "{ARGON2}$argon2id$v=19$m=65536,t=2,p=1$OfcgkOQ96VQ3aJj7NfA9vQ$oS6HQOkYl/bUYg4SejpltQYy7kvqx/RUxvoR4zo1vXU"; - }; - - "cn=module{0}".attrs = { - objectClass = "olcModuleList"; - olcModuleLoad = "argon2"; - }; - - "cn=schema".includes = - map (schema: "${pkgs.openldap}/etc/schema/${schema}.ldif") - [ "core" "cosine" "inetorgperson" "nis" ]; - }; - - # Contents are immutable at runtime, and adding user accounts etc. - # is done statically in the LDIF-formatted contents in this folder. - declarativeContents."dc=tvl,dc=fyi" = '' - dn: dc=tvl,dc=fyi - dc: tvl - o: TVL LDAP server - description: Root entry for tvl.fyi - objectClass: top - objectClass: dcObject - objectClass: organization - - dn: ou=users,dc=tvl,dc=fyi - ou: users - description: All users in TVL - objectClass: top - objectClass: organizationalUnit - - dn: ou=groups,dc=tvl,dc=fyi - ou: groups - description: All groups in TVL - objectClass: top - objectClass: organizationalUnit - - ${lib.concatStringsSep "\n" (map toLdif users)} - ''; - }; -} diff --git a/ops/modules/tvl-users.nix b/ops/modules/tvl-users.nix deleted file mode 100644 index ea83b435f..000000000 --- a/ops/modules/tvl-users.nix +++ /dev/null @@ -1,83 +0,0 @@ -# Standard NixOS users for TVL machines, as well as configuration that -# should following along when they are added to a machine. -{ depot, pkgs, ... }: - -{ - users = { - users.tazjin = { - isNormalUser = true; - extraGroups = [ "git" "wheel" ]; - shell = pkgs.fish; - openssh.authorizedKeys.keys = depot.users.tazjin.keys.all; - }; - - users.lukegb = { - isNormalUser = true; - extraGroups = [ "git" "wheel" ]; - openssh.authorizedKeys.keys = depot.users.lukegb.keys.all; - }; - - users.aspen = { - isNormalUser = true; - extraGroups = [ "git" "wheel" ]; - openssh.authorizedKeys.keys = [ depot.users.aspen.keys.whitby ]; - }; - - users.edef = { - isNormalUser = true; - extraGroups = [ "git" ]; - openssh.authorizedKeys.keys = depot.users.edef.keys.all; - }; - - users.qyliss = { - isNormalUser = true; - description = "Alyssa Ross"; - extraGroups = [ "git" ]; - openssh.authorizedKeys.keys = depot.users.qyliss.keys.all; - }; - - users.eta = { - isNormalUser = true; - extraGroups = [ "git" ]; - openssh.authorizedKeys.keys = depot.users.eta.keys.whitby; - }; - - users.cynthia = { - isNormalUser = true; # I'm normal OwO :3 - extraGroups = [ "git" ]; - openssh.authorizedKeys.keys = depot.users.cynthia.keys.all; - }; - - users.firefly = { - isNormalUser = true; - extraGroups = [ "git" ]; - openssh.authorizedKeys.keys = depot.users.firefly.keys.whitby; - }; - - users.sterni = { - isNormalUser = true; - extraGroups = [ "git" "wheel" ]; - openssh.authorizedKeys.keys = depot.users.sterni.keys.all; - }; - - users.flokli = { - isNormalUser = true; - extraGroups = [ "git" "wheel" ]; - openssh.authorizedKeys.keys = depot.users.flokli.keys.all; - }; - }; - - programs.fish.enable = true; - - environment.systemPackages = with pkgs; [ - alacritty.terminfo - foot.terminfo - rxvt-unicode-unwrapped.terminfo - kitty.terminfo - ]; - - security.sudo.extraRules = [{ - groups = [ "wheel" ]; - commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }]; - }]; -} diff --git a/ops/modules/www/atward.tvl.fyi.nix b/ops/modules/www/atward.tvl.fyi.nix deleted file mode 100644 index 6b3672dd7..000000000 --- a/ops/modules/www/atward.tvl.fyi.nix +++ /dev/null @@ -1,33 +0,0 @@ -# Serve atward, the query redirection ... thing. -{ config, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - # Short link support (i.e. plain http://at) for users with a - # configured tvl.fyi/tvl.su search domain. - services.nginx.virtualHosts."at-shortlink" = { - serverName = "at"; - extraConfig = "return 302 https://atward.tvl.fyi$request_uri;"; - }; - - services.nginx.virtualHosts."atward" = { - serverName = "atward.tvl.fyi"; - enableACME = true; - forceSSL = true; - - serverAliases = [ - "atward.tvl.su" - "at.tvl.fyi" - "at.tvl.su" - ]; - - locations."/" = { - proxyPass = "http://localhost:${toString config.services.depot.atward.port}"; - }; - }; - }; -} diff --git a/ops/modules/www/auth.tvl.fyi.nix b/ops/modules/www/auth.tvl.fyi.nix deleted file mode 100644 index a068f0236..000000000 --- a/ops/modules/www/auth.tvl.fyi.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ config, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."auth.tvl.fyi" = { - serverName = "auth.tvl.fyi"; - enableACME = true; - forceSSL = true; - - extraConfig = '' - # increase buffer size for large headers - proxy_buffers 8 16k; - proxy_buffer_size 16k; - - location / { - proxy_pass http://localhost:${toString config.services.keycloak.settings.http-port}; - proxy_set_header X-Forwarded-For $remote_addr; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header Host $host; - } - ''; - }; - }; -} diff --git a/ops/modules/www/b.tvl.fyi.nix b/ops/modules/www/b.tvl.fyi.nix deleted file mode 100644 index 45f6c6ed5..000000000 --- a/ops/modules/www/b.tvl.fyi.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ config, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."b-shortlink" = { - serverName = "b"; - extraConfig = "return 302 https://b.tvl.fyi$request_uri;"; - }; - - services.nginx.virtualHosts."b.tvl.fyi" = { - serverName = "b.tvl.fyi"; - serverAliases = [ "b.tvl.su" ]; - enableACME = true; - forceSSL = true; - - extraConfig = '' - # Forward short links to issues to the issue itself (b/32) - location ~ ^/(\d+)$ { - return 302 https://b.tvl.fyi/issues$request_uri; - } - - location / { - proxy_pass http://localhost:${toString config.services.depot.panettone.port}; - } - ''; - }; - }; -} diff --git a/ops/modules/www/cache.tvl.fyi.nix b/ops/modules/www/cache.tvl.fyi.nix deleted file mode 100644 index 88f8131c4..000000000 --- a/ops/modules/www/cache.tvl.fyi.nix +++ /dev/null @@ -1,55 +0,0 @@ -# Publicly serve builderball cache. This is an experimental setup, and separate -# from the "normal" harmonia cache on cache.tvl.su. -{ config, ... }: - -let - # This attrset forms a linked list of hosts, which delegate ACME fallbacks to - # each other. These *must* form a circle, otherwise we may end up walking only - # part of the ring. - # - # TODO: remove whitby from here, it is gone; leaving this code for now for - # easier discovery when reconfiguring this. - acmeFallback = host: ({ - whitby = "nevsky.cache.tvl.fyi"; - nevsky = "whitby.cache.tvl.fyi"; # GOTO 1 - })."${host}"; -in -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."cache.tvl.fyi" = { - serverName = "cache.tvl.fyi"; - enableACME = true; - forceSSL = true; - - # This enables fetching TLS certificates for the same domain on different - # hosts. This config is kind of messy; it would be nice to generate a - # correct ring from the depot fixpoint, but this may be impossible due to - # infinite recursion. Please read the comment on `acmeFallback` above. - # - # TODO: whitby is gone, this is not needed at the moment - # acmeFallbackHost = acmeFallback config.networking.hostName; - - extraConfig = '' - location = /cache-key.pub { - alias /run/agenix/nix-cache-pub; - } - - location = / { - proxy_pass http://${config.services.depot.harmonia.settings.bind}; - } - - location / { - proxy_pass http://localhost:${toString config.services.depot.builderball.port}; - } - ''; - }; - - # participating hosts should use their local cache, otherwise they might end - # up querying themselves from afar for data they don't have. - networking.extraHosts = "127.0.0.1 cache.tvl.fyi"; - }; -} diff --git a/ops/modules/www/cache.tvl.su.nix b/ops/modules/www/cache.tvl.su.nix deleted file mode 100644 index 69f0f1e93..000000000 --- a/ops/modules/www/cache.tvl.su.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ config, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."cache.tvl.su" = { - serverName = "cache.tvl.su"; - enableACME = true; - forceSSL = true; - - extraConfig = '' - location = /cache-key.pub { - alias /run/agenix/nix-cache-pub; - } - - location / { - proxy_pass http://${config.services.depot.harmonia.settings.bind}; - } - ''; - }; - }; -} diff --git a/ops/modules/www/cs.tvl.fyi.nix b/ops/modules/www/cs.tvl.fyi.nix deleted file mode 100644 index 9555acf9a..000000000 --- a/ops/modules/www/cs.tvl.fyi.nix +++ /dev/null @@ -1,66 +0,0 @@ -# This configuration redirects from the previous Sourcegraph instance to -# livegrep/cgit where appropriate. -{ config, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."cs.tvl.fyi" = { - serverName = "cs.tvl.fyi"; - serverAliases = [ "cs.tvl.su" ]; - enableACME = true; - forceSSL = true; - - extraConfig = '' - set $lineno ""; - - # depot root - location = /depot { - return 301 https://code.tvl.fyi/tree/; - } - - # folder/file on canon - location ~ ^/depot/-/(blob|tree)/([^\s]*)$ { - set $path $2; - if ($args ~ ^L(\d+)(-\d+)?$) { - set $lineno "#n$1"; - } - - return 302 https://code.tvl.fyi/tree/$path$lineno; - } - - # folder/file on specific commit - location ~ ^/depot@([a-f0-9]+)/-/(blob|tree)/([^\s]*)$ { - set $commit $1; - set $path $3; - - if ($args ~ ^L(\d+)(-\d+)?$) { - set $lineno "#n$1"; - } - - return 302 https://code.tvl.fyi/tree/$path?id=$commit$lineno; - } - - # commit info - location ~ ^/depot/-/commit/([a-f0-9]+)$ { - set $commit $1; - return 302 https://code.tvl.fyi/commit/?id=$commit; - } - - # search handler - # This only redirects to the new search, it doesn't try to parse and - # rewrite the query. - location /search { - return 302 https://grep.tvl.fyi/search; - } - - location / { - return 404 "TVL code search has moved to grep.tvl.fyi and we could not figure out how to rewrite your query. Sorry!"; - } - ''; - }; - }; -} diff --git a/ops/modules/www/deploys.tvl.fyi.nix b/ops/modules/www/deploys.tvl.fyi.nix deleted file mode 100644 index ffbe225b5..000000000 --- a/ops/modules/www/deploys.tvl.fyi.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ pkgs, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - # Ensure the directory for deployment diffs exists. - systemd.tmpfiles.rules = [ - "d /var/html/deploys.tvl.fyi/diff 0755 nginx nginx -" - ]; - - services.nginx.virtualHosts."deploys.tvl.fyi" = { - enableACME = true; - forceSSL = true; - root = "/var/html/deploys.tvl.fyi"; - }; - - services.depot.restic.paths = [ "/var/html/deploys.tvl.fyi" ]; - }; -} diff --git a/ops/modules/www/grep.tvl.fyi.nix b/ops/modules/www/grep.tvl.fyi.nix deleted file mode 100644 index 93ef5eabd..000000000 --- a/ops/modules/www/grep.tvl.fyi.nix +++ /dev/null @@ -1,19 +0,0 @@ -# Experimental configuration for manually Livegrep. -{ config, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."grep.tvl.fyi" = { - enableACME = true; - forceSSL = true; - - locations."/" = { - proxyPass = "http://127.0.0.1:${toString config.services.depot.livegrep.port}"; - }; - }; - }; -} diff --git a/ops/modules/www/inbox.tvl.su.nix b/ops/modules/www/inbox.tvl.su.nix deleted file mode 100644 index 38db5d2a8..000000000 --- a/ops/modules/www/inbox.tvl.su.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ config, depot, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."inbox.tvl.su" = { - enableACME = true; - forceSSL = true; - - extraConfig = '' - # nginx is incapable of serving a single file at /, hence this hack: - location = / { - index /landing-page; - } - - location = /landing-page { - types { } default_type "text/html; charset=utf-8"; - alias ${depot.web.inbox}; - } - - # rest of requests is proxied to public-inbox-httpd - location / { - proxy_pass http://localhost:${toString config.services.public-inbox.http.port}; - } - ''; - }; - }; -} diff --git a/ops/modules/www/self-cache.tvl.fyi.nix b/ops/modules/www/self-cache.tvl.fyi.nix deleted file mode 100644 index e0f87651d..000000000 --- a/ops/modules/www/self-cache.tvl.fyi.nix +++ /dev/null @@ -1,26 +0,0 @@ -# per-host addresses for publicly reachable caches, for use with builderball -# TODO(tazjin): merge with the public cache module; but needs ACME fixes -{ config, lib, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = lib.mkIf config.services.depot.harmonia.enable { - services.nginx.virtualHosts."${config.networking.hostName}.cache.tvl.fyi" = { - enableACME = true; - forceSSL = true; - - extraConfig = '' - location = /cache-key.pub { - alias /run/agenix/nix-cache-pub; - } - - location / { - proxy_pass http://${config.services.depot.harmonia.settings.bind}; - } - ''; - }; - }; -} diff --git a/ops/modules/www/signup.tvl.fyi.nix b/ops/modules/www/signup.tvl.fyi.nix deleted file mode 100644 index 1b193f99a..000000000 --- a/ops/modules/www/signup.tvl.fyi.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ depot, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."signup.tvl.fyi" = { - root = depot.web.pwcrypt; - enableACME = true; - forceSSL = true; - - extraConfig = '' - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - ''; - }; - }; -} diff --git a/ops/modules/www/static.tvl.fyi.nix b/ops/modules/www/static.tvl.fyi.nix deleted file mode 100644 index 7312f78ec..000000000 --- a/ops/modules/www/static.tvl.fyi.nix +++ /dev/null @@ -1,42 +0,0 @@ -# Host the static assets at static.tvl.fyi -# -# All assets are served from $base/$drvhash/$file, but can also be -# included with `latest/` which will return a (non-permanent!) -# redirect to the real location. -# -# For all purposes within depot, using the drvhash of web.static is -# recommended. -{ depot, pkgs, ... }: - -let staticHash = depot.web.static.drvHash; -in { - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."static.tvl.fyi" = { - serverAliases = [ "static.tvl.su" ]; - enableACME = true; - forceSSL = true; - - extraConfig = '' - location = / { - add_header Content-Type text/plain; - return 200 "looking for tvl.fyi or tvl.su?"; - } - - location /latest { - rewrite ^/latest/(.*) /${staticHash}/$1 redirect; - } - - location /${staticHash}/ { - alias ${depot.web.static}/; - expires max; - add_header Access-Control-Allow-Origin "*"; - add_header Cache-Control "public"; - } - ''; - }; - }; -} diff --git a/ops/modules/www/todo.tvl.fyi.nix b/ops/modules/www/todo.tvl.fyi.nix deleted file mode 100644 index b53f5437e..000000000 --- a/ops/modules/www/todo.tvl.fyi.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ depot, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."todo.tvl.fyi" = { - serverName = "todo.tvl.fyi"; - serverAliases = [ "todo.tvl.su" ]; - root = depot.web.todolist; - enableACME = true; - forceSSL = true; - - extraConfig = '' - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - location ~* \.(webp|woff2)$ { - add_header Cache-Control "public, max-age=31536000"; - } - ''; - }; - }; -} diff --git a/ops/modules/www/tvix.dev.nix b/ops/modules/www/tvix.dev.nix deleted file mode 100644 index f884bc30e..000000000 --- a/ops/modules/www/tvix.dev.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ depot, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."tvix.dev" = { - serverName = "tvix.dev"; - enableACME = true; - forceSSL = true; - root = depot.tvix.website; - }; - - services.nginx.virtualHosts."bolt.tvix.dev" = { - root = depot.web.tvixbolt; - enableACME = true; - forceSSL = true; - }; - - # old domain, serve redirect - services.nginx.virtualHosts."tvixbolt.tvl.su" = { - enableACME = true; - forceSSL = true; - extraConfig = "return 301 https://bolt.tvix.dev$request_uri;"; - }; - - services.nginx.virtualHosts."docs.tvix.dev" = { - serverName = "docs.tvix.dev"; - enableACME = true; - forceSSL = true; - - extraConfig = '' - location = / { - # until we have a better default page here - return 301 https://docs.tvix.dev/rust/tvix_eval/index.html; - } - - location /rust/ { - alias ${depot.tvix.rust-docs}/; - } - ''; - }; - }; -} diff --git a/ops/modules/www/tvl.fyi.nix b/ops/modules/www/tvl.fyi.nix deleted file mode 100644 index 59ee1bc27..000000000 --- a/ops/modules/www/tvl.fyi.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ depot, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."tvl.fyi" = { - serverName = "tvl.fyi"; - root = depot.web.tvl; - enableACME = true; - forceSSL = true; - - extraConfig = '' - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - rewrite ^/builds/?$ https://buildkite.com/tvl/depot/ last; - - rewrite ^/monorepo-doc/?$ https://docs.google.com/document/d/1nnyByXcH0F6GOmEezNOUa2RFelpeRpDToBLYD_CtjWE/edit?usp=sharing last; - - rewrite ^/irc/?$ ircs://irc.hackint.org:6697/#tvl last; - rewrite ^/webchat/?$ https://webirc.hackint.org/#ircs://irc.hackint.org/#tvl last; - - location ~* \.(webp|woff2)$ { - add_header Cache-Control "public, max-age=31536000"; - } - - location /blog { - if ($request_uri ~ ^/(.*)\.html$) { - return 302 /$1; - } - - try_files $uri $uri.html $uri/ =404; - } - - location = /blog { - return 302 /#blog; - } - - location = /blog/ { - return 302 /#blog; - } - ''; - }; - }; -} diff --git a/ops/modules/www/tvl.su.nix b/ops/modules/www/tvl.su.nix deleted file mode 100644 index a7c4f6a21..000000000 --- a/ops/modules/www/tvl.su.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ depot, ... }: - -{ - imports = [ - ./base.nix - ]; - - config = { - services.nginx.virtualHosts."tvl.su" = { - serverName = "tvl.su"; - root = depot.corp.website; - enableACME = true; - forceSSL = true; - - extraConfig = '' - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - ''; - }; - }; -} diff --git a/ops/mq_cli/.gitignore b/ops/mq_cli/.gitignore deleted file mode 100644 index 5bd19a47c..000000000 --- a/ops/mq_cli/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/target/ -**/*.rs.bk -.idea/ -*.iml diff --git a/ops/mq_cli/CODE_OF_CONDUCT.md b/ops/mq_cli/CODE_OF_CONDUCT.md deleted file mode 100644 index c4013ac13..000000000 --- a/ops/mq_cli/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,20 +0,0 @@ -A SERMON ON ETHICS AND LOVE -=========================== - -One day Mal-2 asked the messenger spirit Saint Gulik to approach the Goddess and request Her presence for some desperate advice. Shortly afterwards the radio came on by itself, and an ethereal female Voice said **YES?** - -"O! Eris! Blessed Mother of Man! Queen of Chaos! Daughter of Discord! Concubine of Confusion! O! Exquisite Lady, I beseech You to lift a heavy burden from my heart!" - -**WHAT BOTHERS YOU, MAL? YOU DON'T SOUND WELL.** - -"I am filled with fear and tormented with terrible visions of pain. Everywhere people are hurting one another, the planet is rampant with injustices, whole societies plunder groups of their own people, mothers imprison sons, children perish while brothers war. O, woe." - -**WHAT IS THE MATTER WITH THAT, IF IT IS WHAT YOU WANT TO DO?** - -"But nobody Wants it! Everybody hates it." - -**OH. WELL, THEN *STOP*.** - -At which moment She turned herself into an aspirin commercial and left The Polyfather stranded alone with his species. - -SINISTER DEXTER HAS A BROKEN SPIROMETER. diff --git a/ops/mq_cli/Cargo.lock b/ops/mq_cli/Cargo.lock deleted file mode 100644 index 18fed3621..000000000 --- a/ops/mq_cli/Cargo.lock +++ /dev/null @@ -1,168 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "cc" -version = "1.0.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "libc" -version = "0.2.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mq_cli" -version = "3773.0.0" -dependencies = [ - "clap", - "libc", - "nix", - "posix_mq", -] - -[[package]] -name = "nix" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "posix_mq" -version = "3771.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f462ad79a99ea13f3ef76d9c271956e924183f5aeb67a8649c8c2b6bdd079da8" -dependencies = [ - "libc", - "nix", -] - -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/ops/mq_cli/Cargo.toml b/ops/mq_cli/Cargo.toml deleted file mode 100644 index 8f34bd8e9..000000000 --- a/ops/mq_cli/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "mq_cli" -description = "CLI tool for accessing POSIX message queues (mq_overview(7))" -license = "MIT" -version = "3773.0.0" -authors = ["Vincent Ambo "] -homepage = "https://code.tvl.fyi/tree/ops/mq_cli" -repository = "https://code.tvl.fyi/depot.git:/ops/mq_cli.git" - -[dependencies] -clap = "2.34" -libc = "0.2" -nix = "0.23" -posix_mq = "3771.0.0" diff --git a/ops/mq_cli/LICENSE b/ops/mq_cli/LICENSE deleted file mode 100644 index e289cbab8..000000000 --- a/ops/mq_cli/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2017-2018 Langler AS -Copyright (c) 2019-2020 Vincent Ambo - -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/ops/mq_cli/README.md b/ops/mq_cli/README.md deleted file mode 100644 index f45cd2128..000000000 --- a/ops/mq_cli/README.md +++ /dev/null @@ -1,42 +0,0 @@ -mq-cli -====== - -This project provides a very simple CLI interface to [POSIX message queues][]. - -It can be used to create and inspect queues, as well as send and -receive messages from them. - -``` -1.0.0 -Administrate and inspect POSIX message queues - -USAGE: - mq - -FLAGS: - -h, --help Prints help information - -V, --version Prints version information - -SUBCOMMANDS: - create Create a new queue - help Prints this message or the help of the given subcommand(s) - inspect inspect details about a queue - ls list message queues - receive Receive a message from a queue - rlimit Get the message queue rlimit - send Send a message to a queue -``` - -## Development - -Development happens in the [TVL -monorepo](https://code.tvl.fyi/tree/ops/mq_cli). - -Starting from version `3773.0.0`, the version numbers correspond to -_revisions_ of the TVL repository, available as git refs (e.g. -`refs/r/3773`). - -See the TVL documentation for more information about how to contribute -to the codebase. - -[POSIX message queues]: https://linux.die.net/man/7/mq_overview diff --git a/ops/mq_cli/default.nix b/ops/mq_cli/default.nix deleted file mode 100644 index 6b0e32009..000000000 --- a/ops/mq_cli/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ depot, ... }: - -depot.third_party.naersk.buildPackage ./. diff --git a/ops/mq_cli/src/main.rs b/ops/mq_cli/src/main.rs deleted file mode 100644 index 927993b48..000000000 --- a/ops/mq_cli/src/main.rs +++ /dev/null @@ -1,235 +0,0 @@ -extern crate clap; -extern crate libc; -extern crate nix; -extern crate posix_mq; - -use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; -use posix_mq::{Message, Name, Queue}; -use std::fs::{read_dir, File}; -use std::io::{self, Read, Write}; -use std::process::exit; - -fn run_ls() { - let mqueues = read_dir("/dev/mqueue").expect("Could not read message queues"); - - for queue in mqueues { - let path = queue.unwrap().path(); - let status = { - let mut file = File::open(&path).expect("Could not open queue file"); - - let mut content = String::new(); - file.read_to_string(&mut content) - .expect("Could not read queue file"); - - content - }; - - let queue_name = path - .components() - .last() - .unwrap() - .as_os_str() - .to_string_lossy(); - - println!("/{}: {}", queue_name, status) - } -} - -fn run_inspect(queue_name: &str) { - let name = Name::new(queue_name).expect("Invalid queue name"); - let queue = Queue::open(name).expect("Could not open queue"); - - println!("Queue {}:\n", queue_name); - println!("Max. message size: {} bytes", queue.max_size()); - println!("Max. # of pending messages: {}", queue.max_pending()); -} - -fn run_create(cmd: &ArgMatches) { - if let Some(rlimit) = cmd.value_of("rlimit") { - set_rlimit(rlimit.parse().expect("Invalid rlimit value")); - } - - let name = Name::new(cmd.value_of("queue").unwrap()).expect("Invalid queue name"); - - let max_pending: i64 = cmd.value_of("max-pending").unwrap().parse().unwrap(); - let max_size: i64 = cmd.value_of("max-size").unwrap().parse().unwrap(); - - let queue = Queue::create(name, max_pending, max_size * 1024); - - match queue { - Ok(_) => println!("Queue created successfully"), - Err(e) => { - writeln!(io::stderr(), "Could not create queue: {}", e).ok(); - exit(1); - } - }; -} - -fn run_receive(queue_name: &str) { - let name = Name::new(queue_name).expect("Invalid queue name"); - let queue = Queue::open(name).expect("Could not open queue"); - - let message = match queue.receive() { - Ok(msg) => msg, - Err(e) => { - writeln!(io::stderr(), "Failed to receive message: {}", e).ok(); - exit(1); - } - }; - - // Attempt to write the message out as a string, but write out raw bytes if it turns out to not - // be UTF-8 encoded data. - match String::from_utf8(message.data.clone()) { - Ok(string) => println!("{}", string), - Err(_) => { - writeln!(io::stderr(), "Message not UTF-8 encoded!").ok(); - io::stdout().write(message.data.as_ref()).ok(); - } - }; -} - -fn run_send(queue_name: &str, content: &str) { - let name = Name::new(queue_name).expect("Invalid queue name"); - let queue = Queue::open(name).expect("Could not open queue"); - - let message = Message { - data: content.as_bytes().to_vec(), - priority: 0, - }; - - match queue.send(&message) { - Ok(_) => (), - Err(e) => { - writeln!(io::stderr(), "Could not send message: {}", e).ok(); - exit(1); - } - } -} - -fn run_rlimit() { - let mut rlimit = libc::rlimit { - rlim_cur: 0, - rlim_max: 0, - }; - - let mut errno = 0; - unsafe { - let res = libc::getrlimit(libc::RLIMIT_MSGQUEUE, &mut rlimit); - if res != 0 { - errno = nix::errno::errno(); - } - }; - - if errno != 0 { - writeln!( - io::stderr(), - "Could not get message queue rlimit: {}", - errno - ) - .ok(); - } else { - println!("Message queue rlimit:"); - println!("Current limit: {}", rlimit.rlim_cur); - println!("Maximum limit: {}", rlimit.rlim_max); - } -} - -fn set_rlimit(new_limit: u64) { - let rlimit = libc::rlimit { - rlim_cur: new_limit, - rlim_max: new_limit, - }; - - let mut errno: i32 = 0; - unsafe { - let res = libc::setrlimit(libc::RLIMIT_MSGQUEUE, &rlimit); - if res != 0 { - errno = nix::errno::errno(); - } - } - - match errno { - 0 => println!("Set RLIMIT_MSGQUEUE hard limit to {}", new_limit), - _ => { - // Not mapping these error codes to messages for now, the user can - // look up the meaning in setrlimit(2). - panic!("Could not set hard limit: {}", errno); - } - }; -} - -fn main() { - let ls = SubCommand::with_name("ls").about("list message queues"); - - let queue_arg = Arg::with_name("queue").required(true).takes_value(true); - - let rlimit_arg = Arg::with_name("rlimit") - .help("RLIMIT_MSGQUEUE to set for this command") - .long("rlimit") - .takes_value(true); - - let inspect = SubCommand::with_name("inspect") - .about("inspect details about a queue") - .arg(&queue_arg); - - let create = SubCommand::with_name("create") - .about("Create a new queue") - .arg(&queue_arg) - .arg(&rlimit_arg) - .arg( - Arg::with_name("max-size") - .help("maximum message size (in kB)") - .long("max-size") - .required(true) - .takes_value(true), - ) - .arg( - Arg::with_name("max-pending") - .help("maximum # of pending messages") - .long("max-pending") - .required(true) - .takes_value(true), - ); - - let receive = SubCommand::with_name("receive") - .about("Receive a message from a queue") - .arg(&queue_arg); - - let send = SubCommand::with_name("send") - .about("Send a message to a queue") - .arg(&queue_arg) - .arg( - Arg::with_name("message") - .help("the message to send") - .required(true), - ); - - let rlimit = SubCommand::with_name("rlimit") - .about("Get the message queue rlimit") - .setting(AppSettings::SubcommandRequiredElseHelp); - - let matches = App::new("mq") - .setting(AppSettings::SubcommandRequiredElseHelp) - .version("1.0.0") - .about("Administrate and inspect POSIX message queues") - .subcommand(ls) - .subcommand(inspect) - .subcommand(create) - .subcommand(receive) - .subcommand(send) - .subcommand(rlimit) - .get_matches(); - - match matches.subcommand() { - ("ls", _) => run_ls(), - ("inspect", Some(cmd)) => run_inspect(cmd.value_of("queue").unwrap()), - ("create", Some(cmd)) => run_create(cmd), - ("receive", Some(cmd)) => run_receive(cmd.value_of("queue").unwrap()), - ("send", Some(cmd)) => run_send( - cmd.value_of("queue").unwrap(), - cmd.value_of("message").unwrap(), - ), - ("rlimit", _) => run_rlimit(), - _ => unimplemented!(), - } -} diff --git a/ops/nixos.nix b/ops/nixos.nix index de649711f..ad37496ca 100644 --- a/ops/nixos.nix +++ b/ops/nixos.nix @@ -60,8 +60,5 @@ in rec { ''; # Systems that should be built in CI - sandunySystem = (nixosFor depot.ops.machines.sanduny).system; - bugrySystem = (nixosFor depot.ops.machines.bugry).system; - nevskySystem = (nixosFor depot.ops.machines.nevsky).system; - meta.ci.targets = [ "sandunySystem" "bugrySystem" "nevskySystem" ]; + meta.ci.targets = [ ]; } diff --git a/ops/pipelines/static-pipeline.yaml b/ops/pipelines/static-pipeline.yaml index 87bd6eae5..4375529d0 100644 --- a/ops/pipelines/static-pipeline.yaml +++ b/ops/pipelines/static-pipeline.yaml @@ -7,16 +7,6 @@ env: BUILDKITE_TOKEN_PATH: /run/agenix/buildkite-graphql-token steps: - # Run pipeline for tvl-kit when new commits arrive on canon. Since - # it is not part of the depot build tree, this is a useful - # verification to ensure we don't break external things (too much). - - trigger: "tvl-kit" - async: true - label: ":fork:" - branches: "refs/heads/canon" - build: - message: "Verification triggered by ${BUILDKITE_COMMIT}" - # Run pipeline for tvix when new commits arrive on canon. Since # it is not part of the depot build tree, this is a useful # verification to ensure we don't break external things (too much). diff --git a/ops/posix_mq.rs/.gitignore b/ops/posix_mq.rs/.gitignore deleted file mode 100644 index e5b6fdb28..000000000 --- a/ops/posix_mq.rs/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/target/ -**/*.rs.bk -.idea/ diff --git a/ops/posix_mq.rs/CODE_OF_CONDUCT.md b/ops/posix_mq.rs/CODE_OF_CONDUCT.md deleted file mode 100644 index c4013ac13..000000000 --- a/ops/posix_mq.rs/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,20 +0,0 @@ -A SERMON ON ETHICS AND LOVE -=========================== - -One day Mal-2 asked the messenger spirit Saint Gulik to approach the Goddess and request Her presence for some desperate advice. Shortly afterwards the radio came on by itself, and an ethereal female Voice said **YES?** - -"O! Eris! Blessed Mother of Man! Queen of Chaos! Daughter of Discord! Concubine of Confusion! O! Exquisite Lady, I beseech You to lift a heavy burden from my heart!" - -**WHAT BOTHERS YOU, MAL? YOU DON'T SOUND WELL.** - -"I am filled with fear and tormented with terrible visions of pain. Everywhere people are hurting one another, the planet is rampant with injustices, whole societies plunder groups of their own people, mothers imprison sons, children perish while brothers war. O, woe." - -**WHAT IS THE MATTER WITH THAT, IF IT IS WHAT YOU WANT TO DO?** - -"But nobody Wants it! Everybody hates it." - -**OH. WELL, THEN *STOP*.** - -At which moment She turned herself into an aspirin commercial and left The Polyfather stranded alone with his species. - -SINISTER DEXTER HAS A BROKEN SPIROMETER. diff --git a/ops/posix_mq.rs/Cargo.lock b/ops/posix_mq.rs/Cargo.lock deleted file mode 100644 index dc344613d..000000000 --- a/ops/posix_mq.rs/Cargo.lock +++ /dev/null @@ -1,63 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "cc" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "libc" -version = "0.2.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "nix" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "posix_mq" -version = "3771.0.0" -dependencies = [ - "libc", - "nix", -] diff --git a/ops/posix_mq.rs/Cargo.toml b/ops/posix_mq.rs/Cargo.toml deleted file mode 100644 index 3495f9461..000000000 --- a/ops/posix_mq.rs/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "posix_mq" -version = "3771.0.0" -authors = ["Vincent Ambo "] -description = "(Higher-level) Rust bindings to POSIX message queues" -license = "MIT" -homepage = "https://code.tvl.fyi/tree/ops/posix_mq.rs" -repository = "https://code.tvl.fyi/depot.git:/ops/posix_mq.rs.git" - -[dependencies] -nix = "0.23" -libc = "0.2" diff --git a/ops/posix_mq.rs/LICENSE b/ops/posix_mq.rs/LICENSE deleted file mode 100644 index 2389546b1..000000000 --- a/ops/posix_mq.rs/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017-2020 Vincent Ambo - -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/ops/posix_mq.rs/README.md b/ops/posix_mq.rs/README.md deleted file mode 100644 index 91e46b7dc..000000000 --- a/ops/posix_mq.rs/README.md +++ /dev/null @@ -1,44 +0,0 @@ -posix_mq -======== - -[![crates.io](https://img.shields.io/crates/v/posix_mq.svg)](https://crates.io/crates/posix_mq) - -This is a simple, relatively high-level library for the POSIX [message queue API][]. It wraps the lower-level API in a -simpler interface with more robust error handling. - -Check out this project's [sister library][] in Kotlin. - -Usage example: - -```rust -// Values that need to undergo validation are wrapped in safe types: -let name = Name::new("/test-queue").unwrap(); - -// Queue creation with system defaults is simple: -let queue = Queue::open_or_create(name).expect("Opening queue failed"); - -// Sending a message: -let message = Message { - data: "test-message".as_bytes().to_vec(), - priority: 0, -}; -queue.send(&message).expect("message sending failed"); - -// ... and receiving it! -let result = queue.receive().expect("message receiving failed"); -``` - -## Development - -Development happens in the [TVL -monorepo](https://code.tvl.fyi/tree/ops/posix_mq.rs). - -Starting from version `3771.0.0`, the version numbers correspond to -_revisions_ of the TVL repository, available as git refs (e.g. -`refs/r/3771`). - -See the TVL documentation for more information about how to contribute -to the codebase. - -[message queue API]: https://linux.die.net/man/7/mq_overview -[sister library]: https://github.com/aprilabank/posix_mq.kt diff --git a/ops/posix_mq.rs/default.nix b/ops/posix_mq.rs/default.nix deleted file mode 100644 index 6b0e32009..000000000 --- a/ops/posix_mq.rs/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ depot, ... }: - -depot.third_party.naersk.buildPackage ./. diff --git a/ops/posix_mq.rs/src/error.rs b/ops/posix_mq.rs/src/error.rs deleted file mode 100644 index bacd2aeb3..000000000 --- a/ops/posix_mq.rs/src/error.rs +++ /dev/null @@ -1,122 +0,0 @@ -use nix; -use std::{error, fmt, io, num}; - -/// This module implements a simple error type to match the errors that can be thrown from the C -/// functions as well as some extra errors resulting from internal validations. -/// -/// As this crate exposes an opinionated API to the POSIX queues certain errors have been -/// ignored: -/// -/// * ETIMEDOUT: The low-level timed functions are not exported and this error can not occur. -/// * EAGAIN: Non-blocking queue calls are not supported. -/// * EINVAL: Same reason as ETIMEDOUT -/// * EMSGSIZE: The message size is immutable after queue creation and this crate checks it. -/// * ENAMETOOLONG: This crate performs name validation -/// -/// If an unexpected error is encountered it will be wrapped appropriately and should be reported -/// as a bug on https://b.tvl.fyi - -#[derive(Debug)] -pub enum Error { - // These errors are raised inside of the library - InvalidQueueName(&'static str), - ValueReadingError(io::Error), - MessageSizeExceeded(), - MaximumMessageSizeExceeded(), - MaximumMessageCountExceeded(), - - // These errors match what is described in the man pages (from mq_overview(7) onwards). - PermissionDenied(), - InvalidQueueDescriptor(), - QueueCallInterrupted(), - QueueAlreadyExists(), - QueueNotFound(), - InsufficientMemory(), - InsufficientSpace(), - - // These two are (hopefully) unlikely in modern systems - ProcessFileDescriptorLimitReached(), - SystemFileDescriptorLimitReached(), - - // If an unhandled / unknown / unexpected error occurs this error will be used. - // In those cases bug reports would be welcome! - UnknownForeignError(nix::errno::Errno), - - // Some other unexpected / unknown error occured. This is probably an error from - // the nix crate. Bug reports also welcome for this! - UnknownInternalError(), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use Error::*; - f.write_str(match *self { - // This error contains more sensible description strings already - InvalidQueueName(e) => e, - ValueReadingError(_) => "error reading system configuration for message queues", - MessageSizeExceeded() => "message is larger than maximum size for specified queue", - MaximumMessageSizeExceeded() => "specified queue message size exceeds system maximum", - MaximumMessageCountExceeded() => "specified queue message count exceeds system maximum", - PermissionDenied() => "permission to the specified queue was denied", - InvalidQueueDescriptor() => "the internal queue descriptor was invalid", - QueueCallInterrupted() => "queue method interrupted by signal", - QueueAlreadyExists() => "the specified queue already exists", - QueueNotFound() => "the specified queue could not be found", - InsufficientMemory() => "insufficient memory to call queue method", - InsufficientSpace() => "insufficient space to call queue method", - ProcessFileDescriptorLimitReached() => { - "maximum number of process file descriptors reached" - } - SystemFileDescriptorLimitReached() => { - "maximum number of system file descriptors reached" - } - UnknownForeignError(_) => "unknown foreign error occured: please report a bug!", - UnknownInternalError() => "unknown internal error occured: please report a bug!", - }) - } -} - -impl error::Error for Error { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self { - Error::ValueReadingError(e) => Some(e), - Error::UnknownForeignError(e) => Some(e), - _ => None, - } - } -} - -/// This from implementation is used to translate errors from the lower-level -/// C-calls into sensible Rust errors. -impl From for Error { - fn from(err: nix::Error) -> Self { - use nix::errno::Errno::*; - match err { - EACCES => Error::PermissionDenied(), - EBADF => Error::InvalidQueueDescriptor(), - EINTR => Error::QueueCallInterrupted(), - EEXIST => Error::QueueAlreadyExists(), - EMFILE => Error::ProcessFileDescriptorLimitReached(), - ENFILE => Error::SystemFileDescriptorLimitReached(), - ENOENT => Error::QueueNotFound(), - ENOMEM => Error::InsufficientMemory(), - ENOSPC => Error::InsufficientSpace(), - _ => Error::UnknownForeignError(err), - } - } -} - -// This implementation is used when reading system queue settings. -impl From for Error { - fn from(e: io::Error) -> Self { - Error::ValueReadingError(e) - } -} - -// This implementation is used when parsing system queue settings. The unknown error is returned -// here because the system is probably seriously broken if those files don't contain numbers. -impl From for Error { - fn from(_: num::ParseIntError) -> Self { - Error::UnknownInternalError() - } -} diff --git a/ops/posix_mq.rs/src/lib.rs b/ops/posix_mq.rs/src/lib.rs deleted file mode 100644 index ed35fb03b..000000000 --- a/ops/posix_mq.rs/src/lib.rs +++ /dev/null @@ -1,247 +0,0 @@ -extern crate libc; -extern crate nix; - -use error::Error; -use libc::mqd_t; -use nix::mqueue; -use nix::sys::stat; -use std::ffi::CString; -use std::fs::File; -use std::io::Read; -use std::ops::Drop; -use std::string::ToString; - -pub mod error; - -#[cfg(test)] -mod tests; - -/// Wrapper type for queue names that performs basic validation of queue names before calling -/// out to C code. -#[derive(Debug, Clone, PartialEq)] -pub struct Name(CString); - -impl Name { - pub fn new(s: S) -> Result { - let string = s.to_string(); - - if !string.starts_with('/') { - return Err(Error::InvalidQueueName("Queue name must start with '/'")); - } - - // The C library has a special error return for this case, so I assume people must actually - // have tried just using '/' as a queue name. - if string.len() == 1 { - return Err(Error::InvalidQueueName( - "Queue name must be a slash followed by one or more characters", - )); - } - - if string.len() > 255 { - return Err(Error::InvalidQueueName( - "Queue name must not exceed 255 characters", - )); - } - - if string.matches('/').count() > 1 { - return Err(Error::InvalidQueueName( - "Queue name can not contain more than one slash", - )); - } - - // TODO: What error is being thrown away here? Is it possible? - Ok(Name(CString::new(string).unwrap())) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct Message { - pub data: Vec, - pub priority: u32, -} - -/// Represents an open queue descriptor to a POSIX message queue. This carries information -/// about the queue's limitations (i.e. maximum message size and maximum message count). -#[derive(Debug)] -pub struct Queue { - name: Name, - - /// Internal file/queue descriptor. - queue_descriptor: mqd_t, - - /// Maximum number of pending messages in this queue. - max_pending: i64, - - /// Maximum size of this queue. - max_size: usize, -} - -impl Queue { - /// Creates a new queue and fails if it already exists. - /// By default the queue will be read/writable by the current user with no access for other - /// users. - /// Linux users can change this setting themselves by modifying the queue file in /dev/mqueue. - pub fn create(name: Name, max_pending: i64, max_size: i64) -> Result { - if max_pending > read_i64_from_file(MSG_MAX)? { - return Err(Error::MaximumMessageCountExceeded()); - } - - if max_size > read_i64_from_file(MSGSIZE_MAX)? { - return Err(Error::MaximumMessageSizeExceeded()); - } - - let oflags = { - let mut flags = mqueue::MQ_OFlag::empty(); - // Put queue in r/w mode - flags.toggle(mqueue::MQ_OFlag::O_RDWR); - // Enable queue creation - flags.toggle(mqueue::MQ_OFlag::O_CREAT); - // Fail if queue exists already - flags.toggle(mqueue::MQ_OFlag::O_EXCL); - flags - }; - - let attr = mqueue::MqAttr::new(0, max_pending, max_size, 0); - - let queue_descriptor = mqueue::mq_open(&name.0, oflags, default_mode(), Some(&attr))?; - - Ok(Queue { - name, - queue_descriptor, - max_pending, - max_size: max_size as usize, - }) - } - - /// Opens an existing queue. - pub fn open(name: Name) -> Result { - // No extra flags need to be constructed as the default is to open and fail if the - // queue does not exist yet - which is what we want here. - let oflags = mqueue::MQ_OFlag::O_RDWR; - let queue_descriptor = mqueue::mq_open(&name.0, oflags, default_mode(), None)?; - - let attr = mq_getattr(queue_descriptor)?; - - Ok(Queue { - name, - queue_descriptor, - max_pending: attr.mq_maxmsg, - max_size: attr.mq_msgsize as usize, - }) - } - - /// Opens an existing queue or creates a new queue with the OS default settings. - pub fn open_or_create(name: Name) -> Result { - let oflags = { - let mut flags = mqueue::MQ_OFlag::empty(); - // Put queue in r/w mode - flags.toggle(mqueue::MQ_OFlag::O_RDWR); - // Enable queue creation - flags.toggle(mqueue::MQ_OFlag::O_CREAT); - flags - }; - - let default_pending = read_i64_from_file(MSG_DEFAULT)?; - let default_size = read_i64_from_file(MSGSIZE_DEFAULT)?; - let attr = mqueue::MqAttr::new(0, default_pending, default_size, 0); - - let queue_descriptor = mqueue::mq_open(&name.0, oflags, default_mode(), Some(&attr))?; - - let actual_attr = mq_getattr(queue_descriptor)?; - - Ok(Queue { - name, - queue_descriptor, - max_pending: actual_attr.mq_maxmsg, - max_size: actual_attr.mq_msgsize as usize, - }) - } - - /// Delete a message queue from the system. This method will make the queue unavailable for - /// other processes after their current queue descriptors have been closed. - pub fn delete(self) -> Result<(), Error> { - mqueue::mq_unlink(&self.name.0)?; - drop(self); - Ok(()) - } - - /// Send a message to the message queue. - /// If the queue is full this call will block until a message has been consumed. - pub fn send(&self, msg: &Message) -> Result<(), Error> { - if msg.data.len() > self.max_size as usize { - return Err(Error::MessageSizeExceeded()); - } - - mqueue::mq_send(self.queue_descriptor, msg.data.as_ref(), msg.priority) - .map_err(|e| e.into()) - } - - /// Receive a message from the message queue. - /// If the queue is empty this call will block until a message arrives. - pub fn receive(&self) -> Result { - let mut data: Vec = vec![0; self.max_size as usize]; - let mut priority: u32 = 0; - - let msg_size = mqueue::mq_receive(self.queue_descriptor, data.as_mut(), &mut priority)?; - - data.truncate(msg_size); - Ok(Message { data, priority }) - } - - pub fn max_pending(&self) -> i64 { - self.max_pending - } - - pub fn max_size(&self) -> usize { - self.max_size - } -} - -impl Drop for Queue { - fn drop(&mut self) { - // Attempt to close the queue descriptor and discard any possible errors. - // The only error thrown in the C-code is EINVAL, which would mean that the - // descriptor has already been closed. - mqueue::mq_close(self.queue_descriptor).ok(); - } -} - -// Creates the default queue mode (0600). -fn default_mode() -> stat::Mode { - let mut mode = stat::Mode::empty(); - mode.toggle(stat::Mode::S_IRUSR); - mode.toggle(stat::Mode::S_IWUSR); - mode -} - -/// This file defines the default number of maximum pending messages in a queue. -const MSG_DEFAULT: &'static str = "/proc/sys/fs/mqueue/msg_default"; - -/// This file defines the system maximum number of pending messages in a queue. -const MSG_MAX: &'static str = "/proc/sys/fs/mqueue/msg_max"; - -/// This file defines the default maximum size of messages in a queue. -const MSGSIZE_DEFAULT: &'static str = "/proc/sys/fs/mqueue/msgsize_default"; - -/// This file defines the system maximum size for messages in a queue. -const MSGSIZE_MAX: &'static str = "/proc/sys/fs/mqueue/msgsize_max"; - -/// This method is used in combination with the above constants to find system limits. -fn read_i64_from_file(name: &str) -> Result { - let mut file = File::open(name.to_string())?; - let mut content = String::new(); - file.read_to_string(&mut content)?; - Ok(content.trim().parse()?) -} - -/// The mq_getattr implementation in the nix crate hides the maximum message size and count, which -/// is very impractical. -/// To work around it, this method calls the C-function directly. -fn mq_getattr(mqd: mqd_t) -> Result { - use std::mem; - let mut attr = mem::MaybeUninit::::uninit(); - let res = unsafe { libc::mq_getattr(mqd, attr.as_mut_ptr()) }; - nix::errno::Errno::result(res) - .map(|_| unsafe { attr.assume_init() }) - .map_err(|e| e.into()) -} diff --git a/ops/posix_mq.rs/src/tests.rs b/ops/posix_mq.rs/src/tests.rs deleted file mode 100644 index 1f4ea9a58..000000000 --- a/ops/posix_mq.rs/src/tests.rs +++ /dev/null @@ -1,21 +0,0 @@ -use super::*; - -#[test] -fn test_open_delete() { - // Simple test with default queue settings - let name = Name::new("/test-queue").unwrap(); - let queue = Queue::open_or_create(name).expect("Opening queue failed"); - - let message = Message { - data: "test-message".as_bytes().to_vec(), - priority: 0, - }; - - queue.send(&message).expect("message sending failed"); - - let result = queue.receive().expect("message receiving failed"); - - assert_eq!(message, result); - - queue.delete().expect("deleting queue failed"); -} diff --git a/ops/secrets/besadii.age b/ops/secrets/besadii.age deleted file mode 100644 index f52f82449..000000000 Binary files a/ops/secrets/besadii.age and /dev/null differ diff --git a/ops/secrets/depot-replica-key.age b/ops/secrets/depot-replica-key.age deleted file mode 100644 index 08d0ba3b7..000000000 Binary files a/ops/secrets/depot-replica-key.age and /dev/null differ diff --git a/ops/secrets/restic-bugry.age b/ops/secrets/restic-bugry.age deleted file mode 100644 index 293203311..000000000 --- a/ops/secrets/restic-bugry.age +++ /dev/null @@ -1,17 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 wI5oAA TDjaldqySaCEFAPuoUBVMR342403nhkawwtXbsJJenQ -eoeL2v5mCLksay/24miqYkWLJLLhrUIny4p1/e3/iTY --> ssh-ed25519 dcsaLw /KSRH3XUGU7P+Ckpk86PFl8oRfPP/dlLb6zLUW04iH8 -e2nXDvjkd5lzmXflhd820XmGvo/agSxDtfejxM45nhY --> ssh-ed25519 zcCuhA pIxJxTWsOyH6Zqunv427jdy1G7BV7Dpjpp2l+HEe/3s -rxyoDZTQmsGwNB0nCTXNHhc7VCsb11/ynManfsbf5Ss --> ssh-ed25519 1SxhRA K8DkqAk5gPfsjTQiTjLGRNR+63uG9ogacsrH69/afGs -LAt97AuWaPEYG7IlFiIOll9s02cQ+qhrpr0GVXX+e/o --> ssh-ed25519 ch/9tw 6eG9psphjjfW6TRTYxqozX9WLhQgC9u2ngR35rpXiH4 -9dFgdqSDKRXAotKKR19l9gqWlTNxuv9r/IcaMZeO9Oc --> ssh-ed25519 CpJBgQ /t2M57kxjKDq/UMoh9UnmQvlETqiwqClt0Lg6quqKRk -oDblqLXxyJ7gTtZzhbStHep62oZK0iXikJ6fi6EW0gM --> ssh-ed25519 aXKGcg DVn6XZGaBHAeL4pGMaolO8cSOIKRIhmuDycV65pfxhs -M6XVDk1Z9BdCoCvK30NDJsKKnURk/XUcRP4t5pZ7JFk ---- H3D9jfLkrsDOgWfNhUJHZcVGa9dPqr4EuuBU40iJbJs -{:jІpVFx'`5Lz# y|"/>"QX Je W*? \ No newline at end of file diff --git a/ops/secrets/restic-nevsky.age b/ops/secrets/restic-nevsky.age deleted file mode 100644 index f06347b38..000000000 --- a/ops/secrets/restic-nevsky.age +++ /dev/null @@ -1,17 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 xR+E/Q iVPpAC04Up8hrFvnh2RsAXgfrFv2QNk0kwydlGrVslg -2McWSNxxnPypGs9HKMNCjpHe+g2kxA86G6Drt2HWOeU --> ssh-ed25519 dcsaLw Xuw5V21UrJcIwWEoRyI+h60RaoJUdBAJJPqN12TY93U -X4Wxo2qdBgtzQ8ct2UySnvXr9x0EzqBzSoHTBq9jQ9A --> ssh-ed25519 zcCuhA GPMgbaoLctcsQxVtoIPvXUvpfTZEUA2QnvgTXDUiJRI -wnzHlJC8F45s/VzBjy9xfvDujtH+9uBmoX5OrzXapBA --> ssh-ed25519 1SxhRA 3GuXyDOYy6tur+nThpBLKMCvk/2c44XeR+NrLKj3G1Q -LoVYepF0BiZ4E29ZMzXgOAyloK+UhX+FqiM9pPgngZ4 --> ssh-ed25519 ch/9tw ihNjsBfasDmfW3Kcg8vQ1tpym9HKIL/qEzwpO7ye0Cg -brnJzK7V4OV5jLfCFYqNue1oLSpJ88rRNN19KDcMdeM --> ssh-ed25519 CpJBgQ SvLMx+bG59LPZNI4EctDnFutMXoh4Otk2yFd17dXVQ4 -+LO4a5ARK1mpYaenS1P13ajhpNtxndFvin2Po1h0cwM --> ssh-ed25519 aXKGcg VdaJIfDpeet7fzesJ3FGwZhQiAKNzEJMVUXNtbwm8UU -rMqLrCdx55rzkuqJ3/9SrY6BKdSgHCLgAx8E0rrYVfY ---- jNvJTcOvsKU6YkgEDBiOI27GBEzNlEg4JymqeKYa/fA -ؽV(idTL\'HGgD^vܽ11c`}V=zK & \ No newline at end of file diff --git a/ops/secrets/restic-sanduny.age b/ops/secrets/restic-sanduny.age deleted file mode 100644 index 578871ff1..000000000 Binary files a/ops/secrets/restic-sanduny.age and /dev/null differ diff --git a/ops/secrets/wg-bugry.age b/ops/secrets/wg-bugry.age deleted file mode 100644 index 2ce0de6a9..000000000 Binary files a/ops/secrets/wg-bugry.age and /dev/null differ diff --git a/ops/secrets/wg-nevsky.age b/ops/secrets/wg-nevsky.age deleted file mode 100644 index 93b133ce3..000000000 --- a/ops/secrets/wg-nevsky.age +++ /dev/null @@ -1,17 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 xR+E/Q pAv2Rm0oj9HJu8LAIRbT+bvNOufRcDTLlLfanvM84y0 -eTOICFyxEt3b6Kh9NbKMmt9i3+GFsgk4K+jBuR8LjUs --> ssh-ed25519 dcsaLw cYYa3+xqONMvU4y4LsWZ5VZBrQoMdoRYbII70H0x7hw -w7XolSOTiX5WdrnURn/PtAGriMz4n0rBUAulOU4pP3E --> ssh-ed25519 zcCuhA xwUsUilN81ZHuqE6gCzmUddjD+gLd6bkDclSb73K+08 -H2uNajL/IDn+hXJyehDG22Zu5k7RZmjWyWtJnzCxAEw --> ssh-ed25519 1SxhRA rkPyrom+2W0BWU6S9Vy+h5ggrdjEQdVcFd6onYENNmE -AuonnG8d2RwpLUR+FAgf4TrWCmB3dxnO3OFLM4+EVH8 --> ssh-ed25519 ch/9tw DJs3TcbTmAx0HqTWoyvugqfqxdZ13kqerOlaJKADljA -bxyxi0/J7MBm+Hlq6CUM4s9+j4M3E9f55lUgMKx+ABc --> ssh-ed25519 CpJBgQ ralv1E55uSriSrM8X+rOr/h70dbEOVOfux7U20cky0k -lflA+jocbQn7dricKpH6iBQ3P2K+g8ZDvyuRkyCUL7c --> ssh-ed25519 aXKGcg Fb5vBSvT0RaO5yXhd/b/75QdC6IPSDpntUHhtdhhFGw -UASa/ristknh342EyYO24qAT+rAaWI5ks00mSTjPOQY ---- e8mOir6/NeozcVmD17lJkrFVIffhOAXR3kKq5OgqbRw -%ȇlAظ>5.48} @D* uGרy|S-F*&La ,XY='H \ No newline at end of file diff --git a/ops/terraform/README.md b/ops/terraform/README.md deleted file mode 100644 index 9ff6c23d4..000000000 --- a/ops/terraform/README.md +++ /dev/null @@ -1,5 +0,0 @@ -//ops/terraform -=============== - -This folder contains Terraform modules and other related -Terraform-tooling by TVL. diff --git a/ops/terraform/deploy-nixos/README.md b/ops/terraform/deploy-nixos/README.md deleted file mode 100644 index 2580a7c0e..000000000 --- a/ops/terraform/deploy-nixos/README.md +++ /dev/null @@ -1,56 +0,0 @@ - - -deploy-nixos -============ - -This is a Terraform module to deploy a NixOS system closure to a -remote machine. - -The system closure must be accessible by Nix-importing the repository -root and building a specific attribute -(e.g. `nix-build -A ops.machines.machine-name`). - -The target machine must be accessible normally over SSH, and an SSH -key must be used for access. - -Notably this module separates the evaluation of the system closure from building -and deploying it, and uses the closure's derivation hash to determine whether a -deploy is necessary. - -## Usage example: - -```terraform -module "deploy_somehost" { - # Clone just this directory through josh. Add a `ref=` parameter to pin to a specific commit. - source = "git::https://code.tvl.fyi/depot.git:/ops/terraform/deploy-nixos.git" - - # The attribute.path pointing to the expression to instantiate. - attrpath = "ops.nixos.somehost" - - # The path to the Nix file to invoke. Optional. - # If omitted, will shell out to git to determine the repo root, and Nix will - # use `default.nix` in there. - entrypoint = "${path.module}/../../somewhere.nix" - - target_host = "somehost.tvl.su" - target_user = "someone" - target_user_ssh_key = tls_private_key.somehost.private_key_pem -} -``` - -## Future work - -Several things can be improved about this module, for example: - -* The remote system closure could be discovered to restore remote system state - after manual deploys on the target (i.e. "stomping" of changes). - -More ideas and contributions are, of course, welcome. - -## Acknowledgements - -Development of this module was sponsored by [Resoptima](https://resoptima.com/). diff --git a/ops/terraform/deploy-nixos/main.tf b/ops/terraform/deploy-nixos/main.tf deleted file mode 100644 index 50278b248..000000000 --- a/ops/terraform/deploy-nixos/main.tf +++ /dev/null @@ -1,113 +0,0 @@ -# SPDX-FileCopyrightText: 2023 The TVL Authors -# -# SPDX-License-Identifier: MIT - -# This module deploys a NixOS host by building a system closure -# located at the specified attribute in the current repository. -# -# The closure's derivation path is persisted in the Terraform state to -# determine after Nix evaluation whether the system closure has -# changed and needs to be built/deployed. -# -# The system configuration is then built (or substituted) on the -# machine that runs `terraform apply`, then copied and activated on -# the target machine using `nix-copy-closure`. - -variable "attrpath" { - description = "attribute set path pointing to the NixOS system closure" - type = string -} - -variable "target_host" { - description = "address (IP or hostname) at which the target is reachable" - type = string -} - -variable "entrypoint" { - description = < /dev/null -fi - -# Determine the output path. -outPath=$(nix show-derivation "${drv}" | jq -r ".\"${drv}\".outputs.out.path") - -# Return a JSON back to stdout. -# It contains the following keys: -# -# - `drv`: the store path of the Derivation that has been instantiated. -# - `outPath`: the output store path. -jq -n --arg drv "$drv" --arg outPath "$outPath" '{"drv":$drv, "outPath":$outPath}' diff --git a/ops/terraform/deploy-nixos/nixos-copy.sh b/ops/terraform/deploy-nixos/nixos-copy.sh deleted file mode 100755 index 6b843c3a4..000000000 --- a/ops/terraform/deploy-nixos/nixos-copy.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -# SPDX-FileCopyrightText: 2023 The TVL Authors -# -# SPDX-License-Identifier: MIT - -# -# Copies a NixOS system to a target host, using the provided key, -# or whatever ambient key is configured if the key is not set. -set -ueo pipefail - -export NIX_SSHOPTS="\ - -o StrictHostKeyChecking=no\ - -o UserKnownHostsFile=/dev/null\ - -o GlobalKnownHostsFile=/dev/null" - -# If DEPLOY_KEY was passed, write it to $scratch/id_deploy -if [ -n "${DEPLOY_KEY-}" ]; then - scratch="$(mktemp -d)" - trap 'rm -rf -- "${scratch}"' EXIT - - echo -n "$DEPLOY_KEY" > $scratch/id_deploy - chmod 0600 $scratch/id_deploy - export NIX_SSHOPTS="$NIX_SSHOPTS -o IdentityFile=$scratch/id_deploy" -fi - -nix-copy-closure \ - --to ${TARGET_USER}@${TARGET_HOST} \ - ${SYSTEM_DRV} \ - --gzip \ - --include-outputs \ - --use-substitutes diff --git a/ops/yandex-base-image/default.nix b/ops/yandex-base-image/default.nix deleted file mode 100644 index 3dc4b8f58..000000000 --- a/ops/yandex-base-image/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -# Base image for Yandex Cloud VMs. -{ depot, ... }: - -(depot.ops.nixos.nixosFor { - imports = [ - (depot.path.origSrc + ("/ops/modules/yandex-cloud.nix")) - (depot.path.origSrc + ("/ops/modules/tvl-users.nix")) - ]; -}).config.system.build.yandexCloudImage diff --git a/ops/yandex-cloud-rs/.gitignore b/ops/yandex-cloud-rs/.gitignore deleted file mode 100644 index ab3f21a96..000000000 --- a/ops/yandex-cloud-rs/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -target/ -result/ -# Ignore everything under src (except for lib.rs) -src/* -!src/lib.rs diff --git a/ops/yandex-cloud-rs/Cargo.lock b/ops/yandex-cloud-rs/Cargo.lock deleted file mode 100644 index 0015d4310..000000000 --- a/ops/yandex-cloud-rs/Cargo.lock +++ /dev/null @@ -1,1368 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "anyhow" -version = "1.0.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "async-trait" -version = "0.1.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "axum" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" -dependencies = [ - "async-trait", - "axum-core", - "bitflags", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "base64" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "h2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.146" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "log" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" - -[[package]] -name = "matchit" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "petgraph" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "pin-project" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "proc-macro2" -version = "1.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.109", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rustix" -version = "0.37.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustls" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" -dependencies = [ - "base64", -] - -[[package]] -name = "rustls-webpki" -version = "0.100.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" -dependencies = [ - "windows-sys 0.42.0", -] - -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "security-framework" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.164" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" - -[[package]] -name = "slab" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "tempfile" -version = "3.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" -dependencies = [ - "autocfg", - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio" -version = "1.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" -dependencies = [ - "autocfg", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tonic" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64", - "bytes", - "flate2", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "rustls-native-certs", - "rustls-pemfile", - "tokio", - "tokio-rustls", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-build" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "unicode-ident" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.18", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" -dependencies = [ - "either", - "libc", - "once_cell", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "yandex-cloud" -version = "2023.9.4" -dependencies = [ - "prost", - "prost-types", - "tokio", - "tonic", - "tonic-build", - "walkdir", -] diff --git a/ops/yandex-cloud-rs/Cargo.toml b/ops/yandex-cloud-rs/Cargo.toml deleted file mode 100644 index 896c6e034..000000000 --- a/ops/yandex-cloud-rs/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "yandex-cloud" -description = "Generated gRPC clients for the Yandex Cloud API" -license = "MIT" -version = "2023.9.4" -edition = "2021" -homepage = "https://code.tvl.fyi/tree/ops/yandex-cloud-rs" -repository = "https://code.tvl.fyi/depot.git:/ops/yandex-cloud-rs.git" -include = [ "/src", "README.md" ] - -[dependencies] -prost = "0.11" -prost-types = "0.11" - -[dependencies.tonic] -version = "0.9" -features = [ "tls", "tls-roots", "gzip" ] - -[build-dependencies] -tonic-build = "0.9" -walkdir = "2.3.3" - -[dev-dependencies] -tokio = "1.28" # check when updating tonic diff --git a/ops/yandex-cloud-rs/README.md b/ops/yandex-cloud-rs/README.md deleted file mode 100644 index 463bde5c2..000000000 --- a/ops/yandex-cloud-rs/README.md +++ /dev/null @@ -1,49 +0,0 @@ -yandex-cloud-rs -=============== - -Client library for Yandex Cloud gRPC APIs, as published in their -[GitHub repository][repo]. - -Please see the [online documentation][docs] for user-facing -information, this README is intended for library developers. - -The source code of the library lives [in the TVL repository][code]. - -------------- - -In order to build this library, the gRPC API definitions need to be -fetched from GitHub. By default this is done by Nix (see -`default.nix`), which then injects the location of the API definitions -through the `YANDEX_CLOUD_PROTOS` environment variable. - -The actual code generation happens through the calls in `build.rs`. - -Releases of this library are done from *dirty* trees, meaning that the -version on crates.io should already contain all the generated code. In -order to do this, after bumping the version in `Cargo.toml` and the -API commit in `default.nix`, the following release procedure should be -used: - -``` -# Get rid of all generated source files -find src | grep '.rs$' | grep -v '^src/lib.rs$' | xargs rm - -# Get rid of all old artefacts -cargo clean - -# Verify that a clean build works as intended -cargo build - -# Verify that all documentation builds, and verify that it looks fine: -# -# - Is the version correct (current date)? -# - Are all the services included (i.e. not an accidental empty build)? -cargo doc --open - -# If everything looks fine, release: -cargo publish --allow-dirty -``` - -[repo]: https://github.com/yandex-cloud/cloudapi -[docs]: https://docs.rs/yandex-cloud/latest/yandex_cloud/ -[code]: https://code.tvl.fyi/tree/ops/yandex-cloud-rs diff --git a/ops/yandex-cloud-rs/build.rs b/ops/yandex-cloud-rs/build.rs deleted file mode 100644 index e9a96ef9d..000000000 --- a/ops/yandex-cloud-rs/build.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::path::PathBuf; -use walkdir::{DirEntry, WalkDir}; - -fn proto_files(proto_dir: &str) -> Vec { - let mut out = vec![]; - - fn is_proto(entry: &DirEntry) -> bool { - entry.file_type().is_file() - && entry - .path() - .extension() - .map(|e| e.to_string_lossy() == "proto") - .unwrap_or(false) - } - - for entry in WalkDir::new(format!("{}/yandex", proto_dir)).into_iter() { - let entry = entry.expect("failed to list proto files"); - - if is_proto(&entry) { - out.push(entry.into_path()) - } - } - - out -} - -fn main() { - if let Some(proto_dir) = option_env!("YANDEX_CLOUD_PROTOS") { - tonic_build::configure() - .build_client(true) - .build_server(false) - .out_dir("src/") - .include_file("includes.rs") - .compile( - &proto_files(proto_dir), - &[ - format!("{}", proto_dir), - format!("{}/third_party/googleapis", proto_dir), - ], - ) - .expect("failed to generate gRPC clients for Yandex Cloud") - } -} diff --git a/ops/yandex-cloud-rs/default.nix b/ops/yandex-cloud-rs/default.nix deleted file mode 100644 index 6a8b263de..000000000 --- a/ops/yandex-cloud-rs/default.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - protoSrc = pkgs.fetchFromGitHub { - owner = "yandex-cloud"; - repo = "cloudapi"; - rev = "b4383be5ebe360bd946e49c8eaf647a73e9c44c0"; - sha256 = "0z4jyw2cylvyrq5ja8pcaqnlf6lf6ximj85hgjag6ckawayk1rzx"; - }; -in -pkgs.rustPlatform.buildRustPackage rec { - name = "yandex-cloud-rs"; - src = depot.third_party.gitignoreSource ./.; - cargoLock.lockFile = ./Cargo.lock; - YANDEX_CLOUD_PROTOS = "${protoSrc}"; - nativeBuildInputs = [ pkgs.protobuf ]; - - # The generated doc comments contain lots of things that rustc - # *thinks* are doctests, but are actually just garbage leading to - # compiler errors. - doCheck = false; -} diff --git a/ops/yandex-cloud-rs/examples/log-write.rs b/ops/yandex-cloud-rs/examples/log-write.rs deleted file mode 100644 index 84d183421..000000000 --- a/ops/yandex-cloud-rs/examples/log-write.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! This example uses the Yandex Cloud Logging API to write a log entry. - -use prost_types::Timestamp; -use tonic::transport::channel::Endpoint; -use yandex_cloud::yandex::cloud::logging::v1::destination::Destination; -use yandex_cloud::yandex::cloud::logging::v1::log_ingestion_service_client::LogIngestionServiceClient; -use yandex_cloud::yandex::cloud::logging::v1::Destination as OuterDestination; -use yandex_cloud::yandex::cloud::logging::v1::IncomingLogEntry; -use yandex_cloud::yandex::cloud::logging::v1::WriteRequest; -use yandex_cloud::AuthInterceptor; - -#[tokio::main(flavor = "current_thread")] -async fn main() -> Result<(), Box> { - let channel = Endpoint::from_static("https://ingester.logging.yandexcloud.net") - .connect() - .await?; - - let mut client = LogIngestionServiceClient::with_interceptor( - channel, - AuthInterceptor::new("YOUR_TOKEN_HERE"), - ); - - let request = WriteRequest { - destination: Some(OuterDestination { - destination: Some(Destination::LogGroupId("YOUR_LOG_GROUP_ID".into())), - }), - entries: vec![IncomingLogEntry { - timestamp: Some(Timestamp::date_time(2023, 04, 24, 23, 44, 30).unwrap()), - message: "test log message".into(), - ..Default::default() - }], - ..Default::default() - }; - - client.write(request).await.unwrap(); - Ok(()) -} diff --git a/ops/yandex-cloud-rs/src/lib.rs b/ops/yandex-cloud-rs/src/lib.rs deleted file mode 100644 index e7f79c75b..000000000 --- a/ops/yandex-cloud-rs/src/lib.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! This module provides low-level generated gRPC clients for the -//! Yandex Cloud APIs. -//! -//! The clients are generated using the [tonic][] and [prost][] -//! crates and have default configuration. -//! -//! Documentation present in the protos is retained into the generated -//! Rust types, but for detailed API information you should visit the -//! official Yandex Cloud Documentation pages: -//! -//! * [in English](https://cloud.yandex.com/en-ru/docs/overview/api) -//! * [in Russian](https://cloud.yandex.ru/docs/overview/api) -//! -//! The proto sources are available on the [Yandex Cloud GitHub][protos]. -//! -//! [tonic]: https://docs.rs/tonic/latest/tonic/ -//! [prost]: https://docs.rs/prost/latest/prost/ -//! [protos]: https://github.com/yandex-cloud/cloudapi -//! -//! The majority of user-facing structures can be found in the -//! [`yandex::cloud`] module. -//! -//! ## Usage -//! -//! Typically to use these APIs, you need to provide an authentication -//! credential and an endpoint to connect to. The full list of -//! Yandex's endpoints is [available online][endpoints] and you should -//! look up the service you plan to use and pick the correct endpoint -//! from the list. -//! -//! Authentication is done via an HTTP header using an IAM token, -//! which can be done in Tonic using [interceptors][]. The -//! [`AuthInterceptor`] provided by this crate can be used for that -//! purpose. -//! -//! Full usage examples are [available here][examples]. -//! -//! [endpoints]: https://cloud.yandex.com/en/docs/api-design-guide/concepts/endpoints -//! [interceptors]: https://docs.rs/tonic/latest/tonic/service/trait.Interceptor.html -//! [examples]: https://code.tvl.fyi/tree/ops/yandex-cloud-rs/examples - -use tonic::metadata::{Ascii, MetadataValue}; -use tonic::service::Interceptor; - -/// Publicly re-export some types from tonic which users might need -/// for implementing traits, or for naming concrete client types. -pub mod tonic_exports { - pub use tonic::service::interceptor::InterceptedService; - pub use tonic::transport::Channel; - pub use tonic::transport::Endpoint; - pub use tonic::Status; -} - -/// Helper trait for types or closures that can provide authentication -/// tokens for Yandex Cloud. -pub trait TokenProvider { - /// Fetch a currently valid authentication token for Yandex Cloud. - fn get_token<'a>(&'a mut self) -> Result<&'a str, tonic::Status>; -} - -impl TokenProvider for String { - fn get_token<'a>(&'a mut self) -> Result<&'a str, tonic::Status> { - Ok(self.as_str()) - } -} - -impl TokenProvider for &'static str { - fn get_token(&mut self) -> Result<&'static str, tonic::Status> { - Ok(*self) - } -} - -/// Interceptor for adding authentication headers to gRPC requests. -/// This is constructed with a callable that returns authentication -/// tokens. -/// -/// This callable is responsible for ensuring that the returned tokens -/// are valid at the given time, i.e. it should take care of -/// refreshing and so on. -pub struct AuthInterceptor { - token_provider: T, -} - -impl AuthInterceptor { - pub fn new(token_provider: T) -> Self { - Self { token_provider } - } -} - -impl Interceptor for AuthInterceptor { - fn call( - &mut self, - mut request: tonic::Request<()>, - ) -> Result, tonic::Status> { - let token: MetadataValue = format!("Bearer {}", self.token_provider.get_token()?) - .try_into() - .map_err(|_| { - tonic::Status::invalid_argument("authorization token contained invalid characters") - })?; - - request.metadata_mut().insert("authorization", token); - - Ok(request) - } -} - -// The rest of this file is generated by the build script at ../build.rs. -include!("includes.rs"); diff --git a/third_party/cgit/.gitignore b/third_party/cgit/.gitignore deleted file mode 100644 index 661df346c..000000000 --- a/third_party/cgit/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -# Files I don't care to see in git-status/commit -/cgit -cgit.conf -CGIT-CFLAGS -VERSION -cgitrc.5 -cgitrc.5.fo -cgitrc.5.html -cgitrc.5.pdf -cgitrc.5.xml -*.o -*.d diff --git a/third_party/cgit/.mailmap b/third_party/cgit/.mailmap deleted file mode 100644 index 03b54796c..000000000 --- a/third_party/cgit/.mailmap +++ /dev/null @@ -1,10 +0,0 @@ -Florian Pritz -Harley Laue -John Keeping -Lars Hjemli -Lars Hjemli -Lars Hjemli -Lars Hjemli -Lukas Fleischer -Lukas Fleischer -Stefan Bühler diff --git a/third_party/cgit/.skip-subtree b/third_party/cgit/.skip-subtree deleted file mode 100644 index c108a7d34..000000000 --- a/third_party/cgit/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -Subtrees of this directory belong to cgit (third-party). diff --git a/third_party/cgit/AUTHORS b/third_party/cgit/AUTHORS deleted file mode 100644 index 256ea6b3b..000000000 --- a/third_party/cgit/AUTHORS +++ /dev/null @@ -1,13 +0,0 @@ -Maintainer: - June McEnroe - -Contributors: - Jason A. Donenfeld - Lukas Fleischer - Johan Herland - Lars Hjemli - Ferry Huberts - John Keeping - -Previous Maintainer: - Lars Hjemli diff --git a/third_party/cgit/COPYING b/third_party/cgit/COPYING deleted file mode 100644 index d159169d1..000000000 --- a/third_party/cgit/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/third_party/cgit/Makefile b/third_party/cgit/Makefile deleted file mode 100644 index 1a7f1f638..000000000 --- a/third_party/cgit/Makefile +++ /dev/null @@ -1,168 +0,0 @@ -all:: - -CGIT_VERSION = 1.4.1 -CGIT_SCRIPT_NAME = cgit.cgi -CGIT_SCRIPT_PATH = /var/www/htdocs/cgit -CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) -CGIT_CONFIG = /etc/cgitrc -CACHE_ROOT = /var/cache/cgit -prefix = /usr/local -libdir = $(prefix)/lib -filterdir = $(libdir)/cgit/filters -docdir = $(prefix)/share/doc/cgit -htmldir = $(docdir) -pdfdir = $(docdir) -mandir = $(prefix)/share/man -SHA1_HEADER = -GIT_VER = 2.41.0 -GIT_URL = https://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.xz -INSTALL = install -COPYTREE = cp -r -MAN5_TXT = $(wildcard *.5.txt) -MAN_TXT = $(MAN5_TXT) -DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT)) -DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT)) -DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT)) - -ASCIIDOC = asciidoc -ASCIIDOC_EXTRA = -ASCIIDOC_HTML = xhtml11 -ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) -TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML) - -# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) -# do not support the 'size specifiers' introduced by C99, namely ll, hh, -# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). -# some C compilers supported these specifiers prior to C99 as an extension. -# -# Define HAVE_LINUX_SENDFILE to use sendfile() - -#-include config.mak - --include git/config.mak.uname -# -# Let the user override the above settings. -# --include cgit.conf - -export CGIT_VERSION CGIT_SCRIPT_NAME CGIT_SCRIPT_PATH CGIT_DATA_PATH CGIT_CONFIG CACHE_ROOT - -# -# Define a way to invoke make in subdirs quietly, shamelessly ripped -# from git.git -# -QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir -QUIET_SUBDIR1 = - -ifneq ($(findstring w,$(MAKEFLAGS)),w) -PRINT_DIR = --no-print-directory -else # "make -w" -NO_SUBDIR = : -endif - -ifndef V - QUIET_SUBDIR0 = +@subdir= - QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ - $(MAKE) $(PRINT_DIR) -C $$subdir - QUIET_TAGS = @echo ' ' TAGS $@; - export V -endif - -.SUFFIXES: - -all:: cgit - -cgit: - $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) -f ../cgit.mk ../cgit $(EXTRA_GIT_TARGETS) NO_CURL=1 - -sparse: - $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) -f ../cgit.mk NO_CURL=1 cgit-sparse - -test: - @$(MAKE) --no-print-directory cgit EXTRA_GIT_TARGETS=all - $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all - -install: all - $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_SCRIPT_PATH) - $(INSTALL) -m 0755 cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) - $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH) - $(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css - $(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png - $(INSTALL) -m 0644 robots.txt $(DESTDIR)$(CGIT_DATA_PATH)/robots.txt - $(INSTALL) -m 0755 -d $(DESTDIR)$(filterdir) - $(COPYTREE) filters/* $(DESTDIR)$(filterdir) - -install-doc: install-man install-html install-pdf - -install-man: doc-man - $(INSTALL) -m 0755 -d $(DESTDIR)$(mandir)/man5 - $(INSTALL) -m 0644 $(DOC_MAN5) $(DESTDIR)$(mandir)/man5 - -install-html: doc-html - $(INSTALL) -m 0755 -d $(DESTDIR)$(htmldir) - $(INSTALL) -m 0644 $(DOC_HTML) $(DESTDIR)$(htmldir) - -install-pdf: doc-pdf - $(INSTALL) -m 0755 -d $(DESTDIR)$(pdfdir) - $(INSTALL) -m 0644 $(DOC_PDF) $(DESTDIR)$(pdfdir) - -uninstall: - rm -f $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) - rm -f $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css - rm -f $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png - -uninstall-doc: uninstall-man uninstall-html uninstall-pdf - -uninstall-man: - @for i in $(DOC_MAN5); do \ - rm -fv $(DESTDIR)$(mandir)/man5/$$i; \ - done - -uninstall-html: - @for i in $(DOC_HTML); do \ - rm -fv $(DESTDIR)$(htmldir)/$$i; \ - done - -uninstall-pdf: - @for i in $(DOC_PDF); do \ - rm -fv $(DESTDIR)$(pdfdir)/$$i; \ - done - -doc: doc-man doc-html doc-pdf -doc-man: doc-man5 -doc-man5: $(DOC_MAN5) -doc-html: $(DOC_HTML) -doc-pdf: $(DOC_PDF) - -%.5 : %.5.txt - a2x -f manpage $< - -$(DOC_HTML): %.html : %.txt - $(TXT_TO_HTML) -o $@+ $< && \ - mv $@+ $@ - -$(DOC_PDF): %.pdf : %.txt - a2x -f pdf cgitrc.5.txt - -clean: clean-doc - $(RM) cgit VERSION CGIT-CFLAGS *.o tags - $(RM) -r .deps - -cleanall: clean - $(MAKE) -C git clean - -clean-doc: - $(RM) cgitrc.5 cgitrc.5.html cgitrc.5.pdf cgitrc.5.xml cgitrc.5.fo - -get-git: - curl -L $(GIT_URL) | tar -xJf - && rm -rf git && mv git-$(GIT_VER) git - -tags: - $(QUIET_TAGS)find . -name '*.[ch]' | xargs ctags - -.PHONY: all cgit git get-git -.PHONY: clean clean-doc cleanall -.PHONY: doc doc-html doc-man doc-pdf -.PHONY: install install-doc install-html install-man install-pdf -.PHONY: tags test -.PHONY: uninstall uninstall-doc uninstall-html uninstall-man uninstall-pdf diff --git a/third_party/cgit/README b/third_party/cgit/README deleted file mode 100644 index 2094b87df..000000000 --- a/third_party/cgit/README +++ /dev/null @@ -1,88 +0,0 @@ -cgit-pink - CGI for Git -======================= - -This is a fork of cgit, an attempt to create a fast web interface -for the Git SCM, using a built-in cache to decrease server I/O -pressure. - -Installation ------------- - -Building cgit involves building a proper version of Git. How to do this -depends on how you obtained the cgit sources: - -a) If you're working in a cloned cgit repository, you first need to -initialize and update the Git submodule: - - $ git submodule init # register the Git submodule in .git/config - $ $EDITOR .git/config # if you want to specify a different url for git - $ git submodule update # clone/fetch and checkout correct git version - -b) If you're building from a cgit tarball, you can download a proper git -version like this: - - $ make get-git - -When either a) or b) has been performed, you can build and install cgit like -this: - - $ make - $ sudo make install - -This will install `cgit.cgi` and `cgit.css` into `/var/www/htdocs/cgit`. You -can configure this location (and a few other things) by providing a `cgit.conf` -file (see the Makefile for details). - - -Dependencies ------------- - -* libzip -* libcrypto (OpenSSL) -* libssl (OpenSSL) - -Apache configuration --------------------- - -A new `Directory` section must probably be added for cgit, possibly something -like this: - - - AllowOverride None - Options +ExecCGI - Order allow,deny - Allow from all - - - -Runtime configuration ---------------------- - -The file `/etc/cgitrc` is read by cgit before handling a request. In addition -to runtime parameters, this file may also contain a list of repositories -displayed by cgit (see `cgitrc.5.txt` for further details). - -The cache ---------- - -When cgit is invoked it looks for a cache file matching the request and -returns it to the client. If no such cache file exists (or if it has expired), -the content for the request is written into the proper cache file before the -file is returned. - -If the cache file has expired but cgit is unable to obtain a lock for it, the -stale cache file is returned to the client. This is done to favour page -throughput over page freshness. - -The generated content contains the complete response to the client, including -the HTTP headers `Modified` and `Expires`. - -Online presence ---------------- - -* The cgit-pink homepage is hosted by cgit at - - -* Patches, bug reports, discussions and support should go to the cgit-pink - mailing list: . Archives are available at: - diff --git a/third_party/cgit/cache.c b/third_party/cgit/cache.c deleted file mode 100644 index 59372541c..000000000 --- a/third_party/cgit/cache.c +++ /dev/null @@ -1,480 +0,0 @@ -/* cache.c: cache management - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - * - * - * The cache is just a directory structure where each file is a cache slot, - * and each filename is based on the hash of some key (e.g. the cgit url). - * Each file contains the full key followed by the cached content for that - * key. - * - */ - -#include "cgit.h" -#include "cache.h" -#include "html.h" -#ifdef HAVE_LINUX_SENDFILE -#include -#endif - -#define CACHE_BUFSIZE (1024 * 4) - -struct cache_slot { - const char *key; - size_t keylen; - int ttl; - cache_fill_fn fn; - int cache_fd; - int lock_fd; - int stdout_fd; - const char *cache_name; - const char *lock_name; - int match; - struct stat cache_st; - int bufsize; - char buf[CACHE_BUFSIZE]; -}; - -/* Open an existing cache slot and fill the cache buffer with - * (part of) the content of the cache file. Return 0 on success - * and errno otherwise. - */ -static int open_slot(struct cache_slot *slot) -{ - char *bufz; - ssize_t bufkeylen = -1; - - slot->cache_fd = open(slot->cache_name, O_RDONLY); - if (slot->cache_fd == -1) - return errno; - - if (fstat(slot->cache_fd, &slot->cache_st)) - return errno; - - slot->bufsize = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); - if (slot->bufsize < 0) - return errno; - - bufz = memchr(slot->buf, 0, slot->bufsize); - if (bufz) - bufkeylen = bufz - slot->buf; - - if (slot->key) - slot->match = bufkeylen == slot->keylen && - !memcmp(slot->key, slot->buf, bufkeylen + 1); - - return 0; -} - -/* Close the active cache slot */ -static int close_slot(struct cache_slot *slot) -{ - int err = 0; - if (slot->cache_fd > 0) { - if (close(slot->cache_fd)) - err = errno; - else - slot->cache_fd = -1; - } - return err; -} - -/* Print the content of the active cache slot (but skip the key). */ -static int print_slot(struct cache_slot *slot) -{ - off_t off; -#ifdef HAVE_LINUX_SENDFILE - off_t size; -#endif - - off = slot->keylen + 1; - -#ifdef HAVE_LINUX_SENDFILE - size = slot->cache_st.st_size; - - do { - ssize_t ret; - ret = sendfile(STDOUT_FILENO, slot->cache_fd, &off, size - off); - if (ret < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - /* Fall back to read/write on EINVAL or ENOSYS */ - if (errno == EINVAL || errno == ENOSYS) - break; - return errno; - } - if (off == size) - return 0; - } while (1); -#endif - - if (lseek(slot->cache_fd, off, SEEK_SET) != off) - return errno; - - do { - ssize_t ret; - ret = xread(slot->cache_fd, slot->buf, sizeof(slot->buf)); - if (ret < 0) - return errno; - if (ret == 0) - return 0; - if (write_in_full(STDOUT_FILENO, slot->buf, ret) < 0) - return errno; - } while (1); -} - -/* Check if the slot has expired */ -static int is_expired(struct cache_slot *slot) -{ - if (slot->ttl < 0) - return 0; - else - return slot->cache_st.st_mtime + slot->ttl * 60 < time(NULL); -} - -/* Check if the slot has been modified since we opened it. - * NB: If stat() fails, we pretend the file is modified. - */ -static int is_modified(struct cache_slot *slot) -{ - struct stat st; - - if (stat(slot->cache_name, &st)) - return 1; - return (st.st_ino != slot->cache_st.st_ino || - st.st_mtime != slot->cache_st.st_mtime || - st.st_size != slot->cache_st.st_size); -} - -/* Close an open lockfile */ -static int close_lock(struct cache_slot *slot) -{ - int err = 0; - if (slot->lock_fd > 0) { - if (close(slot->lock_fd)) - err = errno; - else - slot->lock_fd = -1; - } - return err; -} - -/* Create a lockfile used to store the generated content for a cache - * slot, and write the slot key + \0 into it. - * Returns 0 on success and errno otherwise. - */ -static int lock_slot(struct cache_slot *slot) -{ - struct flock lock = { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0, - }; - - slot->lock_fd = open(slot->lock_name, O_RDWR | O_CREAT, - S_IRUSR | S_IWUSR); - if (slot->lock_fd == -1) - return errno; - if (fcntl(slot->lock_fd, F_SETLK, &lock) < 0) { - int saved_errno = errno; - close(slot->lock_fd); - slot->lock_fd = -1; - return saved_errno; - } - if (xwrite(slot->lock_fd, slot->key, slot->keylen + 1) < 0) - return errno; - return 0; -} - -/* Release the current lockfile. If `replace_old_slot` is set the - * lockfile replaces the old cache slot, otherwise the lockfile is - * just deleted. - */ -static int unlock_slot(struct cache_slot *slot, int replace_old_slot) -{ - int err; - - if (replace_old_slot) - err = rename(slot->lock_name, slot->cache_name); - else - err = unlink(slot->lock_name); - - /* Restore stdout and close the temporary FD. */ - if (slot->stdout_fd >= 0) { - dup2(slot->stdout_fd, STDOUT_FILENO); - close(slot->stdout_fd); - slot->stdout_fd = -1; - } - - if (err) - return errno; - - return 0; -} - -/* Generate the content for the current cache slot by redirecting - * stdout to the lock-fd and invoking the callback function - */ -static int fill_slot(struct cache_slot *slot) -{ - /* Preserve stdout */ - slot->stdout_fd = dup(STDOUT_FILENO); - if (slot->stdout_fd == -1) - return errno; - - /* Redirect stdout to lockfile */ - if (dup2(slot->lock_fd, STDOUT_FILENO) == -1) - return errno; - - /* Generate cache content */ - slot->fn(); - - /* Make sure any buffered data is flushed to the file */ - if (fflush(stdout)) - return errno; - - /* update stat info */ - if (fstat(slot->lock_fd, &slot->cache_st)) - return errno; - - return 0; -} - -/* Crude implementation of 32-bit FNV-1 hash algorithm, - * see http://www.isthe.com/chongo/tech/comp/fnv/ for details - * about the magic numbers. - */ -#define FNV_OFFSET 0x811c9dc5 -#define FNV_PRIME 0x01000193 - -unsigned long hash_str(const char *str) -{ - unsigned long h = FNV_OFFSET; - unsigned char *s = (unsigned char *)str; - - if (!s) - return h; - - while (*s) { - h *= FNV_PRIME; - h ^= *s++; - } - return h; -} - -static int process_slot(struct cache_slot *slot) -{ - int err; - - /* - * Make sure any buffered data is flushed before we redirect, - * do sendfile(2) or write(2) - */ - if (fflush(stdout)) - return errno; - - err = open_slot(slot); - if (!err && slot->match) { - if (is_expired(slot)) { - if (!lock_slot(slot)) { - /* If the cachefile has been replaced between - * `open_slot` and `lock_slot`, we'll just - * serve the stale content from the original - * cachefile. This way we avoid pruning the - * newly generated slot. The same code-path - * is chosen if fill_slot() fails for some - * reason. - * - * TODO? check if the new slot contains the - * same key as the old one, since we would - * prefer to serve the newest content. - * This will require us to open yet another - * file-descriptor and read and compare the - * key from the new file, so for now we're - * lazy and just ignore the new file. - */ - if (is_modified(slot) || fill_slot(slot)) { - unlock_slot(slot, 0); - close_lock(slot); - } else { - close_slot(slot); - unlock_slot(slot, 1); - slot->cache_fd = slot->lock_fd; - } - } - } - if ((err = print_slot(slot)) != 0) { - cache_log("[cgit] error printing cache %s: %s (%d)\n", - slot->cache_name, - strerror(err), - err); - } - close_slot(slot); - return err; - } - - /* If the cache slot does not exist (or its key doesn't match the - * current key), lets try to create a new cache slot for this - * request. If this fails (for whatever reason), lets just generate - * the content without caching it and fool the caller to believe - * everything worked out (but print a warning on stdout). - */ - - close_slot(slot); - if ((err = lock_slot(slot)) != 0) { - cache_log("[cgit] Unable to lock slot %s: %s (%d)\n", - slot->lock_name, strerror(err), err); - slot->fn(); - return 0; - } - - if ((err = fill_slot(slot)) != 0) { - cache_log("[cgit] Unable to fill slot %s: %s (%d)\n", - slot->lock_name, strerror(err), err); - unlock_slot(slot, 0); - close_lock(slot); - slot->fn(); - return 0; - } - // We've got a valid cache slot in the lock file, which - // is about to replace the old cache slot. But if we - // release the lockfile and then try to open the new cache - // slot, we might get a race condition with a concurrent - // writer for the same cache slot (with a different key). - // Lets avoid such a race by just printing the content of - // the lock file. - slot->cache_fd = slot->lock_fd; - unlock_slot(slot, 1); - if ((err = print_slot(slot)) != 0) { - cache_log("[cgit] error printing cache %s: %s (%d)\n", - slot->cache_name, - strerror(err), - err); - } - close_slot(slot); - return err; -} - -/* Print cached content to stdout, generate the content if necessary. */ -int cache_process(int size, const char *path, const char *key, int ttl, - cache_fill_fn fn) -{ - unsigned long hash; - int i; - struct strbuf filename = STRBUF_INIT; - struct strbuf lockname = STRBUF_INIT; - struct cache_slot slot; - int result; - - /* If the cache is disabled, just generate the content */ - if (size <= 0 || ttl == 0) { - fn(); - return 0; - } - - /* Verify input, calculate filenames */ - if (!path) { - cache_log("[cgit] Cache path not specified, caching is disabled\n"); - fn(); - return 0; - } - if (!key) - key = ""; - hash = hash_str(key) % size; - strbuf_addstr(&filename, path); - strbuf_ensure_end(&filename, '/'); - for (i = 0; i < 8; i++) { - strbuf_addf(&filename, "%x", (unsigned char)(hash & 0xf)); - hash >>= 4; - } - strbuf_addbuf(&lockname, &filename); - strbuf_addstr(&lockname, ".lock"); - slot.fn = fn; - slot.ttl = ttl; - slot.stdout_fd = -1; - slot.cache_name = filename.buf; - slot.lock_name = lockname.buf; - slot.key = key; - slot.keylen = strlen(key); - result = process_slot(&slot); - - strbuf_release(&filename); - strbuf_release(&lockname); - return result; -} - -/* Return a strftime formatted date/time - * NB: the result from this function is to shared memory - */ -static char *sprintftime(const char *format, time_t time) -{ - static char buf[64]; - struct tm tm; - - if (!time) - return NULL; - gmtime_r(&time, &tm); - strftime(buf, sizeof(buf)-1, format, &tm); - return buf; -} - -int cache_ls(const char *path) -{ - DIR *dir; - struct dirent *ent; - int err = 0; - struct cache_slot slot = { NULL }; - struct strbuf fullname = STRBUF_INIT; - size_t prefixlen; - - if (!path) { - cache_log("[cgit] cache path not specified\n"); - return -1; - } - dir = opendir(path); - if (!dir) { - err = errno; - cache_log("[cgit] unable to open path %s: %s (%d)\n", - path, strerror(err), err); - return err; - } - strbuf_addstr(&fullname, path); - strbuf_ensure_end(&fullname, '/'); - prefixlen = fullname.len; - while ((ent = readdir(dir)) != NULL) { - if (strlen(ent->d_name) != 8) - continue; - strbuf_setlen(&fullname, prefixlen); - strbuf_addstr(&fullname, ent->d_name); - slot.cache_name = fullname.buf; - if ((err = open_slot(&slot)) != 0) { - cache_log("[cgit] unable to open path %s: %s (%d)\n", - fullname.buf, strerror(err), err); - continue; - } - htmlf("%s %s %10"PRIuMAX" %s\n", - fullname.buf, - sprintftime("%Y-%m-%d %H:%M:%S", - slot.cache_st.st_mtime), - (uintmax_t)slot.cache_st.st_size, - slot.buf); - close_slot(&slot); - } - closedir(dir); - strbuf_release(&fullname); - return 0; -} - -/* Print a message to stdout */ -void cache_log(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} - diff --git a/third_party/cgit/cache.h b/third_party/cgit/cache.h deleted file mode 100644 index 470da4fc1..000000000 --- a/third_party/cgit/cache.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Since git has it's own cache.h which we include, - * lets test on CGIT_CACHE_H to avoid confusion - */ - -#ifndef CGIT_CACHE_H -#define CGIT_CACHE_H - -typedef void (*cache_fill_fn)(void); - - -/* Print cached content to stdout, generate the content if necessary. - * - * Parameters - * size max number of cache files - * path directory used to store cache files - * key the key used to lookup cache files - * ttl max cache time in seconds for this key - * fn content generator function for this key - * - * Return value - * 0 indicates success, everything else is an error - */ -extern int cache_process(int size, const char *path, const char *key, int ttl, - cache_fill_fn fn); - - -/* List info about all cache entries on stdout */ -extern int cache_ls(const char *path); - -/* Print a message to stdout */ -__attribute__((format (printf,1,2))) -extern void cache_log(const char *format, ...); - -extern unsigned long hash_str(const char *str); - -#endif /* CGIT_CACHE_H */ diff --git a/third_party/cgit/cgit.c b/third_party/cgit/cgit.c deleted file mode 100644 index 40202ead6..000000000 --- a/third_party/cgit/cgit.c +++ /dev/null @@ -1,1107 +0,0 @@ -/* cgit.c: cgi for the git scm - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "cache.h" -#include "cmd.h" -#include "configfile.h" -#include "html.h" -#include "ui-shared.h" -#include "ui-stats.h" -#include "ui-blob.h" -#include "ui-summary.h" -#include "scan-tree.h" - -const char *cgit_version = CGIT_VERSION; - -__attribute__((constructor)) -static void constructor_environment() -{ - /* Do not look in /etc/ for gitconfig and gitattributes. */ - setenv("GIT_CONFIG_NOSYSTEM", "1", 1); - setenv("GIT_ATTR_NOSYSTEM", "1", 1); - unsetenv("HOME"); - unsetenv("XDG_CONFIG_HOME"); -} - -static void add_mimetype(const char *name, const char *value) -{ - struct string_list_item *item; - - item = string_list_insert(&ctx.cfg.mimetypes, name); - item->util = xstrdup(value); -} - -static void process_cached_repolist(const char *path); - -static void repo_config(struct cgit_repo *repo, const char *name, const char *value) -{ - const char *path; - struct string_list_item *item; - - if (!strcmp(name, "name")) - repo->name = xstrdup(value); - else if (!strcmp(name, "clone-url")) - repo->clone_url = xstrdup(value); - else if (!strcmp(name, "desc")) - repo->desc = xstrdup(value); - else if (!strcmp(name, "owner")) - repo->owner = xstrdup(value); - else if (!strcmp(name, "homepage")) - repo->homepage = xstrdup(value); - else if (!strcmp(name, "defbranch")) - repo->defbranch = xstrdup(value); - else if (!strcmp(name, "extra-head-content")) - repo->extra_head_content = xstrdup(value); - else if (!strcmp(name, "snapshots")) - repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); - else if (!strcmp(name, "enable-blame")) - repo->enable_blame = atoi(value); - else if (!strcmp(name, "enable-commit-graph")) - repo->enable_commit_graph = atoi(value); - else if (!strcmp(name, "enable-log-filecount")) - repo->enable_log_filecount = atoi(value); - else if (!strcmp(name, "enable-log-linecount")) - repo->enable_log_linecount = atoi(value); - else if (!strcmp(name, "enable-remote-branches")) - repo->enable_remote_branches = atoi(value); - else if (!strcmp(name, "enable-subject-links")) - repo->enable_subject_links = atoi(value); - else if (!strcmp(name, "enable-html-serving")) - repo->enable_html_serving = atoi(value); - else if (!strcmp(name, "branch-sort")) { - if (!strcmp(value, "age")) - repo->branch_sort = 1; - if (!strcmp(value, "name")) - repo->branch_sort = 0; - } else if (!strcmp(name, "commit-sort")) { - if (!strcmp(value, "date")) - repo->commit_sort = 1; - if (!strcmp(value, "topo")) - repo->commit_sort = 2; - } else if (!strcmp(name, "max-stats")) - repo->max_stats = cgit_find_stats_period(value, NULL); - else if (!strcmp(name, "module-link")) - repo->module_link= xstrdup(value); - else if (skip_prefix(name, "module-link.", &path)) { - item = string_list_append(&repo->submodules, xstrdup(path)); - item->util = xstrdup(value); - } else if (!strcmp(name, "section")) - repo->section = xstrdup(value); - else if (!strcmp(name, "snapshot-prefix")) - repo->snapshot_prefix = xstrdup(value); - else if (!strcmp(name, "readme") && value != NULL) { - if (repo->readme.items == ctx.cfg.readme.items) - memset(&repo->readme, 0, sizeof(repo->readme)); - string_list_append(&repo->readme, xstrdup(value)); - } else if (!strcmp(name, "logo") && value != NULL) - repo->logo = xstrdup(value); - else if (!strcmp(name, "logo-link") && value != NULL) - repo->logo_link = xstrdup(value); - else if (!strcmp(name, "hide")) - repo->hide = atoi(value); - else if (!strcmp(name, "ignore")) - repo->ignore = atoi(value); - else if (ctx.cfg.enable_filter_overrides) { - if (!strcmp(name, "about-filter")) - repo->about_filter = cgit_new_filter(value, ABOUT); - else if (!strcmp(name, "commit-filter")) - repo->commit_filter = cgit_new_filter(value, COMMIT); - else if (!strcmp(name, "source-filter")) - repo->source_filter = cgit_new_filter(value, SOURCE); - else if (!strcmp(name, "email-filter")) - repo->email_filter = cgit_new_filter(value, EMAIL); - else if (!strcmp(name, "owner-filter")) - repo->owner_filter = cgit_new_filter(value, OWNER); - } -} - -static void config_cb(const char *name, const char *value) -{ - const char *arg; - - if (!strcmp(name, "section")) - ctx.cfg.section = xstrdup(value); - else if (!strcmp(name, "repo.url")) - ctx.repo = cgit_add_repo(value); - else if (ctx.repo && !strcmp(name, "repo.path")) - ctx.repo->path = trim_end(value, '/'); - else if (ctx.repo && skip_prefix(name, "repo.", &arg)) - repo_config(ctx.repo, arg, value); - else if (!strcmp(name, "readme")) - string_list_append(&ctx.cfg.readme, xstrdup(value)); - else if (!strcmp(name, "root-title")) - ctx.cfg.root_title = xstrdup(value); - else if (!strcmp(name, "root-desc")) - ctx.cfg.root_desc = xstrdup(value); - else if (!strcmp(name, "root-readme")) - ctx.cfg.root_readme = xstrdup(value); - else if (!strcmp(name, "css")) - ctx.cfg.css = xstrdup(value); - else if (!strcmp(name, "favicon")) - ctx.cfg.favicon = xstrdup(value); - else if (!strcmp(name, "footer")) - ctx.cfg.footer = xstrdup(value); - else if (!strcmp(name, "head-include")) - ctx.cfg.head_include = xstrdup(value); - else if (!strcmp(name, "header")) - ctx.cfg.header = xstrdup(value); - else if (!strcmp(name, "logo")) - ctx.cfg.logo = xstrdup(value); - else if (!strcmp(name, "logo-link")) - ctx.cfg.logo_link = xstrdup(value); - else if (!strcmp(name, "module-link")) - ctx.cfg.module_link = xstrdup(value); - else if (!strcmp(name, "strict-export")) - ctx.cfg.strict_export = xstrdup(value); - else if (!strcmp(name, "virtual-root")) - ctx.cfg.virtual_root = ensure_end(value, '/'); - else if (!strcmp(name, "noplainemail")) - ctx.cfg.noplainemail = atoi(value); - else if (!strcmp(name, "noheader")) - ctx.cfg.noheader = atoi(value); - else if (!strcmp(name, "snapshots")) - ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); - else if (!strcmp(name, "enable-filter-overrides")) - ctx.cfg.enable_filter_overrides = atoi(value); - else if (!strcmp(name, "enable-follow-links")) - ctx.cfg.enable_follow_links = atoi(value); - else if (!strcmp(name, "enable-http-clone")) - ctx.cfg.enable_http_clone = atoi(value); - else if (!strcmp(name, "enable-index-links")) - ctx.cfg.enable_index_links = atoi(value); - else if (!strcmp(name, "enable-index-owner")) - ctx.cfg.enable_index_owner = atoi(value); - else if (!strcmp(name, "enable-blame")) - ctx.cfg.enable_blame = atoi(value); - else if (!strcmp(name, "enable-commit-graph")) - ctx.cfg.enable_commit_graph = atoi(value); - else if (!strcmp(name, "enable-log-filecount")) - ctx.cfg.enable_log_filecount = atoi(value); - else if (!strcmp(name, "enable-log-linecount")) - ctx.cfg.enable_log_linecount = atoi(value); - else if (!strcmp(name, "enable-remote-branches")) - ctx.cfg.enable_remote_branches = atoi(value); - else if (!strcmp(name, "enable-subject-links")) - ctx.cfg.enable_subject_links = atoi(value); - else if (!strcmp(name, "enable-html-serving")) - ctx.cfg.enable_html_serving = atoi(value); - else if (!strcmp(name, "enable-tree-linenumbers")) - ctx.cfg.enable_tree_linenumbers = atoi(value); - else if (!strcmp(name, "enable-git-config")) - ctx.cfg.enable_git_config = atoi(value); - else if (!strcmp(name, "max-stats")) - ctx.cfg.max_stats = cgit_find_stats_period(value, NULL); - else if (!strcmp(name, "cache-size")) - ctx.cfg.cache_size = atoi(value); - else if (!strcmp(name, "cache-root")) - ctx.cfg.cache_root = xstrdup(expand_macros(value)); - else if (!strcmp(name, "cache-root-ttl")) - ctx.cfg.cache_root_ttl = atoi(value); - else if (!strcmp(name, "cache-repo-ttl")) - ctx.cfg.cache_repo_ttl = atoi(value); - else if (!strcmp(name, "cache-scanrc-ttl")) - ctx.cfg.cache_scanrc_ttl = atoi(value); - else if (!strcmp(name, "cache-static-ttl")) - ctx.cfg.cache_static_ttl = atoi(value); - else if (!strcmp(name, "cache-dynamic-ttl")) - ctx.cfg.cache_dynamic_ttl = atoi(value); - else if (!strcmp(name, "cache-about-ttl")) - ctx.cfg.cache_about_ttl = atoi(value); - else if (!strcmp(name, "cache-snapshot-ttl")) - ctx.cfg.cache_snapshot_ttl = atoi(value); - else if (!strcmp(name, "case-sensitive-sort")) - ctx.cfg.case_sensitive_sort = atoi(value); - else if (!strcmp(name, "about-filter")) - ctx.cfg.about_filter = cgit_new_filter(value, ABOUT); - else if (!strcmp(name, "commit-filter")) - ctx.cfg.commit_filter = cgit_new_filter(value, COMMIT); - else if (!strcmp(name, "email-filter")) - ctx.cfg.email_filter = cgit_new_filter(value, EMAIL); - else if (!strcmp(name, "owner-filter")) - ctx.cfg.owner_filter = cgit_new_filter(value, OWNER); - else if (!strcmp(name, "auth-filter")) - ctx.cfg.auth_filter = cgit_new_filter(value, AUTH); - else if (!strcmp(name, "embedded")) - ctx.cfg.embedded = atoi(value); - else if (!strcmp(name, "max-atom-items")) - ctx.cfg.max_atom_items = atoi(value); - else if (!strcmp(name, "max-message-length")) - ctx.cfg.max_msg_len = atoi(value); - else if (!strcmp(name, "max-repodesc-length")) - ctx.cfg.max_repodesc_len = atoi(value); - else if (!strcmp(name, "max-blob-size")) - ctx.cfg.max_blob_size = atoi(value); - else if (!strcmp(name, "max-repo-count")) - ctx.cfg.max_repo_count = atoi(value); - else if (!strcmp(name, "max-commit-count")) - ctx.cfg.max_commit_count = atoi(value); - else if (!strcmp(name, "project-list")) - ctx.cfg.project_list = xstrdup(expand_macros(value)); - else if (!strcmp(name, "scan-path")) - if (ctx.cfg.cache_size) - process_cached_repolist(expand_macros(value)); - else if (ctx.cfg.project_list) - scan_projects(expand_macros(value), - ctx.cfg.project_list, repo_config); - else - scan_tree(expand_macros(value), repo_config); - else if (!strcmp(name, "scan-hidden-path")) - ctx.cfg.scan_hidden_path = atoi(value); - else if (!strcmp(name, "section-from-path")) - ctx.cfg.section_from_path = atoi(value); - else if (!strcmp(name, "repository-sort")) - ctx.cfg.repository_sort = xstrdup(value); - else if (!strcmp(name, "section-sort")) - ctx.cfg.section_sort = atoi(value); - else if (!strcmp(name, "source-filter")) - ctx.cfg.source_filter = cgit_new_filter(value, SOURCE); - else if (!strcmp(name, "summary-log")) - ctx.cfg.summary_log = atoi(value); - else if (!strcmp(name, "summary-branches")) - ctx.cfg.summary_branches = atoi(value); - else if (!strcmp(name, "summary-tags")) - ctx.cfg.summary_tags = atoi(value); - else if (!strcmp(name, "side-by-side-diffs")) - ctx.cfg.difftype = atoi(value) ? DIFF_SSDIFF : DIFF_UNIFIED; - else if (!strcmp(name, "agefile")) - ctx.cfg.agefile = xstrdup(value); - else if (!strcmp(name, "mimetype-file")) - ctx.cfg.mimetype_file = xstrdup(value); - else if (!strcmp(name, "renamelimit")) - ctx.cfg.renamelimit = atoi(value); - else if (!strcmp(name, "remove-suffix")) - ctx.cfg.remove_suffix = atoi(value); - else if (!strcmp(name, "robots")) - ctx.cfg.robots = xstrdup(value); - else if (!strcmp(name, "clone-prefix")) - ctx.cfg.clone_prefix = xstrdup(value); - else if (!strcmp(name, "clone-url")) - ctx.cfg.clone_url = xstrdup(value); - else if (!strcmp(name, "local-time")) - ctx.cfg.local_time = atoi(value); - else if (!strcmp(name, "commit-sort")) { - if (!strcmp(value, "date")) - ctx.cfg.commit_sort = 1; - if (!strcmp(value, "topo")) - ctx.cfg.commit_sort = 2; - } else if (!strcmp(name, "branch-sort")) { - if (!strcmp(value, "age")) - ctx.cfg.branch_sort = 1; - if (!strcmp(value, "name")) - ctx.cfg.branch_sort = 0; - } else if (skip_prefix(name, "mimetype.", &arg)) - add_mimetype(arg, value); - else if (!strcmp(name, "include")) - parse_configfile(expand_macros(value), config_cb); -} - -static void querystring_cb(const char *name, const char *value) -{ - if (!value) - value = ""; - - if (!strcmp(name,"r")) { - ctx.qry.repo = xstrdup(value); - ctx.repo = cgit_get_repoinfo(value); - } else if (!strcmp(name, "p")) { - ctx.qry.page = xstrdup(value); - } else if (!strcmp(name, "url")) { - if (*value == '/') - value++; - ctx.qry.url = xstrdup(value); - cgit_parse_url(value); - } else if (!strcmp(name, "qt")) { - ctx.qry.grep = xstrdup(value); - } else if (!strcmp(name, "q")) { - ctx.qry.search = xstrdup(value); - } else if (!strcmp(name, "h")) { - ctx.qry.head = xstrdup(value); - ctx.qry.has_symref = 1; - } else if (!strcmp(name, "id")) { - ctx.qry.oid = xstrdup(value); - ctx.qry.has_oid = 1; - } else if (!strcmp(name, "id2")) { - ctx.qry.oid2 = xstrdup(value); - ctx.qry.has_oid = 1; - } else if (!strcmp(name, "ofs")) { - ctx.qry.ofs = atoi(value); - } else if (!strcmp(name, "path")) { - ctx.qry.path = trim_end(value, '/'); - } else if (!strcmp(name, "name")) { - ctx.qry.name = xstrdup(value); - } else if (!strcmp(name, "s")) { - ctx.qry.sort = xstrdup(value); - } else if (!strcmp(name, "showmsg")) { - ctx.qry.showmsg = atoi(value); - } else if (!strcmp(name, "period")) { - ctx.qry.period = xstrdup(value); - } else if (!strcmp(name, "dt")) { - ctx.qry.difftype = atoi(value); - ctx.qry.has_difftype = 1; - } else if (!strcmp(name, "ss")) { - /* No longer generated, but there may be links out there. */ - ctx.qry.difftype = atoi(value) ? DIFF_SSDIFF : DIFF_UNIFIED; - ctx.qry.has_difftype = 1; - } else if (!strcmp(name, "all")) { - ctx.qry.show_all = atoi(value); - } else if (!strcmp(name, "context")) { - ctx.qry.context = atoi(value); - } else if (!strcmp(name, "ignorews")) { - ctx.qry.ignorews = atoi(value); - } else if (!strcmp(name, "follow")) { - ctx.qry.follow = atoi(value); - } -} - -static void prepare_context(void) -{ - memset(&ctx, 0, sizeof(ctx)); - ctx.cfg.agefile = "info/web/last-modified"; - ctx.cfg.cache_size = 0; - ctx.cfg.cache_max_create_time = 5; - ctx.cfg.cache_root = CGIT_CACHE_ROOT; - ctx.cfg.cache_about_ttl = 15; - ctx.cfg.cache_snapshot_ttl = 5; - ctx.cfg.cache_repo_ttl = 5; - ctx.cfg.cache_root_ttl = 5; - ctx.cfg.cache_scanrc_ttl = 15; - ctx.cfg.cache_dynamic_ttl = 5; - ctx.cfg.cache_static_ttl = -1; - ctx.cfg.case_sensitive_sort = 1; - ctx.cfg.branch_sort = 0; - ctx.cfg.commit_sort = 0; - ctx.cfg.css = "/cgit.css"; - ctx.cfg.logo = "/cgit.png"; - ctx.cfg.favicon = NULL; - ctx.cfg.local_time = 0; - ctx.cfg.enable_http_clone = 1; - ctx.cfg.enable_index_owner = 1; - ctx.cfg.enable_tree_linenumbers = 1; - ctx.cfg.enable_git_config = 0; - ctx.cfg.max_repo_count = 50; - ctx.cfg.max_commit_count = 50; - ctx.cfg.max_lock_attempts = 5; - ctx.cfg.max_msg_len = 80; - ctx.cfg.max_repodesc_len = 80; - ctx.cfg.max_blob_size = 0; - ctx.cfg.max_stats = 0; - ctx.cfg.project_list = NULL; - ctx.cfg.renamelimit = -1; - ctx.cfg.remove_suffix = 0; - ctx.cfg.robots = "index, nofollow"; - ctx.cfg.root_title = "Git repository browser"; - ctx.cfg.root_desc = "a fast webinterface for the git dscm"; - ctx.cfg.scan_hidden_path = 0; - ctx.cfg.script_name = CGIT_SCRIPT_NAME; - ctx.cfg.section = ""; - ctx.cfg.repository_sort = "name"; - ctx.cfg.section_sort = 1; - ctx.cfg.summary_branches = 10; - ctx.cfg.summary_log = 10; - ctx.cfg.summary_tags = 10; - ctx.cfg.max_atom_items = 10; - ctx.cfg.difftype = DIFF_UNIFIED; - ctx.env.cgit_config = getenv("CGIT_CONFIG"); - ctx.env.http_host = getenv("HTTP_HOST"); - ctx.env.https = getenv("HTTPS"); - ctx.env.no_http = getenv("NO_HTTP"); - ctx.env.path_info = getenv("PATH_INFO"); - ctx.env.query_string = getenv("QUERY_STRING"); - ctx.env.request_method = getenv("REQUEST_METHOD"); - ctx.env.script_name = getenv("SCRIPT_NAME"); - ctx.env.server_name = getenv("SERVER_NAME"); - ctx.env.server_port = getenv("SERVER_PORT"); - ctx.env.http_cookie = getenv("HTTP_COOKIE"); - ctx.env.http_referer = getenv("HTTP_REFERER"); - ctx.env.content_length = getenv("CONTENT_LENGTH") ? strtoul(getenv("CONTENT_LENGTH"), NULL, 10) : 0; - ctx.env.authenticated = 0; - ctx.page.mimetype = "text/html"; - ctx.page.charset = PAGE_ENCODING; - ctx.page.filename = NULL; - ctx.page.size = 0; - ctx.page.modified = time(NULL); - ctx.page.expires = ctx.page.modified; - ctx.page.etag = NULL; - string_list_init_dup(&ctx.cfg.mimetypes); - if (ctx.env.script_name) - ctx.cfg.script_name = xstrdup(ctx.env.script_name); - if (ctx.env.query_string) - ctx.qry.raw = xstrdup(ctx.env.query_string); - if (!ctx.env.cgit_config) - ctx.env.cgit_config = CGIT_CONFIG; -} - -struct refmatch { - char *req_ref; - char *first_ref; - int match; -}; - -static int find_current_ref(const char *refname, const struct object_id *oid, - int flags, void *cb_data) -{ - struct refmatch *info; - - info = (struct refmatch *)cb_data; - if (!strcmp(refname, info->req_ref)) - info->match = 1; - if (!info->first_ref) - info->first_ref = xstrdup(refname); - return info->match; -} - -static void free_refmatch_inner(struct refmatch *info) -{ - if (info->first_ref) - free(info->first_ref); -} - -static char *find_default_branch(struct cgit_repo *repo) -{ - struct refmatch info; - char *ref; - - info.req_ref = repo->defbranch; - info.first_ref = NULL; - info.match = 0; - for_each_branch_ref(find_current_ref, &info); - if (info.match) - ref = info.req_ref; - else - ref = info.first_ref; - if (ref) - ref = xstrdup(ref); - free_refmatch_inner(&info); - - return ref; -} - -static char *guess_defbranch(void) -{ - const char *ref, *refname; - struct object_id oid; - - ref = resolve_ref_unsafe("HEAD", 0, &oid, NULL); - if (!ref || !skip_prefix(ref, "refs/heads/", &refname)) - return "master"; - return xstrdup(refname); -} - -/* The caller must free filename and ref after calling this. */ -static inline void parse_readme(const char *readme, char **filename, char **ref, struct cgit_repo *repo) -{ - const char *colon; - - *filename = NULL; - *ref = NULL; - - if (!readme || !readme[0]) - return; - - /* Check if the readme is tracked in the git repo. */ - colon = strchr(readme, ':'); - if (colon && strlen(colon) > 1) { - /* If it starts with a colon, we want to use head given - * from query or the default branch */ - if (colon == readme && ctx.qry.head) - *ref = xstrdup(ctx.qry.head); - else if (colon == readme && repo->defbranch) - *ref = xstrdup(repo->defbranch); - else - *ref = xstrndup(readme, colon - readme); - readme = colon + 1; - } - - /* Prepend repo path to relative readme path unless tracked. */ - if (!(*ref) && readme[0] != '/') - *filename = fmtalloc("%s/%s", repo->path, readme); - else - *filename = xstrdup(readme); -} -static void choose_readme(struct cgit_repo *repo) -{ - int found; - char *filename, *ref; - struct string_list_item *entry; - - if (!repo->readme.nr) - return; - - found = 0; - for_each_string_list_item(entry, &repo->readme) { - parse_readme(entry->string, &filename, &ref, repo); - if (!filename) { - free(filename); - free(ref); - continue; - } - if (ref) { - if (cgit_ref_path_exists(filename, ref, 1)) { - found = 1; - break; - } - } - else if (!access(filename, R_OK)) { - found = 1; - break; - } - free(filename); - free(ref); - } - repo->readme.strdup_strings = 1; - string_list_clear(&repo->readme, 0); - repo->readme.strdup_strings = 0; - if (found) - string_list_append(&repo->readme, filename)->util = ref; -} - -static void print_no_repo_clone_urls(const char *url) -{ - html(""); - html_txt(url); - html("\n"); -} - -static void prepare_repo_env(int *nongit) -{ - /* The path to the git repository. */ - setenv("GIT_DIR", ctx.repo->path, 1); - - /* Setup the git directory and initialize the notes system. Both of these - * load local configuration from the git repository, so we do them both while - * the HOME variables are unset. */ - setup_git_directory_gently(nongit); - load_display_notes(NULL); -} - -static int prepare_repo_cmd(int nongit) -{ - struct object_id oid; - int rc; - - if (nongit) { - const char *name = ctx.repo->name; - rc = errno; - ctx.page.title = fmtalloc("%s - %s", ctx.cfg.root_title, - "config error"); - ctx.repo = NULL; - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); - cgit_print_error("Failed to open %s: %s", name, - rc ? strerror(rc) : "Not a valid git repository"); - cgit_print_docend(); - return 1; - } - ctx.page.title = fmtalloc("%s - %s", ctx.repo->name, ctx.repo->desc); - - if (!ctx.repo->defbranch) - ctx.repo->defbranch = guess_defbranch(); - - if (!ctx.qry.head) { - ctx.qry.nohead = 1; - ctx.qry.head = find_default_branch(ctx.repo); - } - - if (!ctx.qry.head) { - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); - cgit_print_error("Repository seems to be empty"); - if (!strcmp(ctx.qry.page, "summary")) { - html("\n"); - cgit_prepare_repo_env(ctx.repo); - cgit_add_clone_urls(print_no_repo_clone_urls); - html("
     
    Clone
    \n"); - } - cgit_print_docend(); - return 1; - } - - if (repo_get_oid(the_repository, ctx.qry.head, &oid)) { - char *old_head = ctx.qry.head; - ctx.qry.head = xstrdup(ctx.repo->defbranch); - cgit_print_error_page(404, "Not found", - "Invalid branch: %s", old_head); - free(old_head); - return 1; - } - string_list_sort(&ctx.repo->submodules); - cgit_prepare_repo_env(ctx.repo); - choose_readme(ctx.repo); - return 0; -} - -static inline void open_auth_filter(const char *function) -{ - cgit_open_filter(ctx.cfg.auth_filter, function, - ctx.env.http_cookie ? ctx.env.http_cookie : "", - ctx.env.request_method ? ctx.env.request_method : "", - ctx.env.query_string ? ctx.env.query_string : "", - ctx.env.http_referer ? ctx.env.http_referer : "", - ctx.env.path_info ? ctx.env.path_info : "", - ctx.env.http_host ? ctx.env.http_host : "", - ctx.env.https ? ctx.env.https : "", - ctx.qry.repo ? ctx.qry.repo : "", - ctx.qry.page ? ctx.qry.page : "", - cgit_currentfullurl(), - cgit_loginurl()); -} - -/* We intentionally keep this rather small, instead of looping and - * feeding it to the filter a couple bytes at a time. This way, the - * filter itself does not need to handle any denial of service or - * buffer bloat issues. If this winds up being too small, people - * will complain on the mailing list, and we'll increase it as needed. */ -#define MAX_AUTHENTICATION_POST_BYTES 4096 -/* The filter is expected to spit out "Status: " and all headers. */ -static inline void authenticate_post(void) -{ - char buffer[MAX_AUTHENTICATION_POST_BYTES]; - ssize_t len; - - open_auth_filter("authenticate-post"); - len = ctx.env.content_length; - if (len > MAX_AUTHENTICATION_POST_BYTES) - len = MAX_AUTHENTICATION_POST_BYTES; - if ((len = read(STDIN_FILENO, buffer, len)) < 0) - die_errno("Could not read POST from stdin"); - if (fwrite(buffer, 1, len, stdout) < len) - die_errno("Could not write POST to stdout"); - cgit_close_filter(ctx.cfg.auth_filter); - exit(0); -} - -static inline void authenticate_cookie(void) -{ - /* If we don't have an auth_filter, consider all cookies valid, and thus return early. */ - if (!ctx.cfg.auth_filter) { - ctx.env.authenticated = 1; - return; - } - - /* If we're having something POST'd to /login, we're authenticating POST, - * instead of the cookie, so call authenticate_post and bail out early. - * This pattern here should match /?p=login with POST. */ - if (ctx.env.request_method && ctx.qry.page && !ctx.repo && \ - !strcmp(ctx.env.request_method, "POST") && !strcmp(ctx.qry.page, "login")) { - authenticate_post(); - return; - } - - /* If we've made it this far, we're authenticating the cookie for real, so do that. */ - open_auth_filter("authenticate-cookie"); - ctx.env.authenticated = cgit_close_filter(ctx.cfg.auth_filter); -} - -static void process_request(void) -{ - struct cgit_cmd *cmd; - int nongit = 0; - - /* If we're not yet authenticated, no matter what page we're on, - * display the authentication body from the auth_filter. This should - * never be cached. */ - if (!ctx.env.authenticated) { - ctx.page.title = "Authentication Required"; - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); - open_auth_filter("body"); - cgit_close_filter(ctx.cfg.auth_filter); - cgit_print_docend(); - return; - } - - if (ctx.repo) - prepare_repo_env(&nongit); - - cmd = cgit_get_cmd(); - if (!cmd) { - ctx.page.title = "cgit error"; - cgit_print_error_page(404, "Not found", "Invalid request"); - return; - } - - if (!ctx.cfg.enable_http_clone && cmd->is_clone) { - ctx.page.title = "cgit error"; - cgit_print_error_page(404, "Not found", "Invalid request"); - return; - } - - if (cmd->want_repo && !ctx.repo) { - cgit_print_error_page(400, "Bad request", - "No repository selected"); - return; - } - - /* If cmd->want_vpath is set, assume ctx.qry.path contains a "virtual" - * in-project path limit to be made available at ctx.qry.vpath. - * Otherwise, no path limit is in effect (ctx.qry.vpath = NULL). - */ - ctx.qry.vpath = cmd->want_vpath ? ctx.qry.path : NULL; - - if (ctx.repo && prepare_repo_cmd(nongit)) - return; - - cmd->fn(); -} - -static int cmp_repos(const void *a, const void *b) -{ - const struct cgit_repo *ra = a, *rb = b; - return strcmp(ra->url, rb->url); -} - -static char *build_snapshot_setting(int bitmap) -{ - const struct cgit_snapshot_format *f; - struct strbuf result = STRBUF_INIT; - - for (f = cgit_snapshot_formats; f->suffix; f++) { - if (cgit_snapshot_format_bit(f) & bitmap) { - if (result.len) - strbuf_addch(&result, ' '); - strbuf_addstr(&result, f->suffix); - } - } - return strbuf_detach(&result, NULL); -} - -static char *get_first_line(char *txt) -{ - char *t = xstrdup(txt); - char *p = strchr(t, '\n'); - if (p) - *p = '\0'; - return t; -} - -static void print_repo(FILE *f, struct cgit_repo *repo) -{ - struct string_list_item *item; - fprintf(f, "repo.url=%s\n", repo->url); - fprintf(f, "repo.name=%s\n", repo->name); - fprintf(f, "repo.path=%s\n", repo->path); - if (repo->owner) - fprintf(f, "repo.owner=%s\n", repo->owner); - if (repo->desc) { - char *tmp = get_first_line(repo->desc); - fprintf(f, "repo.desc=%s\n", tmp); - free(tmp); - } - for_each_string_list_item(item, &repo->readme) { - if (item->util) - fprintf(f, "repo.readme=%s:%s\n", (char *)item->util, item->string); - else - fprintf(f, "repo.readme=%s\n", item->string); - } - if (repo->defbranch) - fprintf(f, "repo.defbranch=%s\n", repo->defbranch); - if (repo->extra_head_content) - fprintf(f, "repo.extra-head-content=%s\n", repo->extra_head_content); - if (repo->module_link) - fprintf(f, "repo.module-link=%s\n", repo->module_link); - if (repo->section) - fprintf(f, "repo.section=%s\n", repo->section); - if (repo->homepage) - fprintf(f, "repo.homepage=%s\n", repo->homepage); - if (repo->clone_url) - fprintf(f, "repo.clone-url=%s\n", repo->clone_url); - fprintf(f, "repo.enable-blame=%d\n", - repo->enable_blame); - fprintf(f, "repo.enable-commit-graph=%d\n", - repo->enable_commit_graph); - fprintf(f, "repo.enable-log-filecount=%d\n", - repo->enable_log_filecount); - fprintf(f, "repo.enable-log-linecount=%d\n", - repo->enable_log_linecount); - if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter) - cgit_fprintf_filter(repo->about_filter, f, "repo.about-filter="); - if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter) - cgit_fprintf_filter(repo->commit_filter, f, "repo.commit-filter="); - if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) - cgit_fprintf_filter(repo->source_filter, f, "repo.source-filter="); - if (repo->email_filter && repo->email_filter != ctx.cfg.email_filter) - cgit_fprintf_filter(repo->email_filter, f, "repo.email-filter="); - if (repo->owner_filter && repo->owner_filter != ctx.cfg.owner_filter) - cgit_fprintf_filter(repo->owner_filter, f, "repo.owner-filter="); - if (repo->snapshots != ctx.cfg.snapshots) { - char *tmp = build_snapshot_setting(repo->snapshots); - fprintf(f, "repo.snapshots=%s\n", tmp ? tmp : ""); - free(tmp); - } - if (repo->snapshot_prefix) - fprintf(f, "repo.snapshot-prefix=%s\n", repo->snapshot_prefix); - if (repo->max_stats != ctx.cfg.max_stats) - fprintf(f, "repo.max-stats=%s\n", - cgit_find_stats_periodname(repo->max_stats)); - if (repo->logo) - fprintf(f, "repo.logo=%s\n", repo->logo); - if (repo->logo_link) - fprintf(f, "repo.logo-link=%s\n", repo->logo_link); - fprintf(f, "repo.enable-remote-branches=%d\n", repo->enable_remote_branches); - fprintf(f, "repo.enable-subject-links=%d\n", repo->enable_subject_links); - fprintf(f, "repo.enable-html-serving=%d\n", repo->enable_html_serving); - if (repo->branch_sort == 1) - fprintf(f, "repo.branch-sort=age\n"); - if (repo->commit_sort) { - if (repo->commit_sort == 1) - fprintf(f, "repo.commit-sort=date\n"); - else if (repo->commit_sort == 2) - fprintf(f, "repo.commit-sort=topo\n"); - } - fprintf(f, "repo.hide=%d\n", repo->hide); - fprintf(f, "repo.ignore=%d\n", repo->ignore); - fprintf(f, "\n"); -} - -static void print_repolist(FILE *f, struct cgit_repolist *list, int start) -{ - int i; - - for (i = start; i < list->count; i++) - print_repo(f, &list->repos[i]); -} - -/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' - * and return 0 on success. - */ -static int generate_cached_repolist(const char *path, const char *cached_rc) -{ - struct strbuf locked_rc = STRBUF_INIT; - int result = 0; - int idx; - FILE *f; - - strbuf_addf(&locked_rc, "%s.lock", cached_rc); - f = fopen(locked_rc.buf, "wx"); - if (!f) { - /* Inform about the error unless the lockfile already existed, - * since that only means we've got concurrent requests. - */ - result = errno; - if (result != EEXIST) - fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", - locked_rc.buf, strerror(result), result); - goto out; - } - idx = cgit_repolist.count; - if (ctx.cfg.project_list) - scan_projects(path, ctx.cfg.project_list, repo_config); - else - scan_tree(path, repo_config); - print_repolist(f, &cgit_repolist, idx); - if (rename(locked_rc.buf, cached_rc)) - fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", - locked_rc.buf, cached_rc, strerror(errno), errno); - fclose(f); -out: - strbuf_release(&locked_rc); - return result; -} - -static void process_cached_repolist(const char *path) -{ - struct stat st; - struct strbuf cached_rc = STRBUF_INIT; - time_t age; - unsigned long hash; - - hash = hash_str(path); - if (ctx.cfg.project_list) - hash += hash_str(ctx.cfg.project_list); - strbuf_addf(&cached_rc, "%s/rc-%8lx", ctx.cfg.cache_root, hash); - - if (stat(cached_rc.buf, &st)) { - /* Nothing is cached, we need to scan without forking. And - * if we fail to generate a cached repolist, we need to - * invoke scan_tree manually. - */ - if (generate_cached_repolist(path, cached_rc.buf)) { - if (ctx.cfg.project_list) - scan_projects(path, ctx.cfg.project_list, - repo_config); - else - scan_tree(path, repo_config); - } - goto out; - } - - parse_configfile(cached_rc.buf, config_cb); - - /* If the cached configfile hasn't expired, lets exit now */ - age = time(NULL) - st.st_mtime; - if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) - goto out; - - /* The cached repolist has been parsed, but it was old. So lets - * rescan the specified path and generate a new cached repolist - * in a child-process to avoid latency for the current request. - */ - if (fork()) - goto out; - - exit(generate_cached_repolist(path, cached_rc.buf)); -out: - strbuf_release(&cached_rc); -} - -static void cgit_parse_args(int argc, const char **argv) -{ - int i; - const char *arg; - int scan = 0; - - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "--version")) { - printf("CGit-pink %s | https://git.causal.agency/cgit-pink/\n\nCompiled in features:\n", CGIT_VERSION); -#ifndef HAVE_LINUX_SENDFILE - printf("[-] "); -#else - printf("[+] "); -#endif - printf("Linux sendfile() usage\n"); - - exit(0); - } - if (skip_prefix(argv[i], "--cache=", &arg)) { - ctx.cfg.cache_root = xstrdup(arg); - } else if (!strcmp(argv[i], "--nohttp")) { - ctx.env.no_http = "1"; - } else if (skip_prefix(argv[i], "--query=", &arg)) { - ctx.qry.raw = xstrdup(arg); - } else if (skip_prefix(argv[i], "--repo=", &arg)) { - ctx.qry.repo = xstrdup(arg); - } else if (skip_prefix(argv[i], "--page=", &arg)) { - ctx.qry.page = xstrdup(arg); - } else if (skip_prefix(argv[i], "--head=", &arg)) { - ctx.qry.head = xstrdup(arg); - ctx.qry.has_symref = 1; - } else if (skip_prefix(argv[i], "--oid=", &arg)) { - ctx.qry.oid = xstrdup(arg); - ctx.qry.has_oid = 1; - } else if (skip_prefix(argv[i], "--ofs=", &arg)) { - ctx.qry.ofs = atoi(arg); - } else if (skip_prefix(argv[i], "--scan-tree=", &arg) || - skip_prefix(argv[i], "--scan-path=", &arg)) { - /* - * HACK: The global snapshot bit mask defines the set - * of allowed snapshot formats, but the config file - * hasn't been parsed yet so the mask is currently 0. - * By setting all bits high before scanning we make - * sure that any in-repo cgitrc snapshot setting is - * respected by scan_tree(). - * - * NOTE: We assume that there aren't more than 8 - * different snapshot formats supported by cgit... - */ - ctx.cfg.snapshots = 0xFF; - scan++; - scan_tree(arg, repo_config); - } - } - if (scan) { - qsort(cgit_repolist.repos, cgit_repolist.count, - sizeof(struct cgit_repo), cmp_repos); - print_repolist(stdout, &cgit_repolist, 0); - exit(0); - } -} - -static int calc_ttl(void) -{ - if (!ctx.repo) - return ctx.cfg.cache_root_ttl; - - if (!ctx.qry.page) - return ctx.cfg.cache_repo_ttl; - - if (!strcmp(ctx.qry.page, "about")) - return ctx.cfg.cache_about_ttl; - - if (!strcmp(ctx.qry.page, "snapshot")) - return ctx.cfg.cache_snapshot_ttl; - - if (ctx.qry.has_oid) - return ctx.cfg.cache_static_ttl; - - if (ctx.qry.has_symref) - return ctx.cfg.cache_dynamic_ttl; - - return ctx.cfg.cache_repo_ttl; -} - -int cmd_main(int argc, const char **argv) -{ - const char *path; - int err, ttl; - - atexit(cgit_cleanup_filters); - - prepare_context(); - cgit_repolist.length = 0; - cgit_repolist.count = 0; - cgit_repolist.repos = NULL; - - cgit_parse_args(argc, argv); - parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); - ctx.repo = NULL; - http_parse_querystring(ctx.qry.raw, querystring_cb); - - /* If virtual-root isn't specified in cgitrc, lets pretend - * that virtual-root equals SCRIPT_NAME, minus any possibly - * trailing slashes. - */ - if (!ctx.cfg.virtual_root && ctx.cfg.script_name) - ctx.cfg.virtual_root = ensure_end(ctx.cfg.script_name, '/'); - - /* If no url parameter is specified on the querystring, lets - * use PATH_INFO as url. This allows cgit to work with virtual - * urls without the need for rewriterules in the webserver (as - * long as PATH_INFO is included in the cache lookup key). - */ - path = ctx.env.path_info; - if (!ctx.qry.url && path) { - if (path[0] == '/') - path++; - ctx.qry.url = xstrdup(path); - if (ctx.qry.raw) { - char *newqry = fmtalloc("%s?%s", path, ctx.qry.raw); - free(ctx.qry.raw); - ctx.qry.raw = newqry; - } else - ctx.qry.raw = xstrdup(ctx.qry.url); - cgit_parse_url(ctx.qry.url); - } - - /* Before we go any further, we set ctx.env.authenticated by checking to see - * if the supplied cookie is valid. All cookies are valid if there is no - * auth_filter. If there is an auth_filter, the filter decides. */ - authenticate_cookie(); - - ttl = calc_ttl(); - if (ttl < 0) - ctx.page.expires += 10 * 365 * 24 * 60 * 60; /* 10 years */ - else - ctx.page.expires += ttl * 60; - if (!ctx.env.authenticated || (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))) - ctx.cfg.cache_size = 0; - err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, - ctx.qry.raw, ttl, process_request); - cgit_cleanup_filters(); - if (err) - cgit_print_error("Error processing page: %s (%d)", - strerror(err), err); - return err; -} diff --git a/third_party/cgit/cgit.css b/third_party/cgit/cgit.css deleted file mode 100644 index 7133a7ba3..000000000 --- a/third_party/cgit/cgit.css +++ /dev/null @@ -1,889 +0,0 @@ -div#cgit { - padding: 0em; - margin: 0em; - font-family: sans-serif; - font-size: 10pt; - color: #333; - background: white; - padding: 4px; -} - -div#cgit a { - color: blue; - text-decoration: none; -} - -div#cgit a:hover { - text-decoration: underline; -} - -div#cgit table { - border-collapse: collapse; -} - -div#cgit table#header { - width: 100%; - margin-bottom: 1em; -} - -div#cgit table#header td.logo { - width: 96px; - vertical-align: top; -} - -div#cgit table#header td.main { - font-size: 250%; - padding-left: 10px; - white-space: nowrap; -} - -div#cgit table#header td.main a { - color: #000; -} - -div#cgit table#header td.form { - text-align: right; - vertical-align: bottom; - padding-right: 1em; - padding-bottom: 2px; - white-space: nowrap; -} - -div#cgit table#header td.form form, -div#cgit table#header td.form input, -div#cgit table#header td.form select { - font-size: 90%; -} - -div#cgit table#header td.sub { - color: #777; - border-top: solid 1px #ccc; - padding-left: 10px; -} - -div#cgit table.tabs { - border-bottom: solid 3px #ccc; - border-collapse: collapse; - margin-top: 2em; - margin-bottom: 0px; - width: 100%; -} - -div#cgit table.tabs td { - padding: 0px 1em; - vertical-align: bottom; -} - -div#cgit table.tabs td a { - padding: 2px 0.25em; - color: #777; - font-size: 110%; -} - -div#cgit table.tabs td a.active { - color: #000; - background-color: #ccc; -} - -div#cgit table.tabs a[href^="http://"]:after, div#cgit table.tabs a[href^="https://"]:after { - content: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAQAAAAnOwc2AAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfgAhcJDQY+gm2TAAAAHWlUWHRDb21tZW50AAAAAABDcmVhdGVkIHdpdGggR0lNUGQuZQcAAABbSURBVAhbY2BABs4MU4CwhYHBh2Erww4wrGFQZHjI8B8IgUIscJWyDHcggltQhI4zGDCcRwhChPggHIggP1QoAVmQkSETrGoHsiAEsACtBYN0oDAMbgU6EBcAAL2eHUt4XUU4AAAAAElFTkSuQmCC); - opacity: 0.5; - margin: 0 0 0 5px; -} - -div#cgit table.tabs td.form { - text-align: right; -} - -div#cgit table.tabs td.form form { - padding-bottom: 2px; - font-size: 90%; - white-space: nowrap; -} - -div#cgit table.tabs td.form input, -div#cgit table.tabs td.form select { - font-size: 90%; -} - -div#cgit div.path { - margin: 0px; - padding: 5px 2em 2px 2em; - color: #000; - background-color: #eee; -} - -div#cgit div.content { - margin: 0px; - padding: 2em; - border-bottom: solid 3px #ccc; -} - - -div#cgit table.list { - width: 100%; - border: none; - border-collapse: collapse; -} - -div#cgit table.list tr { - background: white; -} - -div#cgit table.list tr.logheader { - background: #eee; -} - -div#cgit table.list tr:nth-child(even) { - background: #f7f7f7; -} - -div#cgit table.list tr:nth-child(odd) { - background: white; -} - -div#cgit table.list tr:hover { - background: #eee; -} - -div#cgit table.list tr.nohover { - background: white; -} - -div#cgit table.list tr.nohover:hover { - background: white; -} - -div#cgit table.list tr.nohover-highlight:hover:nth-child(even) { - background: #f7f7f7; -} - -div#cgit table.list tr.nohover-highlight:hover:nth-child(odd) { - background: white; -} - -div#cgit table.list th { - font-weight: bold; - /* color: #888; - border-top: dashed 1px #888; - border-bottom: dashed 1px #888; - */ - padding: 0.1em 0.5em 0.05em 0.5em; - vertical-align: baseline; -} - -div#cgit table.list td { - border: none; - padding: 0.1em 0.5em 0.1em 0.5em; -} - -div#cgit table.list td.commitgraph { - font-family: monospace; - white-space: pre; -} - -div#cgit table.list td.commitgraph .column1 { - color: #a00; -} - -div#cgit table.list td.commitgraph .column2 { - color: #0a0; -} - -div#cgit table.list td.commitgraph .column3 { - color: #aa0; -} - -div#cgit table.list td.commitgraph .column4 { - color: #00a; -} - -div#cgit table.list td.commitgraph .column5 { - color: #a0a; -} - -div#cgit table.list td.commitgraph .column6 { - color: #0aa; -} - -div#cgit table.list td.logsubject { - font-family: monospace; - font-weight: bold; -} - -div#cgit table.list td.logmsg { - font-family: monospace; - white-space: pre; - padding: 0 0.5em; -} - -div#cgit table.list td a { - color: black; -} - -div#cgit table.list td a.ls-dir { - font-weight: bold; - color: #00f; -} - -div#cgit table.list td a:hover { - color: #00f; -} - -div#cgit img { - border: none; -} - -div#cgit input#switch-btn { - margin: 2px 0px 0px 0px; -} - -div#cgit td#sidebar input.txt { - width: 100%; - margin: 2px 0px 0px 0px; -} - -div#cgit table#grid { - margin: 0px; -} - -div#cgit td#content { - vertical-align: top; - padding: 1em 2em 1em 1em; - border: none; -} - -div#cgit div#summary { - vertical-align: top; - margin-bottom: 1em; -} - -div#cgit table#downloads { - float: right; - border-collapse: collapse; - border: solid 1px #777; - margin-left: 0.5em; - margin-bottom: 0.5em; -} - -div#cgit table#downloads th { - background-color: #ccc; -} - -div#cgit div#blob { - border: solid 1px black; -} - -div#cgit div.error { - color: red; - font-weight: bold; - margin: 1em 2em; -} - -div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit .ls-mod { - font-family: monospace; -} - -div#cgit td.ls-size { - text-align: right; - font-family: monospace; - width: 10em; -} - -div#cgit td.ls-mode { - font-family: monospace; - width: 10em; -} - -div#cgit table.blob { - margin-top: 0.5em; - border-top: solid 1px black; -} - -div#cgit table.blob td.hashes, -div#cgit table.blob td.lines { - margin: 0; padding: 0 0 0 0.5em; - vertical-align: top; - color: black; -} - -div#cgit table.blob td.linenumbers { - margin: 0; padding: 0 0.5em 0 0.5em; - vertical-align: top; - text-align: right; - border-right: 1px solid gray; -} - -div#cgit table.blob pre { - padding: 0; margin: 0; -} - -div#cgit table.blob td.linenumbers a, -div#cgit table.ssdiff td.lineno a { - color: gray; - text-align: right; - text-decoration: none; -} - -div#cgit table.blob td.linenumbers a:hover, -div#cgit table.ssdiff td.lineno a:hover { - color: black; -} - -div#cgit table.blame td.hashes, -div#cgit table.blame td.lines, -div#cgit table.blame td.linenumbers { - padding: 0; -} - -div#cgit table.blame td.hashes div.alt, -div#cgit table.blame td.lines div.alt { - padding: 0 0.5em 0 0.5em; -} - -div#cgit table.blame td.linenumbers div.alt { - padding: 0 0.5em 0 0; -} - -div#cgit table.blame div.alt:nth-child(even) { - background: #eee; -} - -div#cgit table.blame div.alt:nth-child(odd) { - background: white; -} - -div#cgit table.blame td.lines > div { - position: relative; -} - -div#cgit table.blame td.lines > div > pre { - padding: 0 0 0 0.5em; - position: absolute; - top: 0; -} - -div#cgit table.blame .oid { - font-size: 100%; -} - -div#cgit table.bin-blob { - margin-top: 0.5em; - border: solid 1px black; -} - -div#cgit table.bin-blob th { - font-family: monospace; - white-space: pre; - border: solid 1px #777; - padding: 0.5em 1em; -} - -div#cgit table.bin-blob td { - font-family: monospace; - white-space: pre; - border-left: solid 1px #777; - padding: 0em 1em; -} - -div#cgit table.nowrap td { - white-space: nowrap; -} - -div#cgit table.commit-info { - border-collapse: collapse; - margin-top: 1.5em; -} - -div#cgit div.cgit-panel { - float: right; - margin-top: 1.5em; -} - -div#cgit div.cgit-panel table { - border-collapse: collapse; - border: solid 1px #aaa; - background-color: #eee; -} - -div#cgit div.cgit-panel th { - text-align: center; -} - -div#cgit div.cgit-panel td { - padding: 0.25em 0.5em; -} - -div#cgit div.cgit-panel td.label { - padding-right: 0.5em; -} - -div#cgit div.cgit-panel td.ctrl { - padding-left: 0.5em; -} - -div#cgit table.commit-info th { - text-align: left; - font-weight: normal; - padding: 0.1em 1em 0.1em 0.1em; - vertical-align: top; -} - -div#cgit table.commit-info td { - font-weight: normal; - padding: 0.1em 1em 0.1em 0.1em; -} - -div#cgit div.commit-subject { - font-weight: bold; - font-size: 125%; - margin: 1.5em 0em 0.5em 0em; - padding: 0em; -} - -div#cgit div.notes-header { - font-weight: bold; - padding-top: 1.5em; -} - -div#cgit div.notes { - white-space: pre; - font-family: monospace; - border: solid 1px #ee9; - background-color: #ffd; - padding: 0.3em 2em 0.3em 1em; - float: left; -} - -div#cgit div.notes-footer { - clear: left; -} - -div#cgit div.diffstat-header { - font-weight: bold; - padding-top: 1.5em; -} - -div#cgit table.diffstat { - border-collapse: collapse; - border: solid 1px #aaa; - background-color: #eee; -} - -div#cgit table.diffstat th { - font-weight: normal; - text-align: left; - text-decoration: underline; - padding: 0.1em 1em 0.1em 0.1em; - font-size: 100%; -} - -div#cgit table.diffstat td { - padding: 0.2em 0.2em 0.1em 0.1em; - font-size: 100%; - border: none; -} - -div#cgit table.diffstat td.mode { - white-space: nowrap; -} - -div#cgit table.diffstat td span.modechange { - padding-left: 1em; - color: red; -} - -div#cgit table.diffstat td.add a { - color: green; -} - -div#cgit table.diffstat td.del a { - color: red; -} - -div#cgit table.diffstat td.upd a { - color: blue; -} - -div#cgit table.diffstat td.graph { - width: 500px; - vertical-align: middle; -} - -div#cgit table.diffstat td.graph table { - border: none; -} - -div#cgit table.diffstat td.graph td { - padding: 0px; - border: 0px; - height: 7pt; -} - -div#cgit table.diffstat td.graph td.add { - background-color: #5c5; -} - -div#cgit table.diffstat td.graph td.rem { - background-color: #c55; -} - -div#cgit div.diffstat-summary { - color: #888; - padding-top: 0.5em; -} - -div#cgit table.diff { - width: 100%; -} - -div#cgit table.diff td span.head { - font-weight: bold; - color: black; -} - -div#cgit table.diff td span.hunk { - color: #009; -} - -div#cgit table.diff td span.add { - color: green; -} - -div#cgit table.diff td span.del { - color: red; -} - -div#cgit .oid { - font-family: monospace; - font-size: 90%; -} - -div#cgit .left { - text-align: left; -} - -div#cgit .right { - text-align: right; -} - -div#cgit table.list td.reposection { - font-style: italic; - color: #888; -} - -div#cgit a.button { - font-size: 80%; -} - -div#cgit a.primary { - font-size: 100%; -} - -div#cgit a.secondary { - font-size: 90%; -} - -div#cgit td.toplevel-repo { - -} - -div#cgit table.list td.sublevel-repo { - padding-left: 1.5em; -} - -div#cgit ul.pager { - list-style-type: none; - text-align: center; - margin: 1em 0em 0em 0em; - padding: 0; -} - -div#cgit ul.pager li { - display: inline-block; - margin: 0.25em 0.5em; -} - -div#cgit ul.pager a { - color: #777; -} - -div#cgit ul.pager .current { - font-weight: bold; -} - -div#cgit span.age-mins { - font-weight: bold; - color: #080; -} - -div#cgit span.age-hours { - color: #080; -} - -div#cgit span.age-days { - color: #040; -} - -div#cgit span.age-weeks { - color: #444; -} - -div#cgit span.age-months { - color: #888; -} - -div#cgit span.age-years { - color: #bbb; -} - -div#cgit span.insertions { - color: #080; -} - -div#cgit span.deletions { - color: #800; -} - -div#cgit div.footer { - margin-top: 0.5em; - text-align: center; - font-size: 80%; - color: #ccc; -} - -div#cgit div.footer a { - color: #ccc; - text-decoration: none; -} - -div#cgit div.footer a:hover { - text-decoration: underline; -} - -div#cgit a.branch-deco { - color: #000; - padding: 0px 0.25em; - background-color: #88ff88; - border: solid 1px #007700; -} - -div#cgit a.rev-deco { - color: #000; - padding: 0px 0.25em; - background-color: #eee; - border: solid 1px #aaa; -} - -div#cgit a.tag-deco { - color: #000; - padding: 0px 0.25em; - background-color: #ffff88; - border: solid 1px #777700; -} - -div#cgit a.tag-annotated-deco { - color: #000; - padding: 0px 0.25em; - background-color: #ffcc88; - border: solid 1px #777700; -} - -div#cgit a.remote-deco { - color: #000; - padding: 0px 0.25em; - background-color: #ccccff; - border: solid 1px #000077; -} - -div#cgit a.deco { - color: #000; - padding: 0px 0.25em; - background-color: #ff8888; - border: solid 1px #770000; -} - -div#cgit div.commit-subject a.branch-deco, -div#cgit div.commit-subject a.tag-deco, -div#cgit div.commit-subject a.tag-annotated-deco, -div#cgit div.commit-subject a.remote-deco, -div#cgit div.commit-subject a.rev-deco, -div#cgit div.commit-subject a.deco { - font-size: 75%; -} - -div#cgit table.stats { - border: solid 1px black; - border-collapse: collapse; -} - -div#cgit table.stats th { - text-align: left; - padding: 1px 0.5em; - background-color: #eee; - border: solid 1px black; -} - -div#cgit table.stats td { - text-align: right; - padding: 1px 0.5em; - border: solid 1px black; -} - -div#cgit table.stats td.total { - font-weight: bold; - text-align: left; -} - -div#cgit table.stats td.sum { - color: #c00; - font-weight: bold; -/* background-color: #eee; */ -} - -div#cgit table.stats td.left { - text-align: left; -} - -div#cgit table.vgraph { - border-collapse: separate; - border: solid 1px black; - height: 200px; -} - -div#cgit table.vgraph th { - background-color: #eee; - font-weight: bold; - border: solid 1px white; - padding: 1px 0.5em; -} - -div#cgit table.vgraph td { - vertical-align: bottom; - padding: 0px 10px; -} - -div#cgit table.vgraph div.bar { - background-color: #eee; -} - -div#cgit table.hgraph { - border: solid 1px black; - width: 800px; -} - -div#cgit table.hgraph th { - background-color: #eee; - font-weight: bold; - border: solid 1px black; - padding: 1px 0.5em; -} - -div#cgit table.hgraph td { - vertical-align: middle; - padding: 2px 2px; -} - -div#cgit table.hgraph div.bar { - background-color: #eee; - height: 1em; -} - -div#cgit table.ssdiff { - width: 100%; -} - -div#cgit table.ssdiff td { - font-size: 75%; - font-family: monospace; - white-space: pre; - padding: 1px 4px 1px 4px; - border-left: solid 1px #aaa; - border-right: solid 1px #aaa; -} - -div#cgit table.ssdiff td.add { - color: black; - background: #cfc; - min-width: 50%; -} - -div#cgit table.ssdiff td.add_dark { - color: black; - background: #aca; - min-width: 50%; -} - -div#cgit table.ssdiff span.add { - background: #cfc; - font-weight: bold; -} - -div#cgit table.ssdiff td.del { - color: black; - background: #fcc; - min-width: 50%; -} - -div#cgit table.ssdiff td.del_dark { - color: black; - background: #caa; - min-width: 50%; -} - -div#cgit table.ssdiff span.del { - background: #fcc; - font-weight: bold; -} - -div#cgit table.ssdiff td.changed { - color: black; - background: #ffc; - min-width: 50%; -} - -div#cgit table.ssdiff td.changed_dark { - color: black; - background: #cca; - min-width: 50%; -} - -div#cgit table.ssdiff td.lineno { - color: black; - background: #eee; - text-align: right; - width: 3em; - min-width: 3em; -} - -div#cgit table.ssdiff td.hunk { - color: black; - background: #ccf; - border-top: solid 1px #aaa; - border-bottom: solid 1px #aaa; -} - -div#cgit table.ssdiff td.head { - border-top: solid 1px #aaa; - border-bottom: solid 1px #aaa; -} - -div#cgit table.ssdiff td.head div.head { - font-weight: bold; - color: black; -} - -div#cgit table.ssdiff td.foot { - border-top: solid 1px #aaa; - border-left: none; - border-right: none; - border-bottom: none; -} - -div#cgit table.ssdiff td.space { - border: none; -} - -div#cgit table.ssdiff td.space div { - min-height: 3em; -} diff --git a/third_party/cgit/cgit.h b/third_party/cgit/cgit.h deleted file mode 100644 index f201f82b8..000000000 --- a/third_party/cgit/cgit.h +++ /dev/null @@ -1,405 +0,0 @@ -#ifndef CGIT_H -#define CGIT_H - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Add isgraph(x) to Git's sane ctype support (see git-compat-util.h) */ -#undef isgraph -#define isgraph(x) (isprint((x)) && !isspace((x))) - - -/* - * Limits used for relative dates - */ -#define TM_MIN 60 -#define TM_HOUR (TM_MIN * 60) -#define TM_DAY (TM_HOUR * 24) -#define TM_WEEK (TM_DAY * 7) -#define TM_YEAR (TM_DAY * 365) -#define TM_MONTH (TM_YEAR / 12.0) - - -/* - * Default encoding - */ -#define PAGE_ENCODING "UTF-8" - -#define BIT(x) (1U << (x)) - -typedef void (*configfn)(const char *name, const char *value); -typedef void (*filepair_fn)(struct diff_filepair *pair); -typedef void (*linediff_fn)(char *line, int len); - -typedef enum { - DIFF_UNIFIED, DIFF_SSDIFF, DIFF_STATONLY -} diff_type; - -typedef enum { - ABOUT, COMMIT, SOURCE, EMAIL, AUTH, OWNER -} filter_type; - -struct cgit_filter { - int (*open)(struct cgit_filter *, va_list ap); - int (*close)(struct cgit_filter *); - void (*fprintf)(struct cgit_filter *, FILE *, const char *prefix); - void (*cleanup)(struct cgit_filter *); - int argument_count; -}; - -struct cgit_exec_filter { - struct cgit_filter base; - char *cmd; - char **argv; - int old_stdout; - int pid; -}; - -struct cgit_repo { - char *url; - char *name; - char *path; - char *desc; - char *extra_head_content; - char *owner; - char *homepage; - char *defbranch; - char *module_link; - struct string_list readme; - char *section; - char *clone_url; - char *logo; - char *logo_link; - char *snapshot_prefix; - int snapshots; - int enable_blame; - int enable_commit_graph; - int enable_log_filecount; - int enable_log_linecount; - int enable_remote_branches; - int enable_subject_links; - int enable_html_serving; - int max_stats; - int branch_sort; - int commit_sort; - time_t mtime; - struct cgit_filter *about_filter; - struct cgit_filter *commit_filter; - struct cgit_filter *source_filter; - struct cgit_filter *email_filter; - struct cgit_filter *owner_filter; - struct string_list submodules; - int hide; - int ignore; -}; - -typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name, - const char *value); - -struct cgit_repolist { - int length; - int count; - struct cgit_repo *repos; -}; - -struct commitinfo { - struct commit *commit; - char *author; - char *author_email; - unsigned long author_date; - int author_tz; - char *committer; - char *committer_email; - unsigned long committer_date; - int committer_tz; - char *subject; - char *msg; - char *msg_encoding; -}; - -struct taginfo { - char *tagger; - char *tagger_email; - unsigned long tagger_date; - int tagger_tz; - char *msg; -}; - -struct refinfo { - const char *refname; - struct object *object; - union { - struct taginfo *tag; - struct commitinfo *commit; - }; -}; - -struct reflist { - struct refinfo **refs; - int alloc; - int count; -}; - -struct cgit_query { - int has_symref; - int has_oid; - int has_difftype; - char *raw; - char *repo; - char *page; - char *search; - char *grep; - char *head; - char *oid; - char *oid2; - char *path; - char *name; - char *url; - char *period; - int ofs; - int nohead; - char *sort; - int showmsg; - diff_type difftype; - int show_all; - int context; - int ignorews; - int follow; - char *vpath; -}; - -struct cgit_config { - char *agefile; - char *cache_root; - char *clone_prefix; - char *clone_url; - char *css; - char *favicon; - char *footer; - char *head_include; - char *header; - char *logo; - char *logo_link; - char *mimetype_file; - char *module_link; - char *project_list; - struct string_list readme; - char *robots; - char *root_title; - char *root_desc; - char *root_readme; - char *script_name; - char *section; - char *repository_sort; - char *virtual_root; /* Always ends with '/'. */ - char *strict_export; - int cache_size; - int cache_dynamic_ttl; - int cache_max_create_time; - int cache_repo_ttl; - int cache_root_ttl; - int cache_scanrc_ttl; - int cache_static_ttl; - int cache_about_ttl; - int cache_snapshot_ttl; - int case_sensitive_sort; - int embedded; - int enable_filter_overrides; - int enable_follow_links; - int enable_http_clone; - int enable_index_links; - int enable_index_owner; - int enable_blame; - int enable_commit_graph; - int enable_log_filecount; - int enable_log_linecount; - int enable_remote_branches; - int enable_subject_links; - int enable_html_serving; - int enable_tree_linenumbers; - int enable_git_config; - int local_time; - int max_atom_items; - int max_repo_count; - int max_commit_count; - int max_lock_attempts; - int max_msg_len; - int max_repodesc_len; - int max_blob_size; - int max_stats; - int noplainemail; - int noheader; - int renamelimit; - int remove_suffix; - int scan_hidden_path; - int section_from_path; - int snapshots; - int section_sort; - int summary_branches; - int summary_log; - int summary_tags; - diff_type difftype; - int branch_sort; - int commit_sort; - struct string_list mimetypes; - struct cgit_filter *about_filter; - struct cgit_filter *commit_filter; - struct cgit_filter *source_filter; - struct cgit_filter *email_filter; - struct cgit_filter *owner_filter; - struct cgit_filter *auth_filter; -}; - -struct cgit_page { - time_t modified; - time_t expires; - size_t size; - const char *mimetype; - const char *charset; - const char *filename; - const char *etag; - const char *title; - int status; - const char *statusmsg; -}; - -struct cgit_environment { - const char *cgit_config; - const char *http_host; - const char *https; - const char *no_http; - const char *path_info; - const char *query_string; - const char *request_method; - const char *script_name; - const char *server_name; - const char *server_port; - const char *http_cookie; - const char *http_referer; - unsigned int content_length; - int authenticated; -}; - -struct cgit_context { - struct cgit_environment env; - struct cgit_query qry; - struct cgit_config cfg; - struct cgit_repo *repo; - struct cgit_page page; -}; - -typedef int (*write_archive_fn_t)(const char *, const char *); - -struct cgit_snapshot_format { - const char *suffix; - const char *mimetype; - write_archive_fn_t write_func; -}; - -extern const char *cgit_version; - -extern struct cgit_repolist cgit_repolist; -extern struct cgit_context ctx; -extern const struct cgit_snapshot_format cgit_snapshot_formats[]; - -extern char *cgit_default_repo_desc; -extern struct cgit_repo *cgit_add_repo(const char *url); -extern struct cgit_repo *cgit_get_repoinfo(const char *url); -extern void cgit_repo_config_cb(const char *name, const char *value); - -extern int chk_zero(int result, char *msg); -extern int chk_positive(int result, char *msg); -extern int chk_non_negative(int result, char *msg); - -extern char *trim_end(const char *str, char c); -extern char *ensure_end(const char *str, char c); - -extern void strbuf_ensure_end(struct strbuf *sb, char c); - -extern void cgit_add_ref(struct reflist *list, struct refinfo *ref); -extern void cgit_free_reflist_inner(struct reflist *list); -extern int cgit_refs_cb(const char *refname, const struct object_id *oid, - int flags, void *cb_data); - -extern void cgit_free_commitinfo(struct commitinfo *info); -extern void cgit_free_taginfo(struct taginfo *info); - -void cgit_diff_tree_cb(struct diff_queue_struct *q, - struct diff_options *options, void *data); - -extern int cgit_diff_files(const struct object_id *old_oid, - const struct object_id *new_oid, - unsigned long *old_size, unsigned long *new_size, - int *binary, int context, int ignorews, - linediff_fn fn); - -extern void cgit_diff_tree(const struct object_id *old_oid, - const struct object_id *new_oid, - filepair_fn fn, const char *prefix, int ignorews); - -extern void cgit_diff_commit(struct commit *commit, filepair_fn fn, - const char *prefix); - -__attribute__((format (printf,1,2))) -extern char *fmt(const char *format,...); - -__attribute__((format (printf,1,2))) -extern char *fmtalloc(const char *format,...); - -extern struct commitinfo *cgit_parse_commit(struct commit *commit); -extern struct taginfo *cgit_parse_tag(struct tag *tag); -extern void cgit_parse_url(const char *url); - -extern const char *cgit_repobasename(const char *reponame); - -extern int cgit_parse_snapshots_mask(const char *str); -extern const struct object_id *cgit_snapshot_get_sig(const char *ref, - const struct cgit_snapshot_format *f); -extern const unsigned cgit_snapshot_format_bit(const struct cgit_snapshot_format *f); - -extern int cgit_open_filter(struct cgit_filter *filter, ...); -extern int cgit_close_filter(struct cgit_filter *filter); -extern void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix); -extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv); -extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype); -extern void cgit_cleanup_filters(void); - -extern void cgit_prepare_repo_env(struct cgit_repo * repo); - -extern int readfile(const char *path, char **buf, size_t *size); - -extern char *expand_macros(const char *txt); - -extern char *get_mimetype_for_filename(const char *filename); - -#endif /* CGIT_H */ diff --git a/third_party/cgit/cgit.mk b/third_party/cgit/cgit.mk deleted file mode 100644 index 5b9ed5be8..000000000 --- a/third_party/cgit/cgit.mk +++ /dev/null @@ -1,114 +0,0 @@ -# This Makefile is run in the "git" directory in order to re-use Git's -# build variables and operating system detection. Hence all files in -# CGit's directory must be prefixed with "../". -include Makefile - -CGIT_PREFIX = ../ - --include $(CGIT_PREFIX)cgit.conf - -# The CGIT_* variables are inherited when this file is called from the -# main Makefile - they are defined there. - -$(CGIT_PREFIX)VERSION: force-version - @cd $(CGIT_PREFIX) && '$(SHELL_PATH_SQ)' ./gen-version.sh "$(CGIT_VERSION)" --include $(CGIT_PREFIX)VERSION -.PHONY: force-version - -# CGIT_CFLAGS is a separate variable so that we can track it separately -# and avoid rebuilding all of Git when these variables change. -CGIT_CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"' -CGIT_CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"' -CGIT_CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"' - -PKG_CONFIG ?= pkg-config - -ifdef NO_C99_FORMAT - CFLAGS += -DNO_C99_FORMAT -endif - -# Add -ldl to linker flags on systems that commonly use GNU libc. -ifneq (,$(filter $(uname_S),Linux GNU GNU/kFreeBSD)) - CGIT_LIBS += -ldl -endif - -# glibc 2.1+ offers sendfile which the most common C library on Linux -ifeq ($(uname_S),Linux) - HAVE_LINUX_SENDFILE = YesPlease -endif - -ifdef HAVE_LINUX_SENDFILE - CGIT_CFLAGS += -DHAVE_LINUX_SENDFILE -endif - -CGIT_OBJ_NAMES += cgit.o -CGIT_OBJ_NAMES += cache.o -CGIT_OBJ_NAMES += cmd.o -CGIT_OBJ_NAMES += configfile.o -CGIT_OBJ_NAMES += filter.o -CGIT_OBJ_NAMES += html.o -CGIT_OBJ_NAMES += parsing.o -CGIT_OBJ_NAMES += scan-tree.o -CGIT_OBJ_NAMES += shared.o -CGIT_OBJ_NAMES += ui-atom.o -CGIT_OBJ_NAMES += ui-blame.o -CGIT_OBJ_NAMES += ui-blob.o -CGIT_OBJ_NAMES += ui-clone.o -CGIT_OBJ_NAMES += ui-commit.o -CGIT_OBJ_NAMES += ui-diff.o -CGIT_OBJ_NAMES += ui-log.o -CGIT_OBJ_NAMES += ui-patch.o -CGIT_OBJ_NAMES += ui-plain.o -CGIT_OBJ_NAMES += ui-refs.o -CGIT_OBJ_NAMES += ui-repolist.o -CGIT_OBJ_NAMES += ui-shared.o -CGIT_OBJ_NAMES += ui-snapshot.o -CGIT_OBJ_NAMES += ui-ssdiff.o -CGIT_OBJ_NAMES += ui-stats.o -CGIT_OBJ_NAMES += ui-summary.o -CGIT_OBJ_NAMES += ui-tag.o -CGIT_OBJ_NAMES += ui-tree.o - -CGIT_OBJS := $(addprefix $(CGIT_PREFIX),$(CGIT_OBJ_NAMES)) - -# Only cgit.c reference CGIT_VERSION so we only rebuild its objects when the -# version changes. -CGIT_VERSION_OBJS := $(addprefix $(CGIT_PREFIX),cgit.o cgit.sp) -$(CGIT_VERSION_OBJS): $(CGIT_PREFIX)VERSION -$(CGIT_VERSION_OBJS): EXTRA_CPPFLAGS = \ - -DCGIT_VERSION='"$(CGIT_VERSION)"' - -# Git handles dependencies using ":=" so dependencies in CGIT_OBJ are not -# handled by that and we must handle them ourselves. -cgit_dep_files := $(foreach f,$(CGIT_OBJS),$(dir $f).depend/$(notdir $f).d) -cgit_dep_files_present := $(wildcard $(cgit_dep_files)) -ifneq ($(cgit_dep_files_present),) -include $(cgit_dep_files_present) -endif - -ifeq ($(wildcard $(CGIT_PREFIX).depend),) -missing_dep_dirs += $(CGIT_PREFIX).depend -endif - -$(CGIT_PREFIX).depend: - @mkdir -p $@ - -$(CGIT_PREFIX)CGIT-CFLAGS: FORCE - @FLAGS='$(subst ','\'',$(CGIT_CFLAGS))'; \ - if test x"$$FLAGS" != x"`cat ../CGIT-CFLAGS 2>/dev/null`" ; then \ - echo 1>&2 " * new CGit build flags"; \ - echo "$$FLAGS" >$(CGIT_PREFIX)CGIT-CFLAGS; \ - fi - -$(CGIT_OBJS): %.o: %.c GIT-CFLAGS $(CGIT_PREFIX)CGIT-CFLAGS $(missing_dep_dirs) - $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $< - -$(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS) - $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(CGIT_LIBS) - -CGIT_SP_OBJS := $(patsubst %.o,%.sp,$(CGIT_OBJS)) - -$(CGIT_SP_OBJS): %.sp: %.c GIT-CFLAGS $(CGIT_PREFIX)CGIT-CFLAGS FORCE - $(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $(SPARSE_FLAGS) $< - -cgit-sparse: $(CGIT_SP_OBJS) diff --git a/third_party/cgit/cgit.png b/third_party/cgit/cgit.png deleted file mode 100644 index 425528ee3..000000000 Binary files a/third_party/cgit/cgit.png and /dev/null differ diff --git a/third_party/cgit/cgitrc.5.txt b/third_party/cgit/cgitrc.5.txt deleted file mode 100644 index cafb5355e..000000000 --- a/third_party/cgit/cgitrc.5.txt +++ /dev/null @@ -1,977 +0,0 @@ -:man source: cgit -:man manual: cgit - -CGITRC(5) -======== - - -NAME ----- -cgitrc - runtime configuration for cgit - - -SYNOPSIS --------- -Cgitrc contains all runtime settings for cgit, including the list of git -repositories, formatted as a line-separated list of NAME=VALUE pairs. Blank -lines, and lines starting with '#', are ignored. - - -LOCATION --------- -The default location of cgitrc, defined at compile time, is /etc/cgitrc. At -runtime, cgit will consult the environment variable CGIT_CONFIG and, if -defined, use its value instead. - - -GLOBAL SETTINGS ---------------- -about-filter:: - Specifies a command which will be invoked to format the content of - about pages (both top-level and for each repository). The command will - get the content of the about-file on its STDIN, the name of the file - as the first argument, and the STDOUT from the command will be - included verbatim on the about page. Default value: none. See - also: "FILTER API". - -agefile:: - Specifies a path, relative to each repository path, which can be used - to specify the date and time of the youngest commit in the repository. - The first line in the file is used as input to the "parse_date" - function in libgit. Recommended timestamp-format is "yyyy-mm-dd - hh:mm:ss". You may want to generate this file from a post-receive - hook. Default value: "info/web/last-modified". - -auth-filter:: - Specifies a command that will be invoked for authenticating repository - access. Receives quite a few arguments, and data on both stdin and - stdout for authentication processing. Details follow later in this - document. If no auth-filter is specified, no authentication is - performed. Default value: none. See also: "FILTER API". - -branch-sort:: - Flag which, when set to "age", enables date ordering in the branch ref - list, and when set to "name" enables ordering by branch name. Default - value: "name". - -cache-about-ttl:: - Number which specifies the time-to-live, in minutes, for the cached - version of the repository about page. See also: "CACHE". Default - value: "15". - -cache-dynamic-ttl:: - Number which specifies the time-to-live, in minutes, for the cached - version of repository pages accessed without a fixed SHA1. See also: - "CACHE". Default value: "5". - -cache-repo-ttl:: - Number which specifies the time-to-live, in minutes, for the cached - version of the repository summary page. See also: "CACHE". Default - value: "5". - -cache-root:: - Path used to store the cgit cache entries. Default value: - "/var/cache/cgit". See also: "MACRO EXPANSION". - -cache-root-ttl:: - Number which specifies the time-to-live, in minutes, for the cached - version of the repository index page. See also: "CACHE". Default - value: "5". - -cache-scanrc-ttl:: - Number which specifies the time-to-live, in minutes, for the result - of scanning a path for git repositories. See also: "CACHE". Default - value: "15". - -case-sensitive-sort:: - Sort items in the repo list case sensitively. Default value: "1". - See also: repository-sort, section-sort. - -cache-size:: - The maximum number of entries in the cgit cache. When set to "0", - caching is disabled. See also: "CACHE". Default value: "0" - -cache-snapshot-ttl:: - Number which specifies the time-to-live, in minutes, for the cached - version of snapshots. See also: "CACHE". Default value: "5". - -cache-static-ttl:: - Number which specifies the time-to-live, in minutes, for the cached - version of repository pages accessed with a fixed SHA1. See also: - "CACHE". Default value: -1". - -clone-prefix:: - Space-separated list of common prefixes which, when combined with a - repository url, generates valid clone urls for the repository. This - setting is only used if `repo.clone-url` is unspecified. Default value: - none. - -clone-url:: - Space-separated list of clone-url templates. This setting is only - used if `repo.clone-url` is unspecified. Default value: none. See - also: "MACRO EXPANSION", "FILTER API". - -commit-filter:: - Specifies a command which will be invoked to format commit messages. - The command will get the message on its STDIN, and the STDOUT from the - command will be included verbatim as the commit message, i.e. this can - be used to implement bugtracker integration. Default value: none. - See also: "FILTER API". - -commit-sort:: - Flag which, when set to "date", enables strict date ordering in the - commit log, and when set to "topo" enables strict topological - ordering. If unset, the default ordering of "git log" is used. Default - value: unset. - -css:: - Url which specifies the css document to include in all cgit pages. - Default value: "/cgit.css". - -email-filter:: - Specifies a command which will be invoked to format names and email - address of committers, authors, and taggers, as represented in various - places throughout the cgit interface. This command will receive an - email address and an origin page string as its command line arguments, - and the text to format on STDIN. It is to write the formatted text back - out onto STDOUT. Default value: none. See also: "FILTER API". - -embedded:: - Flag which, when set to "1", will make cgit generate a html fragment - suitable for embedding in other html pages. Default value: none. See - also: "noheader". - -enable-blame:: - Flag which, when set to "1", will allow cgit to provide a "blame" page - for files, and will make it generate links to that page in appropriate - places. Default value: "0". - -enable-commit-graph:: - Flag which, when set to "1", will make cgit print an ASCII-art commit - history graph to the left of the commit messages in the repository - log page. Default value: "0". - -enable-filter-overrides:: - Flag which, when set to "1", allows all filter settings to be - overridden in repository-specific cgitrc files. Default value: none. - -enable-follow-links:: - Flag which, when set to "1", allows users to follow a file in the log - view. Default value: "0". - -enable-git-config:: - Flag which, when set to "1", will allow cgit to use git config to set - any repo specific settings. This option is used in conjunction with - "scan-path", and must be defined prior, to augment repo-specific - settings. The keys gitweb.owner, gitweb.category, gitweb.description, - and gitweb.homepage will map to the cgit keys repo.owner, repo.section, - repo.desc, and repo.homepage respectively. All git config keys that begin - with "cgit." will be mapped to the corresponding "repo." key in cgit. - Default value: "0". See also: scan-path, section-from-path. - -enable-http-clone:: - If set to "1", cgit will act as a dumb HTTP endpoint for git clones. - You can add "http://$HTTP_HOST$SCRIPT_NAME/$CGIT_REPO_URL" to clone-url - to expose this feature. If you use an alternate way of serving git - repositories, you may wish to disable this. Default value: "1". - -enable-html-serving:: - Flag which, when set to "1", will allow the /plain handler to serve - mimetype headers that result in the file being treated as HTML by the - browser. When set to "0", such file types are returned instead as - text/plain or application/octet-stream. Default value: "0". See also: - "repo.enable-html-serving". - -enable-index-links:: - Flag which, when set to "1", will make cgit generate extra links for - each repo in the repository index (specifically, to the "summary", - "commit" and "tree" pages). Default value: "0". - -enable-index-owner:: - Flag which, when set to "1", will make cgit display the owner of - each repo in the repository index. Default value: "1". - -enable-log-filecount:: - Flag which, when set to "1", will make cgit print the number of - modified files for each commit on the repository log page. Default - value: "0". - -enable-log-linecount:: - Flag which, when set to "1", will make cgit print the number of added - and removed lines for each commit on the repository log page. Default - value: "0". - -enable-remote-branches:: - Flag which, when set to "1", will make cgit display remote branches - in the summary and refs views. Default value: "0". See also: - "repo.enable-remote-branches". - -enable-subject-links:: - Flag which, when set to "1", will make cgit use the subject of the - parent commit as link text when generating links to parent commits - in commit view. Default value: "0". See also: - "repo.enable-subject-links". - -enable-tree-linenumbers:: - Flag which, when set to "1", will make cgit generate linenumber links - for plaintext blobs printed in the tree view. Default value: "1". - -favicon:: - Url used as link to a shortcut icon for cgit. It is suggested to use - the value "/favicon.ico" since certain browsers will ignore other - values. Default value: none. - -footer:: - The content of the file specified with this option will be included - verbatim at the bottom of all pages (i.e. it replaces the standard - "generated by..." message. Default value: none. - -head-include:: - The content of the file specified with this option will be included - verbatim in the html HEAD section on all pages. Default value: none. - -header:: - The content of the file specified with this option will be included - verbatim at the top of all pages. Default value: none. - -include:: - Name of a configfile to include before the rest of the current config- - file is parsed. Default value: none. See also: "MACRO EXPANSION". - -local-time:: - Flag which, if set to "1", makes cgit print commit and tag times in the - servers timezone. Default value: "0". - -logo:: - Url which specifies the source of an image which will be used as a logo - on all cgit pages. Default value: "/cgit.png". - -logo-link:: - Url loaded when clicking on the cgit logo image. If unspecified the - calculated url of the repository index page will be used. Default - value: none. - -max-atom-items:: - Specifies the number of items to display in atom feeds view. Default - value: "10". - -max-blob-size:: - Specifies the maximum size of a blob to display HTML for in KBytes. - Default value: "0" (limit disabled). - -max-commit-count:: - Specifies the number of entries to list per page in "log" view. Default - value: "50". - -max-message-length:: - Specifies the maximum number of commit message characters to display in - "log" view. Default value: "80". - -max-repo-count:: - Specifies the number of entries to list per page on the repository - index page. Default value: "50". - -max-repodesc-length:: - Specifies the maximum number of repo description characters to display - on the repository index page. Default value: "80". - -max-stats:: - Set the default maximum statistics period. Valid values are "week", - "month", "quarter" and "year". If unspecified, statistics are - disabled. Default value: none. See also: "repo.max-stats". - -mimetype.:: - Set the mimetype for the specified filename extension. This is used - by the `plain` command when returning blob content. - -mimetype-file:: - Specifies the file to use for automatic mimetype lookup. If specified - then this field is used as a fallback when no "mimetype." match is - found. If unspecified then no such lookup is performed. The typical file - to use on a Linux system is /etc/mime.types. The format of the file must - comply to: - - a comment line is an empty line or a line starting with a hash (#), - optionally preceded by whitespace - - a non-comment line starts with the mimetype (like image/png), followed - by one or more file extensions (like jpg), all separated by whitespace - Default value: none. See also: "mimetype.". - -module-link:: - Text which will be used as the formatstring for a hyperlink when a - submodule is printed in a directory listing. The arguments for the - formatstring are the path and SHA1 of the submodule commit. Default - value: none. - -noplainemail:: - If set to "1" showing full author email addresses will be disabled. - Default value: "0". - -noheader:: - Flag which, when set to "1", will make cgit omit the standard header - on all pages. Default value: none. See also: "embedded". - -owner-filter:: - Specifies a command which will be invoked to format the Owner - column of the main page. The command will get the owner on STDIN, - and the STDOUT from the command will be included verbatim in the - table. This can be used to link to additional context such as an - owners home page. When active this filter is used instead of the - default owner query url. Default value: none. - See also: "FILTER API". - -project-list:: - A list of subdirectories inside of scan-path, relative to it, that - should loaded as git repositories. This must be defined prior to - scan-path. Default value: none. See also: scan-path, "MACRO - EXPANSION". - -readme:: - Text which will be used as default value for "repo.readme". Multiple - config keys may be specified, and cgit will use the first found file - in this list. This is useful in conjunction with scan-path. Default - value: none. See also: scan-path, repo.readme. - -remove-suffix:: - If set to "1" and scan-path is enabled, if any repositories are found - with a suffix of ".git", this suffix will be removed for the url and - name. This must be defined prior to scan-path. Default value: "0". - See also: scan-path. - -renamelimit:: - Maximum number of files to consider when detecting renames. The value - "-1" uses the compiletime value in git (for further info, look at - `man git-diff`). Default value: "-1". - -repository-sort:: - The way in which repositories in each section are sorted. Valid values - are "name" for sorting by the repo name or "age" for sorting by the - most recently updated repository. Default value: "name". See also: - section, case-sensitive-sort, section-sort. - -robots:: - Text used as content for the "robots" meta-tag. Default value: - "index, nofollow". - -root-desc:: - Text printed below the heading on the repository index page. Default - value: "a fast webinterface for the git dscm". - -root-readme:: - The content of the file specified with this option will be included - verbatim below the "about" link on the repository index page. Default - value: none. - -root-title:: - Text printed as heading on the repository index page. Default value: - "Git Repository Browser". - -scan-hidden-path:: - If set to "1" and scan-path is enabled, scan-path will recurse into - directories whose name starts with a period ('.'). Otherwise, - scan-path will stay away from such directories (considered as - "hidden"). Note that this does not apply to the ".git" directory in - non-bare repos. This must be defined prior to scan-path. - Default value: 0. See also: scan-path. - -scan-path:: - A path which will be scanned for repositories. If caching is enabled, - the result will be cached as a cgitrc include-file in the cache - directory. If project-list has been defined prior to scan-path, - scan-path loads only the directories listed in the file pointed to by - project-list. Be advised that only the global settings taken - before the scan-path directive will be applied to each repository. - Default value: none. See also: cache-scanrc-ttl, project-list, - "MACRO EXPANSION". - -section:: - The name of the current repository section - all repositories defined - after this option will inherit the current section name. Default value: - none. - -section-sort:: - Flag which, when set to "1", will sort the sections on the repository - listing by name. Set this flag to "0" if the order in the cgitrc file should - be preserved. Default value: "1". See also: section, - case-sensitive-sort, repository-sort. - -section-from-path:: - A number which, if defined prior to scan-path, specifies how many - path elements from each repo path to use as a default section name. - If negative, cgit will discard the specified number of path elements - above the repo directory. Default value: "0". - -side-by-side-diffs:: - If set to "1" shows side-by-side diffs instead of unidiffs per - default. Default value: "0". - -snapshots:: - Text which specifies the default set of snapshot formats that cgit - generates links for. The value is a space-separated list of zero or - more of the values "tar", "tar.gz", "tar.bz2", "tar.lz", "tar.xz", - "tar.zst" and "zip". The special value "all" enables all snapshot - formats. Default value: none. - All compressors use default settings. Some settings can be influenced - with environment variables, for example set ZSTD_CLEVEL=10 in web - server environment for higher (but slower) zstd compression. - -source-filter:: - Specifies a command which will be invoked to format plaintext blobs - in the tree view. The command will get the blob content on its STDIN - and the name of the blob as its only command line argument. The STDOUT - from the command will be included verbatim as the blob contents, i.e. - this can be used to implement e.g. syntax highlighting. Default value: - none. See also: "FILTER API". - -summary-branches:: - Specifies the number of branches to display in the repository "summary" - view. Default value: "10". - -summary-log:: - Specifies the number of log entries to display in the repository - "summary" view. Default value: "10". - -summary-tags:: - Specifies the number of tags to display in the repository "summary" - view. Default value: "10". - -strict-export:: - Filename which, if specified, needs to be present within the repository - for cgit to allow access to that repository. This can be used to emulate - gitweb's EXPORT_OK and STRICT_EXPORT functionality and limit cgit's - repositories to match those exported by git-daemon. This option must - be defined prior to scan-path. - -virtual-root:: - Url which, if specified, will be used as root for all cgit links. It - will also cause cgit to generate 'virtual urls', i.e. urls like - '/cgit/tree/README' as opposed to '?r=cgit&p=tree&path=README'. Default - value: none. - NOTE: cgit has recently learned how to use PATH_INFO to achieve the - same kind of virtual urls, so this option will probably be deprecated. - - -REPOSITORY SETTINGS -------------------- -repo.about-filter:: - Override the default about-filter. Default value: none. See also: - "enable-filter-overrides". See also: "FILTER API". - -repo.branch-sort:: - Flag which, when set to "age", enables date ordering in the branch ref - list, and when set to "name" enables ordering by branch name. Default - value: "name". - -repo.clone-url:: - A list of space-separated urls which can be used to clone this repo. - Default value: none. See also: "MACRO EXPANSION". - -repo.commit-filter:: - Override the default commit-filter. Default value: none. See also: - "enable-filter-overrides". See also: "FILTER API". - -repo.commit-sort:: - Flag which, when set to "date", enables strict date ordering in the - commit log, and when set to "topo" enables strict topological - ordering. If unset, the default ordering of "git log" is used. Default - value: unset. - -repo.defbranch:: - The name of the default branch for this repository. If no such branch - exists in the repository, the first branch name (when sorted) is used - as default instead. Default value: branch pointed to by HEAD, or - "master" if there is no suitable HEAD. - -repo.desc:: - The value to show as repository description. Default value: none. - -repo.email-filter:: - Override the default email-filter. Default value: none. See also: - "enable-filter-overrides". See also: "FILTER API". - -repo.enable-blame:: - A flag which can be used to disable the global setting - `enable-blame'. Default value: none. - -repo.enable-commit-graph:: - A flag which can be used to disable the global setting - `enable-commit-graph'. Default value: none. - -repo.enable-html-serving:: - A flag which can be used to override the global setting - `enable-html-serving`. Default value: none. - -repo.enable-log-filecount:: - A flag which can be used to disable the global setting - `enable-log-filecount'. Default value: none. - -repo.enable-log-linecount:: - A flag which can be used to disable the global setting - `enable-log-linecount'. Default value: none. - -repo.enable-remote-branches:: - Flag which, when set to "1", will make cgit display remote branches - in the summary and refs views. Default value: . - -repo.enable-subject-links:: - A flag which can be used to override the global setting - `enable-subject-links'. Default value: none. - -repo.extra-head-content:: - This value will be added verbatim to the head section of each page - displayed for this repo. Default value: none. - -repo.hide:: - Flag which, when set to "1", hides the repository from the repository - index. The repository can still be accessed by providing a direct path. - Default value: "0". See also: "repo.ignore". - -repo.homepage:: - The value to show as repository homepage. Default value: none. - -repo.ignore:: - Flag which, when set to "1", ignores the repository. The repository - is not shown in the index and cannot be accessed by providing a direct - path. Default value: "0". See also: "repo.hide". - -repo.logo:: - Url which specifies the source of an image which will be used as a logo - on this repo's pages. Default value: global logo. - -repo.logo-link:: - Url loaded when clicking on the cgit logo image. If unspecified the - calculated url of the repository index page will be used. Default - value: global logo-link. - -repo.module-link:: - Text which will be used as the formatstring for a hyperlink when a - submodule is printed in a directory listing. The arguments for the - formatstring are the path and SHA1 of the submodule commit. Default - value: - -repo.module-link.:: - Text which will be used as the formatstring for a hyperlink when a - submodule with the specified subdirectory path is printed in a - directory listing. The only argument for the formatstring is the SHA1 - of the submodule commit. Default value: none. - -repo.max-stats:: - Override the default maximum statistics period. Valid values are equal - to the values specified for the global "max-stats" setting. Default - value: none. - -repo.name:: - The value to show as repository name. Default value: . - -repo.owner:: - A value used to identify the owner of the repository. Default value: - none. - -repo.owner-filter:: - Override the default owner-filter. Default value: none. See also: - "enable-filter-overrides". See also: "FILTER API". - -repo.path:: - An absolute path to the repository directory. For non-bare repositories - this is the .git-directory. Default value: none. - -repo.readme:: - A path (relative to ) which specifies a file to include - verbatim as the "About" page for this repo. You may also specify a - git refspec by head or by hash by prepending the refspec followed by - a colon. For example, "master:docs/readme.mkd". If the value begins - with a colon, i.e. ":docs/readme.rst", the head giving in query or - the default branch of the repository will be used. Sharing any file - will expose that entire directory tree to the "/about/PATH" endpoints, - so be sure that there are no non-public files located in the same - directory as the readme file. Default value: . - -repo.section:: - Override the current section name for this repository. Default value: - none. - -repo.snapshots:: - A mask of snapshot formats for this repo that cgit generates links for, - restricted by the global "snapshots" setting. Default value: - . - -repo.snapshot-prefix:: - Prefix to use for snapshot links instead of the repository basename. - For example, the "linux-stable" repository may wish to set this to - "linux" so that snapshots are in the format "linux-3.15.4" instead - of "linux-stable-3.15.4". Default value: meaning to use - the repository basename. - -repo.source-filter:: - Override the default source-filter. Default value: none. See also: - "enable-filter-overrides". See also: "FILTER API". - -repo.url:: - The relative url used to access the repository. This must be the first - setting specified for each repo. Default value: none. - - -REPOSITORY-SPECIFIC CGITRC FILE -------------------------------- -When the option "scan-path" is used to auto-discover git repositories, cgit -will try to parse the file "cgitrc" within any found repository. Such a -repo-specific config file may contain any of the repo-specific options -described above, except "repo.url" and "repo.path". Additionally, the "filter" -options are only acknowledged in repo-specific config files when -"enable-filter-overrides" is set to "1". - -Note: the "repo." prefix is dropped from the option names in repo-specific -config files, e.g. "repo.desc" becomes "desc". - - -FILTER API ----------- -By default, filters are separate processes that are executed each time they -are needed. Alternative technologies may be used by prefixing the filter -specification with the relevant string; available values are: - -'exec:':: - The default "one process per filter" mode. - - -Parameters are provided to filters as follows. - -about filter:: - This filter is given a single parameter: the filename of the source - file to filter. The filter can use the filename to determine (for - example) the type of syntax to follow when formatting the readme file. - The about text that is to be filtered is available on standard input - and the filtered text is expected on standard output. - -auth filter:: - The authentication filter receives 12 parameters: - - filter action, explained below, which specifies which action the - filter is called for - - http cookie - - http method - - http referer - - http path - - http https flag - - cgit repo - - cgit page - - cgit url - - cgit login url - When the filter action is "body", this filter must write to output the - HTML for displaying the login form, which POSTs to the login url. When - the filter action is "authenticate-cookie", this filter must validate - the http cookie and return a 0 if it is invalid or 1 if it is invalid, - in the exit code / close function. If the filter action is - "authenticate-post", this filter receives POST'd parameters on - standard input, and should write a complete CGI response, preferably - with a 302 redirect, and write to output one or more "Set-Cookie" - HTTP headers, each followed by a newline. - -commit filter:: - This filter is given no arguments. The commit message text that is to - be filtered is available on standard input and the filtered text is - expected on standard output. - -email filter:: - This filter is given two parameters: the email address of the relevant - author and a string indicating the originating page. The filter will - then receive the text string to format on standard input and is - expected to write to standard output the formatted text to be included - in the page. - -owner filter:: - This filter is given no arguments. The owner text is available on - standard input and the filter is expected to write to standard - output. The output is included in the Owner column. - -source filter:: - This filter is given a single parameter: the filename of the source - file to filter. The filter can use the filename to determine (for - example) the syntax highlighting mode. The contents of the source - file that is to be filtered is available on standard input and the - filtered contents is expected on standard output. - - -All filters are handed the following environment variables: - -- CGIT_REPO_URL (from repo.url) -- CGIT_REPO_NAME (from repo.name) -- CGIT_REPO_PATH (from repo.path) -- CGIT_REPO_OWNER (from repo.owner) -- CGIT_REPO_DEFBRANCH (from repo.defbranch) -- CGIT_REPO_SECTION (from repo.section) -- CGIT_REPO_CLONE_URL (from repo.clone-url) - -If a setting is not defined for a repository and the corresponding global -setting is also not defined (if applicable), then the corresponding -environment variable will be unset. - - -MACRO EXPANSION ---------------- -The following cgitrc options support a simple macro expansion feature, -where tokens prefixed with "$" are replaced with the value of a similarly -named environment variable: - -- cache-root -- include -- project-list -- scan-path - -Macro expansion will also happen on the content of $CGIT_CONFIG, if -defined. - -One usage of this feature is virtual hosting, which in its simplest form -can be accomplished by adding the following line to /etc/cgitrc: - - include=/etc/cgitrc.d/$HTTP_HOST - -The following options are expanded during request processing, and support -the environment variables defined in "FILTER API": - -- clone-url -- repo.clone-url - - -CACHE ------ - -All cache ttl values are in minutes. Negative ttl values indicate that a page -type will never expire, and thus the first time a URL is accessed, the result -will be cached indefinitely, even if the underlying git repository changes. -Conversely, when a ttl value is zero, the cache is disabled for that -particular page type, and the page type is never cached. - -SIGNATURES ----------- - -Cgit can host .asc signatures corresponding to various snapshot formats, -through use of git notes. For example, the following command may be used to -add a signature to a .tar.xz archive: - - git notes --ref=refs/notes/signatures/tar.xz add -C "$( - gpg --output - --armor --detach-sign cgit-1.1.tar.xz | - git hash-object -w --stdin - )" v1.1 - -If it is instead desirable to attach a signature of the underlying .tar, this -will be linked, as a special case, beside a .tar.* link that does not have its -own signature. For example, a signature of a tarball of the latest tag might -be added with a similar command: - - tag="$(git describe --abbrev=0)" - git notes --ref=refs/notes/signatures/tar add -C "$( - git archive --format tar --prefix "cgit-${tag#v}/" "$tag" | - gpg --output - --armor --detach-sign | - git hash-object -w --stdin - )" "$tag" - -Since git-archive(1) is expected to produce stable output between versions, -this allows one to generate a long-term signature of the contents of a given -tag. - -EXAMPLE CGITRC FILE -------------------- - -.... -# Enable caching of up to 1000 output entries -cache-size=1000 - - -# Specify some default clone urls using macro expansion -clone-url=git://foo.org/$CGIT_REPO_URL git@foo.org:$CGIT_REPO_URL - -# Specify the css url -css=/css/cgit.css - - -# Show owner on index page -enable-index-owner=1 - - -# Allow http transport git clone -enable-http-clone=1 - - -# Show extra links for each repository on the index page -enable-index-links=1 - - -# Enable blame page and create links to it from tree page -enable-blame=1 - - -# Enable ASCII art commit history graph on the log pages -enable-commit-graph=1 - - -# Show number of affected files per commit on the log pages -enable-log-filecount=1 - - -# Show number of added/removed lines per commit on the log pages -enable-log-linecount=1 - - -# Sort branches by date -branch-sort=age - - -# Add a cgit favicon -favicon=/favicon.ico - - -# Use a custom logo -logo=/img/mylogo.png - - -# Enable statistics per week, month and quarter -max-stats=quarter - - -# Set the title and heading of the repository index page -root-title=example.com git repositories - - -# Set a subheading for the repository index page -root-desc=tracking the foobar development - - -# Include some more info about example.com on the index page -root-readme=/var/www/htdocs/about.html - - -# Allow download of tar.gz, tar.bz2 and zip-files -snapshots=tar.gz tar.bz2 zip - - -## -## List of common mimetypes -## - -mimetype.gif=image/gif -mimetype.html=text/html -mimetype.jpg=image/jpeg -mimetype.jpeg=image/jpeg -mimetype.pdf=application/pdf -mimetype.png=image/png -mimetype.svg=image/svg+xml - - -# Highlight source code with python pygments-based highlighter -source-filter=/var/www/cgit/filters/syntax-highlighting.py - -# Format markdown, restructuredtext, manpages, text files, and html files -# through the right converters -about-filter=/var/www/cgit/filters/about-formatting.sh - -## -## Search for these files in the root of the default branch of repositories -## for coming up with the about page: -## -readme=:README.md -readme=:readme.md -readme=:README.mkd -readme=:readme.mkd -readme=:README.rst -readme=:readme.rst -readme=:README.html -readme=:readme.html -readme=:README.htm -readme=:readme.htm -readme=:README.txt -readme=:readme.txt -readme=:README -readme=:readme -readme=:INSTALL.md -readme=:install.md -readme=:INSTALL.mkd -readme=:install.mkd -readme=:INSTALL.rst -readme=:install.rst -readme=:INSTALL.html -readme=:install.html -readme=:INSTALL.htm -readme=:install.htm -readme=:INSTALL.txt -readme=:install.txt -readme=:INSTALL -readme=:install - - -## -## List of repositories. -## PS: Any repositories listed when section is unset will not be -## displayed under a section heading -## PPS: This list could be kept in a different file (e.g. '/etc/cgitrepos') -## and included like this: -## include=/etc/cgitrepos -## - - -repo.url=foo -repo.path=/pub/git/foo.git -repo.desc=the master foo repository -repo.owner=fooman@example.com -repo.readme=info/web/about.html - - -repo.url=bar -repo.path=/pub/git/bar.git -repo.desc=the bars for your foo -repo.owner=barman@example.com -repo.readme=info/web/about.html - - -# The next repositories will be displayed under the 'extras' heading -section=extras - - -repo.url=baz -repo.path=/pub/git/baz.git -repo.desc=a set of extensions for bar users - -repo.url=wiz -repo.path=/pub/git/wiz.git -repo.desc=the wizard of foo - - -# Add some mirrored repositories -section=mirrors - - -repo.url=git -repo.path=/pub/git/git.git -repo.desc=the dscm - - -repo.url=linux -repo.path=/pub/git/linux.git -repo.desc=the kernel - -# Disable adhoc downloads of this repo -repo.snapshots=0 - -# Disable line-counts for this repo -repo.enable-log-linecount=0 - -# Restrict the max statistics period for this repo -repo.max-stats=month -.... - - -BUGS ----- -Comments currently cannot appear on the same line as a setting; the comment -will be included as part of the value. E.g. this line: - - robots=index # allow indexing - -will generate the following html element: - - - - - -AUTHOR ------- -Lars Hjemli -Jason A. Donenfeld diff --git a/third_party/cgit/cmd.c b/third_party/cgit/cmd.c deleted file mode 100644 index c664e894f..000000000 --- a/third_party/cgit/cmd.c +++ /dev/null @@ -1,186 +0,0 @@ -/* cmd.c: the cgit command dispatcher - * - * Copyright (C) 2006-2017 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "cmd.h" -#include "cache.h" -#include "ui-shared.h" -#include "ui-atom.h" -#include "ui-blame.h" -#include "ui-blob.h" -#include "ui-clone.h" -#include "ui-commit.h" -#include "ui-diff.h" -#include "ui-log.h" -#include "ui-patch.h" -#include "ui-plain.h" -#include "ui-refs.h" -#include "ui-repolist.h" -#include "ui-snapshot.h" -#include "ui-stats.h" -#include "ui-summary.h" -#include "ui-tag.h" -#include "ui-tree.h" - -static void HEAD_fn(void) -{ - cgit_clone_head(); -} - -static void atom_fn(void) -{ - cgit_print_atom(ctx.qry.head, ctx.qry.path, ctx.cfg.max_atom_items); -} - -static void about_fn(void) -{ - cgit_print_repo_readme(ctx.qry.path); -} - -static void blame_fn(void) -{ - if (ctx.repo->enable_blame) - cgit_print_blame(); - else - cgit_print_error_page(403, "Forbidden", "Blame is disabled"); -} - -static void blob_fn(void) -{ - cgit_print_blob(ctx.qry.oid, ctx.qry.path, ctx.qry.head, 0); -} - -static void commit_fn(void) -{ - cgit_print_commit(ctx.qry.oid, ctx.qry.path); -} - -static void diff_fn(void) -{ - cgit_print_diff(ctx.qry.oid, ctx.qry.oid2, ctx.qry.path, 1, 0); -} - -static void rawdiff_fn(void) -{ - cgit_print_diff(ctx.qry.oid, ctx.qry.oid2, ctx.qry.path, 1, 1); -} - -static void info_fn(void) -{ - cgit_clone_info(); -} - -static void log_fn(void) -{ - cgit_print_log(ctx.qry.oid, ctx.qry.ofs, ctx.cfg.max_commit_count, - ctx.qry.grep, ctx.qry.search, ctx.qry.path, 1, - ctx.repo->enable_commit_graph, - ctx.repo->commit_sort); -} - -static void ls_cache_fn(void) -{ - ctx.page.mimetype = "text/plain"; - ctx.page.filename = "ls-cache.txt"; - cgit_print_http_headers(); - cache_ls(ctx.cfg.cache_root); -} - -static void objects_fn(void) -{ - cgit_clone_objects(); -} - -static void repolist_fn(void) -{ - cgit_print_repolist(); -} - -static void patch_fn(void) -{ - cgit_print_patch(ctx.qry.oid, ctx.qry.oid2, ctx.qry.path); -} - -static void plain_fn(void) -{ - cgit_print_plain(); -} - -static void refs_fn(void) -{ - cgit_print_refs(); -} - -static void snapshot_fn(void) -{ - cgit_print_snapshot(ctx.qry.head, ctx.qry.oid, ctx.qry.path, - ctx.qry.nohead); -} - -static void stats_fn(void) -{ - cgit_show_stats(); -} - -static void summary_fn(void) -{ - cgit_print_summary(); -} - -static void tag_fn(void) -{ - cgit_print_tag(ctx.qry.oid); -} - -static void tree_fn(void) -{ - cgit_print_tree(ctx.qry.oid, ctx.qry.path); -} - -#define def_cmd(name, want_repo, want_vpath, is_clone) \ - {#name, name##_fn, want_repo, want_vpath, is_clone} - -struct cgit_cmd *cgit_get_cmd(void) -{ - static struct cgit_cmd cmds[] = { - def_cmd(HEAD, 1, 0, 1), - def_cmd(atom, 1, 0, 0), - def_cmd(about, 1, 1, 0), - def_cmd(blame, 1, 1, 0), - def_cmd(blob, 1, 0, 0), - def_cmd(commit, 1, 1, 0), - def_cmd(diff, 1, 1, 0), - def_cmd(info, 1, 0, 1), - def_cmd(log, 1, 1, 0), - def_cmd(ls_cache, 0, 0, 0), - def_cmd(objects, 1, 0, 1), - def_cmd(patch, 1, 1, 0), - def_cmd(plain, 1, 0, 0), - def_cmd(rawdiff, 1, 1, 0), - def_cmd(refs, 1, 0, 0), - def_cmd(repolist, 0, 0, 0), - def_cmd(snapshot, 1, 0, 0), - def_cmd(stats, 1, 1, 0), - def_cmd(summary, 1, 0, 0), - def_cmd(tag, 1, 0, 0), - def_cmd(tree, 1, 1, 0), - }; - int i; - - if (ctx.qry.page == NULL) { - if (ctx.repo) - ctx.qry.page = "summary"; - else - ctx.qry.page = "repolist"; - } - - for (i = 0; i < sizeof(cmds)/sizeof(*cmds); i++) - if (!strcmp(ctx.qry.page, cmds[i].name)) - return &cmds[i]; - return NULL; -} diff --git a/third_party/cgit/cmd.h b/third_party/cgit/cmd.h deleted file mode 100644 index 6249b1d89..000000000 --- a/third_party/cgit/cmd.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CMD_H -#define CMD_H - -typedef void (*cgit_cmd_fn)(void); - -struct cgit_cmd { - const char *name; - cgit_cmd_fn fn; - unsigned int want_repo:1, - want_vpath:1, - is_clone:1; -}; - -extern struct cgit_cmd *cgit_get_cmd(void); - -#endif /* CMD_H */ diff --git a/third_party/cgit/configfile.c b/third_party/cgit/configfile.c deleted file mode 100644 index e0391091e..000000000 --- a/third_party/cgit/configfile.c +++ /dev/null @@ -1,90 +0,0 @@ -/* configfile.c: parsing of config files - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include -#include "configfile.h" - -static int next_char(FILE *f) -{ - int c = fgetc(f); - if (c == '\r') { - c = fgetc(f); - if (c != '\n') { - ungetc(c, f); - c = '\r'; - } - } - return c; -} - -static void skip_line(FILE *f) -{ - int c; - - while ((c = next_char(f)) && c != '\n' && c != EOF) - ; -} - -static int read_config_line(FILE *f, struct strbuf *name, struct strbuf *value) -{ - int c = next_char(f); - - strbuf_reset(name); - strbuf_reset(value); - - /* Skip comments and preceding spaces. */ - for(;;) { - if (c == EOF) - return 0; - else if (c == '#' || c == ';') - skip_line(f); - else if (!isspace(c)) - break; - c = next_char(f); - } - - /* Read variable name. */ - while (c != '=') { - if (c == '\n' || c == EOF) - return 0; - strbuf_addch(name, c); - c = next_char(f); - } - - /* Read variable value. */ - c = next_char(f); - while (c != '\n' && c != EOF) { - strbuf_addch(value, c); - c = next_char(f); - } - - return 1; -} - -int parse_configfile(const char *filename, configfile_value_fn fn) -{ - static int nesting; - struct strbuf name = STRBUF_INIT; - struct strbuf value = STRBUF_INIT; - FILE *f; - - /* cancel deeply nested include-commands */ - if (nesting > 8) - return -1; - if (!(f = fopen(filename, "r"))) - return -1; - nesting++; - while (read_config_line(f, &name, &value)) - fn(name.buf, value.buf); - nesting--; - fclose(f); - strbuf_release(&name); - strbuf_release(&value); - return 0; -} - diff --git a/third_party/cgit/configfile.h b/third_party/cgit/configfile.h deleted file mode 100644 index af7ca1973..000000000 --- a/third_party/cgit/configfile.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CONFIGFILE_H -#define CONFIGFILE_H - -#include "cgit.h" - -typedef void (*configfile_value_fn)(const char *name, const char *value); - -extern int parse_configfile(const char *filename, configfile_value_fn fn); - -#endif /* CONFIGFILE_H */ diff --git a/third_party/cgit/contrib/hooks/post-receive.agefile b/third_party/cgit/contrib/hooks/post-receive.agefile deleted file mode 100755 index 2f72ae9c0..000000000 --- a/third_party/cgit/contrib/hooks/post-receive.agefile +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -# -# An example hook to update the "agefile" for CGit's idle time calculation. -# -# This hook assumes that you are using the default agefile location of -# "info/web/last-modified". If you change the value in your cgitrc then you -# must also change it here. -# -# To install the hook, copy (or link) it to the file "hooks/post-receive" in -# each of your repositories. -# - -agefile="$(git rev-parse --git-dir)"/info/web/last-modified - -mkdir -p "$(dirname "$agefile")" && -git for-each-ref \ - --sort=-authordate --count=1 \ - --format='%(authordate:iso8601)' \ - >"$agefile" diff --git a/third_party/cgit/default.nix b/third_party/cgit/default.nix deleted file mode 100644 index bac6a3264..000000000 --- a/third_party/cgit/default.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - inherit (pkgs) stdenv gzip bzip2 xz lzip zstd zlib openssl; -in -stdenv.mkDerivation rec { - pname = "cgit-pink"; - version = "master"; - src = ./.; - - buildInputs = [ openssl zlib ]; - - enableParallelBuilding = true; - - postPatch = '' - sed -e 's|"gzip"|"${gzip}/bin/gzip"|' \ - -e 's|"bzip2"|"${bzip2.bin}/bin/bzip2"|' \ - -e 's|"lzip"|"${lzip}/bin/lzip"|' \ - -e 's|"xz"|"${xz.bin}/bin/xz"|' \ - -e 's|"zstd"|"${zstd}/bin/zstd"|' \ - -i ui-snapshot.c - ''; - - # Give cgit the git source tree including depot patches. Note that - # the version expected by cgit should be kept in sync with the - # version available in nixpkgs. - # - # TODO(tazjin): Add an assert for this somewhere so we notice it on - # channel bumps. - preBuild = - let - # we have to give cgit a git with dottime support to build - git' = pkgs.git.overrideAttrs (old: { - src = pkgs.fetchurl { - url = "https://github.com/git/git/archive/refs/tags/v2.44.2.tar.gz"; - hash = "sha256-3h0LBfAD4MXfZc0tjWQDO81UdbRo3w5C0W7j7rr9m9I="; - }; - patches = (old.patches or [ ]) ++ [ - ../git/0001-feat-third_party-git-date-add-dottime-format.patch - ]; - }); - in - '' - rm -rf git # remove submodule dir ... - cp -r --no-preserve=ownership,mode ${pkgs.srcOnly git'} git - makeFlagsArray+=(prefix="$out" CGIT_SCRIPT_PATH="$out/cgit/") - cat tvl-extra.css >> cgit.css - ''; - - stripDebugList = [ "cgit" ]; - - # We don't use the filters and they require wrapping to find their deps - postInstall = '' - rm -rf "$out/lib/cgit/filters" - find "$out" -type d -empty -delete - ''; - - meta = { - hompepage = "https://git.causal.agency/cgit-pink/"; - description = "cgit fork aiming for better maintenance"; - license = lib.licenses.gpl2; - platforms = lib.platforms.linux; - }; -} diff --git a/third_party/cgit/filter.c b/third_party/cgit/filter.c deleted file mode 100644 index 190fb5501..000000000 --- a/third_party/cgit/filter.c +++ /dev/null @@ -1,222 +0,0 @@ -/* filter.c: filter framework functions - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "html.h" - -static inline void reap_filter(struct cgit_filter *filter) -{ - if (filter && filter->cleanup) - filter->cleanup(filter); -} - -void cgit_cleanup_filters(void) -{ - int i; - reap_filter(ctx.cfg.about_filter); - reap_filter(ctx.cfg.commit_filter); - reap_filter(ctx.cfg.source_filter); - reap_filter(ctx.cfg.email_filter); - reap_filter(ctx.cfg.owner_filter); - reap_filter(ctx.cfg.auth_filter); - for (i = 0; i < cgit_repolist.count; ++i) { - reap_filter(cgit_repolist.repos[i].about_filter); - reap_filter(cgit_repolist.repos[i].commit_filter); - reap_filter(cgit_repolist.repos[i].source_filter); - reap_filter(cgit_repolist.repos[i].email_filter); - reap_filter(cgit_repolist.repos[i].owner_filter); - } -} - -static int open_exec_filter(struct cgit_filter *base, va_list ap) -{ - struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base; - int pipe_fh[2]; - int i; - - for (i = 0; i < filter->base.argument_count; i++) - filter->argv[i + 1] = va_arg(ap, char *); - - chk_zero(fflush(stdout), "unable to flush STDOUT"); - filter->old_stdout = chk_positive(dup(STDOUT_FILENO), - "Unable to duplicate STDOUT"); - chk_zero(pipe(pipe_fh), "Unable to create pipe to subprocess"); - filter->pid = chk_non_negative(fork(), "Unable to create subprocess"); - if (filter->pid == 0) { - close(pipe_fh[1]); - chk_non_negative(dup2(pipe_fh[0], STDIN_FILENO), - "Unable to use pipe as STDIN"); - execvp(filter->cmd, filter->argv); - die_errno("Unable to exec subprocess %s", filter->cmd); - } - close(pipe_fh[0]); - chk_non_negative(dup2(pipe_fh[1], STDOUT_FILENO), - "Unable to use pipe as STDOUT"); - close(pipe_fh[1]); - return 0; -} - -static int close_exec_filter(struct cgit_filter *base) -{ - struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base; - int i, exit_status = 0; - - chk_zero(fflush(stdout), "unable to flush STDOUT"); - chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO), - "Unable to restore STDOUT"); - close(filter->old_stdout); - if (filter->pid < 0) - goto done; - waitpid(filter->pid, &exit_status, 0); - if (WIFEXITED(exit_status)) - goto done; - die("Subprocess %s exited abnormally", filter->cmd); - -done: - for (i = 0; i < filter->base.argument_count; i++) - filter->argv[i + 1] = NULL; - return WEXITSTATUS(exit_status); - -} - -static void fprintf_exec_filter(struct cgit_filter *base, FILE *f, const char *prefix) -{ - struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base; - fprintf(f, "%sexec:%s\n", prefix, filter->cmd); -} - -static void cleanup_exec_filter(struct cgit_filter *base) -{ - struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base; - if (filter->argv) { - free(filter->argv); - filter->argv = NULL; - } - if (filter->cmd) { - free(filter->cmd); - filter->cmd = NULL; - } -} - -static struct cgit_filter *new_exec_filter(const char *cmd, int argument_count) -{ - struct cgit_exec_filter *f; - int args_size = 0; - - f = xmalloc(sizeof(*f)); - /* We leave argv for now and assign it below. */ - cgit_exec_filter_init(f, xstrdup(cmd), NULL); - f->base.argument_count = argument_count; - args_size = (2 + argument_count) * sizeof(char *); - f->argv = xmalloc(args_size); - memset(f->argv, 0, args_size); - f->argv[0] = f->cmd; - return &f->base; -} - -void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv) -{ - memset(filter, 0, sizeof(*filter)); - filter->base.open = open_exec_filter; - filter->base.close = close_exec_filter; - filter->base.fprintf = fprintf_exec_filter; - filter->base.cleanup = cleanup_exec_filter; - filter->cmd = cmd; - filter->argv = argv; - /* The argument count for open_filter is zero by default, unless called from new_filter, above. */ - filter->base.argument_count = 0; -} - -int cgit_open_filter(struct cgit_filter *filter, ...) -{ - int result; - va_list ap; - if (!filter) - return 0; - va_start(ap, filter); - result = filter->open(filter, ap); - va_end(ap); - return result; -} - -int cgit_close_filter(struct cgit_filter *filter) -{ - if (!filter) - return 0; - return filter->close(filter); -} - -void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char *prefix) -{ - (filter->fprintf)(filter, f, prefix); -} - - - -static const struct { - const char *prefix; - struct cgit_filter *(*ctor)(const char *cmd, int argument_count); -} filter_specs[] = { - { "exec", new_exec_filter }, -}; - -struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype) -{ - char *colon; - int i; - size_t len; - int argument_count; - - if (!cmd || !cmd[0]) - return NULL; - - colon = strchr(cmd, ':'); - len = colon - cmd; - /* - * In case we're running on Windows, don't allow a single letter before - * the colon. - */ - if (len == 1) - colon = NULL; - - switch (filtertype) { - case AUTH: - argument_count = 12; - break; - - case EMAIL: - argument_count = 2; - break; - - case OWNER: - argument_count = 0; - break; - - case SOURCE: - case ABOUT: - argument_count = 1; - break; - - case COMMIT: - default: - argument_count = 0; - break; - } - - /* If no prefix is given, exec filter is the default. */ - if (!colon) - return new_exec_filter(cmd, argument_count); - - for (i = 0; i < ARRAY_SIZE(filter_specs); i++) { - if (len == strlen(filter_specs[i].prefix) && - !strncmp(filter_specs[i].prefix, cmd, len)) - return filter_specs[i].ctor(colon + 1, argument_count); - } - - die("Invalid filter type: %.*s", (int) len, cmd); -} diff --git a/third_party/cgit/filters/about-formatting.sh b/third_party/cgit/filters/about-formatting.sh deleted file mode 100755 index 85daf9c26..000000000 --- a/third_party/cgit/filters/about-formatting.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -# This may be used with the about-filter or repo.about-filter setting in cgitrc. -# It passes formatting of about pages to differing programs, depending on the usage. - -# Markdown support requires python and markdown-python. -# RestructuredText support requires python and docutils. -# Man page support requires groff. - -# The following environment variables can be used to retrieve the configuration -# of the repository for which this script is called: -# CGIT_REPO_URL ( = repo.url setting ) -# CGIT_REPO_NAME ( = repo.name setting ) -# CGIT_REPO_PATH ( = repo.path setting ) -# CGIT_REPO_OWNER ( = repo.owner setting ) -# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting ) -# CGIT_REPO_SECTION ( = section setting ) -# CGIT_REPO_CLONE_URL ( = repo.clone-url setting ) - -cd "$(dirname $0)/html-converters/" -case "$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')" in - *.markdown|*.mdown|*.md|*.mkd) exec ./md2html; ;; - *.rst) exec ./rst2html; ;; - *.[1-9]) exec ./man2html; ;; - *.htm|*.html) exec cat; ;; - *.txt|*) exec ./txt2html; ;; -esac diff --git a/third_party/cgit/filters/commit-links.sh b/third_party/cgit/filters/commit-links.sh deleted file mode 100755 index 796ac308d..000000000 --- a/third_party/cgit/filters/commit-links.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh -# This script can be used to generate links in commit messages. -# -# To use this script, refer to this file with either the commit-filter or the -# repo.commit-filter options in cgitrc. -# -# The following environment variables can be used to retrieve the configuration -# of the repository for which this script is called: -# CGIT_REPO_URL ( = repo.url setting ) -# CGIT_REPO_NAME ( = repo.name setting ) -# CGIT_REPO_PATH ( = repo.path setting ) -# CGIT_REPO_OWNER ( = repo.owner setting ) -# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting ) -# CGIT_REPO_SECTION ( = section setting ) -# CGIT_REPO_CLONE_URL ( = repo.clone-url setting ) -# - -regex='' - -# This expression generates links to commits referenced by their SHA1. -regex=$regex' -s|\b([0-9a-fA-F]{7,64})\b|\1|g' - -# This expression generates links to a fictional bugtracker. -regex=$regex' -s|#([0-9]+)\b|#\1|g' - -sed -re "$regex" diff --git a/third_party/cgit/filters/email-gravatar.py b/third_party/cgit/filters/email-gravatar.py deleted file mode 100755 index 012113c59..000000000 --- a/third_party/cgit/filters/email-gravatar.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 - -# This script may be used with the email-filter or repo.email-filter settings in cgitrc. -# -# The following environment variables can be used to retrieve the configuration -# of the repository for which this script is called: -# CGIT_REPO_URL ( = repo.url setting ) -# CGIT_REPO_NAME ( = repo.name setting ) -# CGIT_REPO_PATH ( = repo.path setting ) -# CGIT_REPO_OWNER ( = repo.owner setting ) -# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting ) -# CGIT_REPO_SECTION ( = section setting ) -# CGIT_REPO_CLONE_URL ( = repo.clone-url setting ) -# -# It receives an email address on argv[1] and text on stdin. It prints -# to stdout that text prepended by a gravatar at 10pt. - -import sys -import hashlib -import codecs - -email = sys.argv[1].lower().strip() -if email[0] == '<': - email = email[1:] -if email[-1] == '>': - email = email[0:-1] - -page = sys.argv[2] - -sys.stdin = codecs.getreader("utf-8")(sys.stdin.detach()) -sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach()) - -md5 = hashlib.md5(email.encode()).hexdigest() -text = sys.stdin.read().strip() - -print("Gravatar " + text) diff --git a/third_party/cgit/filters/html-converters/man2html b/third_party/cgit/filters/html-converters/man2html deleted file mode 100755 index 0ef788418..000000000 --- a/third_party/cgit/filters/html-converters/man2html +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -echo "
    " -groff -mandoc -T html -P -r -P -l | egrep -v '(||||||||" diff --git a/third_party/cgit/filters/html-converters/md2html b/third_party/cgit/filters/html-converters/md2html deleted file mode 100755 index 59f43a841..000000000 --- a/third_party/cgit/filters/html-converters/md2html +++ /dev/null @@ -1,304 +0,0 @@ -#!/usr/bin/env python3 -import markdown -import sys -import io -from pygments.formatters import HtmlFormatter -from markdown.extensions.toc import TocExtension -sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8') -sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') -sys.stdout.write(''' - -''') -sys.stdout.write("
    ") -sys.stdout.flush() -# Note: you may want to run this through bleach for sanitization -markdown.markdownFromFile( - output_format="html5", - extensions=[ - "markdown.extensions.fenced_code", - "markdown.extensions.codehilite", - "markdown.extensions.tables", - "markdown.extensions.sane_lists", - TocExtension(anchorlink=True)], - extension_configs={ - "markdown.extensions.codehilite":{"css_class":"highlight"}}) -sys.stdout.write("
    ") diff --git a/third_party/cgit/filters/html-converters/rst2html b/third_party/cgit/filters/html-converters/rst2html deleted file mode 100755 index 02d90f81c..000000000 --- a/third_party/cgit/filters/html-converters/rst2html +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -exec rst2html.py --template <(echo -e "%(stylesheet)s\n%(body_pre_docinfo)s\n%(docinfo)s\n%(body)s") diff --git a/third_party/cgit/filters/html-converters/txt2html b/third_party/cgit/filters/html-converters/txt2html deleted file mode 100755 index 495eeceb2..000000000 --- a/third_party/cgit/filters/html-converters/txt2html +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -echo "
    "
    -sed "s|&|\\&|g;s|'|\\'|g;s|\"|\\"|g;s|<|\\<|g;s|>|\\>|g"
    -echo "
    " diff --git a/third_party/cgit/filters/syntax-highlighting.py b/third_party/cgit/filters/syntax-highlighting.py deleted file mode 100755 index e912594c4..000000000 --- a/third_party/cgit/filters/syntax-highlighting.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 - -# This script uses Pygments and Python3. You must have both installed -# for this to work. -# -# http://pygments.org/ -# http://python.org/ -# -# It may be used with the source-filter or repo.source-filter settings -# in cgitrc. -# -# The following environment variables can be used to retrieve the -# configuration of the repository for which this script is called: -# CGIT_REPO_URL ( = repo.url setting ) -# CGIT_REPO_NAME ( = repo.name setting ) -# CGIT_REPO_PATH ( = repo.path setting ) -# CGIT_REPO_OWNER ( = repo.owner setting ) -# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting ) -# CGIT_REPO_SECTION ( = section setting ) -# CGIT_REPO_CLONE_URL ( = repo.clone-url setting ) - - -import sys -import io -from pygments import highlight -from pygments.util import ClassNotFound -from pygments.lexers import TextLexer -from pygments.lexers import guess_lexer -from pygments.lexers import guess_lexer_for_filename -from pygments.formatters import HtmlFormatter - - -sys.stdin = io.TextIOWrapper(sys.stdin.buffer, encoding='utf-8', errors='replace') -sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') -data = sys.stdin.read() -filename = sys.argv[1] -formatter = HtmlFormatter(style='pastie', nobackground=True) - -try: - lexer = guess_lexer_for_filename(filename, data) -except ClassNotFound: - # check if there is any shebang - if data[0:2] == '#!': - lexer = guess_lexer(data) - else: - lexer = TextLexer() -except TypeError: - lexer = TextLexer() - -# highlight! :-) -# printout pygments' css definitions as well -sys.stdout.write('') -sys.stdout.write(highlight(data, lexer, formatter, outfile=None)) diff --git a/third_party/cgit/filters/syntax-highlighting.sh b/third_party/cgit/filters/syntax-highlighting.sh deleted file mode 100755 index 840bc34ff..000000000 --- a/third_party/cgit/filters/syntax-highlighting.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/sh -# This script can be used to implement syntax highlighting in the cgit -# tree-view by referring to this file with the source-filter or repo.source- -# filter options in cgitrc. -# -# This script requires a shell supporting the ${var##pattern} syntax. -# It is supported by at least dash and bash, however busybox environments -# might have to use an external call to sed instead. -# -# Note: the highlight command (http://www.andre-simon.de/) uses css for syntax -# highlighting, so you'll probably want something like the following included -# in your css file: -# -# Style definition file generated by highlight 2.4.8, http://www.andre-simon.de/ -# -# table.blob .num { color:#2928ff; } -# table.blob .esc { color:#ff00ff; } -# table.blob .str { color:#ff0000; } -# table.blob .dstr { color:#818100; } -# table.blob .slc { color:#838183; font-style:italic; } -# table.blob .com { color:#838183; font-style:italic; } -# table.blob .dir { color:#008200; } -# table.blob .sym { color:#000000; } -# table.blob .kwa { color:#000000; font-weight:bold; } -# table.blob .kwb { color:#830000; } -# table.blob .kwc { color:#000000; font-weight:bold; } -# table.blob .kwd { color:#010181; } -# -# -# Style definition file generated by highlight 2.6.14, http://www.andre-simon.de/ -# -# body.hl { background-color:#ffffff; } -# pre.hl { color:#000000; background-color:#ffffff; font-size:10pt; font-family:'Courier New';} -# .hl.num { color:#2928ff; } -# .hl.esc { color:#ff00ff; } -# .hl.str { color:#ff0000; } -# .hl.dstr { color:#818100; } -# .hl.slc { color:#838183; font-style:italic; } -# .hl.com { color:#838183; font-style:italic; } -# .hl.dir { color:#008200; } -# .hl.sym { color:#000000; } -# .hl.line { color:#555555; } -# .hl.mark { background-color:#ffffbb;} -# .hl.kwa { color:#000000; font-weight:bold; } -# .hl.kwb { color:#830000; } -# .hl.kwc { color:#000000; font-weight:bold; } -# .hl.kwd { color:#010181; } -# -# -# Style definition file generated by highlight 3.8, http://www.andre-simon.de/ -# -# body.hl { background-color:#e0eaee; } -# pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New';} -# .hl.num { color:#b07e00; } -# .hl.esc { color:#ff00ff; } -# .hl.str { color:#bf0303; } -# .hl.pps { color:#818100; } -# .hl.slc { color:#838183; font-style:italic; } -# .hl.com { color:#838183; font-style:italic; } -# .hl.ppc { color:#008200; } -# .hl.opt { color:#000000; } -# .hl.lin { color:#555555; } -# .hl.kwa { color:#000000; font-weight:bold; } -# .hl.kwb { color:#0057ae; } -# .hl.kwc { color:#000000; font-weight:bold; } -# .hl.kwd { color:#010181; } -# -# -# Style definition file generated by highlight 3.13, http://www.andre-simon.de/ -# -# body.hl { background-color:#e0eaee; } -# pre.hl { color:#000000; background-color:#e0eaee; font-size:10pt; font-family:'Courier New',monospace;} -# .hl.num { color:#b07e00; } -# .hl.esc { color:#ff00ff; } -# .hl.str { color:#bf0303; } -# .hl.pps { color:#818100; } -# .hl.slc { color:#838183; font-style:italic; } -# .hl.com { color:#838183; font-style:italic; } -# .hl.ppc { color:#008200; } -# .hl.opt { color:#000000; } -# .hl.ipl { color:#0057ae; } -# .hl.lin { color:#555555; } -# .hl.kwa { color:#000000; font-weight:bold; } -# .hl.kwb { color:#0057ae; } -# .hl.kwc { color:#000000; font-weight:bold; } -# .hl.kwd { color:#010181; } -# -# -# The following environment variables can be used to retrieve the configuration -# of the repository for which this script is called: -# CGIT_REPO_URL ( = repo.url setting ) -# CGIT_REPO_NAME ( = repo.name setting ) -# CGIT_REPO_PATH ( = repo.path setting ) -# CGIT_REPO_OWNER ( = repo.owner setting ) -# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting ) -# CGIT_REPO_SECTION ( = section setting ) -# CGIT_REPO_CLONE_URL ( = repo.clone-url setting ) -# - -# store filename and extension in local vars -BASENAME="$1" -EXTENSION="${BASENAME##*.}" - -[ "${BASENAME}" = "${EXTENSION}" ] && EXTENSION=txt -[ -z "${EXTENSION}" ] && EXTENSION=txt - -# map Makefile and Makefile.* to .mk -[ "${BASENAME%%.*}" = "Makefile" ] && EXTENSION=mk - -# highlight versions 2 and 3 have different commandline options. Specifically, -# the -X option that is used for version 2 is replaced by the -O xhtml option -# for version 3. -# -# Version 2 can be found (for example) on EPEL 5, while version 3 can be -# found (for example) on EPEL 6. -# -# This is for version 2 -exec highlight --force -f -I -X -S "$EXTENSION" 2>/dev/null - -# This is for version 3 -#exec highlight --force -f -I -O xhtml -S "$EXTENSION" 2>/dev/null diff --git a/third_party/cgit/gen-version.sh b/third_party/cgit/gen-version.sh deleted file mode 100755 index 80cf49af4..000000000 --- a/third_party/cgit/gen-version.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# Get version-info specified in Makefile -V=$1 - -# Use `git describe` to get current version if we're inside a git repo -if test "$(git rev-parse --git-dir 2>/dev/null)" = '.git' -then - V=$(git describe --abbrev=4 HEAD 2>/dev/null) -fi - -new="CGIT_VERSION = $V" -old=$(cat VERSION 2>/dev/null) - -# Exit if VERSION is uptodate -test "$old" = "$new" && exit 0 - -# Update VERSION with new version-info -echo "$new" > VERSION -cat VERSION diff --git a/third_party/cgit/html.c b/third_party/cgit/html.c deleted file mode 100644 index ced781adc..000000000 --- a/third_party/cgit/html.c +++ /dev/null @@ -1,344 +0,0 @@ -/* html.c: helper functions for html output - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "html.h" -#include "url.h" - -/* Percent-encoding of each character, except: a-zA-Z0-9!$()*,./:;@- */ -static const char* url_escape_table[256] = { - "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", - "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", - "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", - "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f", - "%20", NULL, "%22", "%23", NULL, "%25", "%26", "%27", - NULL, NULL, NULL, "%2b", NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, "%3c", "%3d", "%3e", "%3f", - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, "%5c", NULL, "%5e", NULL, - "%60", NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, "%7b", "%7c", "%7d", NULL, "%7f", - "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", - "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f", - "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", - "%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f", - "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", - "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af", - "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", - "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", - "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", - "%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf", - "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", - "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df", - "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7", - "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef", - "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", - "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff" -}; - -char *fmt(const char *format, ...) -{ - static char buf[8][1024]; - static int bufidx; - int len; - va_list args; - - bufidx++; - bufidx &= 7; - - va_start(args, format); - len = vsnprintf(buf[bufidx], sizeof(buf[bufidx]), format, args); - va_end(args); - if (len >= sizeof(buf[bufidx])) { - fprintf(stderr, "[html.c] string truncated: %s\n", format); - exit(1); - } - return buf[bufidx]; -} - -char *fmtalloc(const char *format, ...) -{ - struct strbuf sb = STRBUF_INIT; - va_list args; - - va_start(args, format); - strbuf_vaddf(&sb, format, args); - va_end(args); - - return strbuf_detach(&sb, NULL); -} - -void html_raw(const char *data, size_t size) -{ - if (fwrite(data, 1, size, stdout) != size) - die_errno("write error on html output"); -} - -void html(const char *txt) -{ - html_raw(txt, strlen(txt)); -} - -void htmlf(const char *format, ...) -{ - va_list args; - struct strbuf buf = STRBUF_INIT; - - va_start(args, format); - strbuf_vaddf(&buf, format, args); - va_end(args); - html(buf.buf); - strbuf_release(&buf); -} - -void html_txtf(const char *format, ...) -{ - va_list args; - - va_start(args, format); - html_vtxtf(format, args); - va_end(args); -} - -void html_vtxtf(const char *format, va_list ap) -{ - va_list cp; - struct strbuf buf = STRBUF_INIT; - - va_copy(cp, ap); - strbuf_vaddf(&buf, format, cp); - va_end(cp); - html_txt(buf.buf); - strbuf_release(&buf); -} - -void html_txt(const char *txt) -{ - if (txt) - html_ntxt(txt, strlen(txt)); -} - -ssize_t html_ntxt(const char *txt, size_t len) -{ - const char *t = txt; - ssize_t slen; - - if (len > SSIZE_MAX) - return -1; - - slen = (ssize_t) len; - while (t && *t && slen--) { - int c = *t; - if (c == '<' || c == '>' || c == '&') { - html_raw(txt, t - txt); - if (c == '>') - html(">"); - else if (c == '<') - html("<"); - else if (c == '&') - html("&"); - txt = t + 1; - } - t++; - } - if (t != txt) - html_raw(txt, t - txt); - return slen; -} - -void html_attrf(const char *fmt, ...) -{ - va_list ap; - struct strbuf sb = STRBUF_INIT; - - va_start(ap, fmt); - strbuf_vaddf(&sb, fmt, ap); - va_end(ap); - - html_attr(sb.buf); - strbuf_release(&sb); -} - -void html_attr(const char *txt) -{ - const char *t = txt; - while (t && *t) { - int c = *t; - if (c == '<' || c == '>' || c == '\'' || c == '\"' || c == '&') { - html_raw(txt, t - txt); - if (c == '>') - html(">"); - else if (c == '<') - html("<"); - else if (c == '\'') - html("'"); - else if (c == '"') - html("""); - else if (c == '&') - html("&"); - txt = t + 1; - } - t++; - } - if (t != txt) - html(txt); -} - -void html_url_path(const char *txt) -{ - const char *t = txt; - while (t && *t) { - unsigned char c = *t; - const char *e = url_escape_table[c]; - if (e && c != '+' && c != '&') { - html_raw(txt, t - txt); - html(e); - txt = t + 1; - } - t++; - } - if (t != txt) - html(txt); -} - -void html_url_arg(const char *txt) -{ - const char *t = txt; - while (t && *t) { - unsigned char c = *t; - const char *e = url_escape_table[c]; - if (c == ' ') - e = "+"; - if (e) { - html_raw(txt, t - txt); - html(e); - txt = t + 1; - } - t++; - } - if (t != txt) - html(txt); -} - -void html_header_arg_in_quotes(const char *txt) -{ - const char *t = txt; - while (t && *t) { - unsigned char c = *t; - const char *e = NULL; - if (c == '\\') - e = "\\\\"; - else if (c == '\r') - e = "\\r"; - else if (c == '\n') - e = "\\n"; - else if (c == '"') - e = "\\\""; - if (e) { - html_raw(txt, t - txt); - html(e); - txt = t + 1; - } - t++; - } - if (t != txt) - html(txt); - -} - -void html_hidden(const char *name, const char *value) -{ - html(""); -} - -void html_option(const char *value, const char *text, const char *selected_value) -{ - html("\n"); -} - -void html_intoption(int value, const char *text, int selected_value) -{ - htmlf(""); -} - -void html_link_open(const char *url, const char *title, const char *class) -{ - html(""); -} - -void html_link_close(void) -{ - html(""); -} - -void html_fileperm(unsigned short mode) -{ - htmlf("%c%c%c", (mode & 4 ? 'r' : '-'), - (mode & 2 ? 'w' : '-'), (mode & 1 ? 'x' : '-')); -} - -int html_include(const char *filename) -{ - FILE *f; - char buf[4096]; - size_t len; - - if (!(f = fopen(filename, "r"))) { - fprintf(stderr, "[cgit] Failed to include file %s: %s (%d).\n", - filename, strerror(errno), errno); - return -1; - } - while ((len = fread(buf, 1, 4096, f)) > 0) - html_raw(buf, len); - fclose(f); - return 0; -} - -void http_parse_querystring(const char *txt, void (*fn)(const char *name, const char *value)) -{ - const char *t = txt; - - while (t && *t) { - char *name = url_decode_parameter_name(&t); - if (*name) { - char *value = url_decode_parameter_value(&t); - fn(name, value); - free(value); - } - free(name); - } -} diff --git a/third_party/cgit/html.h b/third_party/cgit/html.h deleted file mode 100644 index fa4de7758..000000000 --- a/third_party/cgit/html.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HTML_H -#define HTML_H - -#include "cgit.h" - -extern void html_raw(const char *txt, size_t size); -extern void html(const char *txt); - -__attribute__((format (printf,1,2))) -extern void htmlf(const char *format,...); - -__attribute__((format (printf,1,2))) -extern void html_txtf(const char *format,...); - -__attribute__((format (printf,1,0))) -extern void html_vtxtf(const char *format, va_list ap); - -__attribute__((format (printf,1,2))) -extern void html_attrf(const char *format,...); - -extern void html_txt(const char *txt); -extern ssize_t html_ntxt(const char *txt, size_t len); -extern void html_attr(const char *txt); -extern void html_url_path(const char *txt); -extern void html_url_arg(const char *txt); -extern void html_header_arg_in_quotes(const char *txt); -extern void html_hidden(const char *name, const char *value); -extern void html_option(const char *value, const char *text, const char *selected_value); -extern void html_intoption(int value, const char *text, int selected_value); -extern void html_link_open(const char *url, const char *title, const char *class); -extern void html_link_close(void); -extern void html_fileperm(unsigned short mode); -extern int html_include(const char *filename); - -extern void http_parse_querystring(const char *txt, void (*fn)(const char *name, const char *value)); - -#endif /* HTML_H */ diff --git a/third_party/cgit/parsing.c b/third_party/cgit/parsing.c deleted file mode 100644 index 83d3521e8..000000000 --- a/third_party/cgit/parsing.c +++ /dev/null @@ -1,223 +0,0 @@ -/* parsing.c: parsing of config files - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" - -/* - * url syntax: [repo ['/' cmd [ '/' path]]] - * repo: any valid repo url, may contain '/' - * cmd: log | commit | diff | tree | view | blob | snapshot - * path: any valid path, may contain '/' - * - */ -void cgit_parse_url(const char *url) -{ - char *c, *cmd, *p; - struct cgit_repo *repo; - - if (!url || url[0] == '\0') - return; - - ctx.qry.page = NULL; - ctx.repo = cgit_get_repoinfo(url); - if (ctx.repo) { - ctx.qry.repo = ctx.repo->url; - return; - } - - cmd = NULL; - c = strchr(url, '/'); - while (c) { - c[0] = '\0'; - repo = cgit_get_repoinfo(url); - if (repo) { - ctx.repo = repo; - cmd = c; - } - c[0] = '/'; - c = strchr(c + 1, '/'); - } - - if (ctx.repo) { - ctx.qry.repo = ctx.repo->url; - p = strchr(cmd + 1, '/'); - if (p) { - p[0] = '\0'; - if (p[1]) - ctx.qry.path = trim_end(p + 1, '/'); - } - if (cmd[1]) - ctx.qry.page = xstrdup(cmd + 1); - } -} - -static char *substr(const char *head, const char *tail) -{ - char *buf; - - if (tail < head) - return xstrdup(""); - buf = xmalloc(tail - head + 1); - strlcpy(buf, head, tail - head + 1); - return buf; -} - -static void parse_user(const char *t, char **name, char **email, unsigned long *date, int *tz) -{ - struct ident_split ident; - unsigned email_len; - - if (!split_ident_line(&ident, t, (uintptr_t)strchrnul(t, '\n') - (uintptr_t)t)) { - *name = substr(ident.name_begin, ident.name_end); - - email_len = ident.mail_end - ident.mail_begin; - *email = xmalloc(strlen("<") + email_len + strlen(">") + 1); - xsnprintf(*email, email_len + 3, "<%.*s>", email_len, ident.mail_begin); - - if (ident.date_begin) - *date = strtoul(ident.date_begin, NULL, 10); - if (ident.tz_begin) - *tz = atoi(ident.tz_begin); - } -} - -#ifdef NO_ICONV -#define reencode(a, b, c) -#else -static const char *reencode(char **txt, const char *src_enc, const char *dst_enc) -{ - char *tmp; - - if (!txt) - return NULL; - - if (!*txt || !src_enc || !dst_enc) - return *txt; - - /* no encoding needed if src_enc equals dst_enc */ - if (!strcasecmp(src_enc, dst_enc)) - return *txt; - - tmp = reencode_string(*txt, dst_enc, src_enc); - if (tmp) { - free(*txt); - *txt = tmp; - } - return *txt; -} -#endif - -static const char *next_header_line(const char *p) -{ - p = strchr(p, '\n'); - if (!p) - return NULL; - return p + 1; -} - -static int end_of_header(const char *p) -{ - return !p || (*p == '\n'); -} - -struct commitinfo *cgit_parse_commit(struct commit *commit) -{ - struct commitinfo *ret; - const char *p = repo_get_commit_buffer(the_repository, commit, NULL); - const char *t; - - ret = xcalloc(1, sizeof(struct commitinfo)); - ret->commit = commit; - - if (!p) - return ret; - - if (!skip_prefix(p, "tree ", &p)) - die("Bad commit: %s", oid_to_hex(&commit->object.oid)); - p += the_hash_algo->hexsz + 1; - - while (skip_prefix(p, "parent ", &p)) - p += the_hash_algo->hexsz + 1; - - if (p && skip_prefix(p, "author ", &p)) { - parse_user(p, &ret->author, &ret->author_email, - &ret->author_date, &ret->author_tz); - p = next_header_line(p); - } - - if (p && skip_prefix(p, "committer ", &p)) { - parse_user(p, &ret->committer, &ret->committer_email, - &ret->committer_date, &ret->committer_tz); - p = next_header_line(p); - } - - if (p && skip_prefix(p, "encoding ", &p)) { - t = strchr(p, '\n'); - if (t) { - ret->msg_encoding = substr(p, t + 1); - p = t + 1; - } - } - - if (!ret->msg_encoding) - ret->msg_encoding = xstrdup("UTF-8"); - - while (!end_of_header(p)) - p = next_header_line(p); - while (p && *p == '\n') - p++; - if (!p) - return ret; - - t = strchrnul(p, '\n'); - ret->subject = substr(p, t); - while (*t == '\n') - t++; - ret->msg = xstrdup(t); - - reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING); - reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING); - reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING); - reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING); - reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING); - reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING); - - return ret; -} - -struct taginfo *cgit_parse_tag(struct tag *tag) -{ - void *data; - enum object_type type; - unsigned long size; - const char *p; - struct taginfo *ret = NULL; - - data = repo_read_object_file(the_repository, &tag->object.oid, &type, &size); - if (!data || type != OBJ_TAG) - goto cleanup; - - ret = xcalloc(1, sizeof(struct taginfo)); - - for (p = data; !end_of_header(p); p = next_header_line(p)) { - if (skip_prefix(p, "tagger ", &p)) { - parse_user(p, &ret->tagger, &ret->tagger_email, - &ret->tagger_date, &ret->tagger_tz); - } - } - - while (p && *p == '\n') - p++; - - if (p && *p) - ret->msg = xstrdup(p); - -cleanup: - free(data); - return ret; -} diff --git a/third_party/cgit/robots.txt b/third_party/cgit/robots.txt deleted file mode 100644 index 1b33266d5..000000000 --- a/third_party/cgit/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -User-agent: * -Disallow: /*/snapshot/* -Disallow: /*/blame/* -Allow: / diff --git a/third_party/cgit/scan-tree.c b/third_party/cgit/scan-tree.c deleted file mode 100644 index aa9366542..000000000 --- a/third_party/cgit/scan-tree.c +++ /dev/null @@ -1,268 +0,0 @@ -/* scan-tree.c - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "scan-tree.h" -#include "configfile.h" -#include "html.h" -#include - -/* return 1 if path contains a objects/ directory and a HEAD file */ -static int is_git_dir(const char *path) -{ - struct stat st; - struct strbuf pathbuf = STRBUF_INIT; - int result = 0; - - strbuf_addf(&pathbuf, "%s/objects", path); - if (stat(pathbuf.buf, &st)) { - if (errno != ENOENT) - fprintf(stderr, "Error checking path %s: %s (%d)\n", - path, strerror(errno), errno); - goto out; - } - if (!S_ISDIR(st.st_mode)) - goto out; - - strbuf_reset(&pathbuf); - strbuf_addf(&pathbuf, "%s/HEAD", path); - if (stat(pathbuf.buf, &st)) { - if (errno != ENOENT) - fprintf(stderr, "Error checking path %s: %s (%d)\n", - path, strerror(errno), errno); - goto out; - } - if (!S_ISREG(st.st_mode)) - goto out; - - result = 1; -out: - strbuf_release(&pathbuf); - return result; -} - -static struct cgit_repo *repo; -static repo_config_fn config_fn; - -static void scan_tree_repo_config(const char *name, const char *value) -{ - config_fn(repo, name, value); -} - -static int gitconfig_config(const char *key, const char *value, const struct config_context *, void *cb) -{ - const char *name; - - if (!strcmp(key, "gitweb.owner")) - config_fn(repo, "owner", value); - else if (!strcmp(key, "gitweb.description")) - config_fn(repo, "desc", value); - else if (!strcmp(key, "gitweb.category")) - config_fn(repo, "section", value); - else if (!strcmp(key, "gitweb.homepage")) - config_fn(repo, "homepage", value); - else if (skip_prefix(key, "cgit.", &name)) - config_fn(repo, name, value); - - return 0; -} - -static char *xstrrchr(char *s, char *from, int c) -{ - while (from >= s && *from != c) - from--; - return from < s ? NULL : from; -} - -static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn) -{ - struct stat st; - struct passwd *pwd; - size_t pathlen; - struct strbuf rel = STRBUF_INIT; - char *p, *slash; - int n; - size_t size; - - if (stat(path->buf, &st)) { - fprintf(stderr, "Error accessing %s: %s (%d)\n", - path->buf, strerror(errno), errno); - return; - } - - strbuf_addch(path, '/'); - pathlen = path->len; - - if (ctx.cfg.strict_export) { - strbuf_addstr(path, ctx.cfg.strict_export); - if(stat(path->buf, &st)) - return; - strbuf_setlen(path, pathlen); - } - - strbuf_addstr(path, "noweb"); - if (!stat(path->buf, &st)) - return; - strbuf_setlen(path, pathlen); - - if (!starts_with(path->buf, base)) - strbuf_addbuf(&rel, path); - else - strbuf_addstr(&rel, path->buf + strlen(base) + 1); - - if (!strcmp(rel.buf + rel.len - 5, "/.git")) - strbuf_setlen(&rel, rel.len - 5); - else if (rel.len && rel.buf[rel.len - 1] == '/') - strbuf_setlen(&rel, rel.len - 1); - - repo = cgit_add_repo(rel.buf); - config_fn = fn; - if (ctx.cfg.enable_git_config) { - strbuf_addstr(path, "config"); - git_config_from_file(gitconfig_config, path->buf, NULL); - strbuf_setlen(path, pathlen); - } - - if (ctx.cfg.remove_suffix) { - size_t urllen; - strip_suffix(repo->url, ".git", &urllen); - strip_suffix_mem(repo->url, &urllen, "/"); - repo->url[urllen] = '\0'; - } - repo->path = xstrdup(path->buf); - while (!repo->owner) { - if ((pwd = getpwuid(st.st_uid)) == NULL) { - break; - } - if (pwd->pw_gecos) - if ((p = strchr(pwd->pw_gecos, ','))) - *p = '\0'; - repo->owner = xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name); - } - - if (repo->desc == cgit_default_repo_desc || !repo->desc) { - strbuf_addstr(path, "description"); - if (!stat(path->buf, &st)) - readfile(path->buf, &repo->desc, &size); - strbuf_setlen(path, pathlen); - } - - if (ctx.cfg.section_from_path) { - n = ctx.cfg.section_from_path; - if (n > 0) { - slash = rel.buf - 1; - while (slash && n && (slash = strchr(slash + 1, '/'))) - n--; - } else { - slash = rel.buf + rel.len; - while (slash && n && (slash = xstrrchr(rel.buf, slash - 1, '/'))) - n++; - } - if (slash && !n) { - *slash = '\0'; - repo->section = xstrdup(rel.buf); - *slash = '/'; - if (starts_with(repo->name, repo->section)) { - repo->name += strlen(repo->section); - if (*repo->name == '/') - repo->name++; - } - } - } - - strbuf_addstr(path, "cgitrc"); - if (!stat(path->buf, &st)) - parse_configfile(path->buf, &scan_tree_repo_config); - - strbuf_release(&rel); -} - -static void scan_path(const char *base, const char *path, repo_config_fn fn) -{ - DIR *dir = opendir(path); - struct dirent *ent; - struct strbuf pathbuf = STRBUF_INIT; - size_t pathlen = strlen(path); - struct stat st; - - if (!dir) { - fprintf(stderr, "Error opening directory %s: %s (%d)\n", - path, strerror(errno), errno); - return; - } - - strbuf_add(&pathbuf, path, strlen(path)); - if (is_git_dir(pathbuf.buf)) { - add_repo(base, &pathbuf, fn); - goto end; - } - strbuf_addstr(&pathbuf, "/.git"); - if (is_git_dir(pathbuf.buf)) { - add_repo(base, &pathbuf, fn); - goto end; - } - /* - * Add one because we don't want to lose the trailing '/' when we - * reset the length of pathbuf in the loop below. - */ - pathlen++; - while ((ent = readdir(dir)) != NULL) { - if (ent->d_name[0] == '.') { - if (ent->d_name[1] == '\0') - continue; - if (ent->d_name[1] == '.' && ent->d_name[2] == '\0') - continue; - if (!ctx.cfg.scan_hidden_path) - continue; - } - strbuf_setlen(&pathbuf, pathlen); - strbuf_addstr(&pathbuf, ent->d_name); - if (stat(pathbuf.buf, &st)) { - fprintf(stderr, "Error checking path %s: %s (%d)\n", - pathbuf.buf, strerror(errno), errno); - continue; - } - if (S_ISDIR(st.st_mode)) - scan_path(base, pathbuf.buf, fn); - } -end: - strbuf_release(&pathbuf); - closedir(dir); -} - -void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn) -{ - struct strbuf line = STRBUF_INIT; - FILE *projects; - int err; - - projects = fopen(projectsfile, "r"); - if (!projects) { - fprintf(stderr, "Error opening projectsfile %s: %s (%d)\n", - projectsfile, strerror(errno), errno); - return; - } - while (strbuf_getline(&line, projects) != EOF) { - if (!line.len) - continue; - strbuf_insert(&line, 0, "/", 1); - strbuf_insert(&line, 0, path, strlen(path)); - scan_path(path, line.buf, fn); - } - if ((err = ferror(projects))) { - fprintf(stderr, "Error reading from projectsfile %s: %s (%d)\n", - projectsfile, strerror(err), err); - } - fclose(projects); - strbuf_release(&line); -} - -void scan_tree(const char *path, repo_config_fn fn) -{ - scan_path(path, path, fn); -} diff --git a/third_party/cgit/scan-tree.h b/third_party/cgit/scan-tree.h deleted file mode 100644 index 1afbd4bbc..000000000 --- a/third_party/cgit/scan-tree.h +++ /dev/null @@ -1,2 +0,0 @@ -extern void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn); -extern void scan_tree(const char *path, repo_config_fn fn); diff --git a/third_party/cgit/shared.c b/third_party/cgit/shared.c deleted file mode 100644 index 26b6ddb32..000000000 --- a/third_party/cgit/shared.c +++ /dev/null @@ -1,582 +0,0 @@ -/* shared.c: global vars + some callback functions - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" - -struct cgit_repolist cgit_repolist; -struct cgit_context ctx; - -int chk_zero(int result, char *msg) -{ - if (result != 0) - die_errno("%s", msg); - return result; -} - -int chk_positive(int result, char *msg) -{ - if (result <= 0) - die_errno("%s", msg); - return result; -} - -int chk_non_negative(int result, char *msg) -{ - if (result < 0) - die_errno("%s", msg); - return result; -} - -char *cgit_default_repo_desc = "[no description]"; -struct cgit_repo *cgit_add_repo(const char *url) -{ - struct cgit_repo *ret; - - if (++cgit_repolist.count > cgit_repolist.length) { - if (cgit_repolist.length == 0) - cgit_repolist.length = 8; - else - cgit_repolist.length *= 2; - cgit_repolist.repos = xrealloc(cgit_repolist.repos, - cgit_repolist.length * - sizeof(struct cgit_repo)); - } - - ret = &cgit_repolist.repos[cgit_repolist.count-1]; - memset(ret, 0, sizeof(struct cgit_repo)); - ret->url = trim_end(url, '/'); - ret->name = ret->url; - ret->path = NULL; - ret->desc = cgit_default_repo_desc; - ret->extra_head_content = NULL; - ret->owner = NULL; - ret->homepage = NULL; - ret->section = ctx.cfg.section; - ret->snapshots = ctx.cfg.snapshots; - ret->enable_blame = ctx.cfg.enable_blame; - ret->enable_commit_graph = ctx.cfg.enable_commit_graph; - ret->enable_log_filecount = ctx.cfg.enable_log_filecount; - ret->enable_log_linecount = ctx.cfg.enable_log_linecount; - ret->enable_remote_branches = ctx.cfg.enable_remote_branches; - ret->enable_subject_links = ctx.cfg.enable_subject_links; - ret->enable_html_serving = ctx.cfg.enable_html_serving; - ret->max_stats = ctx.cfg.max_stats; - ret->branch_sort = ctx.cfg.branch_sort; - ret->commit_sort = ctx.cfg.commit_sort; - ret->module_link = ctx.cfg.module_link; - ret->readme = ctx.cfg.readme; - ret->mtime = -1; - ret->about_filter = ctx.cfg.about_filter; - ret->commit_filter = ctx.cfg.commit_filter; - ret->source_filter = ctx.cfg.source_filter; - ret->email_filter = ctx.cfg.email_filter; - ret->owner_filter = ctx.cfg.owner_filter; - ret->clone_url = ctx.cfg.clone_url; - ret->submodules.strdup_strings = 1; - ret->hide = ret->ignore = 0; - return ret; -} - -struct cgit_repo *cgit_get_repoinfo(const char *url) -{ - int i; - struct cgit_repo *repo; - - for (i = 0; i < cgit_repolist.count; i++) { - repo = &cgit_repolist.repos[i]; - if (repo->ignore) - continue; - if (!strcmp(repo->url, url)) - return repo; - } - return NULL; -} - -void cgit_free_commitinfo(struct commitinfo *info) -{ - free(info->author); - free(info->author_email); - free(info->committer); - free(info->committer_email); - free(info->subject); - free(info->msg); - free(info->msg_encoding); - free(info); -} - -char *trim_end(const char *str, char c) -{ - int len; - - if (str == NULL) - return NULL; - len = strlen(str); - while (len > 0 && str[len - 1] == c) - len--; - if (len == 0) - return NULL; - return xstrndup(str, len); -} - -char *ensure_end(const char *str, char c) -{ - size_t len = strlen(str); - char *result; - - if (len && str[len - 1] == c) - return xstrndup(str, len); - - result = xmalloc(len + 2); - memcpy(result, str, len); - result[len] = '/'; - result[len + 1] = '\0'; - return result; -} - -void strbuf_ensure_end(struct strbuf *sb, char c) -{ - if (!sb->len || sb->buf[sb->len - 1] != c) - strbuf_addch(sb, c); -} - -void cgit_add_ref(struct reflist *list, struct refinfo *ref) -{ - size_t size; - - if (list->count >= list->alloc) { - list->alloc += (list->alloc ? list->alloc : 4); - size = list->alloc * sizeof(struct refinfo *); - list->refs = xrealloc(list->refs, size); - } - list->refs[list->count++] = ref; -} - -static struct refinfo *cgit_mk_refinfo(const char *refname, const struct object_id *oid) -{ - struct refinfo *ref; - - ref = xmalloc(sizeof (struct refinfo)); - ref->refname = xstrdup(refname); - ref->object = parse_object(the_repository, oid); - switch (ref->object->type) { - case OBJ_TAG: - ref->tag = cgit_parse_tag((struct tag *)ref->object); - break; - case OBJ_COMMIT: - ref->commit = cgit_parse_commit((struct commit *)ref->object); - break; - } - return ref; -} - -void cgit_free_taginfo(struct taginfo *tag) -{ - if (tag->tagger) - free(tag->tagger); - if (tag->tagger_email) - free(tag->tagger_email); - if (tag->msg) - free(tag->msg); - free(tag); -} - -static void cgit_free_refinfo(struct refinfo *ref) -{ - if (ref->refname) - free((char *)ref->refname); - switch (ref->object->type) { - case OBJ_TAG: - cgit_free_taginfo(ref->tag); - break; - case OBJ_COMMIT: - cgit_free_commitinfo(ref->commit); - break; - } - free(ref); -} - -void cgit_free_reflist_inner(struct reflist *list) -{ - int i; - - for (i = 0; i < list->count; i++) { - cgit_free_refinfo(list->refs[i]); - } - free(list->refs); -} - -int cgit_refs_cb(const char *refname, const struct object_id *oid, int flags, - void *cb_data) -{ - struct reflist *list = (struct reflist *)cb_data; - struct refinfo *info = cgit_mk_refinfo(refname, oid); - - if (info) - cgit_add_ref(list, info); - return 0; -} - -void cgit_diff_tree_cb(struct diff_queue_struct *q, - struct diff_options *options, void *data) -{ - int i; - - for (i = 0; i < q->nr; i++) { - if (q->queue[i]->status == 'U') - continue; - ((filepair_fn)data)(q->queue[i]); - } -} - -static int load_mmfile(mmfile_t *file, const struct object_id *oid) -{ - enum object_type type; - - if (is_null_oid(oid)) { - file->ptr = (char *)""; - file->size = 0; - } else { - file->ptr = repo_read_object_file(the_repository, oid, &type, - (unsigned long *)&file->size); - } - return 1; -} - -/* - * Receive diff-buffers from xdiff and concatenate them as - * needed across multiple callbacks. - * - * This is basically a copy of xdiff-interface.c/xdiff_outf(), - * ripped from git and modified to use globals instead of - * a special callback-struct. - */ -static char *diffbuf = NULL; -static int buflen = 0; - -static int filediff_cb(void *priv, mmbuffer_t *mb, int nbuf) -{ - int i; - - for (i = 0; i < nbuf; i++) { - if (mb[i].ptr[mb[i].size-1] != '\n') { - /* Incomplete line */ - diffbuf = xrealloc(diffbuf, buflen + mb[i].size); - memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); - buflen += mb[i].size; - continue; - } - - /* we have a complete line */ - if (!diffbuf) { - ((linediff_fn)priv)(mb[i].ptr, mb[i].size); - continue; - } - diffbuf = xrealloc(diffbuf, buflen + mb[i].size); - memcpy(diffbuf + buflen, mb[i].ptr, mb[i].size); - ((linediff_fn)priv)(diffbuf, buflen + mb[i].size); - free(diffbuf); - diffbuf = NULL; - buflen = 0; - } - if (diffbuf) { - ((linediff_fn)priv)(diffbuf, buflen); - free(diffbuf); - diffbuf = NULL; - buflen = 0; - } - return 0; -} - -int cgit_diff_files(const struct object_id *old_oid, - const struct object_id *new_oid, unsigned long *old_size, - unsigned long *new_size, int *binary, int context, - int ignorews, linediff_fn fn) -{ - mmfile_t file1, file2; - xpparam_t diff_params; - xdemitconf_t emit_params; - xdemitcb_t emit_cb; - - if (!load_mmfile(&file1, old_oid) || !load_mmfile(&file2, new_oid)) - return 1; - - *old_size = file1.size; - *new_size = file2.size; - - if ((file1.ptr && buffer_is_binary(file1.ptr, file1.size)) || - (file2.ptr && buffer_is_binary(file2.ptr, file2.size))) { - *binary = 1; - if (file1.size) - free(file1.ptr); - if (file2.size) - free(file2.ptr); - return 0; - } - - memset(&diff_params, 0, sizeof(diff_params)); - memset(&emit_params, 0, sizeof(emit_params)); - memset(&emit_cb, 0, sizeof(emit_cb)); - diff_params.flags = XDF_NEED_MINIMAL; - if (ignorews) - diff_params.flags |= XDF_IGNORE_WHITESPACE; - emit_params.ctxlen = context > 0 ? context : 3; - emit_params.flags = XDL_EMIT_FUNCNAMES; - emit_cb.out_line = filediff_cb; - emit_cb.priv = fn; - xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb); - if (file1.size) - free(file1.ptr); - if (file2.size) - free(file2.ptr); - return 0; -} - -void cgit_diff_tree(const struct object_id *old_oid, - const struct object_id *new_oid, - filepair_fn fn, const char *prefix, int ignorews) -{ - struct diff_options opt; - struct pathspec_item *item; - - repo_diff_setup(the_repository, &opt); - opt.output_format = DIFF_FORMAT_CALLBACK; - opt.detect_rename = 1; - opt.rename_limit = ctx.cfg.renamelimit; - opt.flags.recursive = 1; - if (ignorews) - DIFF_XDL_SET(&opt, IGNORE_WHITESPACE); - opt.format_callback = cgit_diff_tree_cb; - opt.format_callback_data = fn; - if (prefix) { - item = xcalloc(1, sizeof(*item)); - item->match = xstrdup(prefix); - item->len = strlen(prefix); - opt.pathspec.nr = 1; - opt.pathspec.items = item; - } - diff_setup_done(&opt); - - if (old_oid && !is_null_oid(old_oid)) - diff_tree_oid(old_oid, new_oid, "", &opt); - else - diff_root_tree_oid(new_oid, "", &opt); - diffcore_std(&opt); - diff_flush(&opt); -} - -void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix) -{ - const struct object_id *old_oid = NULL; - - if (commit->parents) - old_oid = &commit->parents->item->object.oid; - cgit_diff_tree(old_oid, &commit->object.oid, fn, prefix, - ctx.qry.ignorews); -} - -int cgit_parse_snapshots_mask(const char *str) -{ - struct string_list tokens = STRING_LIST_INIT_DUP; - struct string_list_item *item; - const struct cgit_snapshot_format *f; - int rv = 0; - - /* favor legacy setting */ - if (atoi(str)) - return 1; - - if (strcmp(str, "all") == 0) - return INT_MAX; - - string_list_split(&tokens, str, ' ', -1); - string_list_remove_empty_items(&tokens, 0); - - for_each_string_list_item(item, &tokens) { - for (f = cgit_snapshot_formats; f->suffix; f++) { - if (!strcmp(item->string, f->suffix) || - !strcmp(item->string, f->suffix + 1)) { - rv |= cgit_snapshot_format_bit(f); - break; - } - } - } - - string_list_clear(&tokens, 0); - return rv; -} - -typedef struct { - char * name; - char * value; -} cgit_env_var; - -void cgit_prepare_repo_env(struct cgit_repo * repo) -{ - cgit_env_var env_vars[] = { - { .name = "CGIT_REPO_URL", .value = repo->url }, - { .name = "CGIT_REPO_NAME", .value = repo->name }, - { .name = "CGIT_REPO_PATH", .value = repo->path }, - { .name = "CGIT_REPO_OWNER", .value = repo->owner }, - { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch }, - { .name = "CGIT_REPO_SECTION", .value = repo->section }, - { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url } - }; - int env_var_count = ARRAY_SIZE(env_vars); - cgit_env_var *p, *q; - static char *warn = "cgit warning: failed to set env: %s=%s\n"; - - p = env_vars; - q = p + env_var_count; - for (; p < q; p++) - if (p->value && setenv(p->name, p->value, 1)) - fprintf(stderr, warn, p->name, p->value); -} - -/* Read the content of the specified file into a newly allocated buffer, - * zeroterminate the buffer and return 0 on success, errno otherwise. - */ -int readfile(const char *path, char **buf, size_t *size) -{ - int fd, e; - struct stat st; - - fd = open(path, O_RDONLY); - if (fd == -1) - return errno; - if (fstat(fd, &st)) { - e = errno; - close(fd); - return e; - } - if (!S_ISREG(st.st_mode)) { - close(fd); - return EISDIR; - } - *buf = xmalloc(st.st_size + 1); - *size = read_in_full(fd, *buf, st.st_size); - e = errno; - (*buf)[*size] = '\0'; - close(fd); - return (*size == st.st_size ? 0 : e); -} - -static int is_token_char(char c) -{ - return isalnum(c) || c == '_'; -} - -/* Replace name with getenv(name), return pointer to zero-terminating char - */ -static char *expand_macro(char *name, int maxlength) -{ - char *value; - size_t len; - - len = 0; - value = getenv(name); - if (value) { - len = strlen(value) + 1; - if (len > maxlength) - len = maxlength; - strlcpy(name, value, len); - --len; - } - return name + len; -} - -#define EXPBUFSIZE (1024 * 8) - -/* Replace all tokens prefixed by '$' in the specified text with the - * value of the named environment variable. - * NB: the return value is a static buffer, i.e. it must be strdup'd - * by the caller. - */ -char *expand_macros(const char *txt) -{ - static char result[EXPBUFSIZE]; - char *p, *start; - int len; - - p = result; - start = NULL; - while (p < result + EXPBUFSIZE - 1 && txt && *txt) { - *p = *txt; - if (start) { - if (!is_token_char(*txt)) { - if (p - start > 0) { - *p = '\0'; - len = result + EXPBUFSIZE - start - 1; - p = expand_macro(start, len) - 1; - } - start = NULL; - txt--; - } - p++; - txt++; - continue; - } - if (*txt == '$') { - start = p; - txt++; - continue; - } - p++; - txt++; - } - *p = '\0'; - if (start && p - start > 0) { - len = result + EXPBUFSIZE - start - 1; - p = expand_macro(start, len); - *p = '\0'; - } - return result; -} - -char *get_mimetype_for_filename(const char *filename) -{ - char *ext, *mimetype, line[1024]; - struct string_list list = STRING_LIST_INIT_NODUP; - int i; - FILE *file; - struct string_list_item *mime; - - if (!filename) - return NULL; - - ext = strrchr(filename, '.'); - if (!ext) - return NULL; - ++ext; - if (!ext[0]) - return NULL; - mime = string_list_lookup(&ctx.cfg.mimetypes, ext); - if (mime) - return xstrdup(mime->util); - - if (!ctx.cfg.mimetype_file) - return NULL; - file = fopen(ctx.cfg.mimetype_file, "r"); - if (!file) - return NULL; - while (fgets(line, sizeof(line), file)) { - if (!line[0] || line[0] == '#') - continue; - string_list_split_in_place(&list, line, " \t\r\n", -1); - string_list_remove_empty_items(&list, 0); - mimetype = list.items[0].string; - for (i = 1; i < list.nr; i++) { - if (!strcasecmp(ext, list.items[i].string)) { - fclose(file); - return xstrdup(mimetype); - } - } - string_list_clear(&list, 0); - } - fclose(file); - return NULL; -} diff --git a/third_party/cgit/tests/.gitignore b/third_party/cgit/tests/.gitignore deleted file mode 100644 index 3fd2e965c..000000000 --- a/third_party/cgit/tests/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -trash\ directory.t* -test-results diff --git a/third_party/cgit/tests/Makefile b/third_party/cgit/tests/Makefile deleted file mode 100644 index 65e111733..000000000 --- a/third_party/cgit/tests/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -include ../git/config.mak.uname --include ../cgit.conf - -SHELL_PATH ?= $(SHELL) -SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) - -T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) - -all: $(T) - -$(T): - @'$(SHELL_PATH_SQ)' $@ $(CGIT_TEST_OPTS) - -clean: - $(RM) -rf trash - -.PHONY: $(T) clean diff --git a/third_party/cgit/tests/filters/dump.sh b/third_party/cgit/tests/filters/dump.sh deleted file mode 100755 index da6f7a1b1..000000000 --- a/third_party/cgit/tests/filters/dump.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -[ "$#" -gt 0 ] && printf "%s " "$*" -tr '[:lower:]' '[:upper:]' diff --git a/third_party/cgit/tests/setup.sh b/third_party/cgit/tests/setup.sh deleted file mode 100755 index 31e7d5bb2..000000000 --- a/third_party/cgit/tests/setup.sh +++ /dev/null @@ -1,161 +0,0 @@ -# This file should be sourced by all test-scripts -# -# Main functions: -# prepare_tests(description) - setup for testing, i.e. create repos+config -# run_test(description, script) - run one test, i.e. eval script -# -# Helper functions -# cgit_query(querystring) - call cgit with the specified querystring -# cgit_url(url) - call cgit with the specified virtual url -# -# Example script: -# -# . setup.sh -# prepare_tests "html validation" -# run_test 'repo index' 'cgit_url "/" | tidy -e' -# run_test 'repo summary' 'cgit_url "/foo" | tidy -e' - -# We don't want to run Git commands through Valgrind, so we filter out the -# --valgrind option here and handle it ourselves. We copy the arguments -# assuming that none contain a newline, although other whitespace is -# preserved. -LF=' -' -test_argv= - -while test $# != 0 -do - case "$1" in - --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind) - cgit_valgrind=t - test_argv="$test_argv${LF}--verbose" - ;; - *) - test_argv="$test_argv$LF$1" - ;; - esac - shift -done - -OLDIFS=$IFS -IFS=$LF -set -- $test_argv -IFS=$OLDIFS - -: ${TEST_DIRECTORY=$(pwd)/../git/t} -: ${TEST_OUTPUT_DIRECTORY=$(pwd)} -TEST_NO_CREATE_REPO=YesPlease -. "$TEST_DIRECTORY"/test-lib.sh - -# Prepend the directory containing cgit to PATH. -if test -n "$cgit_valgrind" -then - GIT_VALGRIND="$TEST_DIRECTORY/valgrind" - CGIT_VALGRIND=$(cd ../valgrind && pwd) - PATH="$CGIT_VALGRIND/bin:$PATH" - export GIT_VALGRIND CGIT_VALGRIND -else - PATH="$(pwd)/../..:$PATH" -fi - -FILTER_DIRECTORY=$(cd ../filters && pwd) - -mkrepo() { - name=$1 - count=$2 - test_create_repo "$name" - ( - cd "$name" - n=1 - while test $n -le $count - do - echo $n >file-$n - git add file-$n - git commit -m "commit $n" - n=$(expr $n + 1) - done - case "$3" in - testplus) - echo "hello" >a+b - git add a+b - git commit -m "add a+b" - git branch "1+2" - ;; - commit-graph) - git commit-graph write - ;; - esac - ) -} - -setup_repos() -{ - rm -rf cache - mkdir -p cache - mkrepo repos/foo 5 >/dev/null - mkrepo repos/bar 50 commit-graph >/dev/null - mkrepo repos/foo+bar 10 testplus >/dev/null - mkrepo "repos/with space" 2 >/dev/null - mkrepo repos/filter 5 testplus >/dev/null - cat >cgitrc <makefile_version -' - -# Note that Git's GIT-VERSION-GEN script applies "s/-/./g" to the version -# string to produce the internal version in the GIT-VERSION-FILE, so we -# must apply the same transformation to the version in the Makefile before -# comparing them. -test_expect_success 'test Git version matches Makefile' ' - ( cat ../../git/GIT-VERSION-FILE || echo "No GIT-VERSION-FILE" ) | - sed -e "s/GIT_VERSION[ ]*=[ ]*//" -e "s/\\.dirty$//" >git_version && - sed -e "s/-/./g" makefile_version >makefile_git_version && - test_cmp git_version makefile_git_version -' - -test_expect_success 'test submodule version matches Makefile' ' - if ! test -e ../../git/.git - then - echo "git/ is not a Git repository" >&2 - else - ( - cd ../.. && - sm_oid=$(git ls-files --stage -- git | - sed -e "s/^[0-9]* \\([0-9a-f]*\\) [0-9] .*$/\\1/") && - cd git && - git describe --match "v[0-9]*" $sm_oid - ) | sed -e "s/^v//" -e "s/-/./" >sm_version && - test_cmp sm_version makefile_version - fi -' - -test_done diff --git a/third_party/cgit/tests/t0010-validate-html.sh b/third_party/cgit/tests/t0010-validate-html.sh deleted file mode 100755 index ca08d69d1..000000000 --- a/third_party/cgit/tests/t0010-validate-html.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - -test_description='Validate html with tidy' -. ./setup.sh - - -test_url() -{ - tidy_opt="-eq" - test -z "$NO_TIDY_WARNINGS" || tidy_opt+=" --show-warnings no" - cgit_url "$1" >tidy-$test_count.tmp || return - sed -e "1,4d" tidy-$test_count.tmp >tidy-$test_count || return - "$tidy" $tidy_opt tidy-$test_count - rc=$? - - # tidy returns with exitcode 1 on warnings, 2 on error - if test $rc = 2 - then - false - else - : - fi -} - -tidy=`which tidy 2>/dev/null` -test -n "$tidy" || { - skip_all='Skipping html validation tests: tidy not found' - test_done - exit -} - -test_expect_success 'index page' 'test_url ""' -test_expect_success 'foo' 'test_url "foo"' -test_expect_success 'foo/log' 'test_url "foo/log"' -test_expect_success 'foo/tree' 'test_url "foo/tree"' -test_expect_success 'foo/tree/file-1' 'test_url "foo/tree/file-1"' -test_expect_success 'foo/commit' 'test_url "foo/commit"' -test_expect_success 'foo/diff' 'test_url "foo/diff"' - -test_done diff --git a/third_party/cgit/tests/t0020-validate-cache.sh b/third_party/cgit/tests/t0020-validate-cache.sh deleted file mode 100755 index 657765d89..000000000 --- a/third_party/cgit/tests/t0020-validate-cache.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -test_description='Validate cache' -. ./setup.sh - -test_expect_success 'verify cache-size=0' ' - - rm -f cache/* && - sed -e "s/cache-size=1021$/cache-size=0/" cgitrc >cgitrc.tmp && - mv -f cgitrc.tmp cgitrc && - cgit_url "" && - cgit_url "foo" && - cgit_url "foo/refs" && - cgit_url "foo/tree" && - cgit_url "foo/log" && - cgit_url "foo/diff" && - cgit_url "foo/patch" && - cgit_url "bar" && - cgit_url "bar/refs" && - cgit_url "bar/tree" && - cgit_url "bar/log" && - cgit_url "bar/diff" && - cgit_url "bar/patch" && - ls cache >output && - test_line_count = 0 output -' - -test_expect_success 'verify cache-size=1' ' - - rm -f cache/* && - sed -e "s/cache-size=0$/cache-size=1/" cgitrc >cgitrc.tmp && - mv -f cgitrc.tmp cgitrc && - cgit_url "" && - cgit_url "foo" && - cgit_url "foo/refs" && - cgit_url "foo/tree" && - cgit_url "foo/log" && - cgit_url "foo/diff" && - cgit_url "foo/patch" && - cgit_url "bar" && - cgit_url "bar/refs" && - cgit_url "bar/tree" && - cgit_url "bar/log" && - cgit_url "bar/diff" && - cgit_url "bar/patch" && - ls cache >output && - test_line_count = 1 output -' - -test_expect_success 'verify cache-size=1021' ' - - rm -f cache/* && - sed -e "s/cache-size=1$/cache-size=1021/" cgitrc >cgitrc.tmp && - mv -f cgitrc.tmp cgitrc && - cgit_url "" && - cgit_url "foo" && - cgit_url "foo/refs" && - cgit_url "foo/tree" && - cgit_url "foo/log" && - cgit_url "foo/diff" && - cgit_url "foo/patch" && - cgit_url "bar" && - cgit_url "bar/refs" && - cgit_url "bar/tree" && - cgit_url "bar/log" && - cgit_url "bar/diff" && - cgit_url "bar/patch" && - ls cache >output && - test_line_count = 13 output && - cgit_url "foo/ls_cache" >output.full && - strip_headers output && - test_line_count = 13 output && - # Check that ls_cache output is cached correctly - cgit_url "foo/ls_cache" >output.second && - test_cmp output.full output.second -' - -test_done diff --git a/third_party/cgit/tests/t0101-index.sh b/third_party/cgit/tests/t0101-index.sh deleted file mode 100755 index 82ef9b04e..000000000 --- a/third_party/cgit/tests/t0101-index.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh - -test_description='Check content on index page' -. ./setup.sh - -test_expect_success 'generate index page' 'cgit_url "" >tmp' -test_expect_success 'find foo repo' 'grep "foo" tmp' -test_expect_success 'find foo description' 'grep "\[no description\]" tmp' -test_expect_success 'find bar repo' 'grep "bar" tmp' -test_expect_success 'find bar description' 'grep "the bar repo" tmp' -test_expect_success 'find foo+bar repo' 'grep ">foo+bar<" tmp' -test_expect_success 'verify foo+bar link' 'grep "/foo+bar/" tmp' -test_expect_success 'verify "with%20space" link' 'grep "/with%20space/" tmp' -test_expect_success 'no tree-link' '! grep "foo/tree" tmp' -test_expect_success 'no log-link' '! grep "foo/log" tmp' - -test_done diff --git a/third_party/cgit/tests/t0102-summary.sh b/third_party/cgit/tests/t0102-summary.sh deleted file mode 100755 index b8864cb18..000000000 --- a/third_party/cgit/tests/t0102-summary.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -test_description='Check content on summary page' -. ./setup.sh - -test_expect_success 'generate foo summary' 'cgit_url "foo" >tmp' -test_expect_success 'find commit 1' 'grep "commit 1" tmp' -test_expect_success 'find commit 5' 'grep "commit 5" tmp' -test_expect_success 'find branch master' 'grep "master" tmp' -test_expect_success 'no tags' '! grep "tags" tmp' -test_expect_success 'clone-url expanded correctly' ' - grep "git://example.org/foo.git" tmp -' - -test_expect_success 'generate bar summary' 'cgit_url "bar" >tmp' -test_expect_success 'no commit 45' '! grep "commit 45" tmp' -test_expect_success 'find commit 46' 'grep "commit 46" tmp' -test_expect_success 'find commit 50' 'grep "commit 50" tmp' -test_expect_success 'find branch master' 'grep "master" tmp' -test_expect_success 'no tags' '! grep "tags" tmp' -test_expect_success 'clone-url expanded correctly' ' - grep "git://example.org/bar.git" tmp -' - -test_done diff --git a/third_party/cgit/tests/t0103-log.sh b/third_party/cgit/tests/t0103-log.sh deleted file mode 100755 index bdf1435a1..000000000 --- a/third_party/cgit/tests/t0103-log.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -test_description='Check content on log page' -. ./setup.sh - -test_expect_success 'generate foo/log' 'cgit_url "foo/log" >tmp' -test_expect_success 'find commit 1' 'grep "commit 1" tmp' -test_expect_success 'find commit 5' 'grep "commit 5" tmp' - -test_expect_success 'generate bar/log' 'cgit_url "bar/log" >tmp' -test_expect_success 'find commit 1' 'grep "commit 1" tmp' -test_expect_success 'find commit 50' 'grep "commit 50" tmp' - -test_expect_success 'generate "with%20space/log?qt=grep&q=commit+1"' ' - cgit_url "with+space/log&qt=grep&q=commit+1" >tmp -' -test_expect_success 'find commit 1' 'grep "commit 1" tmp' -test_expect_success 'find link with %20 in path' 'grep "/with%20space/log/?qt=grep" tmp' -test_expect_success 'find link with + in arg' 'grep "/log/?qt=grep&q=commit+1" tmp' -test_expect_success 'no links with space in path' '! grep "href=./with space/" tmp' -test_expect_success 'no links with space in arg' '! grep "q=commit 1" tmp' -test_expect_success 'commit 2 is not visible' '! grep "commit 2" tmp' - -test_done diff --git a/third_party/cgit/tests/t0104-tree.sh b/third_party/cgit/tests/t0104-tree.sh deleted file mode 100755 index 2e140f593..000000000 --- a/third_party/cgit/tests/t0104-tree.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -test_description='Check content on tree page' -. ./setup.sh - -test_expect_success 'generate bar/tree' 'cgit_url "bar/tree" >tmp' -test_expect_success 'find file-1' 'grep "file-1" tmp' -test_expect_success 'find file-50' 'grep "file-50" tmp' - -test_expect_success 'generate bar/tree/file-50' 'cgit_url "bar/tree/file-50" >tmp' - -test_expect_success 'find line 1' ' - grep "1" tmp -' - -test_expect_success 'no line 2' ' - ! grep "2" tmp -' - -test_expect_success 'generate foo+bar/tree' 'cgit_url "foo%2bbar/tree" >tmp' - -test_expect_success 'verify a+b link' ' - grep "/foo+bar/tree/a+b" tmp -' - -test_expect_success 'generate foo+bar/tree?h=1+2' 'cgit_url "foo%2bbar/tree&h=1%2b2" >tmp' - -test_expect_success 'verify a+b?h=1+2 link' ' - grep "/foo+bar/tree/a+b?h=1%2b2" tmp -' - -test_done diff --git a/third_party/cgit/tests/t0105-commit.sh b/third_party/cgit/tests/t0105-commit.sh deleted file mode 100755 index cfed1e7d6..000000000 --- a/third_party/cgit/tests/t0105-commit.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -test_description='Check content on commit page' -. ./setup.sh - -test_expect_success 'generate foo/commit' 'cgit_url "foo/commit" >tmp' -test_expect_success 'find tree link' 'grep "" tmp' -test_expect_success 'find parent link' 'grep -E "" tmp' - -test_expect_success 'find commit subject' ' - grep "
    commit 5<" tmp -' - -test_expect_success 'find commit msg' 'grep "
    " tmp'
    -test_expect_success 'find diffstat' 'grep "" tmp'
    -
    -test_expect_success 'find diff summary' '
    -	grep "1 files changed, 1 insertions, 0 deletions" tmp
    -'
    -
    -test_expect_success 'get root commit' '
    -	root=$(cd repos/foo && git rev-list --reverse HEAD | head -1) &&
    -	cgit_url "foo/commit&id=$root" >tmp &&
    -	grep "" tmp
    -'
    -
    -test_expect_success 'root commit contains diffstat' '
    -	grep "file-1" tmp
    -'
    -
    -test_expect_success 'root commit contains diff' '
    -	grep ">diff --git a/file-1 b/file-1" tmp &&
    -	grep "+1" tmp
    -'
    -
    -test_done
    diff --git a/third_party/cgit/tests/t0106-diff.sh b/third_party/cgit/tests/t0106-diff.sh
    deleted file mode 100755
    index 62a0a74a6..000000000
    --- a/third_party/cgit/tests/t0106-diff.sh
    +++ /dev/null
    @@ -1,19 +0,0 @@
    -#!/bin/sh
    -
    -test_description='Check content on diff page'
    -. ./setup.sh
    -
    -test_expect_success 'generate foo/diff' 'cgit_url "foo/diff" >tmp'
    -test_expect_success 'find diff header' 'grep "a/file-5 b/file-5" tmp'
    -test_expect_success 'find blob link' 'grep "@@ -0,0 +1 @@" tmp
    -'
    -
    -test_expect_success 'find added line' '
    -	grep "+5" tmp
    -'
    -
    -test_done
    diff --git a/third_party/cgit/tests/t0107-snapshot.sh b/third_party/cgit/tests/t0107-snapshot.sh
    deleted file mode 100755
    index 0811ec407..000000000
    --- a/third_party/cgit/tests/t0107-snapshot.sh
    +++ /dev/null
    @@ -1,205 +0,0 @@
    -#!/bin/sh
    -
    -test_description='Verify snapshot'
    -. ./setup.sh
    -
    -test_expect_success 'get foo/snapshot/master.tar.gz' '
    -	cgit_url "foo/snapshot/master.tar.gz" >tmp
    -'
    -
    -test_expect_success 'check html headers' '
    -	head -n 1 tmp |
    -	grep "Content-Type: application/x-gzip" &&
    -
    -	head -n 2 tmp |
    -	grep "Content-Disposition: inline; filename=.master.tar.gz."
    -'
    -
    -test_expect_success 'strip off the header lines' '
    -	strip_headers master.tar.gz
    -'
    -
    -test_expect_success 'verify gzip format' '
    -	gunzip --test master.tar.gz
    -'
    -
    -test_expect_success 'untar' '
    -	rm -rf master &&
    -	gzip -dc master.tar.gz | tar -xf -
    -'
    -
    -test_expect_success 'count files' '
    -	ls master/ >output &&
    -	test_line_count = 5 output
    -'
    -
    -test_expect_success 'verify untarred file-5' '
    -	grep "^5$" master/file-5 &&
    -	test_line_count = 1 master/file-5
    -'
    -
    -if test -n "$(which lzip 2>/dev/null)"; then
    -	test_set_prereq LZIP
    -else
    -	say 'Skipping LZIP validation tests: lzip not found'
    -fi
    -
    -test_expect_success LZIP 'get foo/snapshot/master.tar.lz' '
    -	cgit_url "foo/snapshot/master.tar.lz" >tmp
    -'
    -
    -test_expect_success LZIP 'check html headers' '
    -	head -n 1 tmp |
    -	grep "Content-Type: application/x-lzip" &&
    -
    -	head -n 2 tmp |
    -	grep "Content-Disposition: inline; filename=.master.tar.lz."
    -'
    -
    -test_expect_success LZIP 'strip off the header lines' '
    -	strip_headers master.tar.lz
    -'
    -
    -test_expect_success LZIP 'verify lzip format' '
    -	lzip --test master.tar.lz
    -'
    -
    -test_expect_success LZIP 'untar' '
    -	rm -rf master &&
    -	lzip -dc master.tar.lz | tar -xf -
    -'
    -
    -test_expect_success LZIP 'count files' '
    -	ls master/ >output &&
    -	test_line_count = 5 output
    -'
    -
    -test_expect_success LZIP 'verify untarred file-5' '
    -	grep "^5$" master/file-5 &&
    -	test_line_count = 1 master/file-5
    -'
    -
    -if test -n "$(which xz 2>/dev/null)"; then
    -	test_set_prereq XZ
    -else
    -	say 'Skipping XZ validation tests: xz not found'
    -fi
    -
    -test_expect_success XZ 'get foo/snapshot/master.tar.xz' '
    -	cgit_url "foo/snapshot/master.tar.xz" >tmp
    -'
    -
    -test_expect_success XZ 'check html headers' '
    -	head -n 1 tmp |
    -	grep "Content-Type: application/x-xz" &&
    -
    -	head -n 2 tmp |
    -	grep "Content-Disposition: inline; filename=.master.tar.xz."
    -'
    -
    -test_expect_success XZ 'strip off the header lines' '
    -	strip_headers master.tar.xz
    -'
    -
    -test_expect_success XZ 'verify xz format' '
    -	xz --test master.tar.xz
    -'
    -
    -test_expect_success XZ 'untar' '
    -	rm -rf master &&
    -	xz -dc master.tar.xz | tar -xf -
    -'
    -
    -test_expect_success XZ 'count files' '
    -	ls master/ >output &&
    -	test_line_count = 5 output
    -'
    -
    -test_expect_success XZ 'verify untarred file-5' '
    -	grep "^5$" master/file-5 &&
    -	test_line_count = 1 master/file-5
    -'
    -
    -if test -n "$(which zstd 2>/dev/null)"; then
    -	test_set_prereq ZSTD
    -else
    -	say 'Skipping ZSTD validation tests: zstd not found'
    -fi
    -
    -test_expect_success ZSTD 'get foo/snapshot/master.tar.zst' '
    -	cgit_url "foo/snapshot/master.tar.zst" >tmp
    -'
    -
    -test_expect_success ZSTD 'check html headers' '
    -	head -n 1 tmp |
    -	grep "Content-Type: application/x-zstd" &&
    -
    -	head -n 2 tmp |
    -	grep "Content-Disposition: inline; filename=.master.tar.zst."
    -'
    -
    -test_expect_success ZSTD 'strip off the header lines' '
    -	strip_headers master.tar.zst
    -'
    -
    -test_expect_success ZSTD 'verify zstd format' '
    -	zstd --test master.tar.zst
    -'
    -
    -test_expect_success ZSTD 'untar' '
    -	rm -rf master &&
    -	zstd -dc master.tar.zst | tar -xf -
    -'
    -
    -test_expect_success ZSTD 'count files' '
    -	ls master/ >output &&
    -	test_line_count = 5 output
    -'
    -
    -test_expect_success ZSTD 'verify untarred file-5' '
    -	grep "^5$" master/file-5 &&
    -	test_line_count = 1 master/file-5
    -'
    -
    -test_expect_success 'get foo/snapshot/master.zip' '
    -	cgit_url "foo/snapshot/master.zip" >tmp
    -'
    -
    -test_expect_success 'check HTML headers (zip)' '
    -	head -n 1 tmp |
    -	grep "Content-Type: application/x-zip" &&
    -
    -	head -n 2 tmp |
    -	grep "Content-Disposition: inline; filename=.master.zip."
    -'
    -
    -test_expect_success 'strip off the header lines (zip)' '
    -	strip_headers master.zip
    -'
    -
    -if test -n "$(which unzip 2>/dev/null)"; then
    -	test_set_prereq UNZIP
    -else
    -	say 'Skipping ZIP validation tests: unzip not found'
    -fi
    -
    -test_expect_success UNZIP 'verify zip format' '
    -	unzip -t master.zip
    -'
    -
    -test_expect_success UNZIP 'unzip' '
    -	rm -rf master &&
    -	unzip master.zip
    -'
    -
    -test_expect_success UNZIP 'count files (zip)' '
    -	ls master/ >output &&
    -	test_line_count = 5 output
    -'
    -
    -test_expect_success UNZIP 'verify unzipped file-5' '
    -	grep "^5$" master/file-5 &&
    -	test_line_count = 1 master/file-5
    -'
    -
    -test_done
    diff --git a/third_party/cgit/tests/t0108-patch.sh b/third_party/cgit/tests/t0108-patch.sh
    deleted file mode 100755
    index 013d68024..000000000
    --- a/third_party/cgit/tests/t0108-patch.sh
    +++ /dev/null
    @@ -1,62 +0,0 @@
    -#!/bin/sh
    -
    -test_description='Check content on patch page'
    -. ./setup.sh
    -
    -test_expect_success 'generate foo/patch' '
    -	cgit_query "url=foo/patch" >tmp
    -'
    -
    -test_expect_success 'find `From:` line' '
    -	grep "^From: " tmp
    -'
    -
    -test_expect_success 'find `Date:` line' '
    -	grep "^Date: " tmp
    -'
    -
    -test_expect_success 'find `Subject:` line' '
    -	grep "^Subject: commit 5" tmp
    -'
    -
    -test_expect_success 'find `cgit` signature' '
    -	tail -2 tmp | head -1 | grep "^cgit"
    -'
    -
    -test_expect_success 'compare with output of git-format-patch(1)' '
    -	CGIT_VERSION=$(sed -n "s/CGIT_VERSION = //p" ../../VERSION) &&
    -	git --git-dir="$PWD/repos/foo/.git" format-patch --subject-prefix="" --signature="cgit $CGIT_VERSION" --stdout HEAD^ >tmp2 &&
    -	strip_headers tmp_ &&
    -	test_cmp tmp_ tmp2
    -'
    -
    -test_expect_success 'find initial commit' '
    -	root=$(git --git-dir="$PWD/repos/foo/.git" rev-list --max-parents=0 HEAD)
    -'
    -
    -test_expect_success 'generate patch for initial commit' '
    -	cgit_query "url=foo/patch&id=$root" >tmp
    -'
    -
    -test_expect_success 'find `cgit` signature' '
    -	tail -2 tmp | head -1 | grep "^cgit"
    -'
    -
    -test_expect_success 'generate patches for multiple commits' '
    -	id=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD) &&
    -	id2=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD~3) &&
    -	cgit_query "url=foo/patch&id=$id&id2=$id2" >tmp
    -'
    -
    -test_expect_success 'find `cgit` signature' '
    -	tail -2 tmp | head -1 | grep "^cgit"
    -'
    -
    -test_expect_success 'compare with output of git-format-patch(1)' '
    -	CGIT_VERSION=$(sed -n "s/CGIT_VERSION = //p" ../../VERSION) &&
    -	git --git-dir="$PWD/repos/foo/.git" format-patch -N --subject-prefix="" --signature="cgit $CGIT_VERSION" --stdout HEAD~3..HEAD >tmp2 &&
    -	strip_headers tmp_ &&
    -	test_cmp tmp_ tmp2
    -'
    -
    -test_done
    diff --git a/third_party/cgit/tests/t0109-gitconfig.sh b/third_party/cgit/tests/t0109-gitconfig.sh
    deleted file mode 100755
    index 189ef2816..000000000
    --- a/third_party/cgit/tests/t0109-gitconfig.sh
    +++ /dev/null
    @@ -1,48 +0,0 @@
    -#!/bin/sh
    -
    -test_description='Ensure that git does not access $HOME'
    -. ./setup.sh
    -
    -test -n "$(which strace 2>/dev/null)" || {
    -	skip_all='Skipping access validation tests: strace not found'
    -	test_done
    -	exit
    -}
    -
    -strace true 2>/dev/null || {
    -	skip_all='Skipping access validation tests: strace not functional'
    -	test_done
    -	exit
    -}
    -
    -test_no_home_access () {
    -	non_existent_path="/path/to/some/place/that/does/not/possibly/exist"
    -	while test -d "$non_existent_path"; do
    -		non_existent_path="$non_existent_path/$(date +%N)"
    -	done &&
    -	strace \
    -		-E HOME="$non_existent_path" \
    -		-E CGIT_CONFIG="$PWD/cgitrc" \
    -		-E QUERY_STRING="url=$1" \
    -		-e access -f -o strace.out cgit &&
    -	! grep "$non_existent_path" strace.out
    -}
    -
    -test_no_home_access_success() {
    -	test_expect_success "do not access \$HOME: $1" "
    -		test_no_home_access '$1'
    -	"
    -}
    -
    -test_no_home_access_success
    -test_no_home_access_success foo
    -test_no_home_access_success foo/refs
    -test_no_home_access_success foo/log
    -test_no_home_access_success foo/tree
    -test_no_home_access_success foo/tree/file-1
    -test_no_home_access_success foo/commit
    -test_no_home_access_success foo/diff
    -test_no_home_access_success foo/patch
    -test_no_home_access_success foo/snapshot/master.tar.gz
    -
    -test_done
    diff --git a/third_party/cgit/tests/t0110-rawdiff.sh b/third_party/cgit/tests/t0110-rawdiff.sh
    deleted file mode 100755
    index 66fa7d5d3..000000000
    --- a/third_party/cgit/tests/t0110-rawdiff.sh
    +++ /dev/null
    @@ -1,42 +0,0 @@
    -#!/bin/sh
    -
    -test_description='Check content on rawdiff page'
    -. ./setup.sh
    -
    -test_expect_success 'generate foo/rawdiff' '
    -	cgit_query "url=foo/rawdiff" >tmp
    -'
    -
    -test_expect_success 'compare with output of git-diff(1)' '
    -	git --git-dir="$PWD/repos/foo/.git" diff HEAD^.. >tmp2 &&
    -	sed "1,4d" tmp >tmp_ &&
    -	cmp tmp_ tmp2
    -'
    -
    -test_expect_success 'find initial commit' '
    -	root=$(git --git-dir="$PWD/repos/foo/.git" rev-list --max-parents=0 HEAD)
    -'
    -
    -test_expect_success 'generate diff for initial commit' '
    -	cgit_query "url=foo/rawdiff&id=$root" >tmp
    -'
    -
    -test_expect_success 'compare with output of git-diff-tree(1)' '
    -	git --git-dir="$PWD/repos/foo/.git" diff-tree -p --no-commit-id --root "$root" >tmp2 &&
    -	sed "1,4d" tmp >tmp_ &&
    -	cmp tmp_ tmp2
    -'
    -
    -test_expect_success 'generate diff for multiple commits' '
    -	id=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD) &&
    -	id2=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD~3) &&
    -	cgit_query "url=foo/rawdiff&id=$id&id2=$id2" >tmp
    -'
    -
    -test_expect_success 'compare with output of git-diff(1)' '
    -	git --git-dir="$PWD/repos/foo/.git" diff HEAD~3..HEAD >tmp2 &&
    -	sed "1,4d" tmp >tmp_ &&
    -	cmp tmp_ tmp2
    -'
    -
    -test_done
    diff --git a/third_party/cgit/tests/t0111-filter.sh b/third_party/cgit/tests/t0111-filter.sh
    deleted file mode 100755
    index e5d357507..000000000
    --- a/third_party/cgit/tests/t0111-filter.sh
    +++ /dev/null
    @@ -1,43 +0,0 @@
    -#!/bin/sh
    -
    -test_description='Check filtered content'
    -. ./setup.sh
    -
    -prefixes="exec"
    -
    -for prefix in $prefixes
    -do
    -	test_expect_success "generate filter-$prefix/tree/a%2bb" "
    -		cgit_url 'filter-$prefix/tree/a%2bb' >tmp
    -	"
    -
    -	test_expect_success "check whether the $prefix source filter works" '
    -		grep "a+b HELLO$" tmp
    -	'
    -
    -	test_expect_success "generate filter-$prefix/about/" "
    -		cgit_url 'filter-$prefix/about/' >tmp
    -	"
    -
    -	test_expect_success "check whether the $prefix about filter works" '
    -		grep "
    a+b HELLO$" tmp - ' - - test_expect_success "generate filter-$prefix/commit/" " - cgit_url 'filter-$prefix/commit/' >tmp - " - - test_expect_success "check whether the $prefix commit filter works" ' - grep "
    ADD A+B" tmp - ' - - test_expect_success "check whether the $prefix email filter works for authors" ' - grep " commit A U THOR <AUTHOR@EXAMPLE.COM>" tmp - ' - - test_expect_success "check whether the $prefix email filter works for committers" ' - grep " commit C O MITTER <COMMITTER@EXAMPLE.COM>" tmp - ' -done - -test_done diff --git a/third_party/cgit/tests/valgrind/bin/cgit b/third_party/cgit/tests/valgrind/bin/cgit deleted file mode 100755 index dcdfbe532..000000000 --- a/third_party/cgit/tests/valgrind/bin/cgit +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# Note that we currently use Git's suppression file and there are variables -# $GIT_VALGRIND and $CGIT_VALGRIND which point to different places. -exec valgrind -q --error-exitcode=126 \ - --suppressions="$GIT_VALGRIND/default.supp" \ - --gen-suppressions=all \ - --leak-check=no \ - --track-origins=yes \ - --log-fd=4 \ - --input-fd=4 \ - "$CGIT_VALGRIND/../../cgit" "$@" diff --git a/third_party/cgit/tvl-extra.css b/third_party/cgit/tvl-extra.css deleted file mode 100644 index 41f5041d6..000000000 --- a/third_party/cgit/tvl-extra.css +++ /dev/null @@ -1,35 +0,0 @@ -/* limit the width of /about/** to help readability */ -.content #summary { - max-width: 800px; -} - -/* highlight cheddar callouts in cgit about views */ -.cheddar-callout { - display: block; - padding: 10px; -} - -.cheddar-question { - color: #3367d6; - background-color: #e8f0fe; -} - -.cheddar-todo { - color: #616161; - background-color: #eeeeee; -} - -.cheddar-tip { - color: #00796b; - background-color: #e0f2f1; -} - -.cheddar-warning { - color: #a52714; - background-color: #fbe9e7; -} - -/* add some padding next to the logo */ -td.logo { - padding-right: 10px; -} diff --git a/third_party/cgit/ui-atom.c b/third_party/cgit/ui-atom.c deleted file mode 100644 index fefbc7980..000000000 --- a/third_party/cgit/ui-atom.c +++ /dev/null @@ -1,157 +0,0 @@ -/* ui-atom.c: functions for atom feeds - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-atom.h" -#include "html.h" -#include "ui-shared.h" - -static void add_entry(struct commit *commit, const char *host) -{ - char delim = '&'; - char *hex; - char *mail, *t, *t2; - struct commitinfo *info; - - info = cgit_parse_commit(commit); - hex = oid_to_hex(&commit->object.oid); - html("\n"); - html(""); - html_txt(info->subject); - html("\n"); - html(""); - html_txt(show_date(info->committer_date, 0, - date_mode_from_type(DATE_ISO8601_STRICT))); - html("\n"); - html("\n"); - if (info->author) { - html(""); - html_txt(info->author); - html("\n"); - } - if (info->author_email && !ctx.cfg.noplainemail) { - mail = xstrdup(info->author_email); - t = strchr(mail, '<'); - if (t) - t++; - else - t = mail; - t2 = strchr(t, '>'); - if (t2) - *t2 = '\0'; - html(""); - html_txt(t); - html("\n"); - free(mail); - } - html("\n"); - html(""); - html_txt(show_date(info->author_date, 0, - date_mode_from_type(DATE_ISO8601_STRICT))); - html("\n"); - if (host) { - char *pageurl; - html("\n"); - free(pageurl); - } - html(""); - html_txtf("urn:%s:%s", the_hash_algo->name, hex); - html("\n"); - html("\n"); - html_txt(info->msg); - html("\n"); - html("\n"); - cgit_free_commitinfo(info); -} - - -void cgit_print_atom(char *tip, const char *path, int max_count) -{ - char *host; - const char *argv[] = {NULL, tip, NULL, NULL, NULL}; - struct commit *commit; - struct rev_info rev; - int argc = 2; - int first = 1; - - if (ctx.qry.show_all) - argv[1] = "--all"; - else if (!tip) - argv[1] = ctx.qry.head; - - if (path) { - argv[argc++] = "--"; - argv[argc++] = path; - } - - repo_init_revisions(the_repository, &rev, NULL); - rev.abbrev = DEFAULT_ABBREV; - rev.commit_format = CMIT_FMT_DEFAULT; - rev.verbose_header = 1; - rev.show_root_diff = 0; - rev.max_count = max_count; - setup_revisions(argc, argv, &rev, NULL); - prepare_revision_walk(&rev); - - host = cgit_hosturl(); - ctx.page.mimetype = "text/xml"; - ctx.page.charset = "utf-8"; - cgit_print_http_headers(); - html("\n"); - html(""); - html_txt(ctx.repo->name); - if (path) { - html("/"); - html_txt(path); - } - if (tip && !ctx.qry.show_all) { - html(", branch "); - html_txt(tip); - } - html("\n"); - html(""); - html_txt(ctx.repo->desc); - html("\n"); - if (host) { - char *fullurl = cgit_currentfullurl(); - char *repourl = cgit_repourl(ctx.repo->url); - html(""); - html_txtf("%s%s%s", cgit_httpscheme(), host, fullurl); - html("\n"); - html("\n"); - html("\n"); - free(fullurl); - free(repourl); - } - while ((commit = get_revision(&rev)) != NULL) { - if (first) { - html(""); - html_txt(show_date(commit->date, 0, - date_mode_from_type(DATE_ISO8601_STRICT))); - html("\n"); - first = 0; - } - add_entry(commit, host); - release_commit_memory(the_repository->parsed_objects, commit); - commit->parents = NULL; - } - html("\n"); - free(host); -} diff --git a/third_party/cgit/ui-atom.h b/third_party/cgit/ui-atom.h deleted file mode 100644 index dda953bbf..000000000 --- a/third_party/cgit/ui-atom.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UI_ATOM_H -#define UI_ATOM_H - -extern void cgit_print_atom(char *tip, const char *path, int max_count); - -#endif diff --git a/third_party/cgit/ui-blame.c b/third_party/cgit/ui-blame.c deleted file mode 100644 index 6418b2422..000000000 --- a/third_party/cgit/ui-blame.c +++ /dev/null @@ -1,315 +0,0 @@ -/* ui-blame.c: functions for blame output - * - * Copyright (C) 2006-2017 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-blame.h" -#include "html.h" -#include "ui-shared.h" -#include "strvec.h" -#include "blame.h" - - -static char *emit_suspect_detail(struct blame_origin *suspect) -{ - struct commitinfo *info; - struct strbuf detail = STRBUF_INIT; - - info = cgit_parse_commit(suspect->commit); - - strbuf_addf(&detail, "author %s", info->author); - if (!ctx.cfg.noplainemail) - strbuf_addf(&detail, " %s", info->author_email); - strbuf_addf(&detail, " %s\n", - show_date(info->author_date, info->author_tz, - cgit_date_mode(DATE_DOTTIME))); - - strbuf_addf(&detail, "committer %s", info->committer); - if (!ctx.cfg.noplainemail) - strbuf_addf(&detail, " %s", info->committer_email); - strbuf_addf(&detail, " %s\n\n", - show_date(info->committer_date, info->committer_tz, - cgit_date_mode(DATE_DOTTIME))); - - strbuf_addstr(&detail, info->subject); - - cgit_free_commitinfo(info); - return strbuf_detach(&detail, NULL); -} - -static void emit_blame_entry_hash(struct blame_entry *ent) -{ - struct blame_origin *suspect = ent->suspect; - struct object_id *oid = &suspect->commit->object.oid; - unsigned long line = 0; - - char *detail = emit_suspect_detail(suspect); - html(""); - cgit_commit_link(repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV), detail, - NULL, ctx.qry.head, oid_to_hex(oid), suspect->path); - html(""); - free(detail); - - if (!repo_parse_commit(the_repository, suspect->commit) && suspect->commit->parents) { - struct commit *parent = suspect->commit->parents->item; - - html(" "); - cgit_blame_link("^", "Blame the previous revision", NULL, - ctx.qry.head, oid_to_hex(&parent->object.oid), - suspect->path); - } - - while (line++ < ent->num_lines) - html("\n"); -} - -static void emit_blame_entry_linenumber(struct blame_entry *ent) -{ - const char *numberfmt = "%1$d\n"; - - unsigned long lineno = ent->lno; - while (lineno < ent->lno + ent->num_lines) - htmlf(numberfmt, ++lineno); -} - -static void emit_blame_entry_line_background(struct blame_scoreboard *sb, - struct blame_entry *ent) -{ - unsigned long line; - size_t len, maxlen = 2; - const char* pos, *endpos; - - for (line = ent->lno; line < ent->lno + ent->num_lines; line++) { - html("\n"); - pos = blame_nth_line(sb, line); - endpos = blame_nth_line(sb, line + 1); - len = 0; - while (pos < endpos) { - len++; - if (*pos++ == '\t') - len = (len + 7) & ~7; - } - if (len > maxlen) - maxlen = len; - } - - for (len = 0; len < maxlen - 1; len++) - html(" "); -} - -struct walk_tree_context { - char *curr_rev; - int match_baselen; - int state; -}; - -static void print_object(const struct object_id *oid, const char *path, - const char *basename, const char *rev) -{ - enum object_type type; - char *buf; - unsigned long size; - struct strvec rev_argv = STRVEC_INIT; - struct rev_info revs; - struct blame_scoreboard sb; - struct blame_origin *o; - struct blame_entry *ent = NULL; - - type = oid_object_info(the_repository, oid, &size); - if (type == OBJ_BAD) { - cgit_print_error_page(404, "Not found", "Bad object name: %s", - oid_to_hex(oid)); - return; - } - - buf = repo_read_object_file(the_repository, oid, &type, &size); - if (!buf) { - cgit_print_error_page(500, "Internal server error", - "Error reading object %s", oid_to_hex(oid)); - return; - } - - strvec_push(&rev_argv, "blame"); - strvec_push(&rev_argv, rev); - repo_init_revisions(the_repository, &revs, NULL); - revs.diffopt.flags.allow_textconv = 1; - setup_revisions(rev_argv.nr, rev_argv.v, &revs, NULL); - init_scoreboard(&sb); - sb.revs = &revs; - sb.repo = the_repository; - sb.path = path; - setup_scoreboard(&sb, &o); - o->suspects = blame_entry_prepend(NULL, 0, sb.num_lines, o); - prio_queue_put(&sb.commits, o->commit); - blame_origin_decref(o); - sb.ent = NULL; - sb.path = path; - assign_blame(&sb, 0); - blame_sort_final(&sb); - blame_coalesce(&sb); - - cgit_set_title_from_path(path); - - cgit_print_layout_start(); - htmlf("blob: %s (", oid_to_hex(oid)); - cgit_plain_link("plain", NULL, NULL, ctx.qry.head, rev, path); - html(") ("); - cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path); - html(")\n"); - - if (buffer_is_binary(buf, size)) { - html("
    blob is binary.
    "); - goto cleanup; - } - if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) { - htmlf("
    blob size (%ldKB)" - " exceeds display size limit (%dKB).
    ", - size / 1024, ctx.cfg.max_blob_size); - goto cleanup; - } - - html("
    \n\n"); - - /* Commit hashes */ - html("\n"); - - /* Line numbers */ - if (ctx.cfg.enable_tree_linenumbers) { - html("\n"); - } - - html("\n"); - - html("\n
    "); - for (ent = sb.ent; ent; ent = ent->next) { - html("
    ");
    -		emit_blame_entry_hash(ent);
    -		html("
    "); - } - html("
    "); - for (ent = sb.ent; ent; ent = ent->next) { - html("
    ");
    -			emit_blame_entry_linenumber(ent);
    -			html("
    "); - } - html("
    "); - - /* Colored bars behind lines */ - html("
    "); - for (ent = sb.ent; ent; ) { - struct blame_entry *e = ent->next; - html("
    ");
    -		emit_blame_entry_line_background(&sb, ent);
    -		html("
    "); - free(ent); - ent = e; - } - html("
    "); - - free((void *)sb.final_buf); - - /* Lines */ - html("
    ");
    -	if (ctx.repo->source_filter) {
    -		char *filter_arg = xstrdup(basename);
    -		cgit_open_filter(ctx.repo->source_filter, filter_arg);
    -		html_raw(buf, size);
    -		cgit_close_filter(ctx.repo->source_filter);
    -		free(filter_arg);
    -	} else {
    -		html_txt(buf);
    -	}
    -	html("
    "); - - html("
    \n"); - - cgit_print_layout_end(); - -cleanup: - free(buf); -} - -static int walk_tree(const struct object_id *oid, struct strbuf *base, - const char *pathname, unsigned mode, void *cbdata) -{ - struct walk_tree_context *walk_tree_ctx = cbdata; - - if (base->len == walk_tree_ctx->match_baselen) { - if (S_ISREG(mode)) { - struct strbuf buffer = STRBUF_INIT; - strbuf_addbuf(&buffer, base); - strbuf_addstr(&buffer, pathname); - print_object(oid, buffer.buf, pathname, - walk_tree_ctx->curr_rev); - strbuf_release(&buffer); - walk_tree_ctx->state = 1; - } else if (S_ISDIR(mode)) { - walk_tree_ctx->state = 2; - } - } else if (base->len < INT_MAX - && (int)base->len > walk_tree_ctx->match_baselen) { - walk_tree_ctx->state = 2; - } else if (S_ISDIR(mode)) { - return READ_TREE_RECURSIVE; - } - return 0; -} - -static int basedir_len(const char *path) -{ - char *p = strrchr(path, '/'); - if (p) - return p - path + 1; - return 0; -} - -void cgit_print_blame(void) -{ - const char *rev = ctx.qry.oid; - struct object_id oid; - struct commit *commit; - struct pathspec_item path_items = { - .match = ctx.qry.path, - .len = ctx.qry.path ? strlen(ctx.qry.path) : 0 - }; - struct pathspec paths = { - .nr = 1, - .items = &path_items - }; - struct walk_tree_context walk_tree_ctx = { - .state = 0 - }; - - if (!rev) - rev = ctx.qry.head; - - if (repo_get_oid(the_repository, rev, &oid)) { - cgit_print_error_page(404, "Not found", - "Invalid revision name: %s", rev); - return; - } - commit = lookup_commit_reference(the_repository, &oid); - if (!commit || repo_parse_commit(the_repository, commit)) { - cgit_print_error_page(404, "Not found", - "Invalid commit reference: %s", rev); - return; - } - - walk_tree_ctx.curr_rev = xstrdup(rev); - walk_tree_ctx.match_baselen = (path_items.match) ? - basedir_len(path_items.match) : -1; - - read_tree(the_repository, repo_get_commit_tree(the_repository, commit), - &paths, walk_tree, &walk_tree_ctx); - if (!walk_tree_ctx.state) - cgit_print_error_page(404, "Not found", "Not found"); - else if (walk_tree_ctx.state == 2) - cgit_print_error_page(404, "No blame for folders", - "Blame is not available for folders."); - - free(walk_tree_ctx.curr_rev); -} diff --git a/third_party/cgit/ui-blame.h b/third_party/cgit/ui-blame.h deleted file mode 100644 index 5b97e0359..000000000 --- a/third_party/cgit/ui-blame.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UI_BLAME_H -#define UI_BLAME_H - -extern void cgit_print_blame(void); - -#endif /* UI_BLAME_H */ diff --git a/third_party/cgit/ui-blob.c b/third_party/cgit/ui-blob.c deleted file mode 100644 index 08f94ee97..000000000 --- a/third_party/cgit/ui-blob.c +++ /dev/null @@ -1,182 +0,0 @@ -/* ui-blob.c: show blob content - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-blob.h" -#include "html.h" -#include "ui-shared.h" - -struct walk_tree_context { - const char *match_path; - struct object_id *matched_oid; - unsigned int found_path:1; - unsigned int file_only:1; -}; - -static int walk_tree(const struct object_id *oid, struct strbuf *base, - const char *pathname, unsigned mode, void *cbdata) -{ - struct walk_tree_context *walk_tree_ctx = cbdata; - - if (walk_tree_ctx->file_only && !S_ISREG(mode)) - return READ_TREE_RECURSIVE; - if (strncmp(base->buf, walk_tree_ctx->match_path, base->len) - || strcmp(walk_tree_ctx->match_path + base->len, pathname)) - return READ_TREE_RECURSIVE; - oidcpy(walk_tree_ctx->matched_oid, oid); - walk_tree_ctx->found_path = 1; - return 0; -} - -int cgit_ref_path_exists(const char *path, const char *ref, int file_only) -{ - struct object_id oid; - unsigned long size; - struct pathspec_item path_items = { - .match = xstrdup(path), - .len = strlen(path) - }; - struct pathspec paths = { - .nr = 1, - .items = &path_items - }; - struct walk_tree_context walk_tree_ctx = { - .match_path = path, - .matched_oid = &oid, - .found_path = 0, - .file_only = file_only - }; - - if (repo_get_oid(the_repository, ref, &oid)) - goto done; - if (oid_object_info(the_repository, &oid, &size) != OBJ_COMMIT) - goto done; - read_tree(the_repository, - repo_get_commit_tree(the_repository, lookup_commit_reference(the_repository, &oid)), - &paths, walk_tree, &walk_tree_ctx); - -done: - free(path_items.match); - return walk_tree_ctx.found_path; -} - -int cgit_print_file(char *path, const char *head, int file_only) -{ - struct object_id oid; - enum object_type type; - char *buf; - unsigned long size; - struct commit *commit; - struct pathspec_item path_items = { - .match = path, - .len = strlen(path) - }; - struct pathspec paths = { - .nr = 1, - .items = &path_items - }; - struct walk_tree_context walk_tree_ctx = { - .match_path = path, - .matched_oid = &oid, - .found_path = 0, - .file_only = file_only - }; - - if (repo_get_oid(the_repository, head, &oid)) - return -1; - type = oid_object_info(the_repository, &oid, &size); - if (type == OBJ_COMMIT) { - commit = lookup_commit_reference(the_repository, &oid); - read_tree(the_repository, repo_get_commit_tree(the_repository, commit), - &paths, walk_tree, &walk_tree_ctx); - if (!walk_tree_ctx.found_path) - return -1; - type = oid_object_info(the_repository, &oid, &size); - } - if (type == OBJ_BAD) - return -1; - buf = repo_read_object_file(the_repository, &oid, &type, &size); - if (!buf) - return -1; - buf[size] = '\0'; - html_raw(buf, size); - free(buf); - return 0; -} - -void cgit_print_blob(const char *hex, char *path, const char *head, int file_only) -{ - struct object_id oid; - enum object_type type; - char *buf; - unsigned long size; - struct commit *commit; - struct pathspec_item path_items = { - .match = path, - .len = path ? strlen(path) : 0 - }; - struct pathspec paths = { - .nr = 1, - .items = &path_items - }; - struct walk_tree_context walk_tree_ctx = { - .match_path = path, - .matched_oid = &oid, - .found_path = 0, - .file_only = file_only - }; - - if (hex) { - if (get_oid_hex(hex, &oid)) { - cgit_print_error_page(400, "Bad request", - "Bad hex value: %s", hex); - return; - } - } else { - if (repo_get_oid(the_repository, head, &oid)) { - cgit_print_error_page(404, "Not found", - "Bad ref: %s", head); - return; - } - } - - type = oid_object_info(the_repository, &oid, &size); - - if ((!hex) && type == OBJ_COMMIT && path) { - commit = lookup_commit_reference(the_repository, &oid); - read_tree(the_repository, repo_get_commit_tree(the_repository, commit), - &paths, walk_tree, &walk_tree_ctx); - type = oid_object_info(the_repository, &oid, &size); - } - - if (type == OBJ_BAD) { - cgit_print_error_page(404, "Not found", - "Bad object name: %s", hex); - return; - } - - buf = repo_read_object_file(the_repository, &oid, &type, &size); - if (!buf) { - cgit_print_error_page(500, "Internal server error", - "Error reading object %s", hex); - return; - } - - buf[size] = '\0'; - if (buffer_is_binary(buf, size)) - ctx.page.mimetype = "application/octet-stream"; - else - ctx.page.mimetype = "text/plain"; - ctx.page.filename = path; - - html("X-Content-Type-Options: nosniff\n"); - html("Content-Security-Policy: default-src 'none'\n"); - cgit_print_http_headers(); - html_raw(buf, size); - free(buf); -} diff --git a/third_party/cgit/ui-blob.h b/third_party/cgit/ui-blob.h deleted file mode 100644 index 16847b20b..000000000 --- a/third_party/cgit/ui-blob.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef UI_BLOB_H -#define UI_BLOB_H - -extern int cgit_ref_path_exists(const char *path, const char *ref, int file_only); -extern int cgit_print_file(char *path, const char *head, int file_only); -extern void cgit_print_blob(const char *hex, char *path, const char *head, int file_only); - -#endif /* UI_BLOB_H */ diff --git a/third_party/cgit/ui-clone.c b/third_party/cgit/ui-clone.c deleted file mode 100644 index 5dccb6397..000000000 --- a/third_party/cgit/ui-clone.c +++ /dev/null @@ -1,126 +0,0 @@ -/* ui-clone.c: functions for http cloning, based on - * git's http-backend.c by Shawn O. Pearce - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-clone.h" -#include "html.h" -#include "ui-shared.h" -#include "packfile.h" -#include "object-store.h" - -static int print_ref_info(const char *refname, const struct object_id *oid, - int flags, void *cb_data) -{ - struct object *obj; - - if (!(obj = parse_object(the_repository, oid))) - return 0; - - htmlf("%s\t%s\n", oid_to_hex(oid), refname); - if (obj->type == OBJ_TAG) { - if (!(obj = deref_tag(the_repository, obj, refname, 0))) - return 0; - htmlf("%s\t%s^{}\n", oid_to_hex(&obj->oid), refname); - } - return 0; -} - -static void print_pack_info(void) -{ - struct packed_git *pack; - char *offset; - - ctx.page.mimetype = "text/plain"; - ctx.page.filename = "objects/info/packs"; - cgit_print_http_headers(); - reprepare_packed_git(the_repository); - for (pack = get_packed_git(the_repository); pack; pack = pack->next) { - if (pack->pack_local) { - offset = strrchr(pack->pack_name, '/'); - if (offset && offset[1] != '\0') - ++offset; - else - offset = pack->pack_name; - htmlf("P %s\n", offset); - } - } -} - -static void send_file(const char *path) -{ - struct stat st; - - if (stat(path, &st)) { - switch (errno) { - case ENOENT: - cgit_print_error_page(404, "Not found", "Not found"); - break; - case EACCES: - cgit_print_error_page(403, "Forbidden", "Forbidden"); - break; - default: - cgit_print_error_page(400, "Bad request", "Bad request"); - } - return; - } - ctx.page.mimetype = "application/octet-stream"; - ctx.page.filename = path; - skip_prefix(path, ctx.repo->path, &ctx.page.filename); - skip_prefix(ctx.page.filename, "/", &ctx.page.filename); - cgit_print_http_headers(); - html_include(path); -} - -void cgit_clone_info(void) -{ - if (!ctx.qry.path || strcmp(ctx.qry.path, "refs")) { - cgit_print_error_page(400, "Bad request", "Bad request"); - return; - } - - ctx.page.mimetype = "text/plain"; - ctx.page.filename = "info/refs"; - cgit_print_http_headers(); - for_each_ref(print_ref_info, NULL); -} - -void cgit_clone_objects(void) -{ - char *p; - - if (!ctx.qry.path) - goto err; - - if (!strcmp(ctx.qry.path, "info/packs")) { - print_pack_info(); - return; - } - - /* Avoid directory traversal by forbidding "..", but also work around - * other funny business by just specifying a fairly strict format. For - * example, now we don't have to stress out about the Cygwin port. - */ - for (p = ctx.qry.path; *p; ++p) { - if (*p == '.' && *(p + 1) == '.') - goto err; - if (!isalnum(*p) && *p != '/' && *p != '.' && *p != '-') - goto err; - } - - send_file(git_path("objects/%s", ctx.qry.path)); - return; - -err: - cgit_print_error_page(400, "Bad request", "Bad request"); -} - -void cgit_clone_head(void) -{ - send_file(git_path("%s", "HEAD")); -} diff --git a/third_party/cgit/ui-clone.h b/third_party/cgit/ui-clone.h deleted file mode 100644 index 3e460a3db..000000000 --- a/third_party/cgit/ui-clone.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef UI_CLONE_H -#define UI_CLONE_H - -void cgit_clone_info(void); -void cgit_clone_objects(void); -void cgit_clone_head(void); - -#endif /* UI_CLONE_H */ diff --git a/third_party/cgit/ui-commit.c b/third_party/cgit/ui-commit.c deleted file mode 100644 index 6517e50cc..000000000 --- a/third_party/cgit/ui-commit.c +++ /dev/null @@ -1,148 +0,0 @@ -/* ui-commit.c: generate commit view - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-commit.h" -#include "html.h" -#include "ui-shared.h" -#include "ui-diff.h" -#include "ui-log.h" - -void cgit_print_commit(char *hex, const char *prefix) -{ - struct commit *commit, *parent; - struct commitinfo *info, *parent_info; - struct commit_list *p; - struct strbuf notes = STRBUF_INIT; - struct object_id oid; - char *tmp, *tmp2; - int parents = 0; - - if (!hex) - hex = ctx.qry.head; - - if (repo_get_oid(the_repository, hex, &oid)) { - cgit_print_error_page(400, "Bad request", - "Bad object id: %s", hex); - return; - } - commit = lookup_commit_reference(the_repository, &oid); - if (!commit) { - cgit_print_error_page(404, "Not found", - "Bad commit reference: %s", hex); - return; - } - info = cgit_parse_commit(commit); - - format_display_notes(&oid, ¬es, PAGE_ENCODING, 1); - - load_ref_decorations(NULL, DECORATE_FULL_REFS); - - ctx.page.title = fmtalloc("%s - %s", info->subject, ctx.page.title); - cgit_print_layout_start(); - cgit_print_diff_ctrls(); - html("\n"); - html("\n"); - html("\n"); - html("\n"); - html("\n"); - for (p = commit->parents; p; p = p->next) { - parent = lookup_commit_reference(the_repository, &p->item->object.oid); - if (!parent) { - html(""); - continue; - } - html("" - ""); - parents++; - } - if (ctx.repo->snapshots) { - html(""); - } - html("
    author"); - cgit_open_filter(ctx.repo->email_filter, info->author_email, "commit"); - html_txt(info->author); - if (!ctx.cfg.noplainemail) { - html(" "); - html_txt(info->author_email); - } - cgit_close_filter(ctx.repo->email_filter); - html(""); - html_txt(show_date(info->author_date, info->author_tz, - cgit_date_mode(DATE_DOTTIME))); - html("
    committer"); - cgit_open_filter(ctx.repo->email_filter, info->committer_email, "commit"); - html_txt(info->committer); - if (!ctx.cfg.noplainemail) { - html(" "); - html_txt(info->committer_email); - } - cgit_close_filter(ctx.repo->email_filter); - html(""); - html_txt(show_date(info->committer_date, info->committer_tz, - cgit_date_mode(DATE_DOTTIME))); - html("
    commit"); - tmp = oid_to_hex(&commit->object.oid); - cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, prefix); - html(" ("); - cgit_patch_link("patch", NULL, NULL, NULL, tmp, prefix); - html(")
    tree"); - tmp = xstrdup(hex); - cgit_tree_link(oid_to_hex(get_commit_tree_oid(commit)), NULL, NULL, - ctx.qry.head, tmp, NULL); - if (prefix) { - html(" /"); - cgit_tree_link(prefix, NULL, NULL, ctx.qry.head, tmp, prefix); - } - free(tmp); - html("
    "); - cgit_print_error("Error reading parent commit"); - html("
    parent"); - tmp = tmp2 = oid_to_hex(&p->item->object.oid); - if (ctx.repo->enable_subject_links) { - parent_info = cgit_parse_commit(parent); - tmp2 = parent_info->subject; - } - cgit_commit_link(tmp2, NULL, NULL, ctx.qry.head, tmp, prefix); - html(" ("); - cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, - oid_to_hex(&p->item->object.oid), prefix); - html(")
    download"); - cgit_print_snapshot_links(ctx.repo, hex, "
    "); - html("
    \n"); - html("
    "); - cgit_open_filter(ctx.repo->commit_filter); - html_txt(info->subject); - cgit_close_filter(ctx.repo->commit_filter); - show_commit_decorations(commit); - html("
    "); - html("
    ");
    -	cgit_open_filter(ctx.repo->commit_filter);
    -	html_txt(info->msg);
    -	cgit_close_filter(ctx.repo->commit_filter);
    -	html("
    "); - if (notes.len != 0) { - html("
    Notes
    "); - html("
    "); - cgit_open_filter(ctx.repo->commit_filter); - html_txt(notes.buf); - cgit_close_filter(ctx.repo->commit_filter); - html("
    "); - html(""); - } - if (parents < 3) { - if (parents) - tmp = oid_to_hex(&commit->parents->item->object.oid); - else - tmp = NULL; - cgit_print_diff(ctx.qry.oid, tmp, prefix, 0, 0); - } - strbuf_release(¬es); - cgit_free_commitinfo(info); - cgit_print_layout_end(); -} diff --git a/third_party/cgit/ui-commit.h b/third_party/cgit/ui-commit.h deleted file mode 100644 index 8198b4bac..000000000 --- a/third_party/cgit/ui-commit.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UI_COMMIT_H -#define UI_COMMIT_H - -extern void cgit_print_commit(char *hex, const char *prefix); - -#endif /* UI_COMMIT_H */ diff --git a/third_party/cgit/ui-diff.c b/third_party/cgit/ui-diff.c deleted file mode 100644 index a82313fc6..000000000 --- a/third_party/cgit/ui-diff.c +++ /dev/null @@ -1,505 +0,0 @@ -/* ui-diff.c: show diff between two blobs - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-diff.h" -#include "html.h" -#include "ui-shared.h" -#include "ui-ssdiff.h" - -struct object_id old_rev_oid[1]; -struct object_id new_rev_oid[1]; - -static int files, slots; -static int total_adds, total_rems, max_changes; -static int lines_added, lines_removed; - -static struct fileinfo { - char status; - struct object_id old_oid[1]; - struct object_id new_oid[1]; - unsigned short old_mode; - unsigned short new_mode; - char *old_path; - char *new_path; - unsigned int added; - unsigned int removed; - unsigned long old_size; - unsigned long new_size; - unsigned int binary:1; -} *items; - -static int use_ssdiff = 0; -static struct diff_filepair *current_filepair; -static const char *current_prefix; - -struct diff_filespec *cgit_get_current_old_file(void) -{ - return current_filepair->one; -} - -struct diff_filespec *cgit_get_current_new_file(void) -{ - return current_filepair->two; -} - -static void print_fileinfo(struct fileinfo *info) -{ - char *class; - - switch (info->status) { - case DIFF_STATUS_ADDED: - class = "add"; - break; - case DIFF_STATUS_COPIED: - class = "cpy"; - break; - case DIFF_STATUS_DELETED: - class = "del"; - break; - case DIFF_STATUS_MODIFIED: - class = "upd"; - break; - case DIFF_STATUS_RENAMED: - class = "mov"; - break; - case DIFF_STATUS_TYPE_CHANGED: - class = "typ"; - break; - case DIFF_STATUS_UNKNOWN: - class = "unk"; - break; - case DIFF_STATUS_UNMERGED: - class = "stg"; - break; - default: - die("bug: unhandled diff status %c", info->status); - } - - html(""); - html(""); - if (is_null_oid(info->new_oid)) { - cgit_print_filemode(info->old_mode); - } else { - cgit_print_filemode(info->new_mode); - } - - if (info->old_mode != info->new_mode && - !is_null_oid(info->old_oid) && - !is_null_oid(info->new_oid)) { - html("["); - cgit_print_filemode(info->old_mode); - html("]"); - } - htmlf("", class); - cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.oid, - ctx.qry.oid2, info->new_path); - if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) { - htmlf(" (%s from ", - info->status == DIFF_STATUS_COPIED ? "copied" : "renamed"); - html_txt(info->old_path); - html(")"); - } - html(""); - if (info->binary) { - htmlf("bin%ld -> %ld bytes", - info->old_size, info->new_size); - return; - } - htmlf("%d", info->added + info->removed); - html(""); - htmlf("", (max_changes > 100 ? 100 : max_changes)); - htmlf("
    ", - info->added * 100.0 / max_changes); - htmlf("", - info->removed * 100.0 / max_changes); - htmlf("", - (max_changes - info->removed - info->added) * 100.0 / max_changes); - html("
    \n"); -} - -static void count_diff_lines(char *line, int len) -{ - if (line && (len > 0)) { - if (line[0] == '+') - lines_added++; - else if (line[0] == '-') - lines_removed++; - } -} - -static int show_filepair(struct diff_filepair *pair) -{ - /* Always show if we have no limiting prefix. */ - if (!current_prefix) - return 1; - - /* Show if either path in the pair begins with the prefix. */ - if (starts_with(pair->one->path, current_prefix) || - starts_with(pair->two->path, current_prefix)) - return 1; - - /* Otherwise we don't want to show this filepair. */ - return 0; -} - -static void inspect_filepair(struct diff_filepair *pair) -{ - int binary = 0; - unsigned long old_size = 0; - unsigned long new_size = 0; - - if (!show_filepair(pair)) - return; - - files++; - lines_added = 0; - lines_removed = 0; - cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size, &new_size, - &binary, 0, ctx.qry.ignorews, count_diff_lines); - if (files >= slots) { - if (slots == 0) - slots = 4; - else - slots = slots * 2; - items = xrealloc(items, slots * sizeof(struct fileinfo)); - } - items[files-1].status = pair->status; - oidcpy(items[files-1].old_oid, &pair->one->oid); - oidcpy(items[files-1].new_oid, &pair->two->oid); - items[files-1].old_mode = pair->one->mode; - items[files-1].new_mode = pair->two->mode; - items[files-1].old_path = xstrdup(pair->one->path); - items[files-1].new_path = xstrdup(pair->two->path); - items[files-1].added = lines_added; - items[files-1].removed = lines_removed; - items[files-1].old_size = old_size; - items[files-1].new_size = new_size; - items[files-1].binary = binary; - if (lines_added + lines_removed > max_changes) - max_changes = lines_added + lines_removed; - total_adds += lines_added; - total_rems += lines_removed; -} - -static void cgit_print_diffstat(const struct object_id *old_oid, - const struct object_id *new_oid, - const char *prefix) -{ - int i; - - html("
    "); - cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.oid, - ctx.qry.oid2, NULL); - if (prefix) { - html(" (limited to '"); - html_txt(prefix); - html("')"); - } - html("
    "); - html(""); - max_changes = 0; - cgit_diff_tree(old_oid, new_oid, inspect_filepair, prefix, - ctx.qry.ignorews); - for (i = 0; i"); - html("
    "); - htmlf("%d files changed, %d insertions, %d deletions", - files, total_adds, total_rems); - html("
    "); -} - - -/* - * print a single line returned from xdiff - */ -static void print_line(char *line, int len) -{ - char *class = "ctx"; - char c = line[len-1]; - - if (line[0] == '+') - class = "add"; - else if (line[0] == '-') - class = "del"; - else if (line[0] == '@') - class = "hunk"; - - htmlf("", class); - line[len-1] = '\0'; - html_txt(line); - line[len-1] = c; - html("\n"); -} - -static void header(const struct object_id *oid1, char *path1, int mode1, - const struct object_id *oid2, char *path2, int mode2) -{ - char *abbrev1, *abbrev2; - int subproject; - - subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2)); - html(""); - html("diff --git a/"); - html_txt(path1); - html(" b/"); - html_txt(path2); - html("\n"); - - if (mode1 == 0) - htmlf("new file mode %.6o\n", mode2); - - if (mode2 == 0) - htmlf("deleted file mode %.6o\n", mode1); - - if (!subproject) { - abbrev1 = xstrdup(repo_find_unique_abbrev(the_repository, oid1, DEFAULT_ABBREV)); - abbrev2 = xstrdup(repo_find_unique_abbrev(the_repository, oid2, DEFAULT_ABBREV)); - htmlf("index %s..%s", abbrev1, abbrev2); - free(abbrev1); - free(abbrev2); - if (mode1 != 0 && mode2 != 0) { - htmlf(" %.6o", mode1); - if (mode2 != mode1) - htmlf("..%.6o", mode2); - } - html("\n"); - if (is_null_oid(oid1)) { - path1 = "dev/null"; - html("--- /"); - } else - html("--- a/"); - if (mode1 != 0) - cgit_tree_link(path1, NULL, NULL, ctx.qry.head, - oid_to_hex(old_rev_oid), path1); - else - html_txt(path1); - html("\n"); - if (is_null_oid(oid2)) { - path2 = "dev/null"; - html("+++ /"); - } else - html("+++ b/"); - if (mode2 != 0) - cgit_tree_link(path2, NULL, NULL, ctx.qry.head, - oid_to_hex(new_rev_oid), path2); - else - html_txt(path2); - html("\n"); - } - html(""); -} - -static void filepair_cb(struct diff_filepair *pair) -{ - unsigned long old_size = 0; - unsigned long new_size = 0; - int binary = 0; - linediff_fn print_line_fn = print_line; - - if (!show_filepair(pair)) - return; - - current_filepair = pair; - if (use_ssdiff) { - cgit_ssdiff_header_begin(); - print_line_fn = cgit_ssdiff_line_cb; - } - header(&pair->one->oid, pair->one->path, pair->one->mode, - &pair->two->oid, pair->two->path, pair->two->mode); - if (use_ssdiff) - cgit_ssdiff_header_end(); - if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { - if (S_ISGITLINK(pair->one->mode)) - print_line_fn(fmt("-Subproject %s", oid_to_hex(&pair->one->oid)), 52); - if (S_ISGITLINK(pair->two->mode)) - print_line_fn(fmt("+Subproject %s", oid_to_hex(&pair->two->oid)), 52); - if (use_ssdiff) - cgit_ssdiff_footer(); - return; - } - if (cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size, - &new_size, &binary, ctx.qry.context, - ctx.qry.ignorews, print_line_fn)) - cgit_print_error("Error running diff"); - if (binary) { - if (use_ssdiff) - html("
    "); - else - html("Binary files differ"); - } - if (use_ssdiff) - cgit_ssdiff_footer(); -} - -void cgit_print_diff_ctrls(void) -{ - int i, curr; - - html("
    "); - html("diff options"); - html("
    "); - cgit_add_hidden_formfields(1, 0, ctx.qry.page); - html("
    Binary files differ
    "); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html(""); - html("
    context:"); - html(""); - html("
    space:"); - html(""); - html("
    mode:"); - html("
    "); - html(""); - html("
    "); - html(""); - html("
    "); -} - -void cgit_print_diff(const char *new_rev, const char *old_rev, - const char *prefix, int show_ctrls, int raw) -{ - struct commit *commit, *commit2; - const struct object_id *old_tree_oid, *new_tree_oid; - diff_type difftype; - - /* - * If "follow" is set then the diff machinery needs to examine the - * entire commit to detect renames so we must limit the paths in our - * own callbacks and not pass the prefix to the diff machinery. - */ - if (ctx.qry.follow && ctx.cfg.enable_follow_links) { - current_prefix = prefix; - prefix = ""; - } else { - current_prefix = NULL; - } - - if (!new_rev) - new_rev = ctx.qry.head; - if (repo_get_oid(the_repository, new_rev, new_rev_oid)) { - cgit_print_error_page(404, "Not found", - "Bad object name: %s", new_rev); - return; - } - commit = lookup_commit_reference(the_repository, new_rev_oid); - if (!commit || repo_parse_commit(the_repository, commit)) { - cgit_print_error_page(404, "Not found", - "Bad commit: %s", oid_to_hex(new_rev_oid)); - return; - } - new_tree_oid = get_commit_tree_oid(commit); - - if (old_rev) { - if (repo_get_oid(the_repository, old_rev, old_rev_oid)) { - cgit_print_error_page(404, "Not found", - "Bad object name: %s", old_rev); - return; - } - } else if (commit->parents && commit->parents->item) { - oidcpy(old_rev_oid, &commit->parents->item->object.oid); - } else { - oidclr(old_rev_oid); - } - - if (!is_null_oid(old_rev_oid)) { - commit2 = lookup_commit_reference(the_repository, old_rev_oid); - if (!commit2 || repo_parse_commit(the_repository, commit2)) { - cgit_print_error_page(404, "Not found", - "Bad commit: %s", oid_to_hex(old_rev_oid)); - return; - } - old_tree_oid = get_commit_tree_oid(commit2); - } else { - old_tree_oid = NULL; - } - - if (raw) { - struct diff_options diffopt; - - repo_diff_setup(the_repository, &diffopt); - diffopt.output_format = DIFF_FORMAT_PATCH; - diffopt.flags.recursive = 1; - diff_setup_done(&diffopt); - - ctx.page.mimetype = "text/plain"; - cgit_print_http_headers(); - if (old_tree_oid) { - diff_tree_oid(old_tree_oid, new_tree_oid, "", - &diffopt); - } else { - diff_root_tree_oid(new_tree_oid, "", &diffopt); - } - diffcore_std(&diffopt); - diff_flush(&diffopt); - - return; - } - - difftype = ctx.qry.has_difftype ? ctx.qry.difftype : ctx.cfg.difftype; - use_ssdiff = difftype == DIFF_SSDIFF; - - if (show_ctrls) { - cgit_print_layout_start(); - cgit_print_diff_ctrls(); - } - - /* - * Clicking on a link to a file in the diff stat should show a diff - * of the file, showing the diff stat limited to a single file is - * pretty useless. All links from this point on will be to - * individual files, so we simply reset the difftype in the query - * here to avoid propagating DIFF_STATONLY to the individual files. - */ - if (difftype == DIFF_STATONLY) - ctx.qry.difftype = ctx.cfg.difftype; - - cgit_print_diffstat(old_rev_oid, new_rev_oid, prefix); - - if (difftype == DIFF_STATONLY) - return; - - if (use_ssdiff) { - html(""); - } else { - html("
    "); - html(""); - html("
    ");
    -	}
    -	cgit_diff_tree(old_rev_oid, new_rev_oid, filepair_cb, prefix,
    -		       ctx.qry.ignorews);
    -	if (!use_ssdiff)
    -		html("
    "); - - if (show_ctrls) - cgit_print_layout_end(); -} diff --git a/third_party/cgit/ui-diff.h b/third_party/cgit/ui-diff.h deleted file mode 100644 index 39264a164..000000000 --- a/third_party/cgit/ui-diff.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef UI_DIFF_H -#define UI_DIFF_H - -extern void cgit_print_diff_ctrls(void); - -extern void cgit_print_diff(const char *new_hex, const char *old_hex, - const char *prefix, int show_ctrls, int raw); - -extern struct diff_filespec *cgit_get_current_old_file(void); -extern struct diff_filespec *cgit_get_current_new_file(void); - -extern struct object_id old_rev_oid[1]; -extern struct object_id new_rev_oid[1]; - -#endif /* UI_DIFF_H */ diff --git a/third_party/cgit/ui-log.c b/third_party/cgit/ui-log.c deleted file mode 100644 index 358cdec4e..000000000 --- a/third_party/cgit/ui-log.c +++ /dev/null @@ -1,564 +0,0 @@ -/* ui-log.c: functions for log output - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-log.h" -#include "html.h" -#include "ui-shared.h" -#include "strvec.h" - -static int files, add_lines, rem_lines, lines_counted; - -/* - * The list of available column colors in the commit graph. - */ -static const char *column_colors_html[] = { - "", - "", - "", - "", - "", - "", - "", -}; - -#define COLUMN_COLORS_HTML_MAX (ARRAY_SIZE(column_colors_html) - 1) - -static void count_lines(char *line, int size) -{ - if (size <= 0) - return; - - if (line[0] == '+') - add_lines++; - - else if (line[0] == '-') - rem_lines++; -} - -static void inspect_files(struct diff_filepair *pair) -{ - unsigned long old_size = 0; - unsigned long new_size = 0; - int binary = 0; - - files++; - if (ctx.repo->enable_log_linecount) - cgit_diff_files(&pair->one->oid, &pair->two->oid, &old_size, - &new_size, &binary, 0, ctx.qry.ignorews, - count_lines); -} - -void show_commit_decorations(struct commit *commit) -{ - const struct name_decoration *deco; - static char buf[1024]; - - buf[sizeof(buf) - 1] = 0; - deco = get_name_decoration(&commit->object); - if (!deco) - return; - html(""); - while (deco) { - struct object_id oid_tag, peeled; - int is_annotated = 0; - - strlcpy(buf, prettify_refname(deco->name), sizeof(buf)); - switch(deco->type) { - case DECORATION_NONE: - /* If it is a depot revision, display it, otherwise - * ... */ - if (strncmp("refs/r/", buf, 7) == 0) { - html(" "); - cgit_log_link(/* trim 'refs/' */ buf + 5, - NULL, "rev-deco", buf, NULL, - ctx.qry.vpath, 0, NULL, NULL, - ctx.qry.showmsg, 0); - } - - /* If the git-core doesn't recognize it, - * don't display anything. */ - break; - case DECORATION_REF_LOCAL: - html(" "); - cgit_log_link(buf, NULL, "branch-deco", buf, NULL, - ctx.qry.vpath, 0, NULL, NULL, - ctx.qry.showmsg, 0); - break; - case DECORATION_REF_TAG: - html(" "); - if (!read_ref(deco->name, &oid_tag) && !peel_iterated_oid(&oid_tag, &peeled)) - is_annotated = !oideq(&oid_tag, &peeled); - cgit_tag_link(buf, NULL, is_annotated ? "tag-annotated-deco" : "tag-deco", buf); - break; - case DECORATION_REF_REMOTE: - if (!ctx.repo->enable_remote_branches) - break; - html(" "); - cgit_log_link(buf, NULL, "remote-deco", NULL, - oid_to_hex(&commit->object.oid), - ctx.qry.vpath, 0, NULL, NULL, - ctx.qry.showmsg, 0); - break; - default: - html(" "); - cgit_commit_link(buf, NULL, "deco", ctx.qry.head, - oid_to_hex(&commit->object.oid), - ctx.qry.vpath); - break; - } - deco = deco->next; - } - html(""); -} - -static void handle_rename(struct diff_filepair *pair) -{ - /* - * After we have seen a rename, we generate links to the previous - * name of the file so that commit & diff views get fed the path - * that is correct for the commit they are showing, avoiding the - * need to walk the entire history leading back to every commit we - * show in order detect renames. - */ - if (0 != strcmp(ctx.qry.vpath, pair->two->path)) { - free(ctx.qry.vpath); - ctx.qry.vpath = xstrdup(pair->two->path); - } - inspect_files(pair); -} - -static int show_commit(struct commit *commit, struct rev_info *revs) -{ - struct commit_list *parents = commit->parents; - struct commit *parent; - int found = 0, saved_fmt; - struct diff_flags saved_flags = revs->diffopt.flags; - - /* Always show if we're not in "follow" mode with a single file. */ - if (!ctx.qry.follow) - return 1; - - /* - * In "follow" mode, we don't show merges. This is consistent with - * "git log --follow -- ". - */ - if (parents && parents->next) - return 0; - - /* - * If this is the root commit, do what rev_info tells us. - */ - if (!parents) - return revs->show_root_diff; - - /* When we get here we have precisely one parent. */ - parent = parents->item; - /* If we can't parse the commit, let print_commit() report an error. */ - if (repo_parse_commit(the_repository, parent)) - return 1; - - files = 0; - add_lines = 0; - rem_lines = 0; - - revs->diffopt.flags.recursive = 1; - diff_tree_oid(get_commit_tree_oid(parent), - get_commit_tree_oid(commit), - "", &revs->diffopt); - diffcore_std(&revs->diffopt); - - found = !diff_queue_is_empty(&revs->diffopt); - saved_fmt = revs->diffopt.output_format; - revs->diffopt.output_format = DIFF_FORMAT_CALLBACK; - revs->diffopt.format_callback = cgit_diff_tree_cb; - revs->diffopt.format_callback_data = handle_rename; - diff_flush(&revs->diffopt); - revs->diffopt.output_format = saved_fmt; - revs->diffopt.flags = saved_flags; - - lines_counted = 1; - return found; -} - -static void print_commit(struct commit *commit, struct rev_info *revs) -{ - struct commitinfo *info; - int columns = revs->graph ? 4 : 3; - struct strbuf graphbuf = STRBUF_INIT; - struct strbuf msgbuf = STRBUF_INIT; - - if (ctx.repo->enable_log_filecount) - columns++; - if (ctx.repo->enable_log_linecount) - columns++; - - if (revs->graph) { - /* Advance graph until current commit */ - while (!graph_next_line(revs->graph, &graphbuf)) { - /* Print graph segment in otherwise empty table row */ - html(""); - html(graphbuf.buf); - htmlf("\n", columns); - strbuf_setlen(&graphbuf, 0); - } - /* Current commit's graph segment is now ready in graphbuf */ - } - - info = cgit_parse_commit(commit); - htmlf("", ctx.qry.showmsg ? " class='logheader'" : ""); - - if (revs->graph) { - /* Print graph segment for current commit */ - html(""); - html(graphbuf.buf); - html(""); - strbuf_setlen(&graphbuf, 0); - } - else { - html(""); - cgit_print_age(info->committer_date, info->committer_tz, TM_WEEK * 2); - html(""); - } - - htmlf("", ctx.qry.showmsg ? " class='logsubject'" : ""); - if (ctx.qry.showmsg) { - /* line-wrap long commit subjects instead of truncating them */ - size_t subject_len = strlen(info->subject); - - if (subject_len > ctx.cfg.max_msg_len && - ctx.cfg.max_msg_len >= 15) { - /* symbol for signaling line-wrap (in PAGE_ENCODING) */ - const char wrap_symbol[] = { ' ', 0xE2, 0x86, 0xB5, 0 }; - int i = ctx.cfg.max_msg_len - strlen(wrap_symbol); - - /* Rewind i to preceding space character */ - while (i > 0 && !isspace(info->subject[i])) - --i; - if (!i) /* Oops, zero spaces. Reset i */ - i = ctx.cfg.max_msg_len - strlen(wrap_symbol); - - /* add remainder starting at i to msgbuf */ - strbuf_add(&msgbuf, info->subject + i, subject_len - i); - strbuf_trim(&msgbuf); - strbuf_add(&msgbuf, "\n\n", 2); - - /* Place wrap_symbol at position i in info->subject */ - strlcpy(info->subject + i, wrap_symbol, subject_len - i + 1); - } - } - show_commit_decorations(commit); - html(" "); - cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head, - oid_to_hex(&commit->object.oid), ctx.qry.vpath); - html(""); - cgit_open_filter(ctx.repo->email_filter, info->author_email, "log"); - html_txt(info->author); - cgit_close_filter(ctx.repo->email_filter); - - if (revs->graph) { - html(""); - cgit_print_age(info->committer_date, info->committer_tz, TM_WEEK * 2); - } - - if (!lines_counted && (ctx.repo->enable_log_filecount || - ctx.repo->enable_log_linecount)) { - files = 0; - add_lines = 0; - rem_lines = 0; - cgit_diff_commit(commit, inspect_files, ctx.qry.vpath); - } - - if (ctx.repo->enable_log_filecount) - htmlf("%d", files); - if (ctx.repo->enable_log_linecount) - htmlf("-%d/" - "+%d", rem_lines, add_lines); - - html("\n"); - - if ((revs->graph && !graph_is_commit_finished(revs->graph)) - || ctx.qry.showmsg) { /* Print a second table row */ - html(""); - - if (ctx.qry.showmsg) { - /* Concatenate commit message + notes in msgbuf */ - if (info->msg && *(info->msg)) { - strbuf_addstr(&msgbuf, info->msg); - strbuf_addch(&msgbuf, '\n'); - } - format_display_notes(&commit->object.oid, - &msgbuf, PAGE_ENCODING, 0); - strbuf_addch(&msgbuf, '\n'); - strbuf_ltrim(&msgbuf); - } - - if (revs->graph) { - int lines = 0; - - /* Calculate graph padding */ - if (ctx.qry.showmsg) { - /* Count #lines in commit message + notes */ - const char *p = msgbuf.buf; - lines = 1; - while ((p = strchr(p, '\n'))) { - p++; - lines++; - } - } - - /* Print graph padding */ - html(""); - while (lines > 0 || !graph_is_commit_finished(revs->graph)) { - if (graphbuf.len) - html("\n"); - strbuf_setlen(&graphbuf, 0); - graph_next_line(revs->graph, &graphbuf); - html(graphbuf.buf); - lines--; - } - html("\n"); - } - else - html(""); /* Empty 'Age' column */ - - /* Print msgbuf into remainder of table row */ - htmlf("\n", columns - (revs->graph ? 1 : 0), - ctx.qry.showmsg ? " class='logmsg'" : ""); - html_txt(msgbuf.buf); - html("\n"); - } - - strbuf_release(&msgbuf); - strbuf_release(&graphbuf); - cgit_free_commitinfo(info); -} - -static const char *disambiguate_ref(const char *ref, int *must_free_result) -{ - struct object_id oid; - struct strbuf longref = STRBUF_INIT; - - strbuf_addf(&longref, "refs/heads/%s", ref); - if (repo_get_oid(the_repository, longref.buf, &oid) == 0) { - *must_free_result = 1; - return strbuf_detach(&longref, NULL); - } - - *must_free_result = 0; - strbuf_release(&longref); - return ref; -} - -static char *next_token(char **src) -{ - char *result; - - if (!src || !*src) - return NULL; - while (isspace(**src)) - (*src)++; - if (!**src) - return NULL; - result = *src; - while (**src) { - if (isspace(**src)) { - **src = '\0'; - (*src)++; - break; - } - (*src)++; - } - return result; -} - -void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern, - const char *path, int pager, int commit_graph, int commit_sort) -{ - struct rev_info rev; - struct commit *commit; - struct strvec rev_argv = STRVEC_INIT; - int i, columns = commit_graph ? 4 : 3; - int must_free_tip = 0; - - /* rev_argv.argv[0] will be ignored by setup_revisions */ - strvec_push(&rev_argv, "log_rev_setup"); - - if (!tip) - tip = ctx.qry.head; - tip = disambiguate_ref(tip, &must_free_tip); - strvec_push(&rev_argv, tip); - - if (grep && pattern && *pattern) { - pattern = xstrdup(pattern); - if (!strcmp(grep, "grep") || !strcmp(grep, "author") || - !strcmp(grep, "committer")) { - strvec_pushf(&rev_argv, "--%s=%s", grep, pattern); - } else if (!strcmp(grep, "range")) { - char *arg; - /* Split the pattern at whitespace and add each token - * as a revision expression. Do not accept other - * rev-list options. Also, replace the previously - * pushed tip (it's no longer relevant). - */ - strvec_pop(&rev_argv); - while ((arg = next_token(&pattern))) { - if (*arg == '-') { - fprintf(stderr, "Bad range expr: %s\n", - arg); - break; - } - strvec_push(&rev_argv, arg); - } - } - } - - if (!path || !ctx.cfg.enable_follow_links) { - /* - * If we don't have a path, "follow" is a no-op so make sure - * the variable is set to false to avoid needing to check - * both this and whether we have a path everywhere. - */ - ctx.qry.follow = 0; - } - - if (commit_graph && !ctx.qry.follow) { - strvec_push(&rev_argv, "--graph"); - strvec_push(&rev_argv, "--color"); - graph_set_column_colors(column_colors_html, - COLUMN_COLORS_HTML_MAX); - } - - if (commit_sort == 1) - strvec_push(&rev_argv, "--date-order"); - else if (commit_sort == 2) - strvec_push(&rev_argv, "--topo-order"); - - if (path && ctx.qry.follow) - strvec_push(&rev_argv, "--follow"); - strvec_push(&rev_argv, "--"); - if (path) - strvec_push(&rev_argv, path); - - repo_init_revisions(the_repository, &rev, NULL); - rev.abbrev = DEFAULT_ABBREV; - rev.commit_format = CMIT_FMT_DEFAULT; - rev.verbose_header = 1; - rev.show_root_diff = 0; - rev.ignore_missing = 1; - rev.simplify_history = 1; - setup_revisions(rev_argv.nr, rev_argv.v, &rev, NULL); - load_ref_decorations(NULL, DECORATE_FULL_REFS); - rev.show_decorations = 1; - rev.grep_filter.ignore_case = 1; - - rev.diffopt.detect_rename = 1; - rev.diffopt.rename_limit = ctx.cfg.renamelimit; - if (ctx.qry.ignorews) - DIFF_XDL_SET(&rev.diffopt, IGNORE_WHITESPACE); - - compile_grep_patterns(&rev.grep_filter); - prepare_revision_walk(&rev); - - if (pager) { - cgit_print_layout_start(); - html(""); - } - - html(""); - if (commit_graph) - html(""); - else - html(""); - html(""); - if (rev.graph) - html(""); - if (ctx.repo->enable_log_filecount) { - html(""); - columns++; - } - if (ctx.repo->enable_log_linecount) { - html(""); - columns++; - } - html("\n"); - - if (ofs<0) - ofs = 0; - - for (i = 0; i < ofs && (commit = get_revision(&rev)) != NULL; /* nop */) { - if (show_commit(commit, &rev)) - i++; - release_commit_memory(the_repository->parsed_objects, commit); - commit->parents = NULL; - } - - for (i = 0; i < cnt && (commit = get_revision(&rev)) != NULL; /* nop */) { - /* - * In "follow" mode, we must count the files and lines the - * first time we invoke diff on a given commit, and we need - * to do that to see if the commit touches the path we care - * about, so we do it in show_commit. Hence we must clear - * lines_counted here. - * - * This has the side effect of avoiding running diff twice - * when we are both following renames and showing file - * and/or line counts. - */ - lines_counted = 0; - if (show_commit(commit, &rev)) { - i++; - print_commit(commit, &rev); - } - release_commit_memory(the_repository->parsed_objects, commit); - commit->parents = NULL; - } - if (pager) { - html("
    AgeCommit message"); - if (pager) { - html(" ("); - cgit_log_link(ctx.qry.showmsg ? "Collapse" : "Expand", NULL, - NULL, ctx.qry.head, ctx.qry.oid, - ctx.qry.vpath, ctx.qry.ofs, ctx.qry.grep, - ctx.qry.search, ctx.qry.showmsg ? 0 : 1, - ctx.qry.follow); - html(")"); - } - html("AuthorAgeFilesLines
      "); - if (ofs > 0) { - html("
    • "); - cgit_log_link("[prev]", NULL, NULL, ctx.qry.head, - ctx.qry.oid, ctx.qry.vpath, - ofs - cnt, ctx.qry.grep, - ctx.qry.search, ctx.qry.showmsg, - ctx.qry.follow); - html("
    • "); - } - if ((commit = get_revision(&rev)) != NULL) { - html("
    • "); - cgit_log_link("[next]", NULL, NULL, ctx.qry.head, - ctx.qry.oid, ctx.qry.vpath, - ofs + cnt, ctx.qry.grep, - ctx.qry.search, ctx.qry.showmsg, - ctx.qry.follow); - html("
    • "); - } - html("
    "); - cgit_print_layout_end(); - } else if ((commit = get_revision(&rev)) != NULL) { - htmlf("", columns); - cgit_log_link("[...]", NULL, NULL, ctx.qry.head, NULL, - ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg, - ctx.qry.follow); - html("\n"); - } - - /* If we allocated tip then it is safe to cast away const. */ - if (must_free_tip) - free((char*) tip); -} diff --git a/third_party/cgit/ui-log.h b/third_party/cgit/ui-log.h deleted file mode 100644 index 325607cda..000000000 --- a/third_party/cgit/ui-log.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef UI_LOG_H -#define UI_LOG_H - -extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, - char *pattern, const char *path, int pager, - int commit_graph, int commit_sort); -extern void show_commit_decorations(struct commit *commit); - -#endif /* UI_LOG_H */ diff --git a/third_party/cgit/ui-patch.c b/third_party/cgit/ui-patch.c deleted file mode 100644 index 3819a8152..000000000 --- a/third_party/cgit/ui-patch.c +++ /dev/null @@ -1,98 +0,0 @@ -/* ui-patch.c: generate patch view - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-patch.h" -#include "html.h" -#include "ui-shared.h" - -/* two commit hashes with two dots in between and termination */ -#define REV_RANGE_LEN 2 * GIT_MAX_HEXSZ + 3 - -void cgit_print_patch(const char *new_rev, const char *old_rev, - const char *prefix) -{ - struct rev_info rev; - struct commit *commit; - struct object_id new_rev_oid, old_rev_oid; - char rev_range[REV_RANGE_LEN]; - const char *rev_argv[] = { NULL, "--reverse", "--format=email", rev_range, "--", prefix, NULL }; - int rev_argc = ARRAY_SIZE(rev_argv) - 1; - char *patchname; - - if (!prefix) - rev_argc--; - - if (!new_rev) - new_rev = ctx.qry.head; - - if (repo_get_oid(the_repository, new_rev, &new_rev_oid)) { - cgit_print_error_page(404, "Not found", - "Bad object id: %s", new_rev); - return; - } - commit = lookup_commit_reference(the_repository, &new_rev_oid); - if (!commit) { - cgit_print_error_page(404, "Not found", - "Bad commit reference: %s", new_rev); - return; - } - - if (old_rev) { - if (repo_get_oid(the_repository, old_rev, &old_rev_oid)) { - cgit_print_error_page(404, "Not found", - "Bad object id: %s", old_rev); - return; - } - if (!lookup_commit_reference(the_repository, &old_rev_oid)) { - cgit_print_error_page(404, "Not found", - "Bad commit reference: %s", old_rev); - return; - } - } else if (commit->parents && commit->parents->item) { - oidcpy(&old_rev_oid, &commit->parents->item->object.oid); - } else { - oidclr(&old_rev_oid); - } - - if (is_null_oid(&old_rev_oid)) { - memcpy(rev_range, oid_to_hex(&new_rev_oid), the_hash_algo->hexsz + 1); - } else { - xsnprintf(rev_range, REV_RANGE_LEN, "%s..%s", oid_to_hex(&old_rev_oid), - oid_to_hex(&new_rev_oid)); - } - - patchname = fmt("%s.patch", rev_range); - ctx.page.mimetype = "text/plain"; - ctx.page.filename = patchname; - cgit_print_http_headers(); - - if (ctx.cfg.noplainemail) { - rev_argv[2] = "--format=format:From %H Mon Sep 17 00:00:00 " - "2001%nFrom: %an%nDate: %aD%n%w(78,0,1)Subject: " - "%s%n%n%w(0)%b"; - } - - repo_init_revisions(the_repository, &rev, NULL); - rev.abbrev = DEFAULT_ABBREV; - rev.verbose_header = 1; - rev.diff = 1; - rev.show_root_diff = 1; - rev.max_parents = 1; - rev.diffopt.output_format |= DIFF_FORMAT_DIFFSTAT | - DIFF_FORMAT_PATCH | DIFF_FORMAT_SUMMARY; - if (prefix) - rev.diffopt.stat_sep = fmt("(limited to '%s')\n\n", prefix); - setup_revisions(rev_argc, rev_argv, &rev, NULL); - prepare_revision_walk(&rev); - - while ((commit = get_revision(&rev)) != NULL) { - log_tree_commit(&rev, commit); - printf("-- \ncgit %s\n\n", cgit_version); - } -} diff --git a/third_party/cgit/ui-patch.h b/third_party/cgit/ui-patch.h deleted file mode 100644 index 7a6cacd5a..000000000 --- a/third_party/cgit/ui-patch.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef UI_PATCH_H -#define UI_PATCH_H - -extern void cgit_print_patch(const char *new_rev, const char *old_rev, - const char *prefix); - -#endif /* UI_PATCH_H */ diff --git a/third_party/cgit/ui-plain.c b/third_party/cgit/ui-plain.c deleted file mode 100644 index a66c5a1de..000000000 --- a/third_party/cgit/ui-plain.c +++ /dev/null @@ -1,207 +0,0 @@ -/* ui-plain.c: functions for output of plain blobs by path - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-plain.h" -#include "html.h" -#include "ui-shared.h" - -struct walk_tree_context { - int match_baselen; - int match; -}; - -static int print_object(const struct object_id *oid, const char *path) -{ - enum object_type type; - char *buf, *mimetype; - unsigned long size; - - type = oid_object_info(the_repository, oid, &size); - if (type == OBJ_BAD) { - cgit_print_error_page(404, "Not found", "Not found"); - return 0; - } - - buf = repo_read_object_file(the_repository, oid, &type, &size); - if (!buf) { - cgit_print_error_page(404, "Not found", "Not found"); - return 0; - } - - mimetype = get_mimetype_for_filename(path); - ctx.page.mimetype = mimetype; - - if (!ctx.repo->enable_html_serving) { - html("X-Content-Type-Options: nosniff\n"); - html("Content-Security-Policy: default-src 'none'\n"); - if (mimetype) { - /* Built-in white list allows PDF and everything that isn't text/ and application/ */ - if ((!strncmp(mimetype, "text/", 5) || !strncmp(mimetype, "application/", 12)) && strcmp(mimetype, "application/pdf")) - ctx.page.mimetype = NULL; - } - } - - if (!ctx.page.mimetype) { - if (buffer_is_binary(buf, size)) { - ctx.page.mimetype = "application/octet-stream"; - ctx.page.charset = NULL; - } else { - ctx.page.mimetype = "text/plain"; - } - } - ctx.page.filename = path; - ctx.page.size = size; - ctx.page.etag = oid_to_hex(oid); - cgit_print_http_headers(); - html_raw(buf, size); - free(mimetype); - free(buf); - return 1; -} - -static char *buildpath(const char *base, int baselen, const char *path) -{ - if (path[0]) - return fmtalloc("%.*s%s/", baselen, base, path); - else - return fmtalloc("%.*s/", baselen, base); -} - -static void print_dir(const struct object_id *oid, const char *base, - int baselen, const char *path) -{ - char *fullpath, *slash; - size_t len; - - fullpath = buildpath(base, baselen, path); - slash = (fullpath[0] == '/' ? "" : "/"); - ctx.page.etag = oid_to_hex(oid); - cgit_print_http_headers(); - htmlf("%s", slash); - html_txt(fullpath); - htmlf("\n\n

    %s", slash); - html_txt(fullpath); - html("

    \n
      \n"); - len = strlen(fullpath); - if (len > 1) { - fullpath[len - 1] = 0; - slash = strrchr(fullpath, '/'); - if (slash) - *(slash + 1) = 0; - else { - free(fullpath); - fullpath = NULL; - } - html("
    • "); - cgit_plain_link("../", NULL, NULL, ctx.qry.head, ctx.qry.oid, - fullpath); - html("
    • \n"); - } - free(fullpath); -} - -static void print_dir_entry(const struct object_id *oid, const char *base, - int baselen, const char *path, unsigned mode) -{ - char *fullpath; - - fullpath = buildpath(base, baselen, path); - if (!S_ISDIR(mode) && !S_ISGITLINK(mode)) - fullpath[strlen(fullpath) - 1] = 0; - html("
    • "); - if (S_ISGITLINK(mode)) { - cgit_submodule_link(NULL, fullpath, oid_to_hex(oid)); - } else - cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.oid, - fullpath); - html("
    • \n"); - free(fullpath); -} - -static void print_dir_tail(void) -{ - html("
    \n\n"); -} - -static int walk_tree(const struct object_id *oid, struct strbuf *base, - const char *pathname, unsigned mode, void *cbdata) -{ - struct walk_tree_context *walk_tree_ctx = cbdata; - - if (base->len == walk_tree_ctx->match_baselen) { - if (S_ISREG(mode) || S_ISLNK(mode)) { - if (print_object(oid, pathname)) - walk_tree_ctx->match = 1; - } else if (S_ISDIR(mode)) { - print_dir(oid, base->buf, base->len, pathname); - walk_tree_ctx->match = 2; - return READ_TREE_RECURSIVE; - } - } else if (base->len < INT_MAX && (int)base->len > walk_tree_ctx->match_baselen) { - print_dir_entry(oid, base->buf, base->len, pathname, mode); - walk_tree_ctx->match = 2; - } else if (S_ISDIR(mode)) { - return READ_TREE_RECURSIVE; - } - - return 0; -} - -static int basedir_len(const char *path) -{ - char *p = strrchr(path, '/'); - if (p) - return p - path + 1; - return 0; -} - -void cgit_print_plain(void) -{ - const char *rev = ctx.qry.oid; - struct object_id oid; - struct commit *commit; - struct pathspec_item path_items = { - .match = ctx.qry.path, - .len = ctx.qry.path ? strlen(ctx.qry.path) : 0 - }; - struct pathspec paths = { - .nr = 1, - .items = &path_items - }; - struct walk_tree_context walk_tree_ctx = { - .match = 0 - }; - - if (!rev) - rev = ctx.qry.head; - - if (repo_get_oid(the_repository, rev, &oid)) { - cgit_print_error_page(404, "Not found", "Not found"); - return; - } - commit = lookup_commit_reference(the_repository, &oid); - if (!commit || repo_parse_commit(the_repository, commit)) { - cgit_print_error_page(404, "Not found", "Not found"); - return; - } - if (!path_items.match) { - path_items.match = ""; - walk_tree_ctx.match_baselen = -1; - print_dir(get_commit_tree_oid(commit), "", 0, ""); - walk_tree_ctx.match = 2; - } - else - walk_tree_ctx.match_baselen = basedir_len(path_items.match); - read_tree(the_repository, repo_get_commit_tree(the_repository, commit), - &paths, walk_tree, &walk_tree_ctx); - if (!walk_tree_ctx.match) - cgit_print_error_page(404, "Not found", "Not found"); - else if (walk_tree_ctx.match == 2) - print_dir_tail(); -} diff --git a/third_party/cgit/ui-plain.h b/third_party/cgit/ui-plain.h deleted file mode 100644 index 5bff07b83..000000000 --- a/third_party/cgit/ui-plain.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UI_PLAIN_H -#define UI_PLAIN_H - -extern void cgit_print_plain(void); - -#endif /* UI_PLAIN_H */ diff --git a/third_party/cgit/ui-refs.c b/third_party/cgit/ui-refs.c deleted file mode 100644 index 456f610df..000000000 --- a/third_party/cgit/ui-refs.c +++ /dev/null @@ -1,219 +0,0 @@ -/* ui-refs.c: browse symbolic refs - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-refs.h" -#include "html.h" -#include "ui-shared.h" - -static inline int cmp_age(int age1, int age2) -{ - /* age1 and age2 are assumed to be non-negative */ - return age2 - age1; -} - -static int cmp_ref_name(const void *a, const void *b) -{ - struct refinfo *r1 = *(struct refinfo **)a; - struct refinfo *r2 = *(struct refinfo **)b; - - return strcmp(r1->refname, r2->refname); -} - -static int cmp_branch_age(const void *a, const void *b) -{ - struct refinfo *r1 = *(struct refinfo **)a; - struct refinfo *r2 = *(struct refinfo **)b; - - return cmp_age(r1->commit->committer_date, r2->commit->committer_date); -} - -static int get_ref_age(struct refinfo *ref) -{ - if (!ref->object) - return 0; - switch (ref->object->type) { - case OBJ_TAG: - return ref->tag ? ref->tag->tagger_date : 0; - case OBJ_COMMIT: - return ref->commit ? ref->commit->committer_date : 0; - } - return 0; -} - -static int cmp_tag_age(const void *a, const void *b) -{ - struct refinfo *r1 = *(struct refinfo **)a; - struct refinfo *r2 = *(struct refinfo **)b; - - return cmp_age(get_ref_age(r1), get_ref_age(r2)); -} - -static int print_branch(struct refinfo *ref) -{ - struct commitinfo *info = ref->commit; - char *name = (char *)ref->refname; - - if (!info) - return 1; - html(""); - cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL, - ctx.qry.showmsg, 0); - html(""); - - if (ref->object->type == OBJ_COMMIT) { - cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL); - html(""); - cgit_open_filter(ctx.repo->email_filter, info->author_email, "refs"); - html_txt(info->author); - cgit_close_filter(ctx.repo->email_filter); - html(""); - cgit_print_age(info->committer_date, info->committer_tz, -1); - } else { - html(""); - cgit_object_link(ref->object); - } - html("\n"); - return 0; -} - -static void print_tag_header(void) -{ - html("Tag" - "Download" - "Author" - "Age\n"); -} - -static int print_tag(struct refinfo *ref) -{ - struct tag *tag = NULL; - struct taginfo *info = NULL; - char *name = (char *)ref->refname; - struct object *obj = ref->object; - - if (obj->type == OBJ_TAG) { - tag = (struct tag *)obj; - obj = tag->tagged; - info = ref->tag; - if (!info) - return 1; - } - - html(""); - cgit_tag_link(name, NULL, NULL, name); - html(""); - if (ctx.repo->snapshots && (obj->type == OBJ_COMMIT)) - cgit_print_snapshot_links(ctx.repo, name, "  "); - else - cgit_object_link(obj); - html(""); - if (info) { - if (info->tagger) { - cgit_open_filter(ctx.repo->email_filter, info->tagger_email, "refs"); - html_txt(info->tagger); - cgit_close_filter(ctx.repo->email_filter); - } - } else if (ref->object->type == OBJ_COMMIT) { - cgit_open_filter(ctx.repo->email_filter, ref->commit->author_email, "refs"); - html_txt(ref->commit->author); - cgit_close_filter(ctx.repo->email_filter); - } - html(""); - if (info) { - if (info->tagger_date > 0) - cgit_print_age(info->tagger_date, info->tagger_tz, -1); - } else if (ref->object->type == OBJ_COMMIT) { - cgit_print_age(ref->commit->commit->date, 0, -1); - } - html("\n"); - - return 0; -} - -static void print_refs_link(const char *path) -{ - html(""); - cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path); - html(""); -} - -void cgit_print_branches(int maxcount) -{ - struct reflist list; - int i; - - html("Branch" - "Commit message" - "Author" - "Age\n"); - - list.refs = NULL; - list.alloc = list.count = 0; - for_each_branch_ref(cgit_refs_cb, &list); - if (ctx.repo->enable_remote_branches) - for_each_remote_ref(cgit_refs_cb, &list); - - if (maxcount == 0 || maxcount > list.count) - maxcount = list.count; - - qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); - if (ctx.repo->branch_sort == 0) - qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name); - - for (i = 0; i < maxcount; i++) - print_branch(list.refs[i]); - - if (maxcount < list.count) - print_refs_link("heads"); - - cgit_free_reflist_inner(&list); -} - -void cgit_print_tags(int maxcount) -{ - struct reflist list; - int i; - - list.refs = NULL; - list.alloc = list.count = 0; - for_each_tag_ref(cgit_refs_cb, &list); - if (list.count == 0) - return; - qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age); - if (!maxcount) - maxcount = list.count; - else if (maxcount > list.count) - maxcount = list.count; - print_tag_header(); - for (i = 0; i < maxcount; i++) - print_tag(list.refs[i]); - - if (maxcount < list.count) - print_refs_link("tags"); - - cgit_free_reflist_inner(&list); -} - -void cgit_print_refs(void) -{ - cgit_print_layout_start(); - html(""); - - if (ctx.qry.path && starts_with(ctx.qry.path, "heads")) - cgit_print_branches(0); - else if (ctx.qry.path && starts_with(ctx.qry.path, "tags")) - cgit_print_tags(0); - else { - cgit_print_branches(0); - html(""); - cgit_print_tags(0); - } - html("
     
    "); - cgit_print_layout_end(); -} diff --git a/third_party/cgit/ui-refs.h b/third_party/cgit/ui-refs.h deleted file mode 100644 index 1d4a54a2c..000000000 --- a/third_party/cgit/ui-refs.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef UI_REFS_H -#define UI_REFS_H - -extern void cgit_print_branches(int maxcount); -extern void cgit_print_tags(int maxcount); -extern void cgit_print_refs(void); - -#endif /* UI_REFS_H */ diff --git a/third_party/cgit/ui-repolist.c b/third_party/cgit/ui-repolist.c deleted file mode 100644 index 97b11c5f1..000000000 --- a/third_party/cgit/ui-repolist.c +++ /dev/null @@ -1,381 +0,0 @@ -/* ui-repolist.c: functions for generating the repolist page - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-repolist.h" -#include "html.h" -#include "ui-shared.h" - -static time_t read_agefile(const char *path) -{ - time_t result; - size_t size; - char *buf = NULL; - struct strbuf date_buf = STRBUF_INIT; - - if (readfile(path, &buf, &size)) { - free(buf); - return 0; - } - - if (parse_date(buf, &date_buf) == 0) - result = strtoul(date_buf.buf, NULL, 10); - else - result = 0; - free(buf); - strbuf_release(&date_buf); - return result; -} - -static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime) -{ - struct strbuf path = STRBUF_INIT; - struct stat s; - struct cgit_repo *r = (struct cgit_repo *)repo; - - if (repo->mtime != -1) { - *mtime = repo->mtime; - return 1; - } - strbuf_addf(&path, "%s/%s", repo->path, ctx.cfg.agefile); - if (stat(path.buf, &s) == 0) { - *mtime = read_agefile(path.buf); - if (*mtime) { - r->mtime = *mtime; - goto end; - } - } - - strbuf_reset(&path); - strbuf_addf(&path, "%s/refs/heads/%s", repo->path, - repo->defbranch ? repo->defbranch : "master"); - if (stat(path.buf, &s) == 0) { - *mtime = s.st_mtime; - r->mtime = *mtime; - goto end; - } - - strbuf_reset(&path); - strbuf_addf(&path, "%s/%s", repo->path, "packed-refs"); - if (stat(path.buf, &s) == 0) { - *mtime = s.st_mtime; - r->mtime = *mtime; - goto end; - } - - *mtime = 0; - r->mtime = *mtime; -end: - strbuf_release(&path); - return (r->mtime != 0); -} - -static void print_modtime(struct cgit_repo *repo) -{ - time_t t; - if (get_repo_modtime(repo, &t)) - cgit_print_age(t, 0, -1); -} - -static int is_match(struct cgit_repo *repo) -{ - if (!ctx.qry.search) - return 1; - if (repo->url && strcasestr(repo->url, ctx.qry.search)) - return 1; - if (repo->name && strcasestr(repo->name, ctx.qry.search)) - return 1; - if (repo->desc && strcasestr(repo->desc, ctx.qry.search)) - return 1; - if (repo->owner && strcasestr(repo->owner, ctx.qry.search)) - return 1; - return 0; -} - -static int is_in_url(struct cgit_repo *repo) -{ - if (!ctx.qry.url) - return 1; - if (repo->url && starts_with(repo->url, ctx.qry.url)) - return 1; - return 0; -} - -static int is_visible(struct cgit_repo *repo) -{ - if (repo->hide || repo->ignore) - return 0; - if (!(is_match(repo) && is_in_url(repo))) - return 0; - return 1; -} - -static int any_repos_visible(void) -{ - int i; - - for (i = 0; i < cgit_repolist.count; i++) { - if (is_visible(&cgit_repolist.repos[i])) - return 1; - } - return 0; -} - -static void print_sort_header(const char *title, const char *sort) -{ - char *currenturl = cgit_currenturl(); - html("%s", title); - free(currenturl); -} - -static void print_header(void) -{ - html(""); - print_sort_header("Name", "name"); - print_sort_header("Description", "desc"); - if (ctx.cfg.enable_index_owner) - print_sort_header("Owner", "owner"); - print_sort_header("Idle", "idle"); - if (ctx.cfg.enable_index_links) - html("Links"); - html("\n"); -} - - -static void print_pager(int items, int pagelen, char *search, char *sort) -{ - int i, ofs; - char *class = NULL; - html("
      "); - for (i = 0, ofs = 0; ofs < items; i++, ofs = i * pagelen) { - class = (ctx.qry.ofs == ofs) ? "current" : NULL; - html("
    • "); - cgit_index_link(fmt("[%d]", i + 1), fmt("Page %d", i + 1), - class, search, sort, ofs, 0); - html("
    • "); - } - html("
    "); -} - -static int cmp(const char *s1, const char *s2) -{ - if (s1 && s2) { - if (ctx.cfg.case_sensitive_sort) - return strcmp(s1, s2); - else - return strcasecmp(s1, s2); - } - if (s1 && !s2) - return -1; - if (s2 && !s1) - return 1; - return 0; -} - -static int sort_name(const void *a, const void *b) -{ - const struct cgit_repo *r1 = a; - const struct cgit_repo *r2 = b; - - return cmp(r1->name, r2->name); -} - -static int sort_desc(const void *a, const void *b) -{ - const struct cgit_repo *r1 = a; - const struct cgit_repo *r2 = b; - - return cmp(r1->desc, r2->desc); -} - -static int sort_owner(const void *a, const void *b) -{ - const struct cgit_repo *r1 = a; - const struct cgit_repo *r2 = b; - - return cmp(r1->owner, r2->owner); -} - -static int sort_idle(const void *a, const void *b) -{ - const struct cgit_repo *r1 = a; - const struct cgit_repo *r2 = b; - time_t t1, t2; - - t1 = t2 = 0; - get_repo_modtime(r1, &t1); - get_repo_modtime(r2, &t2); - return t2 - t1; -} - -static int sort_section(const void *a, const void *b) -{ - const struct cgit_repo *r1 = a; - const struct cgit_repo *r2 = b; - int result; - - result = cmp(r1->section, r2->section); - if (!result) { - if (!strcmp(ctx.cfg.repository_sort, "age")) - result = sort_idle(r1, r2); - if (!result) - result = cmp(r1->name, r2->name); - } - return result; -} - -struct sortcolumn { - const char *name; - int (*fn)(const void *a, const void *b); -}; - -static const struct sortcolumn sortcolumn[] = { - {"section", sort_section}, - {"name", sort_name}, - {"desc", sort_desc}, - {"owner", sort_owner}, - {"idle", sort_idle}, - {NULL, NULL} -}; - -static int sort_repolist(char *field) -{ - const struct sortcolumn *column; - - for (column = &sortcolumn[0]; column->name; column++) { - if (strcmp(field, column->name)) - continue; - qsort(cgit_repolist.repos, cgit_repolist.count, - sizeof(struct cgit_repo), column->fn); - return 1; - } - return 0; -} - - -void cgit_print_repolist(void) -{ - int i, columns = 3, hits = 0, header = 0; - char *last_section = NULL; - char *section; - char *repourl; - int sorted = 0; - - if (!any_repos_visible()) { - cgit_print_error_page(404, "Not found", "No repositories found"); - return; - } - - if (ctx.cfg.enable_index_links) - ++columns; - if (ctx.cfg.enable_index_owner) - ++columns; - - ctx.page.title = ctx.cfg.root_title; - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); - - if (ctx.qry.sort) - sorted = sort_repolist(ctx.qry.sort); - else if (ctx.cfg.section_sort) - sort_repolist("section"); - - html(""); - for (i = 0; i < cgit_repolist.count; i++) { - ctx.repo = &cgit_repolist.repos[i]; - if (!is_visible(ctx.repo)) - continue; - hits++; - if (hits <= ctx.qry.ofs) - continue; - if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) - continue; - if (!header++) - print_header(); - section = ctx.repo->section; - if (section && !strcmp(section, "")) - section = NULL; - if (!sorted && - ((last_section == NULL && section != NULL) || - (last_section != NULL && section == NULL) || - (last_section != NULL && section != NULL && - strcmp(section, last_section)))) { - htmlf(""); - last_section = section; - } - htmlf(""); - if (ctx.cfg.enable_index_links) { - html(""); - } - html("\n"); - } - html("
    ", - columns); - html_txt(section); - html("
    ", - !sorted && section ? "sublevel-repo" : "toplevel-repo"); - cgit_summary_link(ctx.repo->name, NULL, NULL, NULL); - html(""); - repourl = cgit_repourl(ctx.repo->url); - html_link_open(repourl, NULL, NULL); - free(repourl); - if (html_ntxt(ctx.repo->desc, ctx.cfg.max_repodesc_len) < 0) - html("..."); - html_link_close(); - html(""); - if (ctx.cfg.enable_index_owner) { - if (ctx.repo->owner_filter) { - cgit_open_filter(ctx.repo->owner_filter); - html_txt(ctx.repo->owner); - cgit_close_filter(ctx.repo->owner_filter); - } else { - char *currenturl = cgit_currenturl(); - html(""); - html_txt(ctx.repo->owner); - html(""); - free(currenturl); - } - html(""); - } - print_modtime(ctx.repo); - html(""); - cgit_summary_link("summary", NULL, "button", NULL); - html(" "); - cgit_log_link("log", NULL, "button", NULL, NULL, NULL, - 0, NULL, NULL, ctx.qry.showmsg, 0); - html(" "); - cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); - html("
    "); - if (hits > ctx.cfg.max_repo_count) - print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort); - cgit_print_docend(); -} - -void cgit_print_site_readme(void) -{ - cgit_print_layout_start(); - if (!ctx.cfg.root_readme) - goto done; - cgit_open_filter(ctx.cfg.about_filter, ctx.cfg.root_readme); - html_include(ctx.cfg.root_readme); - cgit_close_filter(ctx.cfg.about_filter); -done: - cgit_print_layout_end(); -} diff --git a/third_party/cgit/ui-repolist.h b/third_party/cgit/ui-repolist.h deleted file mode 100644 index 1b6b3227d..000000000 --- a/third_party/cgit/ui-repolist.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef UI_REPOLIST_H -#define UI_REPOLIST_H - -extern void cgit_print_repolist(void); -extern void cgit_print_site_readme(void); - -#endif /* UI_REPOLIST_H */ diff --git a/third_party/cgit/ui-shared.c b/third_party/cgit/ui-shared.c deleted file mode 100644 index d047f9a13..000000000 --- a/third_party/cgit/ui-shared.c +++ /dev/null @@ -1,1239 +0,0 @@ -/* ui-shared.c: common web output functions - * - * Copyright (C) 2006-2017 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-shared.h" -#include "cmd.h" -#include "html.h" -#include "version.h" - -static const char cgit_doctype[] = -"\n"; - -static char *http_date(time_t t) -{ - static char day[][4] = - {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - static char month[][4] = - {"Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; - struct tm tm; - gmtime_r(&t, &tm); - return fmt("%s, %02d %s %04d %02d:%02d:%02d GMT", day[tm.tm_wday], - tm.tm_mday, month[tm.tm_mon], 1900 + tm.tm_year, - tm.tm_hour, tm.tm_min, tm.tm_sec); -} - -void cgit_print_error(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - cgit_vprint_error(fmt, ap); - va_end(ap); -} - -void cgit_vprint_error(const char *fmt, va_list ap) -{ - va_list cp; - html("
    "); - va_copy(cp, ap); - html_vtxtf(fmt, cp); - va_end(cp); - html("
    \n"); -} - -const char *cgit_httpscheme(void) -{ - if (ctx.env.https && !strcmp(ctx.env.https, "on")) - return "https://"; - else - return "http://"; -} - -char *cgit_hosturl(void) -{ - if (ctx.env.http_host) - return xstrdup(ctx.env.http_host); - if (!ctx.env.server_name) - return NULL; - if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80) - return xstrdup(ctx.env.server_name); - return fmtalloc("%s:%s", ctx.env.server_name, ctx.env.server_port); -} - -char *cgit_currenturl(void) -{ - const char *root = cgit_rooturl(); - - if (!ctx.qry.url) - return xstrdup(root); - if (root[0] && root[strlen(root) - 1] == '/') - return fmtalloc("%s%s", root, ctx.qry.url); - return fmtalloc("%s/%s", root, ctx.qry.url); -} - -char *cgit_currentfullurl(void) -{ - const char *root = cgit_rooturl(); - const char *orig_query = ctx.env.query_string ? ctx.env.query_string : ""; - size_t len = strlen(orig_query); - char *query = xmalloc(len + 2), *start_url, *ret; - - /* Remove all url=... parts from query string */ - memcpy(query + 1, orig_query, len + 1); - query[0] = '?'; - start_url = query; - while ((start_url = strstr(start_url, "url=")) != NULL) { - if (start_url[-1] == '?' || start_url[-1] == '&') { - const char *end_url = strchr(start_url, '&'); - if (end_url) - memmove(start_url, end_url + 1, strlen(end_url)); - else - start_url[0] = '\0'; - } else - ++start_url; - } - if (!query[1]) - query[0] = '\0'; - - if (!ctx.qry.url) - ret = fmtalloc("%s%s", root, query); - else if (root[0] && root[strlen(root) - 1] == '/') - ret = fmtalloc("%s%s%s", root, ctx.qry.url, query); - else - ret = fmtalloc("%s/%s%s", root, ctx.qry.url, query); - free(query); - return ret; -} - -const char *cgit_rooturl(void) -{ - if (ctx.cfg.virtual_root) - return ctx.cfg.virtual_root; - else - return ctx.cfg.script_name; -} - -const char *cgit_loginurl(void) -{ - static const char *login_url; - if (!login_url) - login_url = fmtalloc("%s?p=login", cgit_rooturl()); - return login_url; -} - -char *cgit_repourl(const char *reponame) -{ - // my cgit instance *only* serves the depot, hence that's the only value ever - // needed. - return fmtalloc("/"); -} - -char *cgit_fileurl(const char *reponame, const char *pagename, - const char *filename, const char *query) -{ - struct strbuf sb = STRBUF_INIT; - - strbuf_addf(&sb, "%s%s/%s", ctx.cfg.virtual_root, - pagename, (filename ? filename:"")); - - if (query) { - strbuf_addf(&sb, "%s%s", "?", query); - } - - return strbuf_detach(&sb, NULL); -} - -char *cgit_pageurl(const char *reponame, const char *pagename, - const char *query) -{ - return cgit_fileurl(reponame, pagename, NULL, query); -} - -const char *cgit_repobasename(const char *reponame) -{ - /* I assume we don't need to store more than one repo basename */ - static char rvbuf[1024]; - int p; - const char *rv; - size_t len; - - len = strlcpy(rvbuf, reponame, sizeof(rvbuf)); - if (len >= sizeof(rvbuf)) - die("cgit_repobasename: truncated repository name '%s'", reponame); - p = len - 1; - /* strip trailing slashes */ - while (p && rvbuf[p] == '/') - rvbuf[p--] = '\0'; - /* strip trailing .git */ - if (p >= 3 && starts_with(&rvbuf[p-3], ".git")) { - p -= 3; - rvbuf[p--] = '\0'; - } - /* strip more trailing slashes if any */ - while (p && rvbuf[p] == '/') - rvbuf[p--] = '\0'; - /* find last slash in the remaining string */ - rv = strrchr(rvbuf, '/'); - if (rv) - return ++rv; - return rvbuf; -} - -const char *cgit_snapshot_prefix(const struct cgit_repo *repo) -{ - if (repo->snapshot_prefix) - return repo->snapshot_prefix; - - return cgit_repobasename(repo->url); -} - -static void site_url(const char *page, const char *search, const char *sort, int ofs, int always_root) -{ - char *delim = "?"; - - if (always_root || page) - html_attr(cgit_rooturl()); - else { - char *currenturl = cgit_currenturl(); - html_attr(currenturl); - free(currenturl); - } - - if (page) { - htmlf("?p=%s", page); - delim = "&"; - } - if (search) { - html(delim); - html("q="); - html_attr(search); - delim = "&"; - } - if (sort) { - html(delim); - html("s="); - html_attr(sort); - delim = "&"; - } - if (ofs) { - html(delim); - htmlf("ofs=%d", ofs); - } -} - -static void site_link(const char *page, const char *name, const char *title, - const char *class, const char *search, const char *sort, int ofs, int always_root) -{ - html(""); - html_txt(name); - html(""); -} - -void cgit_index_link(const char *name, const char *title, const char *class, - const char *pattern, const char *sort, int ofs, int always_root) -{ - site_link(NULL, name, title, class, pattern, sort, ofs, always_root); -} - -static char *repolink(const char *title, const char *class, const char *page, - const char *head, const char *path) -{ - char *delim = "?"; - - html("defbranch && strcmp(head, ctx.repo->defbranch)) { - html(delim); - html("h="); - html_url_arg(head); - delim = "&"; - } - return fmt("%s", delim); -} - -static void reporevlink(const char *page, const char *name, const char *title, - const char *class, const char *head, const char *rev, - const char *path) -{ - char *delim; - - delim = repolink(title, class, page, head, path); - if (rev && ctx.qry.head != NULL && strcmp(rev, ctx.qry.head)) { - html(delim); - html("id="); - html_url_arg(rev); - } - html("'>"); - html_txt(name); - html(""); -} - -void cgit_summary_link(const char *name, const char *title, const char *class, - const char *head) -{ - reporevlink(NULL, name, title, class, head, NULL, NULL); -} - -void cgit_tag_link(const char *name, const char *title, const char *class, - const char *tag) -{ - reporevlink("tag", name, title, class, tag, NULL, NULL); -} - -void cgit_about_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, const char *path) -{ - reporevlink("about", name, title, class, head, rev, path); -} - -void cgit_tree_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, const char *path) -{ - reporevlink("tree", name, title, class, head, rev, path); -} - -void cgit_plain_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, const char *path) -{ - reporevlink("plain", name, title, class, head, rev, path); -} - -void cgit_blame_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, const char *path) -{ - reporevlink("blame", name, title, class, head, rev, path); -} - -void cgit_log_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, const char *path, - int ofs, const char *grep, const char *pattern, int showmsg, - int follow) -{ - char *delim; - - delim = repolink(title, class, "log", head, path); - if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) { - html(delim); - html("id="); - html_url_arg(rev); - delim = "&"; - } - if (grep && pattern) { - html(delim); - html("qt="); - html_url_arg(grep); - delim = "&"; - html(delim); - html("q="); - html_url_arg(pattern); - } - if (ofs > 0) { - html(delim); - html("ofs="); - htmlf("%d", ofs); - delim = "&"; - } - if (showmsg) { - html(delim); - html("showmsg=1"); - delim = "&"; - } - if (follow) { - html(delim); - html("follow=1"); - } - html("'>"); - html_txt(name); - html(""); -} - -void cgit_commit_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, const char *path) -{ - char *delim; - - delim = repolink(title, class, "commit", head, path); - if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) { - html(delim); - html("id="); - html_url_arg(rev); - delim = "&"; - } - if (ctx.qry.difftype) { - html(delim); - htmlf("dt=%d", ctx.qry.difftype); - delim = "&"; - } - if (ctx.qry.context > 0 && ctx.qry.context != 3) { - html(delim); - html("context="); - htmlf("%d", ctx.qry.context); - delim = "&"; - } - if (ctx.qry.ignorews) { - html(delim); - html("ignorews=1"); - delim = "&"; - } - if (ctx.qry.follow) { - html(delim); - html("follow=1"); - } - html("'>"); - if (name[0] != '\0') { - if (strlen(name) > ctx.cfg.max_msg_len && ctx.cfg.max_msg_len >= 15) { - html_ntxt(name, ctx.cfg.max_msg_len - 3); - html("..."); - } else - html_txt(name); - } else - html_txt("(no commit message)"); - html(""); -} - -void cgit_refs_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, const char *path) -{ - reporevlink("refs", name, title, class, head, rev, path); -} - -void cgit_snapshot_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, - const char *archivename) -{ - reporevlink("snapshot", name, title, class, head, rev, archivename); -} - -void cgit_diff_link(const char *name, const char *title, const char *class, - const char *head, const char *new_rev, const char *old_rev, - const char *path) -{ - char *delim; - - delim = repolink(title, class, "diff", head, path); - if (new_rev && ctx.qry.head != NULL && strcmp(new_rev, ctx.qry.head)) { - html(delim); - html("id="); - html_url_arg(new_rev); - delim = "&"; - } - if (old_rev) { - html(delim); - html("id2="); - html_url_arg(old_rev); - delim = "&"; - } - if (ctx.qry.difftype) { - html(delim); - htmlf("dt=%d", ctx.qry.difftype); - delim = "&"; - } - if (ctx.qry.context > 0 && ctx.qry.context != 3) { - html(delim); - html("context="); - htmlf("%d", ctx.qry.context); - delim = "&"; - } - if (ctx.qry.ignorews) { - html(delim); - html("ignorews=1"); - delim = "&"; - } - if (ctx.qry.follow) { - html(delim); - html("follow=1"); - } - html("'>"); - html_txt(name); - html(""); -} - -void cgit_patch_link(const char *name, const char *title, const char *class, - const char *head, const char *rev, const char *path) -{ - reporevlink("patch", name, title, class, head, rev, path); -} - -void cgit_stats_link(const char *name, const char *title, const char *class, - const char *head, const char *path) -{ - reporevlink("stats", name, title, class, head, NULL, path); -} - -static void cgit_self_link(char *name, const char *title, const char *class) -{ - if (!strcmp(ctx.qry.page, "repolist")) - cgit_index_link(name, title, class, ctx.qry.search, ctx.qry.sort, - ctx.qry.ofs, 1); - else if (!strcmp(ctx.qry.page, "about")) - cgit_about_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "summary")) - cgit_summary_link(name, title, class, ctx.qry.head); - else if (!strcmp(ctx.qry.page, "tag")) - cgit_tag_link(name, title, class, ctx.qry.has_oid ? - ctx.qry.oid : ctx.qry.head); - else if (!strcmp(ctx.qry.page, "tree")) - cgit_tree_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "plain")) - cgit_plain_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "blame")) - cgit_blame_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "log")) - cgit_log_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path, ctx.qry.ofs, - ctx.qry.grep, ctx.qry.search, - ctx.qry.showmsg, ctx.qry.follow); - else if (!strcmp(ctx.qry.page, "commit")) - cgit_commit_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "patch")) - cgit_patch_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "refs")) - cgit_refs_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "snapshot")) - cgit_snapshot_link(name, title, class, ctx.qry.head, - ctx.qry.has_oid ? ctx.qry.oid : NULL, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "diff")) - cgit_diff_link(name, title, class, ctx.qry.head, - ctx.qry.oid, ctx.qry.oid2, - ctx.qry.path); - else if (!strcmp(ctx.qry.page, "stats")) - cgit_stats_link(name, title, class, ctx.qry.head, - ctx.qry.path); - else { - /* Don't known how to make link for this page */ - repolink(title, class, ctx.qry.page, ctx.qry.head, ctx.qry.path); - html(">"); - html_txt(name); - html(""); - } -} - -void cgit_object_link(struct object *obj) -{ - char *page, *shortrev, *fullrev, *name; - - fullrev = oid_to_hex(&obj->oid); - shortrev = xstrdup(fullrev); - shortrev[10] = '\0'; - if (obj->type == OBJ_COMMIT) { - cgit_commit_link(fmt("commit %s...", shortrev), NULL, NULL, - ctx.qry.head, fullrev, NULL); - return; - } else if (obj->type == OBJ_TREE) - page = "tree"; - else if (obj->type == OBJ_TAG) - page = "tag"; - else - page = "blob"; - name = fmt("%s %s...", type_name(obj->type), shortrev); - reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); -} - -static struct string_list_item *lookup_path(struct string_list *list, - const char *path) -{ - struct string_list_item *item; - - while (path && path[0]) { - if ((item = string_list_lookup(list, path))) - return item; - if (!(path = strchr(path, '/'))) - break; - path++; - } - return NULL; -} - -void cgit_submodule_link(const char *class, char *path, const char *rev) -{ - struct string_list *list; - struct string_list_item *item; - char tail, *dir; - size_t len; - - len = 0; - tail = 0; - list = &ctx.repo->submodules; - item = lookup_path(list, path); - if (!item) { - len = strlen(path); - tail = path[len - 1]; - if (tail == '/') { - path[len - 1] = 0; - item = lookup_path(list, path); - } - } - if (item || ctx.repo->module_link) { - html("module_link, dir, rev); - } - html("'>"); - html_txt(path); - html(""); - } else { - html(""); - html_txt(path); - html("
    "); - } - html_txtf(" @ %.7s", rev); - if (item && tail) - path[len - 1] = tail; -} - -const struct date_mode *cgit_date_mode(enum date_mode_type type) -{ - static struct date_mode mode; - mode.type = type; - mode.local = ctx.cfg.local_time; - return &mode; -} - -static void print_rel_date(time_t t, int tz, double value, - const char *class, const char *suffix) -{ - htmlf("%.0f %s", value, suffix); -} - -void cgit_print_age(time_t t, int tz, time_t max_relative) -{ - time_t now, secs; - - if (!t) - return; - time(&now); - secs = now - t; - if (secs < 0) - secs = 0; - - if (secs > max_relative && max_relative >= 0) { - html(""); - html_txt(show_date(t, tz, cgit_date_mode(DATE_SHORT))); - html(""); - return; - } - - if (secs < TM_HOUR * 2) { - print_rel_date(t, tz, secs * 1.0 / TM_MIN, "age-mins", "min."); - return; - } - if (secs < TM_DAY * 2) { - print_rel_date(t, tz, secs * 1.0 / TM_HOUR, "age-hours", "hours"); - return; - } - if (secs < TM_WEEK * 2) { - print_rel_date(t, tz, secs * 1.0 / TM_DAY, "age-days", "days"); - return; - } - if (secs < TM_MONTH * 2) { - print_rel_date(t, tz, secs * 1.0 / TM_WEEK, "age-weeks", "weeks"); - return; - } - if (secs < TM_YEAR * 2) { - print_rel_date(t, tz, secs * 1.0 / TM_MONTH, "age-months", "months"); - return; - } - print_rel_date(t, tz, secs * 1.0 / TM_YEAR, "age-years", "years"); -} - -void cgit_print_http_headers(void) -{ - if (ctx.env.no_http && !strcmp(ctx.env.no_http, "1")) - return; - - if (ctx.page.status) - htmlf("Status: %d %s\n", ctx.page.status, ctx.page.statusmsg); - if (ctx.page.mimetype && ctx.page.charset) - htmlf("Content-Type: %s; charset=%s\n", ctx.page.mimetype, - ctx.page.charset); - else if (ctx.page.mimetype) - htmlf("Content-Type: %s\n", ctx.page.mimetype); - if (ctx.page.size) - htmlf("Content-Length: %zd\n", ctx.page.size); - if (ctx.page.filename) { - html("Content-Disposition: inline; filename=\""); - html_header_arg_in_quotes(ctx.page.filename); - html("\"\n"); - } - if (!ctx.env.authenticated) - html("Cache-Control: no-cache, no-store\n"); - htmlf("Last-Modified: %s\n", http_date(ctx.page.modified)); - htmlf("Expires: %s\n", http_date(ctx.page.expires)); - if (ctx.page.etag) - htmlf("ETag: \"%s\"\n", ctx.page.etag); - html("\n"); - if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) - exit(0); -} - -void cgit_redirect(const char *url, bool permanent) -{ - htmlf("Status: %d %s\n", permanent ? 301 : 302, permanent ? "Moved" : "Found"); - html("Location: "); - html_url_path(url); - html("\n\n"); -} - -static void print_rel_vcs_link(const char *url) -{ - html("\n"); -} - -void cgit_print_docstart(void) -{ - char *host = cgit_hosturl(); - - if (ctx.cfg.embedded) { - if (ctx.cfg.header) - html_include(ctx.cfg.header); - return; - } - - html(cgit_doctype); - html("\n"); - html("\n"); - html(""); - html_txt(ctx.page.title); - html("\n"); - htmlf("\n", cgit_version); - if (ctx.cfg.robots && *ctx.cfg.robots) - htmlf("\n", ctx.cfg.robots); - html("\n"); - if (ctx.cfg.favicon) { - html("\n"); - } - if (host && ctx.repo && ctx.qry.head) { - char *fileurl; - struct strbuf sb = STRBUF_INIT; - strbuf_addf(&sb, "h=%s", ctx.qry.head); - - html("\n"); - strbuf_release(&sb); - free(fileurl); - } - if (ctx.repo) - cgit_add_clone_urls(print_rel_vcs_link); - if (ctx.cfg.head_include) - html_include(ctx.cfg.head_include); - if (ctx.repo && ctx.repo->extra_head_content) - html(ctx.repo->extra_head_content); - html("\n"); - html("\n"); - if (ctx.cfg.header) - html_include(ctx.cfg.header); - free(host); -} - -void cgit_print_docend(void) -{ - html("
    \n"); - if (ctx.cfg.embedded) { - html(" \n"); - if (ctx.cfg.footer) - html_include(ctx.cfg.footer); - return; - } - if (ctx.cfg.footer) - html_include(ctx.cfg.footer); - else { - htmlf("\n"); - } - html(" \n"); - html("\n\n"); -} - -void cgit_print_error_page(int code, const char *msg, const char *fmt, ...) -{ - va_list ap; - ctx.page.expires = ctx.cfg.cache_dynamic_ttl; - ctx.page.status = code; - ctx.page.statusmsg = msg; - cgit_print_layout_start(); - va_start(ap, fmt); - cgit_vprint_error(fmt, ap); - va_end(ap); - cgit_print_layout_end(); -} - -void cgit_print_layout_start(void) -{ - cgit_print_http_headers(); - cgit_print_docstart(); - cgit_print_pageheader(); -} - -void cgit_print_layout_end(void) -{ - cgit_print_docend(); -} - -static void add_clone_urls(void (*fn)(const char *), char *txt, char *suffix) -{ - struct strbuf **url_list = strbuf_split_str(txt, ' ', 0); - int i; - - for (i = 0; url_list[i]; i++) { - strbuf_rtrim(url_list[i]); - if (url_list[i]->len == 0) - continue; - if (suffix && *suffix) - strbuf_addf(url_list[i], "/%s", suffix); - fn(url_list[i]->buf); - } - - strbuf_list_free(url_list); -} - -void cgit_add_clone_urls(void (*fn)(const char *)) -{ - if (ctx.repo->clone_url) - add_clone_urls(fn, expand_macros(ctx.repo->clone_url), NULL); - else if (ctx.cfg.clone_prefix) - add_clone_urls(fn, ctx.cfg.clone_prefix, ctx.repo->url); -} - -static int print_this_commit_option(void) -{ - struct object_id oid; - if (!ctx.qry.head || repo_get_oid(the_repository, ctx.qry.head, &oid)) - return 1; - html_option(oid_to_hex(&oid), "this commit", ctx.qry.head); - return 0; -} - -static int print_branch_option(const char *refname, const struct object_id *oid, - int flags, void *cb_data) -{ - char *name = (char *)refname; - html_option(name, name, ctx.qry.head); - return 0; -} - -void cgit_add_hidden_formfields(int incl_head, int incl_search, - const char *page) -{ - if (!ctx.cfg.virtual_root) { - struct strbuf url = STRBUF_INIT; - - strbuf_addf(&url, "%s/%s", ctx.qry.repo, page); - if (ctx.qry.vpath) - strbuf_addf(&url, "/%s", ctx.qry.vpath); - html_hidden("url", url.buf); - strbuf_release(&url); - } - - if (incl_head && ctx.qry.head && ctx.repo->defbranch && - strcmp(ctx.qry.head, ctx.repo->defbranch)) - html_hidden("h", ctx.qry.head); - - if (ctx.qry.oid) - html_hidden("id", ctx.qry.oid); - if (ctx.qry.oid2) - html_hidden("id2", ctx.qry.oid2); - if (ctx.qry.showmsg) - html_hidden("showmsg", "1"); - - if (incl_search) { - if (ctx.qry.grep) - html_hidden("qt", ctx.qry.grep); - if (ctx.qry.search) - html_hidden("q", ctx.qry.search); - } -} - -static const char *hc(const char *page) -{ - if (!ctx.qry.page) - return NULL; - - return strcmp(ctx.qry.page, page) ? NULL : "active"; -} - -static void cgit_print_path_crumbs(char *path) -{ - char *old_path = ctx.qry.path; - char *p = path, *q, *end = path + strlen(path); - int levels = 0; - - ctx.qry.path = NULL; - cgit_self_link("root", NULL, NULL); - ctx.qry.path = p = path; - while (p < end) { - if (!(q = strchr(p, '/')) || levels > 15) - q = end; - *q = '\0'; - html_txt("/"); - cgit_self_link(p, NULL, NULL); - if (q < end) - *q = '/'; - p = q + 1; - ++levels; - } - ctx.qry.path = old_path; -} - -static void print_header(void) -{ - char *logo = NULL, *logo_link = NULL; - - html("\n"); - html("\n"); - - if (ctx.repo && ctx.repo->logo && *ctx.repo->logo) - logo = ctx.repo->logo; - else - logo = ctx.cfg.logo; - if (ctx.repo && ctx.repo->logo_link && *ctx.repo->logo_link) - logo_link = ctx.repo->logo_link; - else - logo_link = ctx.cfg.logo_link; - if (logo && *logo) { - html("\n"); - } - - html("\n"); - - html("\n"); -} - -void cgit_print_pageheader(void) -{ - html("
    "); - if (!ctx.env.authenticated || !ctx.cfg.noheader) - print_header(); - - html("
    \n"); - if (ctx.env.authenticated && ctx.repo) { - if (ctx.repo->readme.nr) { - cgit_about_link("about", NULL, hc("about"), ctx.qry.head, - ctx.qry.oid, ctx.qry.vpath); - html(" "); - } - cgit_summary_link("summary", NULL, hc("summary"), - ctx.qry.head); - html(" "); - cgit_refs_link("refs", NULL, hc("refs"), ctx.qry.head, - ctx.qry.oid, NULL); - html(" "); - cgit_log_link("log", NULL, hc("log"), ctx.qry.head, - NULL, ctx.qry.vpath, 0, NULL, NULL, - ctx.qry.showmsg, ctx.qry.follow); - html(" "); - if (ctx.qry.page && !strcmp(ctx.qry.page, "blame")) - cgit_blame_link("blame", NULL, hc("blame"), ctx.qry.head, - ctx.qry.oid, ctx.qry.vpath); - else - cgit_tree_link("tree", NULL, hc("tree"), ctx.qry.head, - ctx.qry.oid, ctx.qry.vpath); - html(" "); - cgit_commit_link("commit", NULL, hc("commit"), - ctx.qry.head, ctx.qry.oid, ctx.qry.vpath); - html(" "); - cgit_diff_link("diff", NULL, hc("diff"), ctx.qry.head, - ctx.qry.oid, ctx.qry.oid2, ctx.qry.vpath); - if (ctx.repo->max_stats) { - html(" "); - cgit_stats_link("stats", NULL, hc("stats"), - ctx.qry.head, ctx.qry.vpath); - } - if (ctx.repo->homepage) { - html(" homepage"); - } - html(""); - html("
    \n"); - cgit_add_hidden_formfields(1, 0, "log"); - html("\n"); - html("\n"); - html("\n"); - html("
    \n"); - } else if (ctx.env.authenticated) { - char *currenturl = cgit_currenturl(); - site_link(NULL, "index", NULL, hc("repolist"), NULL, NULL, 0, 1); - if (ctx.cfg.root_readme) - site_link("about", "about", NULL, hc("about"), - NULL, NULL, 0, 1); - html("
    "); - html("
    \n"); - html("\n"); - html("\n"); - html("
    "); - free(currenturl); - } - html("
    \n"); - if (ctx.env.authenticated && ctx.repo && ctx.qry.vpath) { - html("
    "); - html("path: "); - cgit_print_path_crumbs(ctx.qry.vpath); - if (ctx.cfg.enable_follow_links && !strcmp(ctx.qry.page, "log")) { - html(" ("); - ctx.qry.follow = !ctx.qry.follow; - cgit_self_link(ctx.qry.follow ? "follow" : "unfollow", - NULL, NULL); - ctx.qry.follow = !ctx.qry.follow; - html(")"); - } - html("
    "); - } - html("
    "); -} - -void cgit_print_filemode(unsigned short mode) -{ - if (S_ISDIR(mode)) - html("d"); - else if (S_ISLNK(mode)) - html("l"); - else if (S_ISGITLINK(mode)) - html("m"); - else - html("-"); - html_fileperm(mode >> 6); - html_fileperm(mode >> 3); - html_fileperm(mode); -} - -void cgit_compose_snapshot_prefix(struct strbuf *filename, const char *base, - const char *ref) -{ - struct object_id oid; - - /* - * Prettify snapshot names by stripping leading "v" or "V" if the tag - * name starts with {v,V}[0-9] and the prettify mapping is injective, - * i.e. each stripped tag can be inverted without ambiguities. - */ - if (repo_get_oid(the_repository, fmt("refs/tags/%s", ref), &oid) == 0 && - (ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1]) && - ((repo_get_oid(the_repository, fmt("refs/tags/%s", ref + 1), &oid) == 0) + - (repo_get_oid(the_repository, fmt("refs/tags/v%s", ref + 1), &oid) == 0) + - (repo_get_oid(the_repository, fmt("refs/tags/V%s", ref + 1), &oid) == 0) == 1)) - ref++; - - strbuf_addf(filename, "%s-%s", base, ref); -} - -void cgit_print_snapshot_links(const struct cgit_repo *repo, const char *ref, - const char *separator) -{ - const struct cgit_snapshot_format *f; - struct strbuf filename = STRBUF_INIT; - const char *basename; - size_t prefixlen; - - basename = cgit_snapshot_prefix(repo); - if (starts_with(ref, basename)) - strbuf_addstr(&filename, ref); - else - cgit_compose_snapshot_prefix(&filename, basename, ref); - - prefixlen = filename.len; - for (f = cgit_snapshot_formats; f->suffix; f++) { - if (!(repo->snapshots & cgit_snapshot_format_bit(f))) - continue; - strbuf_setlen(&filename, prefixlen); - strbuf_addstr(&filename, f->suffix); - cgit_snapshot_link(filename.buf, NULL, NULL, NULL, NULL, - filename.buf); - if (cgit_snapshot_get_sig(ref, f)) { - strbuf_addstr(&filename, ".asc"); - html(" ("); - cgit_snapshot_link("sig", NULL, NULL, NULL, NULL, - filename.buf); - html(")"); - } else if (starts_with(f->suffix, ".tar") && cgit_snapshot_get_sig(ref, &cgit_snapshot_formats[0])) { - strbuf_setlen(&filename, strlen(filename.buf) - strlen(f->suffix)); - strbuf_addstr(&filename, ".tar.asc"); - html(" ("); - cgit_snapshot_link("sig", NULL, NULL, NULL, NULL, - filename.buf); - html(")"); - } - html(separator); - } - strbuf_release(&filename); -} - -void cgit_set_title_from_path(const char *path) -{ - struct strbuf sb = STRBUF_INIT; - const char *slash, *last_slash; - - if (!path) - return; - - last_slash = path + strlen(path); - for (slash = last_slash; slash > path; --slash) { - if (*slash != '/') continue; - strbuf_add(&sb, slash + 1, last_slash - slash - 1); - strbuf_addstr(&sb, " \xc2\xab "); - last_slash = slash; - } - strbuf_add(&sb, path, last_slash - path); - strbuf_addf(&sb, " - %s", ctx.page.title); - ctx.page.title = strbuf_detach(&sb, NULL); -} diff --git a/third_party/cgit/ui-shared.h b/third_party/cgit/ui-shared.h deleted file mode 100644 index 6964873a6..000000000 --- a/third_party/cgit/ui-shared.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef UI_SHARED_H -#define UI_SHARED_H - -extern const char *cgit_httpscheme(void); -extern char *cgit_hosturl(void); -extern const char *cgit_rooturl(void); -extern char *cgit_currenturl(void); -extern char *cgit_currentfullurl(void); -extern const char *cgit_loginurl(void); -extern char *cgit_repourl(const char *reponame); -extern char *cgit_fileurl(const char *reponame, const char *pagename, - const char *filename, const char *query); -extern char *cgit_pageurl(const char *reponame, const char *pagename, - const char *query); - -extern void cgit_add_clone_urls(void (*fn)(const char *)); - -extern void cgit_index_link(const char *name, const char *title, - const char *class, const char *pattern, const char *sort, int ofs, int always_root); -extern void cgit_summary_link(const char *name, const char *title, - const char *class, const char *head); -extern void cgit_tag_link(const char *name, const char *title, - const char *class, const char *tag); -extern void cgit_tree_link(const char *name, const char *title, - const char *class, const char *head, - const char *rev, const char *path); -extern void cgit_plain_link(const char *name, const char *title, - const char *class, const char *head, - const char *rev, const char *path); -extern void cgit_blame_link(const char *name, const char *title, - const char *class, const char *head, - const char *rev, const char *path); -extern void cgit_log_link(const char *name, const char *title, - const char *class, const char *head, const char *rev, - const char *path, int ofs, const char *grep, - const char *pattern, int showmsg, int follow); -extern void cgit_commit_link(const char *name, const char *title, - const char *class, const char *head, - const char *rev, const char *path); -extern void cgit_patch_link(const char *name, const char *title, - const char *class, const char *head, - const char *rev, const char *path); -extern void cgit_refs_link(const char *name, const char *title, - const char *class, const char *head, - const char *rev, const char *path); -extern void cgit_snapshot_link(const char *name, const char *title, - const char *class, const char *head, - const char *rev, const char *archivename); -extern void cgit_diff_link(const char *name, const char *title, - const char *class, const char *head, - const char *new_rev, const char *old_rev, - const char *path); -extern void cgit_stats_link(const char *name, const char *title, - const char *class, const char *head, - const char *path); -extern void cgit_object_link(struct object *obj); - -extern void cgit_submodule_link(const char *class, char *path, - const char *rev); - -extern void cgit_print_layout_start(void); -extern void cgit_print_layout_end(void); - -__attribute__((format (printf,1,2))) -extern void cgit_print_error(const char *fmt, ...); -__attribute__((format (printf,1,0))) -extern void cgit_vprint_error(const char *fmt, va_list ap); -extern const struct date_mode *cgit_date_mode(enum date_mode_type type); -extern void cgit_print_age(time_t t, int tz, time_t max_relative); -extern void cgit_print_http_headers(void); -extern void cgit_redirect(const char *url, bool permanent); -extern void cgit_print_docstart(void); -extern void cgit_print_docend(void); -__attribute__((format (printf,3,4))) -extern void cgit_print_error_page(int code, const char *msg, const char *fmt, ...); -extern void cgit_print_pageheader(void); -extern void cgit_print_filemode(unsigned short mode); -extern void cgit_compose_snapshot_prefix(struct strbuf *filename, - const char *base, const char *ref); -extern void cgit_print_snapshot_links(const struct cgit_repo *repo, - const char *ref, const char *separator); -extern const char *cgit_snapshot_prefix(const struct cgit_repo *repo); -extern void cgit_add_hidden_formfields(int incl_head, int incl_search, - const char *page); - -extern void cgit_set_title_from_path(const char *path); -#endif /* UI_SHARED_H */ diff --git a/third_party/cgit/ui-snapshot.c b/third_party/cgit/ui-snapshot.c deleted file mode 100644 index 992853bcd..000000000 --- a/third_party/cgit/ui-snapshot.c +++ /dev/null @@ -1,319 +0,0 @@ -/* ui-snapshot.c: generate snapshot of a commit - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-snapshot.h" -#include "html.h" -#include "ui-shared.h" - -static int write_archive_type(const char *format, const char *hex, const char *prefix) -{ - struct strvec argv = STRVEC_INIT; - const char **nargv; - int result; - strvec_push(&argv, "snapshot"); - strvec_push(&argv, format); - if (prefix) { - struct strbuf buf = STRBUF_INIT; - strbuf_addstr(&buf, prefix); - strbuf_addch(&buf, '/'); - strvec_push(&argv, "--prefix"); - strvec_push(&argv, buf.buf); - strbuf_release(&buf); - } - strvec_push(&argv, hex); - /* - * Now we need to copy the pointers to arguments into a new - * structure because write_archive will rearrange its arguments - * which may result in duplicated/missing entries causing leaks - * or double-frees in strvec_clear. - */ - nargv = xmalloc(sizeof(char *) * (argv.nr + 1)); - /* strvec guarantees a trailing NULL entry. */ - memcpy(nargv, argv.v, sizeof(char *) * (argv.nr + 1)); - - if (fflush(stdout)) - return errno; - - result = write_archive(argv.nr, nargv, NULL, the_repository, NULL, 0); - strvec_clear(&argv); - free(nargv); - return result; -} - -static int write_tar_archive(const char *hex, const char *prefix) -{ - return write_archive_type("--format=tar", hex, prefix); -} - -static int write_zip_archive(const char *hex, const char *prefix) -{ - return write_archive_type("--format=zip", hex, prefix); -} - -static int write_compressed_tar_archive(const char *hex, - const char *prefix, - char *filter_argv[]) -{ - int rv; - struct cgit_exec_filter f; - cgit_exec_filter_init(&f, filter_argv[0], filter_argv); - - cgit_open_filter(&f.base); - rv = write_tar_archive(hex, prefix); - cgit_close_filter(&f.base); - return rv; -} - -static int write_tar_gzip_archive(const char *hex, const char *prefix) -{ - char *argv[] = { "gzip", "-n", NULL }; - return write_compressed_tar_archive(hex, prefix, argv); -} - -static int write_tar_bzip2_archive(const char *hex, const char *prefix) -{ - char *argv[] = { "bzip2", NULL }; - return write_compressed_tar_archive(hex, prefix, argv); -} - -static int write_tar_lzip_archive(const char *hex, const char *prefix) -{ - char *argv[] = { "lzip", NULL }; - return write_compressed_tar_archive(hex, prefix, argv); -} - -static int write_tar_xz_archive(const char *hex, const char *prefix) -{ - char *argv[] = { "xz", NULL }; - return write_compressed_tar_archive(hex, prefix, argv); -} - -static int write_tar_zstd_archive(const char *hex, const char *prefix) -{ - char *argv[] = { "zstd", "-T0", NULL }; - return write_compressed_tar_archive(hex, prefix, argv); -} - -const struct cgit_snapshot_format cgit_snapshot_formats[] = { - /* .tar must remain the 0 index */ - { ".tar", "application/x-tar", write_tar_archive }, - { ".tar.gz", "application/x-gzip", write_tar_gzip_archive }, - { ".tar.bz2", "application/x-bzip2", write_tar_bzip2_archive }, - { ".tar.lz", "application/x-lzip", write_tar_lzip_archive }, - { ".tar.xz", "application/x-xz", write_tar_xz_archive }, - { ".tar.zst", "application/x-zstd", write_tar_zstd_archive }, - { ".zip", "application/x-zip", write_zip_archive }, - { NULL } -}; - -static struct notes_tree snapshot_sig_notes[ARRAY_SIZE(cgit_snapshot_formats)]; - -const struct object_id *cgit_snapshot_get_sig(const char *ref, - const struct cgit_snapshot_format *f) -{ - struct notes_tree *tree; - struct object_id oid; - - if (repo_get_oid(the_repository, ref, &oid)) - return NULL; - - tree = &snapshot_sig_notes[f - &cgit_snapshot_formats[0]]; - if (!tree->initialized) { - struct strbuf notes_ref = STRBUF_INIT; - - strbuf_addf(¬es_ref, "refs/notes/signatures/%s", - f->suffix + 1); - - init_notes(tree, notes_ref.buf, combine_notes_ignore, 0); - strbuf_release(¬es_ref); - } - - return get_note(tree, &oid); -} - -static const struct cgit_snapshot_format *get_format(const char *filename) -{ - const struct cgit_snapshot_format *fmt; - - for (fmt = cgit_snapshot_formats; fmt->suffix; fmt++) { - if (ends_with(filename, fmt->suffix)) - return fmt; - } - return NULL; -} - -const unsigned cgit_snapshot_format_bit(const struct cgit_snapshot_format *f) -{ - return BIT(f - &cgit_snapshot_formats[0]); -} - -static int make_snapshot(const struct cgit_snapshot_format *format, - const char *hex, const char *prefix, - const char *filename) -{ - struct object_id oid; - - if (repo_get_oid(the_repository, hex, &oid)) { - cgit_print_error_page(404, "Not found", - "Bad object id: %s", hex); - return 1; - } - if (!lookup_commit_reference(the_repository, &oid)) { - cgit_print_error_page(400, "Bad request", - "Not a commit reference: %s", hex); - return 1; - } - ctx.page.etag = oid_to_hex(&oid); - ctx.page.mimetype = xstrdup(format->mimetype); - ctx.page.filename = xstrdup(filename); - cgit_print_http_headers(); - init_archivers(); - format->write_func(hex, prefix); - return 0; -} - -static int write_sig(const struct cgit_snapshot_format *format, - const char *hex, const char *archive, - const char *filename) -{ - const struct object_id *note = cgit_snapshot_get_sig(hex, format); - enum object_type type; - unsigned long size; - char *buf; - - if (!note) { - cgit_print_error_page(404, "Not found", - "No signature for %s", archive); - return 0; - } - - buf = repo_read_object_file(the_repository, note, &type, &size); - if (!buf) { - cgit_print_error_page(404, "Not found", "Not found"); - return 0; - } - - html("X-Content-Type-Options: nosniff\n"); - html("Content-Security-Policy: default-src 'none'\n"); - ctx.page.etag = oid_to_hex(note); - ctx.page.mimetype = xstrdup("application/pgp-signature"); - ctx.page.filename = xstrdup(filename); - cgit_print_http_headers(); - - html_raw(buf, size); - free(buf); - return 0; -} - -/* Try to guess the requested revision from the requested snapshot name. - * First the format extension is stripped, e.g. "cgit-0.7.2.tar.gz" become - * "cgit-0.7.2". If this is a valid commit object name we've got a winner. - * Otherwise, if the snapshot name has a prefix matching the result from - * repo_basename(), we strip the basename and any following '-' and '_' - * characters ("cgit-0.7.2" -> "0.7.2") and check the resulting name once - * more. If this still isn't a valid commit object name, we check if pre- - * pending a 'v' or a 'V' to the remaining snapshot name ("0.7.2" -> - * "v0.7.2") gives us something valid. - */ -static const char *get_ref_from_filename(const struct cgit_repo *repo, - const char *filename, - const struct cgit_snapshot_format *format) -{ - const char *reponame; - struct object_id oid; - struct strbuf snapshot = STRBUF_INIT; - int result = 1; - - strbuf_addstr(&snapshot, filename); - strbuf_setlen(&snapshot, snapshot.len - strlen(format->suffix)); - - if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0) - goto out; - - reponame = cgit_snapshot_prefix(repo); - if (starts_with(snapshot.buf, reponame)) { - const char *new_start = snapshot.buf; - new_start += strlen(reponame); - while (new_start && (*new_start == '-' || *new_start == '_')) - new_start++; - strbuf_splice(&snapshot, 0, new_start - snapshot.buf, "", 0); - } - - if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0) - goto out; - - strbuf_insert(&snapshot, 0, "v", 1); - if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0) - goto out; - - strbuf_splice(&snapshot, 0, 1, "V", 1); - if (repo_get_oid(the_repository, snapshot.buf, &oid) == 0) - goto out; - - result = 0; - strbuf_release(&snapshot); - -out: - return result ? strbuf_detach(&snapshot, NULL) : NULL; -} - -void cgit_print_snapshot(const char *head, const char *hex, - const char *filename, int dwim) -{ - const struct cgit_snapshot_format* f; - const char *sig_filename = NULL; - char *adj_filename = NULL; - char *prefix = NULL; - - if (!filename) { - cgit_print_error_page(400, "Bad request", - "No snapshot name specified"); - return; - } - - if (ends_with(filename, ".asc")) { - sig_filename = filename; - - /* Strip ".asc" from filename for common format processing */ - adj_filename = xstrdup(filename); - adj_filename[strlen(adj_filename) - 4] = '\0'; - filename = adj_filename; - } - - f = get_format(filename); - if (!f || (!sig_filename && !(ctx.repo->snapshots & cgit_snapshot_format_bit(f)))) { - cgit_print_error_page(400, "Bad request", - "Unsupported snapshot format: %s", filename); - return; - } - - if (!hex && dwim) { - hex = get_ref_from_filename(ctx.repo, filename, f); - if (hex == NULL) { - cgit_print_error_page(404, "Not found", "Not found"); - return; - } - prefix = xstrdup(filename); - prefix[strlen(filename) - strlen(f->suffix)] = '\0'; - } - - if (!hex) - hex = head; - - if (!prefix) - prefix = xstrdup(cgit_snapshot_prefix(ctx.repo)); - - if (sig_filename) - write_sig(f, hex, filename, sig_filename); - else - make_snapshot(f, hex, prefix, filename); - - free(prefix); - free(adj_filename); -} diff --git a/third_party/cgit/ui-snapshot.h b/third_party/cgit/ui-snapshot.h deleted file mode 100644 index a8deec369..000000000 --- a/third_party/cgit/ui-snapshot.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef UI_SNAPSHOT_H -#define UI_SNAPSHOT_H - -extern void cgit_print_snapshot(const char *head, const char *hex, - const char *filename, int dwim); - -#endif /* UI_SNAPSHOT_H */ diff --git a/third_party/cgit/ui-ssdiff.c b/third_party/cgit/ui-ssdiff.c deleted file mode 100644 index af8bc9e06..000000000 --- a/third_party/cgit/ui-ssdiff.c +++ /dev/null @@ -1,420 +0,0 @@ -#include "cgit.h" -#include "ui-ssdiff.h" -#include "html.h" -#include "ui-shared.h" -#include "ui-diff.h" - -extern int use_ssdiff; - -static int current_old_line, current_new_line; -static int **L = NULL; - -struct deferred_lines { - int line_no; - char *line; - struct deferred_lines *next; -}; - -static struct deferred_lines *deferred_old, *deferred_old_last; -static struct deferred_lines *deferred_new, *deferred_new_last; - -static void create_or_reset_lcs_table(void) -{ - int i; - - if (L != NULL) { - memset(*L, 0, sizeof(int) * MAX_SSDIFF_SIZE); - return; - } - - // xcalloc will die if we ran out of memory; - // not very helpful for debugging - L = (int**)xcalloc(MAX_SSDIFF_M, sizeof(int *)); - *L = (int*)xcalloc(MAX_SSDIFF_SIZE, sizeof(int)); - - for (i = 1; i < MAX_SSDIFF_M; i++) { - L[i] = *L + i * MAX_SSDIFF_N; - } -} - -static char *longest_common_subsequence(char *A, char *B) -{ - int i, j, ri; - int m = strlen(A); - int n = strlen(B); - int tmp1, tmp2; - int lcs_length; - char *result; - - // We bail if the lines are too long - if (m >= MAX_SSDIFF_M || n >= MAX_SSDIFF_N) - return NULL; - - create_or_reset_lcs_table(); - - for (i = m; i >= 0; i--) { - for (j = n; j >= 0; j--) { - if (A[i] == '\0' || B[j] == '\0') { - L[i][j] = 0; - } else if (A[i] == B[j]) { - L[i][j] = 1 + L[i + 1][j + 1]; - } else { - tmp1 = L[i + 1][j]; - tmp2 = L[i][j + 1]; - L[i][j] = (tmp1 > tmp2 ? tmp1 : tmp2); - } - } - } - - lcs_length = L[0][0]; - result = xmalloc(lcs_length + 2); - memset(result, 0, sizeof(*result) * (lcs_length + 2)); - - ri = 0; - i = 0; - j = 0; - while (i < m && j < n) { - if (A[i] == B[j]) { - result[ri] = A[i]; - ri += 1; - i += 1; - j += 1; - } else if (L[i + 1][j] >= L[i][j + 1]) { - i += 1; - } else { - j += 1; - } - } - - return result; -} - -static int line_from_hunk(char *line, char type) -{ - char *buf1, *buf2; - int len, res; - - buf1 = strchr(line, type); - if (buf1 == NULL) - return 0; - buf1 += 1; - buf2 = strchr(buf1, ','); - if (buf2 == NULL) - return 0; - len = buf2 - buf1; - buf2 = xmalloc(len + 1); - strlcpy(buf2, buf1, len + 1); - res = atoi(buf2); - free(buf2); - return res; -} - -static char *replace_tabs(char *line) -{ - char *prev_buf = line; - char *cur_buf; - size_t linelen = strlen(line); - int n_tabs = 0; - int i; - char *result; - size_t result_len; - - if (linelen == 0) { - result = xmalloc(1); - result[0] = '\0'; - return result; - } - - for (i = 0; i < linelen; i++) { - if (line[i] == '\t') - n_tabs += 1; - } - result_len = linelen + n_tabs * 8; - result = xmalloc(result_len + 1); - result[0] = '\0'; - - for (;;) { - cur_buf = strchr(prev_buf, '\t'); - if (!cur_buf) { - linelen = strlen(result); - strlcpy(&result[linelen], prev_buf, result_len - linelen + 1); - break; - } else { - linelen = strlen(result); - strlcpy(&result[linelen], prev_buf, cur_buf - prev_buf + 1); - linelen = strlen(result); - memset(&result[linelen], ' ', 8 - (linelen % 8)); - result[linelen + 8 - (linelen % 8)] = '\0'; - } - prev_buf = cur_buf + 1; - } - return result; -} - -static int calc_deferred_lines(struct deferred_lines *start) -{ - struct deferred_lines *item = start; - int result = 0; - while (item) { - result += 1; - item = item->next; - } - return result; -} - -static void deferred_old_add(char *line, int line_no) -{ - struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines)); - item->line = xstrdup(line); - item->line_no = line_no; - item->next = NULL; - if (deferred_old) { - deferred_old_last->next = item; - deferred_old_last = item; - } else { - deferred_old = deferred_old_last = item; - } -} - -static void deferred_new_add(char *line, int line_no) -{ - struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines)); - item->line = xstrdup(line); - item->line_no = line_no; - item->next = NULL; - if (deferred_new) { - deferred_new_last->next = item; - deferred_new_last = item; - } else { - deferred_new = deferred_new_last = item; - } -} - -static void print_part_with_lcs(char *class, char *line, char *lcs) -{ - int line_len = strlen(line); - int i, j; - char c[2] = " "; - int same = 1; - - j = 0; - for (i = 0; i < line_len; i++) { - c[0] = line[i]; - if (same) { - if (line[i] == lcs[j]) - j += 1; - else { - same = 0; - htmlf("", class); - } - } else if (line[i] == lcs[j]) { - same = 1; - html(""); - j += 1; - } - html_txt(c); - } - if (!same) - html(""); -} - -static void print_ssdiff_line(char *class, - int old_line_no, - char *old_line, - int new_line_no, - char *new_line, int individual_chars) -{ - char *lcs = NULL; - - if (old_line) - old_line = replace_tabs(old_line + 1); - if (new_line) - new_line = replace_tabs(new_line + 1); - if (individual_chars && old_line && new_line) - lcs = longest_common_subsequence(old_line, new_line); - html("\n"); - if (old_line_no > 0) { - struct diff_filespec *old_file = cgit_get_current_old_file(); - char *lineno_str = fmt("n%d", old_line_no); - char *id_str = fmt("id=%s#%s", is_null_oid(&old_file->oid)?"HEAD":oid_to_hex(old_rev_oid), lineno_str); - char *fileurl = cgit_fileurl(ctx.repo->url, "tree", old_file->path, id_str); - html("%s", lineno_str + 1); - html(""); - htmlf("", class); - free(fileurl); - } else if (old_line) - htmlf("", class); - else - htmlf("", class); - if (old_line) { - if (lcs) - print_part_with_lcs("del", old_line, lcs); - else - html_txt(old_line); - } - - html("\n"); - if (new_line_no > 0) { - struct diff_filespec *new_file = cgit_get_current_new_file(); - char *lineno_str = fmt("n%d", new_line_no); - char *id_str = fmt("id=%s#%s", is_null_oid(&new_file->oid)?"HEAD":oid_to_hex(new_rev_oid), lineno_str); - char *fileurl = cgit_fileurl(ctx.repo->url, "tree", new_file->path, id_str); - html("%s", lineno_str + 1); - html(""); - htmlf("", class); - free(fileurl); - } else if (new_line) - htmlf("", class); - else - htmlf("", class); - if (new_line) { - if (lcs) - print_part_with_lcs("add", new_line, lcs); - else - html_txt(new_line); - } - - html(""); - if (lcs) - free(lcs); - if (new_line) - free(new_line); - if (old_line) - free(old_line); -} - -static void print_deferred_old_lines(void) -{ - struct deferred_lines *iter_old, *tmp; - iter_old = deferred_old; - while (iter_old) { - print_ssdiff_line("del", iter_old->line_no, - iter_old->line, -1, NULL, 0); - tmp = iter_old->next; - free(iter_old); - iter_old = tmp; - } -} - -static void print_deferred_new_lines(void) -{ - struct deferred_lines *iter_new, *tmp; - iter_new = deferred_new; - while (iter_new) { - print_ssdiff_line("add", -1, NULL, - iter_new->line_no, iter_new->line, 0); - tmp = iter_new->next; - free(iter_new); - iter_new = tmp; - } -} - -static void print_deferred_changed_lines(void) -{ - struct deferred_lines *iter_old, *iter_new, *tmp; - int n_old_lines = calc_deferred_lines(deferred_old); - int n_new_lines = calc_deferred_lines(deferred_new); - int individual_chars = (n_old_lines == n_new_lines ? 1 : 0); - - iter_old = deferred_old; - iter_new = deferred_new; - while (iter_old || iter_new) { - if (iter_old && iter_new) - print_ssdiff_line("changed", iter_old->line_no, - iter_old->line, - iter_new->line_no, iter_new->line, - individual_chars); - else if (iter_old) - print_ssdiff_line("changed", iter_old->line_no, - iter_old->line, -1, NULL, 0); - else if (iter_new) - print_ssdiff_line("changed", -1, NULL, - iter_new->line_no, iter_new->line, 0); - if (iter_old) { - tmp = iter_old->next; - free(iter_old); - iter_old = tmp; - } - - if (iter_new) { - tmp = iter_new->next; - free(iter_new); - iter_new = tmp; - } - } -} - -void cgit_ssdiff_print_deferred_lines(void) -{ - if (!deferred_old && !deferred_new) - return; - if (deferred_old && !deferred_new) - print_deferred_old_lines(); - else if (!deferred_old && deferred_new) - print_deferred_new_lines(); - else - print_deferred_changed_lines(); - deferred_old = deferred_old_last = NULL; - deferred_new = deferred_new_last = NULL; -} - -/* - * print a single line returned from xdiff - */ -void cgit_ssdiff_line_cb(char *line, int len) -{ - char c = line[len - 1]; - line[len - 1] = '\0'; - if (line[0] == '@') { - current_old_line = line_from_hunk(line, '-'); - current_new_line = line_from_hunk(line, '+'); - } - - if (line[0] == ' ') { - if (deferred_old || deferred_new) - cgit_ssdiff_print_deferred_lines(); - print_ssdiff_line("ctx", current_old_line, line, - current_new_line, line, 0); - current_old_line += 1; - current_new_line += 1; - } else if (line[0] == '+') { - deferred_new_add(line, current_new_line); - current_new_line += 1; - } else if (line[0] == '-') { - deferred_old_add(line, current_old_line); - current_old_line += 1; - } else if (line[0] == '@') { - html(""); - html_txt(line); - html(""); - } else { - html(""); - html_txt(line); - html(""); - } - line[len - 1] = c; -} - -void cgit_ssdiff_header_begin(void) -{ - current_old_line = -1; - current_new_line = -1; - html("
    "); - html(""); -} - -void cgit_ssdiff_header_end(void) -{ - html(""); -} - -void cgit_ssdiff_footer(void) -{ - if (deferred_old || deferred_new) - cgit_ssdiff_print_deferred_lines(); - html(""); -} diff --git a/third_party/cgit/ui-ssdiff.h b/third_party/cgit/ui-ssdiff.h deleted file mode 100644 index 11f271440..000000000 --- a/third_party/cgit/ui-ssdiff.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef UI_SSDIFF_H -#define UI_SSDIFF_H - -/* - * ssdiff line limits - */ -#ifndef MAX_SSDIFF_M -#define MAX_SSDIFF_M 128 -#endif - -#ifndef MAX_SSDIFF_N -#define MAX_SSDIFF_N 128 -#endif -#define MAX_SSDIFF_SIZE ((MAX_SSDIFF_M) * (MAX_SSDIFF_N)) - -extern void cgit_ssdiff_print_deferred_lines(void); - -extern void cgit_ssdiff_line_cb(char *line, int len); - -extern void cgit_ssdiff_header_begin(void); -extern void cgit_ssdiff_header_end(void); - -extern void cgit_ssdiff_footer(void); - -#endif /* UI_SSDIFF_H */ diff --git a/third_party/cgit/ui-stats.c b/third_party/cgit/ui-stats.c deleted file mode 100644 index 9aed4ac3b..000000000 --- a/third_party/cgit/ui-stats.c +++ /dev/null @@ -1,425 +0,0 @@ -#include "cgit.h" -#include "ui-stats.h" -#include "html.h" -#include "ui-shared.h" - -struct authorstat { - long total; - struct string_list list; -}; - -#define DAY_SECS (60 * 60 * 24) -#define WEEK_SECS (DAY_SECS * 7) - -static void trunc_week(struct tm *tm) -{ - time_t t = timegm(tm); - t -= ((tm->tm_wday + 6) % 7) * DAY_SECS; - gmtime_r(&t, tm); -} - -static void dec_week(struct tm *tm) -{ - time_t t = timegm(tm); - t -= WEEK_SECS; - gmtime_r(&t, tm); -} - -static void inc_week(struct tm *tm) -{ - time_t t = timegm(tm); - t += WEEK_SECS; - gmtime_r(&t, tm); -} - -static char *pretty_week(struct tm *tm) -{ - static char buf[10]; - - strftime(buf, sizeof(buf), "W%V %G", tm); - return buf; -} - -static void trunc_month(struct tm *tm) -{ - tm->tm_mday = 1; -} - -static void dec_month(struct tm *tm) -{ - tm->tm_mon--; - if (tm->tm_mon < 0) { - tm->tm_year--; - tm->tm_mon = 11; - } -} - -static void inc_month(struct tm *tm) -{ - tm->tm_mon++; - if (tm->tm_mon > 11) { - tm->tm_year++; - tm->tm_mon = 0; - } -} - -static char *pretty_month(struct tm *tm) -{ - static const char *months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - return fmt("%s %d", months[tm->tm_mon], tm->tm_year + 1900); -} - -static void trunc_quarter(struct tm *tm) -{ - trunc_month(tm); - while (tm->tm_mon % 3 != 0) - dec_month(tm); -} - -static void dec_quarter(struct tm *tm) -{ - dec_month(tm); - dec_month(tm); - dec_month(tm); -} - -static void inc_quarter(struct tm *tm) -{ - inc_month(tm); - inc_month(tm); - inc_month(tm); -} - -static char *pretty_quarter(struct tm *tm) -{ - return fmt("Q%d %d", tm->tm_mon / 3 + 1, tm->tm_year + 1900); -} - -static void trunc_year(struct tm *tm) -{ - trunc_month(tm); - tm->tm_mon = 0; -} - -static void dec_year(struct tm *tm) -{ - tm->tm_year--; -} - -static void inc_year(struct tm *tm) -{ - tm->tm_year++; -} - -static char *pretty_year(struct tm *tm) -{ - return fmt("%d", tm->tm_year + 1900); -} - -static const struct cgit_period periods[] = { - {'w', "week", 12, 4, trunc_week, dec_week, inc_week, pretty_week}, - {'m', "month", 12, 4, trunc_month, dec_month, inc_month, pretty_month}, - {'q', "quarter", 12, 4, trunc_quarter, dec_quarter, inc_quarter, pretty_quarter}, - {'y', "year", 12, 4, trunc_year, dec_year, inc_year, pretty_year}, -}; - -/* Given a period code or name, return a period index (1, 2, 3 or 4) - * and update the period pointer to the correcsponding struct. - * If no matching code is found, return 0. - */ -int cgit_find_stats_period(const char *expr, const struct cgit_period **period) -{ - int i; - char code = '\0'; - - if (!expr) - return 0; - - if (strlen(expr) == 1) - code = expr[0]; - - for (i = 0; i < sizeof(periods) / sizeof(periods[0]); i++) - if (periods[i].code == code || !strcmp(periods[i].name, expr)) { - if (period) - *period = &periods[i]; - return i + 1; - } - return 0; -} - -const char *cgit_find_stats_periodname(int idx) -{ - if (idx > 0 && idx < 4) - return periods[idx - 1].name; - else - return ""; -} - -static void add_commit(struct string_list *authors, struct commit *commit, - const struct cgit_period *period) -{ - struct commitinfo *info; - struct string_list_item *author, *item; - struct authorstat *authorstat; - struct string_list *items; - char *tmp; - struct tm date; - time_t t; - uintptr_t *counter; - - info = cgit_parse_commit(commit); - tmp = xstrdup(info->author); - author = string_list_insert(authors, tmp); - if (!author->util) - author->util = xcalloc(1, sizeof(struct authorstat)); - else - free(tmp); - authorstat = author->util; - items = &authorstat->list; - t = info->committer_date; - gmtime_r(&t, &date); - period->trunc(&date); - tmp = xstrdup(period->pretty(&date)); - item = string_list_insert(items, tmp); - counter = (uintptr_t *)&item->util; - if (*counter) - free(tmp); - (*counter)++; - - authorstat->total++; - cgit_free_commitinfo(info); -} - -static int cmp_total_commits(const void *a1, const void *a2) -{ - const struct string_list_item *i1 = a1; - const struct string_list_item *i2 = a2; - const struct authorstat *auth1 = i1->util; - const struct authorstat *auth2 = i2->util; - - return auth2->total - auth1->total; -} - -/* Walk the commit DAG and collect number of commits per author per - * timeperiod into a nested string_list collection. - */ -static struct string_list collect_stats(const struct cgit_period *period) -{ - struct string_list authors; - struct rev_info rev; - struct commit *commit; - const char *argv[] = {NULL, ctx.qry.head, NULL, NULL, NULL, NULL}; - int argc = 3; - time_t now; - long i; - struct tm tm; - char tmp[11]; - - time(&now); - gmtime_r(&now, &tm); - period->trunc(&tm); - for (i = 1; i < period->count; i++) - period->dec(&tm); - strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm); - argv[2] = xstrdup(fmt("--since=%s", tmp)); - if (ctx.qry.path) { - argv[3] = "--"; - argv[4] = ctx.qry.path; - argc += 2; - } - repo_init_revisions(the_repository, &rev, NULL); - rev.abbrev = DEFAULT_ABBREV; - rev.commit_format = CMIT_FMT_DEFAULT; - rev.max_parents = 1; - rev.verbose_header = 1; - rev.show_root_diff = 0; - setup_revisions(argc, argv, &rev, NULL); - prepare_revision_walk(&rev); - memset(&authors, 0, sizeof(authors)); - while ((commit = get_revision(&rev)) != NULL) { - add_commit(&authors, commit, period); - release_commit_memory(the_repository->parsed_objects, commit); - commit->parents = NULL; - } - return authors; -} - -static void print_combined_authorrow(struct string_list *authors, int from, - int to, const char *name, - const char *leftclass, - const char *centerclass, - const char *rightclass, - const struct cgit_period *period) -{ - struct string_list_item *author; - struct authorstat *authorstat; - struct string_list *items; - struct string_list_item *date; - time_t now; - long i, j, total, subtotal; - struct tm tm; - char *tmp; - - time(&now); - gmtime_r(&now, &tm); - period->trunc(&tm); - for (i = 1; i < period->count; i++) - period->dec(&tm); - - total = 0; - htmlf("%s", leftclass, - fmt(name, to - from + 1)); - for (j = 0; j < period->count; j++) { - tmp = period->pretty(&tm); - period->inc(&tm); - subtotal = 0; - for (i = from; i <= to; i++) { - author = &authors->items[i]; - authorstat = author->util; - items = &authorstat->list; - date = string_list_lookup(items, tmp); - if (date) - subtotal += (uintptr_t)date->util; - } - htmlf("%ld", centerclass, subtotal); - total += subtotal; - } - htmlf("%ld", rightclass, total); -} - -static void print_authors(struct string_list *authors, int top, - const struct cgit_period *period) -{ - struct string_list_item *author; - struct authorstat *authorstat; - struct string_list *items; - struct string_list_item *date; - time_t now; - long i, j, total; - struct tm tm; - char *tmp; - - time(&now); - gmtime_r(&now, &tm); - period->trunc(&tm); - for (i = 1; i < period->count; i++) - period->dec(&tm); - - html(""); - for (j = 0; j < period->count; j++) { - tmp = period->pretty(&tm); - htmlf("", tmp); - period->inc(&tm); - } - html("\n"); - - if (top <= 0 || top > authors->nr) - top = authors->nr; - - for (i = 0; i < top; i++) { - author = &authors->items[i]; - html(""); - authorstat = author->util; - items = &authorstat->list; - total = 0; - for (j = 0; j < period->count; j++) - period->dec(&tm); - for (j = 0; j < period->count; j++) { - tmp = period->pretty(&tm); - period->inc(&tm); - date = string_list_lookup(items, tmp); - if (!date) - html(""); - else { - htmlf("", (uintptr_t)date->util); - total += (uintptr_t)date->util; - } - } - htmlf("", total); - } - - if (top < authors->nr) - print_combined_authorrow(authors, top, authors->nr - 1, - "Others (%ld)", "left", "", "sum", period); - - print_combined_authorrow(authors, 0, authors->nr - 1, "Total", - "total", "sum", "sum", period); - html("
    Author%sTotal
    "); - html_txt(author->string); - html("0%lu%ld
    "); -} - -/* Create a sorted string_list with one entry per author. The util-field - * for each author is another string_list which is used to calculate the - * number of commits per time-interval. - */ -void cgit_show_stats(void) -{ - struct string_list authors; - const struct cgit_period *period; - int top, i; - const char *code = "w"; - - if (ctx.qry.period) - code = ctx.qry.period; - - i = cgit_find_stats_period(code, &period); - if (!i) { - cgit_print_error_page(404, "Not found", - "Unknown statistics type: %c", code[0]); - return; - } - if (i > ctx.repo->max_stats) { - cgit_print_error_page(400, "Bad request", - "Statistics type disabled: %s", period->name); - return; - } - authors = collect_stats(period); - qsort(authors.items, authors.nr, sizeof(struct string_list_item), - cmp_total_commits); - - top = ctx.qry.ofs; - if (!top) - top = 10; - - cgit_print_layout_start(); - html("
    "); - html("stat options"); - html("
    "); - cgit_add_hidden_formfields(1, 0, "stats"); - html(""); - if (ctx.repo->max_stats > 1) { - html(""); - html(""); - } - html(""); - html(""); - html("
    Period:
    Authors:
    "); - html(""); - html("
    "); - html("
    "); - html("
    "); - htmlf("

    Commits per author per %s", period->name); - if (ctx.qry.path) { - html(" (path '"); - html_txt(ctx.qry.path); - html("')"); - } - html("

    "); - print_authors(&authors, top, period); - cgit_print_layout_end(); -} - diff --git a/third_party/cgit/ui-stats.h b/third_party/cgit/ui-stats.h deleted file mode 100644 index 0e61b03da..000000000 --- a/third_party/cgit/ui-stats.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef UI_STATS_H -#define UI_STATS_H - -#include "cgit.h" - -struct cgit_period { - const char code; - const char *name; - int max_periods; - int count; - - /* Convert a tm value to the first day in the period */ - void (*trunc)(struct tm *tm); - - /* Update tm value to start of next/previous period */ - void (*dec)(struct tm *tm); - void (*inc)(struct tm *tm); - - /* Pretty-print a tm value */ - char *(*pretty)(struct tm *tm); -}; - -extern int cgit_find_stats_period(const char *expr, const struct cgit_period **period); -extern const char *cgit_find_stats_periodname(int idx); - -extern void cgit_show_stats(void); - -#endif /* UI_STATS_H */ diff --git a/third_party/cgit/ui-summary.c b/third_party/cgit/ui-summary.c deleted file mode 100644 index ec7b76fab..000000000 --- a/third_party/cgit/ui-summary.c +++ /dev/null @@ -1,163 +0,0 @@ -/* ui-summary.c: functions for generating repo summary page - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-summary.h" -#include "html.h" -#include "ui-blob.h" -#include "ui-log.h" -#include "ui-plain.h" -#include "ui-refs.h" -#include "ui-shared.h" - -static int urls; - -static void print_url(const char *url) -{ - int columns = 3; - - if (ctx.repo->enable_log_filecount) - columns++; - if (ctx.repo->enable_log_linecount) - columns++; - - if (urls++ == 0) { - htmlf(" ", columns); - htmlf("Clone\n", columns); - } - - htmlf(""); - html_txt(url); - html("\n"); -} - -void cgit_print_summary(void) -{ - int columns = 3; - - if (ctx.repo->enable_log_filecount) - columns++; - if (ctx.repo->enable_log_linecount) - columns++; - - cgit_print_layout_start(); - html(""); - cgit_print_branches(ctx.cfg.summary_branches); - htmlf("", columns); - cgit_print_tags(ctx.cfg.summary_tags); - if (ctx.cfg.summary_log > 0) { - htmlf("", columns); - cgit_print_log(ctx.qry.head, 0, ctx.cfg.summary_log, NULL, - NULL, NULL, 0, 0, 0); - } - urls = 0; - cgit_add_clone_urls(print_url); - html("
     
     
    "); - cgit_print_layout_end(); -} - -/* The caller must free the return value. */ -static char* append_readme_path(const char *filename, const char *ref, const char *path) -{ - char *file, *base_dir, *full_path, *resolved_base = NULL, *resolved_full = NULL; - /* If a subpath is specified for the about page, make it relative - * to the directory containing the configured readme. */ - - file = xstrdup(filename); - base_dir = dirname(file); - if (!strcmp(base_dir, ".") || !strcmp(base_dir, "..")) { - if (!ref) { - free(file); - return NULL; - } - full_path = xstrdup(path); - } else - full_path = fmtalloc("%s/%s", base_dir, path); - - if (!ref) { - resolved_base = realpath(base_dir, NULL); - resolved_full = realpath(full_path, NULL); - if (!resolved_base || !resolved_full || !starts_with(resolved_full, resolved_base)) { - free(full_path); - full_path = NULL; - } - } - - free(file); - free(resolved_base); - free(resolved_full); - - return full_path; -} - -void cgit_print_repo_readme(const char *path) -{ - char *filename, *ref, *mimetype; - int free_filename = 0; - - mimetype = get_mimetype_for_filename(path); - if (mimetype && (!strncmp(mimetype, "image/", 6) || !strncmp(mimetype, "video/", 6))) { - ctx.page.mimetype = mimetype; - ctx.page.charset = NULL; - cgit_print_plain(); - free(mimetype); - return; - } - free(mimetype); - - if (path) - ctx.page.title = fmtalloc("%s - %s", path, ctx.page.title); - - cgit_print_layout_start(); - if (ctx.repo->readme.nr == 0) - goto done; - - filename = ctx.repo->readme.items[0].string; - ref = ctx.repo->readme.items[0].util; - - if (path) { - free_filename = 1; - filename = append_readme_path(filename, ref, path); - if (!filename) - goto done; - } - - /* Determine which file to serve by checking whether the given filename is - * already a valid file and otherwise appending the expected file name of - * the readme. - * - * If neither yield a valid file, the user gets a blank page. Could probably - * do with an error message in between there, but whatever. - */ - if (path && ref && !cgit_ref_path_exists(filename, ref, 1)) { - filename = fmtalloc("%s/%s", path, ctx.repo->readme.items[0].string); - free_filename = 1; - } - - /* Print the calculated readme, either from the git repo or from the - * filesystem, while applying the about-filter. - */ - html("
    "); - cgit_open_filter(ctx.repo->about_filter, filename); - if (ref) - cgit_print_file(filename, ref, 1); - else - html_include(filename); - cgit_close_filter(ctx.repo->about_filter); - - html("
    "); - if (free_filename) - free(filename); - -done: - cgit_print_layout_end(); -} diff --git a/third_party/cgit/ui-summary.h b/third_party/cgit/ui-summary.h deleted file mode 100644 index cba696af5..000000000 --- a/third_party/cgit/ui-summary.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef UI_SUMMARY_H -#define UI_SUMMARY_H - -extern void cgit_print_summary(void); -extern void cgit_print_repo_readme(const char *path); - -#endif /* UI_SUMMARY_H */ diff --git a/third_party/cgit/ui-tag.c b/third_party/cgit/ui-tag.c deleted file mode 100644 index be1122b90..000000000 --- a/third_party/cgit/ui-tag.c +++ /dev/null @@ -1,120 +0,0 @@ -/* ui-tag.c: display a tag - * - * Copyright (C) 2006-2014 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-tag.h" -#include "html.h" -#include "ui-shared.h" - -static void print_tag_content(char *buf) -{ - char *p; - - if (!buf) - return; - - html("
    "); - p = strchr(buf, '\n'); - if (p) - *p = '\0'; - html_txt(buf); - html("
    "); - if (p) { - html("
    ");
    -		html_txt(++p);
    -		html("
    "); - } -} - -static void print_download_links(char *revname) -{ - html("download"); - cgit_print_snapshot_links(ctx.repo, revname, "
    "); - html(""); -} - -void cgit_print_tag(char *revname) -{ - struct strbuf fullref = STRBUF_INIT; - struct object_id oid; - struct object *obj; - - if (!revname) - revname = ctx.qry.head; - - strbuf_addf(&fullref, "refs/tags/%s", revname); - if (repo_get_oid(the_repository, fullref.buf, &oid)) { - cgit_print_error_page(404, "Not found", - "Bad tag reference: %s", revname); - goto cleanup; - } - obj = parse_object(the_repository, &oid); - if (!obj) { - cgit_print_error_page(500, "Internal server error", - "Bad object id: %s", oid_to_hex(&oid)); - goto cleanup; - } - if (obj->type == OBJ_TAG) { - struct tag *tag; - struct taginfo *info; - - tag = lookup_tag(the_repository, &oid); - if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) { - cgit_print_error_page(500, "Internal server error", - "Bad tag object: %s", revname); - goto cleanup; - } - cgit_print_layout_start(); - html("\n"); - html("\n", oid_to_hex(&oid)); - if (info->tagger_date > 0) { - html("\n"); - } - if (info->tagger) { - html("\n"); - } - html("\n"); - if (ctx.repo->snapshots) - print_download_links(revname); - html("
    tag name"); - html_txt(revname); - htmlf(" (%s)
    tag date"); - html_txt(show_date(info->tagger_date, info->tagger_tz, - cgit_date_mode(DATE_DOTTIME))); - html("
    tagged by"); - cgit_open_filter(ctx.repo->email_filter, info->tagger_email, "tag"); - html_txt(info->tagger); - if (info->tagger_email && !ctx.cfg.noplainemail) { - html(" "); - html_txt(info->tagger_email); - } - cgit_close_filter(ctx.repo->email_filter); - html("
    tagged object"); - cgit_object_link(tag->tagged); - html("
    \n"); - print_tag_content(info->msg); - cgit_print_layout_end(); - cgit_free_taginfo(info); - } else { - cgit_print_layout_start(); - html("\n"); - html("\n"); - html("\n"); - if (ctx.repo->snapshots) - print_download_links(revname); - html("
    tag name"); - html_txt(revname); - html("
    tagged object"); - cgit_object_link(obj); - html("
    \n"); - cgit_print_layout_end(); - } - -cleanup: - strbuf_release(&fullref); -} diff --git a/third_party/cgit/ui-tag.h b/third_party/cgit/ui-tag.h deleted file mode 100644 index d295cdcdb..000000000 --- a/third_party/cgit/ui-tag.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UI_TAG_H -#define UI_TAG_H - -extern void cgit_print_tag(char *revname); - -#endif /* UI_TAG_H */ diff --git a/third_party/cgit/ui-tree.c b/third_party/cgit/ui-tree.c deleted file mode 100644 index 436b33380..000000000 --- a/third_party/cgit/ui-tree.c +++ /dev/null @@ -1,411 +0,0 @@ -/* ui-tree.c: functions for tree output - * - * Copyright (C) 2006-2017 cgit Development Team - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" -#include "ui-tree.h" -#include "html.h" -#include "ui-shared.h" - -struct walk_tree_context { - char *curr_rev; - char *match_path; - int state; -}; - -static void print_text_buffer(const char *name, char *buf, unsigned long size) -{ - unsigned long lineno, idx; - const char *numberfmt = "%1$d\n"; - - html("\n"); - - if (ctx.cfg.enable_tree_linenumbers) { - html("\n"); - } - else { - html("\n"); - } - - if (ctx.repo->source_filter) { - char *filter_arg = xstrdup(name); - html("
    ");
    -		idx = 0;
    -		lineno = 0;
    -
    -		if (size) {
    -			htmlf(numberfmt, ++lineno);
    -			while (idx < size - 1) { // skip absolute last newline
    -				if (buf[idx] == '\n')
    -					htmlf(numberfmt, ++lineno);
    -				idx++;
    -			}
    -		}
    -		html("
    ");
    -		cgit_open_filter(ctx.repo->source_filter, filter_arg);
    -		html_raw(buf, size);
    -		cgit_close_filter(ctx.repo->source_filter);
    -		free(filter_arg);
    -		html("
    \n"); - return; - } - - html("
    ");
    -	html_txt(buf);
    -	html("
    \n"); -} - -#define ROWLEN 32 - -static void print_binary_buffer(char *buf, unsigned long size) -{ - unsigned long ofs, idx; - static char ascii[ROWLEN + 1]; - - html("\n"); - html(""); - for (ofs = 0; ofs < size; ofs += ROWLEN, buf += ROWLEN) { - htmlf("\n"); - } - html("
    ofshex dumpascii
    %04lx", ofs); - for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) - htmlf("%*s%02x", - idx == 16 ? 4 : 1, "", - buf[idx] & 0xff); - html(" "); - for (idx = 0; idx < ROWLEN && ofs + idx < size; idx++) - ascii[idx] = isgraph(buf[idx]) ? buf[idx] : '.'; - ascii[idx] = '\0'; - html_txt(ascii); - html("
    \n"); -} - -static void print_object(const struct object_id *oid, const char *path, const char *basename, const char *rev) -{ - enum object_type type; - char *buf; - unsigned long size; - int is_binary; - - type = oid_object_info(the_repository, oid, &size); - if (type == OBJ_BAD) { - cgit_print_error_page(404, "Not found", - "Bad object name: %s", oid_to_hex(oid)); - return; - } - - buf = repo_read_object_file(the_repository, oid, &type, &size); - if (!buf) { - cgit_print_error_page(500, "Internal server error", - "Error reading object %s", oid_to_hex(oid)); - return; - } - is_binary = buffer_is_binary(buf, size); - - cgit_set_title_from_path(path); - - cgit_print_layout_start(); - htmlf("blob: %s (", oid_to_hex(oid)); - cgit_plain_link("plain", NULL, NULL, ctx.qry.head, - rev, path); - if (ctx.repo->enable_blame && !is_binary) { - html(") ("); - cgit_blame_link("blame", NULL, NULL, ctx.qry.head, - rev, path); - } - html(")\n"); - - if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) { - htmlf("
    blob size (%ldKB) exceeds display size limit (%dKB).
    ", - size / 1024, ctx.cfg.max_blob_size); - return; - } - - if (is_binary) - print_binary_buffer(buf, size); - else - print_text_buffer(basename, buf, size); - - free(buf); -} - -struct single_tree_ctx { - struct strbuf *path; - struct object_id oid; - char *name; - size_t count; -}; - -static int single_tree_cb(const struct object_id *oid, struct strbuf *base, - const char *pathname, unsigned mode, void *cbdata) -{ - struct single_tree_ctx *ctx = cbdata; - - if (++ctx->count > 1) - return -1; - - if (!S_ISDIR(mode)) { - ctx->count = 2; - return -1; - } - - ctx->name = xstrdup(pathname); - oidcpy(&ctx->oid, oid); - strbuf_addf(ctx->path, "/%s", pathname); - return 0; -} - -static void write_tree_link(const struct object_id *oid, char *name, - char *rev, struct strbuf *fullpath) -{ - size_t initial_length = fullpath->len; - struct tree *tree; - struct single_tree_ctx tree_ctx = { - .path = fullpath, - .count = 1, - }; - struct pathspec paths = { - .nr = 0 - }; - - oidcpy(&tree_ctx.oid, oid); - - while (tree_ctx.count == 1) { - cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, rev, - fullpath->buf); - - tree = lookup_tree(the_repository, &tree_ctx.oid); - if (!tree) - return; - - free(tree_ctx.name); - tree_ctx.name = NULL; - tree_ctx.count = 0; - - read_tree(the_repository, tree, &paths, single_tree_cb, &tree_ctx); - - if (tree_ctx.count != 1) - break; - - html(" / "); - name = tree_ctx.name; - } - - strbuf_setlen(fullpath, initial_length); -} - -static int ls_item(const struct object_id *oid, struct strbuf *base, - const char *pathname, unsigned mode, void *cbdata) -{ - struct walk_tree_context *walk_tree_ctx = cbdata; - char *name; - struct strbuf fullpath = STRBUF_INIT; - struct strbuf linkpath = STRBUF_INIT; - struct strbuf class = STRBUF_INIT; - enum object_type type; - unsigned long size = 0; - char *buf; - - name = xstrdup(pathname); - strbuf_addf(&fullpath, "%s%s%s", ctx.qry.path ? ctx.qry.path : "", - ctx.qry.path ? "/" : "", name); - - if (!S_ISGITLINK(mode)) { - type = oid_object_info(the_repository, oid, &size); - if (type == OBJ_BAD) { - htmlf("Bad object: %s %s", - name, - oid_to_hex(oid)); - goto cleanup; - } - } - - html(""); - cgit_print_filemode(mode); - html(""); - if (S_ISGITLINK(mode)) { - cgit_submodule_link("ls-mod", fullpath.buf, oid_to_hex(oid)); - } else if (S_ISDIR(mode)) { - write_tree_link(oid, name, walk_tree_ctx->curr_rev, - &fullpath); - } else { - char *ext = strrchr(name, '.'); - strbuf_addstr(&class, "ls-blob"); - if (ext) - strbuf_addf(&class, " %s", ext + 1); - cgit_tree_link(name, NULL, class.buf, ctx.qry.head, - walk_tree_ctx->curr_rev, fullpath.buf); - } - if (S_ISLNK(mode)) { - html(" -> "); - buf = repo_read_object_file(the_repository, oid, &type, &size); - if (!buf) { - htmlf("Error reading object: %s", oid_to_hex(oid)); - goto cleanup; - } - strbuf_addbuf(&linkpath, &fullpath); - strbuf_addf(&linkpath, "/../%s", buf); - strbuf_normalize_path(&linkpath); - cgit_tree_link(buf, NULL, class.buf, ctx.qry.head, - walk_tree_ctx->curr_rev, linkpath.buf); - free(buf); - strbuf_release(&linkpath); - } - htmlf("%li", size); - - html(""); - cgit_log_link("log", NULL, "button", ctx.qry.head, - walk_tree_ctx->curr_rev, fullpath.buf, 0, NULL, NULL, - ctx.qry.showmsg, 0); - if (ctx.repo->max_stats) { - html(" "); - cgit_stats_link("stats", NULL, "button", ctx.qry.head, - fullpath.buf); - } - if (!S_ISGITLINK(mode)) { - html(" "); - cgit_plain_link("plain", NULL, "button", ctx.qry.head, - walk_tree_ctx->curr_rev, fullpath.buf); - } - if (!S_ISDIR(mode) && ctx.repo->enable_blame) { - html(" "); - cgit_blame_link("blame", NULL, "button", ctx.qry.head, - walk_tree_ctx->curr_rev, fullpath.buf); - } - html("\n"); - -cleanup: - free(name); - strbuf_release(&fullpath); - strbuf_release(&class); - return 0; -} - -static void ls_head(void) -{ - cgit_print_layout_start(); - html("\n"); - html(""); - html(""); - html(""); - html(""); - html("\n"); -} - -static void ls_tail(void) -{ - html("
    ModeNameSize"); - html("
    \n"); - cgit_print_layout_end(); -} - -static void ls_tree(const struct object_id *oid, const char *path, struct walk_tree_context *walk_tree_ctx) -{ - struct tree *tree; - struct pathspec paths = { - .nr = 0 - }; - - tree = parse_tree_indirect(oid); - if (!tree) { - cgit_print_error_page(404, "Not found", - "Not a tree object: %s", oid_to_hex(oid)); - return; - } - - ls_head(); - read_tree(the_repository, tree, &paths, ls_item, walk_tree_ctx); - ls_tail(); -} - - -static int walk_tree(const struct object_id *oid, struct strbuf *base, - const char *pathname, unsigned mode, void *cbdata) -{ - struct walk_tree_context *walk_tree_ctx = cbdata; - - if (walk_tree_ctx->state == 0) { - struct strbuf buffer = STRBUF_INIT; - - strbuf_addbuf(&buffer, base); - strbuf_addstr(&buffer, pathname); - if (strcmp(walk_tree_ctx->match_path, buffer.buf)) - return READ_TREE_RECURSIVE; - - if (S_ISDIR(mode)) { - walk_tree_ctx->state = 1; - cgit_set_title_from_path(buffer.buf); - strbuf_release(&buffer); - ls_head(); - return READ_TREE_RECURSIVE; - } else { - walk_tree_ctx->state = 2; - print_object(oid, buffer.buf, pathname, walk_tree_ctx->curr_rev); - strbuf_release(&buffer); - return 0; - } - } - ls_item(oid, base, pathname, mode, walk_tree_ctx); - return 0; -} - -/* - * Show a tree or a blob - * rev: the commit pointing at the root tree object - * path: path to tree or blob - */ -void cgit_print_tree(const char *rev, char *path) -{ - struct object_id oid; - struct commit *commit; - struct pathspec_item path_items = { - .match = path, - .len = path ? strlen(path) : 0 - }; - struct pathspec paths = { - .nr = path ? 1 : 0, - .items = &path_items - }; - struct walk_tree_context walk_tree_ctx = { - .match_path = path, - .state = 0 - }; - - if (!rev) - rev = ctx.qry.head; - - if (repo_get_oid(the_repository, rev, &oid)) { - cgit_print_error_page(404, "Not found", - "Invalid revision name: %s", rev); - return; - } - commit = lookup_commit_reference(the_repository, &oid); - if (!commit || repo_parse_commit(the_repository, commit)) { - cgit_print_error_page(404, "Not found", - "Invalid commit reference: %s", rev); - return; - } - - walk_tree_ctx.curr_rev = xstrdup(rev); - - if (path == NULL) { - ls_tree(get_commit_tree_oid(commit), NULL, &walk_tree_ctx); - goto cleanup; - } - - read_tree(the_repository, repo_get_commit_tree(the_repository, commit), - &paths, walk_tree, &walk_tree_ctx); - if (walk_tree_ctx.state == 1) - ls_tail(); - else if (walk_tree_ctx.state == 2) - cgit_print_layout_end(); - else - cgit_print_error_page(404, "Not found", "Path not found"); - -cleanup: - free(walk_tree_ctx.curr_rev); -} diff --git a/third_party/cgit/ui-tree.h b/third_party/cgit/ui-tree.h deleted file mode 100644 index bbd34e356..000000000 --- a/third_party/cgit/ui-tree.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef UI_TREE_H -#define UI_TREE_H - -extern void cgit_print_tree(const char *rev, char *path); - -#endif /* UI_TREE_H */ diff --git a/third_party/elmPackages_0_18/default.nix b/third_party/elmPackages_0_18/default.nix deleted file mode 100644 index 0481d0940..000000000 --- a/third_party/elmPackages_0_18/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -# Backports Elm packages for Elm 0.18 from an older channel of -# nixpkgs. -# -# Elm 0.19 changed the language & package ecosystem completely, -# essentially requiring a partial rewrite of all Elm apps. However, -# //fun/gemma uses Elm 0.18 and I don't have time to rewrite it. -# -# Since the ABIs of current glibc and the pinned version have diverged -# too much, we need to build //fun/gemma completely based on a historical -# nixpkgs version. - -{ pkgs, ... }: - -(import - (pkgs.fetchFromGitHub { - owner = "NixOS"; - repo = "nixpkgs"; - rev = "14f9ee66e63077539252f8b4550049381a082518"; - sha256 = "1wn7nmb1cqfk2j91l3rwc6yhimfkzxprb8wknw5wi57yhq9m6lv1"; - }) -{ }) diff --git a/third_party/emacs/rcirc/default.nix b/third_party/emacs/rcirc/default.nix deleted file mode 100644 index f34cbed78..000000000 --- a/third_party/emacs/rcirc/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage rec { - pname = "rcirc"; - version = "1"; - src = ./rcirc.el; -} diff --git a/third_party/emacs/rcirc/rcirc.el b/third_party/emacs/rcirc/rcirc.el deleted file mode 100644 index b59cb4e9a..000000000 --- a/third_party/emacs/rcirc/rcirc.el +++ /dev/null @@ -1,3133 +0,0 @@ -;;; rcirc.el --- default, simple IRC client -*- lexical-binding: t; -*- - -;; Copyright (C) 2005-2019 Free Software Foundation, Inc. - -;; Author: Ryan Yeske -;; Maintainers: Ryan Yeske , -;; Leo Liu -;; Keywords: comm - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; Internet Relay Chat (IRC) is a form of instant communication over -;; the Internet. It is mainly designed for group (many-to-many) -;; communication in discussion forums called channels, but also allows -;; one-to-one communication. - -;; Rcirc has simple defaults and clear and consistent behavior. -;; Message arrival timestamps, activity notification on the mode line, -;; message filling, nick completion, and keepalive pings are all -;; enabled by default, but can easily be adjusted or turned off. Each -;; discussion takes place in its own buffer and there is a single -;; server buffer per connection. - -;; Open a new irc connection with: -;; M-x irc RET - -;;; Todo: - -;;; Code: - -(require 'cl-lib) -(require 'ring) -(require 'time-date) -(require 'subr-x) - -(defgroup rcirc nil - "Simple IRC client." - :version "22.1" - :prefix "rcirc-" - :link '(custom-manual "(rcirc)") - :group 'applications) - -(defcustom rcirc-server-alist - '(("irc.freenode.net" :channels ("#rcirc") - ;; Don't use the TLS port by default, in case gnutls is not available. - ;; :port 7000 :encryption tls - )) - "An alist of IRC connections to establish when running `rcirc'. -Each element looks like (SERVER-NAME PARAMETERS). - -SERVER-NAME is a string describing the server to connect -to. - -The optional PARAMETERS come in pairs PARAMETER VALUE. - -The following parameters are recognized: - -`:nick' - -VALUE must be a string. If absent, `rcirc-default-nick' is used -for this connection. - -`:port' - -VALUE must be a number or string. If absent, -`rcirc-default-port' is used. - -`:user-name' - -VALUE must be a string. If absent, `rcirc-default-user-name' is -used. - -`:password' - -VALUE must be a string. If absent, no PASS command will be sent -to the server. - -`:full-name' - -VALUE must be a string. If absent, `rcirc-default-full-name' is -used. - -`:channels' - -VALUE must be a list of strings describing which channels to join -when connecting to this server. If absent, no channels will be -connected to automatically. - -`:encryption' - -VALUE must be `plain' (the default) for unencrypted connections, or `tls' -for connections using SSL/TLS. - -`:server-alias' - -VALUE must be a string that will be used instead of the server name for -display purposes. If absent, the real server name will be displayed instead." - :type '(alist :key-type string - :value-type (plist :options - ((:nick string) - (:port integer) - (:user-name string) - (:password string) - (:full-name string) - (:channels (repeat string)) - (:encryption (choice (const tls) - (const plain))) - (:server-alias string)))) - :group 'rcirc) - -(defcustom rcirc-default-port 6667 - "The default port to connect to." - :type 'integer - :group 'rcirc) - -(defcustom rcirc-default-nick (user-login-name) - "Your nick." - :type 'string - :group 'rcirc) - -(defcustom rcirc-default-user-name "user" - "Your user name sent to the server when connecting." - :version "24.1" ; changed default - :type 'string - :group 'rcirc) - -(defcustom rcirc-default-full-name "unknown" - "The full name sent to the server when connecting." - :version "24.1" ; changed default - :type 'string - :group 'rcirc) - -(defcustom rcirc-fill-flag t - "Non-nil means line-wrap messages printed in channel buffers." - :type 'boolean - :group 'rcirc) - -(defcustom rcirc-fill-column nil - "Column beyond which automatic line-wrapping should happen. -If nil, use value of `fill-column'. -If a function (e.g., `frame-text-width' or `window-text-width'), -call it to compute the number of columns." - :risky t ; can get funcalled - :type '(choice (const :tag "Value of `fill-column'" nil) - (integer :tag "Number of columns") - (function :tag "Function returning the number of columns")) - :group 'rcirc) - -(defcustom rcirc-fill-prefix nil - "Text to insert before filled lines. -If nil, calculate the prefix dynamically to line up text -underneath each nick." - :type '(choice (const :tag "Dynamic" nil) - (string :tag "Prefix text")) - :group 'rcirc) - -(defvar rcirc-ignore-buffer-activity-flag nil - "If non-nil, ignore activity in this buffer.") -(make-variable-buffer-local 'rcirc-ignore-buffer-activity-flag) - -(defvar rcirc-low-priority-flag nil - "If non-nil, activity in this buffer is considered low priority.") -(make-variable-buffer-local 'rcirc-low-priority-flag) - -(defcustom rcirc-omit-responses - '("JOIN" "PART" "QUIT" "NICK") - "Responses which will be hidden when `rcirc-omit-mode' is enabled." - :type '(repeat string) - :group 'rcirc) - -(defvar rcirc-prompt-start-marker nil) - -(define-minor-mode rcirc-omit-mode - "Toggle the hiding of \"uninteresting\" lines. -With a prefix argument ARG, enable Rcirc-Omit mode if ARG is -positive, and disable it otherwise. If called from Lisp, enable -the mode if ARG is omitted or nil. - -Uninteresting lines are those whose responses are listed in -`rcirc-omit-responses'." - nil " Omit" nil - (if rcirc-omit-mode - (progn - (add-to-invisibility-spec '(rcirc-omit . nil)) - (message "Rcirc-Omit mode enabled")) - (remove-from-invisibility-spec '(rcirc-omit . nil)) - (message "Rcirc-Omit mode disabled")) - (dolist (window (get-buffer-window-list (current-buffer))) - (with-selected-window window - (recenter (when (> (point) rcirc-prompt-start-marker) -1))))) - -(defcustom rcirc-time-format "%H:%M " - "Describes how timestamps are printed. -Used as the first arg to `format-time-string'." - :type 'string - :group 'rcirc) - -(defcustom rcirc-input-ring-size 1024 - "Size of input history ring." - :type 'integer - :group 'rcirc) - -(defcustom rcirc-read-only-flag t - "Non-nil means make text in IRC buffers read-only." - :type 'boolean - :group 'rcirc) - -(defcustom rcirc-buffer-maximum-lines nil - "The maximum size in lines for rcirc buffers. -Channel buffers are truncated from the top to be no greater than this -number. If zero or nil, no truncating is done." - :type '(choice (const :tag "No truncation" nil) - (integer :tag "Number of lines")) - :group 'rcirc) - -(defcustom rcirc-scroll-show-maximum-output t - "If non-nil, scroll buffer to keep the point at the bottom of -the window." - :type 'boolean - :group 'rcirc) - -(defcustom rcirc-authinfo nil - "List of authentication passwords. -Each element of the list is a list with a SERVER-REGEXP string -and a method symbol followed by method specific arguments. - -The valid METHOD symbols are `nickserv', `chanserv' and -`bitlbee'. - -The ARGUMENTS for each METHOD symbol are: - `nickserv': NICK PASSWORD [NICKSERV-NICK] - `chanserv': NICK CHANNEL PASSWORD - `bitlbee': NICK PASSWORD - `quakenet': ACCOUNT PASSWORD - -Examples: - ((\"freenode\" nickserv \"bob\" \"p455w0rd\") - (\"freenode\" chanserv \"bob\" \"#bobland\" \"passwd99\") - (\"bitlbee\" bitlbee \"robert\" \"sekrit\") - (\"dal.net\" nickserv \"bob\" \"sekrit\" \"NickServ@services.dal.net\") - (\"quakenet.org\" quakenet \"bobby\" \"sekrit\"))" - :type '(alist :key-type (string :tag "Server") - :value-type (choice (list :tag "NickServ" - (const nickserv) - (string :tag "Nick") - (string :tag "Password")) - (list :tag "ChanServ" - (const chanserv) - (string :tag "Nick") - (string :tag "Channel") - (string :tag "Password")) - (list :tag "BitlBee" - (const bitlbee) - (string :tag "Nick") - (string :tag "Password")) - (list :tag "QuakeNet" - (const quakenet) - (string :tag "Account") - (string :tag "Password")))) - :group 'rcirc) - -(defcustom rcirc-auto-authenticate-flag t - "Non-nil means automatically send authentication string to server. -See also `rcirc-authinfo'." - :type 'boolean - :group 'rcirc) - -(defcustom rcirc-authenticate-before-join t - "Non-nil means authenticate to services before joining channels. -Currently only works with NickServ on some networks." - :version "24.1" - :type 'boolean - :group 'rcirc) - -(defcustom rcirc-prompt "> " - "Prompt string to use in IRC buffers. - -The following replacements are made: -%n is your nick. -%s is the server. -%t is the buffer target, a channel or a user. - -Setting this alone will not affect the prompt; -use either M-x customize or also call `rcirc-update-prompt'." - :type 'string - :set 'rcirc-set-changed - :initialize 'custom-initialize-default - :group 'rcirc) - -(defcustom rcirc-keywords nil - "List of keywords to highlight in message text." - :type '(repeat string) - :group 'rcirc) - -(defcustom rcirc-ignore-list () - "List of ignored nicks. -Use /ignore to list them, use /ignore NICK to add or remove a nick." - :type '(repeat string) - :group 'rcirc) - -(defvar rcirc-ignore-list-automatic () - "List of ignored nicks added to `rcirc-ignore-list' because of renaming. -When an ignored person renames, their nick is added to both lists. -Nicks will be removed from the automatic list on follow-up renamings or -parts.") - -(defcustom rcirc-bright-nicks nil - "List of nicks to be emphasized. -See `rcirc-bright-nick' face." - :type '(repeat string) - :group 'rcirc) - -(defcustom rcirc-dim-nicks nil - "List of nicks to be deemphasized. -See `rcirc-dim-nick' face." - :type '(repeat string) - :group 'rcirc) - -(define-obsolete-variable-alias 'rcirc-print-hooks - 'rcirc-print-functions "24.3") -(defcustom rcirc-print-functions nil - "Hook run after text is printed. -Called with 5 arguments, PROCESS, SENDER, RESPONSE, TARGET and TEXT." - :type 'hook - :group 'rcirc) - -(defvar rcirc-authenticated-hook nil - "Hook run after successfully authenticated.") - -(defcustom rcirc-always-use-server-buffer-flag nil - "Non-nil means messages without a channel target will go to the server buffer." - :type 'boolean - :group 'rcirc) - -(defcustom rcirc-decode-coding-system 'utf-8 - "Coding system used to decode incoming irc messages. -Set to `undecided' if you want the encoding of the incoming -messages autodetected." - :type 'coding-system - :group 'rcirc) - -(defcustom rcirc-encode-coding-system 'utf-8 - "Coding system used to encode outgoing irc messages." - :type 'coding-system - :group 'rcirc) - -(defcustom rcirc-coding-system-alist nil - "Alist to decide a coding system to use for a channel I/O operation. -The format is ((PATTERN . VAL) ...). -PATTERN is either a string or a cons of strings. -If PATTERN is a string, it is used to match a target. -If PATTERN is a cons of strings, the car part is used to match a -target, and the cdr part is used to match a server. -VAL is either a coding system or a cons of coding systems. -If VAL is a coding system, it is used for both decoding and encoding -messages. -If VAL is a cons of coding systems, the car part is used for decoding, -and the cdr part is used for encoding." - :type '(alist :key-type (choice (string :tag "Channel Regexp") - (cons (string :tag "Channel Regexp") - (string :tag "Server Regexp"))) - :value-type (choice coding-system - (cons (coding-system :tag "Decode") - (coding-system :tag "Encode")))) - :group 'rcirc) - -(defcustom rcirc-multiline-major-mode 'fundamental-mode - "Major-mode function to use in multiline edit buffers." - :type 'function - :group 'rcirc) - -(defcustom rcirc-nick-completion-format "%s: " - "Format string to use in nick completions. - -The format string is only used when completing at the beginning -of a line. The string is passed as the first argument to -`format' with the nickname as the second argument." - :version "24.1" - :type 'string - :group 'rcirc) - -(defcustom rcirc-kill-channel-buffers nil - "When non-nil, kill channel buffers when the server buffer is killed. -Only the channel buffers associated with the server in question -will be killed." - :version "24.3" - :type 'boolean - :group 'rcirc) - -(defvar rcirc-nick nil) - -(defvar rcirc-prompt-end-marker nil) - -(defvar rcirc-nick-table nil) - -(defvar rcirc-recent-quit-alist nil - "Alist of nicks that have recently quit or parted the channel.") - -(defvar rcirc-nick-syntax-table - (let ((table (make-syntax-table text-mode-syntax-table))) - (mapc (lambda (c) (modify-syntax-entry c "w" table)) - "[]\\`_^{|}-") - (modify-syntax-entry ?' "_" table) - table) - "Syntax table which includes all nick characters as word constituents.") - -;; each process has an alist of (target . buffer) pairs -(defvar rcirc-buffer-alist nil) - -(defvar rcirc-activity nil - "List of buffers with unviewed activity.") - -(defvar rcirc-activity-string "" - "String displayed in mode line representing `rcirc-activity'.") -(put 'rcirc-activity-string 'risky-local-variable t) - -(defvar rcirc-server-buffer nil - "The server buffer associated with this channel buffer.") - -(defvar rcirc-target nil - "The channel or user associated with this buffer.") - -(defvar rcirc-urls nil - "List of URLs seen in the current buffer and their start positions.") -(put 'rcirc-urls 'permanent-local t) - -(defvar rcirc-timeout-seconds 600 - "Kill connection after this many seconds if there is no activity.") - -(defconst rcirc-id-string (concat "rcirc on GNU Emacs " emacs-version)) - -(defvar rcirc-startup-channels nil) - -(defvar rcirc-server-name-history nil - "History variable for \\[rcirc] call.") - -(defvar rcirc-server-port-history nil - "History variable for \\[rcirc] call.") - -(defvar rcirc-nick-name-history nil - "History variable for \\[rcirc] call.") - -(defvar rcirc-user-name-history nil - "History variable for \\[rcirc] call.") - -(defvar rcirc-last-message-time nil) - -;;;###autoload -(defun rcirc (arg) - "Connect to all servers in `rcirc-server-alist'. - -Do not connect to a server if it is already connected. - -If ARG is non-nil, instead prompt for connection parameters." - (interactive "P") - (if arg - (let* ((server (completing-read "IRC Server: " - rcirc-server-alist - nil nil - (caar rcirc-server-alist) - 'rcirc-server-name-history)) - (server-plist (cdr (assoc-string server rcirc-server-alist))) - (port (read-string "IRC Port: " - (number-to-string - (or (plist-get server-plist :port) - rcirc-default-port)) - 'rcirc-server-port-history)) - (nick (read-string "IRC Nick: " - (or (plist-get server-plist :nick) - rcirc-default-nick) - 'rcirc-nick-name-history)) - (user-name (read-string "IRC Username: " - (or (plist-get server-plist :user-name) - rcirc-default-user-name) - 'rcirc-user-name-history)) - (password (read-passwd "IRC Password: " nil - (plist-get server-plist :password))) - (channels (split-string - (read-string "IRC Channels: " - (mapconcat 'identity - (plist-get server-plist - :channels) - " ")) - "[, ]+" t)) - (encryption (rcirc-prompt-for-encryption server-plist))) - (rcirc-connect server port nick user-name - rcirc-default-full-name - channels password encryption)) - ;; connect to servers in `rcirc-server-alist' - (let (connected-servers) - (dolist (c rcirc-server-alist) - (let ((server (car c)) - (nick (or (plist-get (cdr c) :nick) rcirc-default-nick)) - (port (or (plist-get (cdr c) :port) rcirc-default-port)) - (user-name (or (plist-get (cdr c) :user-name) - rcirc-default-user-name)) - (full-name (or (plist-get (cdr c) :full-name) - rcirc-default-full-name)) - (channels (plist-get (cdr c) :channels)) - (password (plist-get (cdr c) :password)) - (encryption (plist-get (cdr c) :encryption)) - (server-alias (plist-get (cdr c) :server-alias)) - contact) - (when server - (let (connected) - (dolist (p (rcirc-process-list)) - (when (string= (or server-alias server) (process-name p)) - (setq connected p))) - (if (not connected) - (condition-case nil - (rcirc-connect server port nick user-name - full-name channels password encryption - server-alias) - (quit (message "Quit connecting to %s" - (or server-alias server)))) - (with-current-buffer (process-buffer connected) - (setq contact (process-contact - (get-buffer-process (current-buffer)) :name)) - (setq connected-servers - (cons (if (stringp contact) - contact (or server-alias server)) - connected-servers)))))))) - (when connected-servers - (message "Already connected to %s" - (if (cdr connected-servers) - (concat (mapconcat 'identity (butlast connected-servers) ", ") - ", and " - (car (last connected-servers))) - (car connected-servers))))))) - -;;;###autoload -(defalias 'irc 'rcirc) - - -(defvar rcirc-process-output nil) -(defvar rcirc-topic nil) -(defvar rcirc-keepalive-timer nil) -(defvar rcirc-last-server-message-time nil) -(defvar rcirc-server nil) ; server provided by server -(defvar rcirc-server-name nil) ; server name given by 001 response -(defvar rcirc-timeout-timer nil) -(defvar rcirc-user-authenticated nil) -(defvar rcirc-user-disconnect nil) -(defvar rcirc-connecting nil) -(defvar rcirc-connection-info nil) -(defvar rcirc-process nil) - -;;;###autoload -(defun rcirc-connect (server &optional port nick user-name - full-name startup-channels password encryption - server-alias) - (save-excursion - (message "Connecting to %s..." (or server-alias server)) - (let* ((inhibit-eol-conversion) - (port-number (if port - (if (stringp port) - (string-to-number port) - port) - rcirc-default-port)) - (nick (or nick rcirc-default-nick)) - (user-name (or user-name rcirc-default-user-name)) - (full-name (or full-name rcirc-default-full-name)) - (startup-channels startup-channels) - (process (open-network-stream - (or server-alias server) nil server port-number - :type (or encryption 'plain)))) - ;; set up process - (set-process-coding-system process 'raw-text 'raw-text) - (switch-to-buffer (rcirc-generate-new-buffer-name process nil)) - (set-process-buffer process (current-buffer)) - (rcirc-mode process nil) - (set-process-sentinel process 'rcirc-sentinel) - (set-process-filter process 'rcirc-filter) - - (setq-local rcirc-connection-info - (list server port nick user-name full-name startup-channels - password encryption server-alias)) - (setq-local rcirc-process process) - (setq-local rcirc-server server) - (setq-local rcirc-server-name - (or server-alias server)) ; Update when we get 001 response. - (setq-local rcirc-buffer-alist nil) - (setq-local rcirc-nick-table (make-hash-table :test 'equal)) - (setq-local rcirc-nick nick) - (setq-local rcirc-process-output nil) - (setq-local rcirc-startup-channels startup-channels) - (setq-local rcirc-last-server-message-time (current-time)) - - (setq-local rcirc-timeout-timer nil) - (setq-local rcirc-user-disconnect nil) - (setq-local rcirc-user-authenticated nil) - (setq-local rcirc-connecting t) - - (add-hook 'auto-save-hook 'rcirc-log-write) - - ;; identify - (unless (zerop (length password)) - (rcirc-send-string process (concat "PASS " password))) - (rcirc-send-string process (concat "NICK " nick)) - (rcirc-send-string process "CAP LS 302") - (rcirc-send-string process (concat "USER " user-name - " 0 * :" full-name)) - - ;; setup ping timer if necessary - (unless rcirc-keepalive-timer - (setq rcirc-keepalive-timer - (run-at-time 0 (/ rcirc-timeout-seconds 2) 'rcirc-keepalive))) - - (message "Connecting to %s...done" (or server-alias server)) - - ;; return process object - process))) - -(defmacro with-rcirc-process-buffer (process &rest body) - (declare (indent 1) (debug t)) - `(with-current-buffer (process-buffer ,process) - ,@body)) - -(defmacro with-rcirc-server-buffer (&rest body) - (declare (indent 0) (debug t)) - `(with-current-buffer rcirc-server-buffer - ,@body)) - -(define-obsolete-function-alias 'rcirc-float-time 'float-time "26.1") - -(defun rcirc-prompt-for-encryption (server-plist) - "Prompt the user for the encryption method to use. -SERVER-PLIST is the property list for the server." - (let ((msg "Encryption (default %s): ") - (choices '("plain" "tls")) - (default (or (plist-get server-plist :encryption) - 'plain))) - (intern - (completing-read (format msg default) - choices nil t nil nil (symbol-name default))))) - -(defun rcirc-keepalive () - "Send keep alive pings to active rcirc processes. -Kill processes that have not received a server message since the -last ping." - (if (rcirc-process-list) - (mapc (lambda (process) - (with-rcirc-process-buffer process - (when (not rcirc-connecting) - (rcirc-send-ctcp process - rcirc-nick - (format "KEEPALIVE %f" - (float-time)))))) - (rcirc-process-list)) - ;; no processes, clean up timer - (when (timerp rcirc-keepalive-timer) - (cancel-timer rcirc-keepalive-timer)) - (setq rcirc-keepalive-timer nil))) - -(defun rcirc-handler-ctcp-KEEPALIVE (process _target _sender message) - (with-rcirc-process-buffer process - (setq header-line-format (format "%f" (- (float-time) - (string-to-number message)))))) - -(defvar rcirc-debug-buffer "*rcirc debug*") -(defvar rcirc-debug-flag nil - "If non-nil, write information to `rcirc-debug-buffer'.") -(defun rcirc-debug (process text) - "Add an entry to the debug log including PROCESS and TEXT. -Debug text is written to `rcirc-debug-buffer' if `rcirc-debug-flag' -is non-nil." - (when rcirc-debug-flag - (with-current-buffer (get-buffer-create rcirc-debug-buffer) - (goto-char (point-max)) - (insert (concat - "[" - (format-time-string "%Y-%m-%dT%T ") (process-name process) - "] " - text))))) - -(define-obsolete-variable-alias 'rcirc-sentinel-hooks - 'rcirc-sentinel-functions "24.3") -(defvar rcirc-sentinel-functions nil - "Hook functions called when the process sentinel is called. -Functions are called with PROCESS and SENTINEL arguments.") - -(defcustom rcirc-reconnect-delay 0 - "The minimum interval in seconds between reconnect attempts. -When 0, do not auto-reconnect." - :version "25.1" - :type 'integer - :group 'rcirc) - -(defvar rcirc-last-connect-time nil - "The last time the buffer was connected.") - -(defun rcirc-sentinel (process sentinel) - "Called when PROCESS receives SENTINEL." - (let ((sentinel (replace-regexp-in-string "\n" "" sentinel))) - (rcirc-debug process (format "SENTINEL: %S %S\n" process sentinel)) - (with-rcirc-process-buffer process - (dolist (buffer (cons nil (mapcar 'cdr rcirc-buffer-alist))) - (with-current-buffer (or buffer (current-buffer)) - (rcirc-print process "rcirc.el" "ERROR" rcirc-target - (format "%s: %s (%S)" - (process-name process) - sentinel - (process-status process)) - (not rcirc-target)) - (rcirc-disconnect-buffer))) - (when (and (string= sentinel "deleted") - (< 0 rcirc-reconnect-delay)) - (let ((now (current-time))) - (when (or (null rcirc-last-connect-time) - (< rcirc-reconnect-delay - (float-time (time-subtract now rcirc-last-connect-time)))) - (setq rcirc-last-connect-time now) - (rcirc-cmd-reconnect nil)))) - (run-hook-with-args 'rcirc-sentinel-functions process sentinel)))) - -(defun rcirc-disconnect-buffer (&optional buffer) - (with-current-buffer (or buffer (current-buffer)) - ;; set rcirc-target to nil for each channel so cleanup - ;; doesn't happen when we reconnect - (setq rcirc-target nil) - (setq mode-line-process ":disconnected"))) - -(defun rcirc-process-list () - "Return a list of rcirc processes." - (let (ps) - (mapc (lambda (p) - (when (buffer-live-p (process-buffer p)) - (with-rcirc-process-buffer p - (when (eq major-mode 'rcirc-mode) - (setq ps (cons p ps)))))) - (process-list)) - ps)) - -(define-obsolete-variable-alias 'rcirc-receive-message-hooks - 'rcirc-receive-message-functions "24.3") -(defvar rcirc-receive-message-functions nil - "Hook functions run when a message is received from server. -Function is called with PROCESS, COMMAND, SENDER, ARGS and LINE.") -(defun rcirc-filter (process output) - "Called when PROCESS receives OUTPUT." - (rcirc-debug process output) - (rcirc-reschedule-timeout process) - (with-rcirc-process-buffer process - (setq rcirc-last-server-message-time (current-time)) - (setq rcirc-process-output (concat rcirc-process-output output)) - (when (= ?\n (aref rcirc-process-output - (1- (length rcirc-process-output)))) - (let ((lines (split-string rcirc-process-output "[\n\r]" t))) - (setq rcirc-process-output nil) - (dolist (line lines) - (rcirc-process-server-response process line)))))) - -(defun rcirc-reschedule-timeout (process) - (with-rcirc-process-buffer process - (when (not rcirc-connecting) - (with-rcirc-process-buffer process - (when rcirc-timeout-timer (cancel-timer rcirc-timeout-timer)) - (setq rcirc-timeout-timer (run-at-time rcirc-timeout-seconds nil - 'rcirc-delete-process - process)))))) - -(defun rcirc-delete-process (process) - (delete-process process)) - -(defvar rcirc-trap-errors-flag t) -(defun rcirc-process-server-response (process text) - (if rcirc-trap-errors-flag - (condition-case err - (rcirc-process-server-response-1 process text) - (error - (rcirc-print process "RCIRC" "ERROR" nil - (format "\"%s\" %s" text err) t))) - (rcirc-process-server-response-1 process text))) - -(defun rcirc-handle-message-tags (tags) - (if-let* ((time (cdr (assoc "time" tags))) - (timestamp (floor (float-time (date-to-time time))))) - (setq rcirc-last-message-time timestamp))) - -(defun rcirc-parse-tags (tags) - "Parse TAGS message prefix." - (mapcar (lambda (tag) - (let ((p (split-string tag "="))) - `(,(car p) . ,(cadr p)))) - (split-string tags ";"))) - -(defun rcirc-process-server-response-1 (process text) - - ;; attempt to extract and handle IRCv3 message tags (which contain server-time) - (if (string-match "^\\(@\\([^ ]+\\) \\)?\\(\\(:[^ ]+ \\)?[^ ]+ .+\\)$" text) - (let ((tags (match-string 2 text)) - (rest (match-string 3 text))) - (when tags - (rcirc-handle-message-tags (rcirc-parse-tags tags))) - (setq text rest))) - - (if (string-match "^\\(:\\([^ ]+\\) \\)?\\([^ ]+\\) \\(.+\\)$" text) - (let* ((user (match-string 2 text)) - (sender (rcirc-user-nick user)) - (cmd (match-string 3 text)) - (args (match-string 4 text)) - (handler (intern-soft (concat "rcirc-handler-" cmd)))) - (string-match "^\\([^:]*\\):?\\(.+\\)?$" args) - (let* ((args1 (match-string 1 args)) - (args2 (match-string 2 args)) - (args (delq nil (append (split-string args1 " " t) - (list args2))))) - (if (not (fboundp handler)) - (rcirc-handler-generic process cmd sender args text) - (funcall handler process sender args text)) - (run-hook-with-args 'rcirc-receive-message-functions - process cmd sender args text))) - (message "UNHANDLED: %s" text))) - -(defvar rcirc-responses-no-activity '("305" "306") - "Responses that don't trigger activity in the mode-line indicator.") - -(defun rcirc-handler-generic (process response sender args _text) - "Generic server response handler." - (rcirc-print process sender response nil - (mapconcat 'identity (cdr args) " ") - (not (member response rcirc-responses-no-activity)))) - -(defun rcirc--connection-open-p (process) - (memq (process-status process) '(run open))) - -(defun rcirc-send-string (process string) - "Send PROCESS a STRING plus a newline." - (let ((string (concat (encode-coding-string string rcirc-encode-coding-system) - "\n"))) - (unless (rcirc--connection-open-p process) - (error "Network connection to %s is not open" - (process-name process))) - (rcirc-debug process string) - (process-send-string process string))) - -(defun rcirc-send-privmsg (process target string) - (rcirc-send-string process (format "PRIVMSG %s :%s" target string))) - -(defun rcirc-send-ctcp (process target request &optional args) - (let ((args (if args (concat " " args) ""))) - (rcirc-send-privmsg process target - (format "\C-a%s%s\C-a" request args)))) - -(defun rcirc-buffer-process (&optional buffer) - "Return the process associated with channel BUFFER. -With no argument or nil as argument, use the current buffer." - (let ((buffer (or buffer (and (buffer-live-p rcirc-server-buffer) - rcirc-server-buffer)))) - (if buffer - (with-current-buffer buffer rcirc-process) - rcirc-process))) - -(defun rcirc-server-name (process) - "Return PROCESS server name, given by the 001 response." - (with-rcirc-process-buffer process - (or rcirc-server-name - (warn "server name for process %S unknown" process)))) - -(defun rcirc-nick (process) - "Return PROCESS nick." - (with-rcirc-process-buffer process - (or rcirc-nick rcirc-default-nick))) - -(defun rcirc-buffer-nick (&optional buffer) - "Return the nick associated with BUFFER. -With no argument or nil as argument, use the current buffer." - (with-current-buffer (or buffer (current-buffer)) - (with-current-buffer rcirc-server-buffer - (or rcirc-nick rcirc-default-nick)))) - -(defvar rcirc-max-message-length 420 - "Messages longer than this value will be split.") - -(defun rcirc-split-message (message) - "Split MESSAGE into chunks within `rcirc-max-message-length'." - ;; `rcirc-encode-coding-system' can have buffer-local value. - (let ((encoding rcirc-encode-coding-system)) - (with-temp-buffer - (insert message) - (goto-char (point-min)) - (let (result) - (while (not (eobp)) - (goto-char (or (byte-to-position rcirc-max-message-length) - (point-max))) - ;; max message length is 512 including CRLF - (while (and (not (bobp)) - (> (length (encode-coding-region - (point-min) (point) encoding t)) - rcirc-max-message-length)) - (forward-char -1)) - (push (delete-and-extract-region (point-min) (point)) result)) - (nreverse result))))) - -(defun rcirc-send-message (process target message &optional noticep silent) - "Send TARGET associated with PROCESS a privmsg with text MESSAGE. -If NOTICEP is non-nil, send a notice instead of privmsg. -If SILENT is non-nil, do not print the message in any irc buffer." - (let ((response (if noticep "NOTICE" "PRIVMSG"))) - (rcirc-get-buffer-create process target) - (dolist (msg (rcirc-split-message message)) - (rcirc-send-string process (concat response " " target " :" msg)) - (unless silent - (rcirc-print process (rcirc-nick process) response target msg))))) - -(defvar rcirc-input-ring nil) -(defvar rcirc-input-ring-index 0) - -(defun rcirc-prev-input-string (arg) - (ring-ref rcirc-input-ring (+ rcirc-input-ring-index arg))) - -(defun rcirc-insert-prev-input () - (interactive) - (when (<= rcirc-prompt-end-marker (point)) - (delete-region rcirc-prompt-end-marker (point-max)) - (insert (rcirc-prev-input-string 0)) - (setq rcirc-input-ring-index (1+ rcirc-input-ring-index)))) - -(defun rcirc-insert-next-input () - (interactive) - (when (<= rcirc-prompt-end-marker (point)) - (delete-region rcirc-prompt-end-marker (point-max)) - (setq rcirc-input-ring-index (1- rcirc-input-ring-index)) - (insert (rcirc-prev-input-string -1)))) - -(defvar rcirc-server-commands - '("/admin" "/away" "/connect" "/die" "/error" "/info" - "/invite" "/ison" "/join" "/kick" "/kill" "/links" - "/list" "/lusers" "/mode" "/motd" "/names" "/nick" - "/notice" "/oper" "/part" "/pass" "/ping" "/pong" - "/privmsg" "/quit" "/rehash" "/restart" "/service" "/servlist" - "/server" "/squery" "/squit" "/stats" "/summon" "/time" - "/topic" "/trace" "/user" "/userhost" "/users" "/version" - "/wallops" "/who" "/whois" "/whowas") - "A list of user commands by IRC server. -The value defaults to RFCs 1459 and 2812.") - -;; /me and /ctcp are not defined by `defun-rcirc-command'. -(defvar rcirc-client-commands '("/me" "/ctcp") - "A list of user commands defined by IRC client rcirc. -The list is updated automatically by `defun-rcirc-command'.") - -(defun rcirc-completion-at-point () - "Function used for `completion-at-point-functions' in `rcirc-mode'." - (and (rcirc-looking-at-input) - (let* ((beg (save-excursion - ;; On some networks it is common to message or - ;; mention someone using @nick instead of just - ;; nick. - (if (re-search-backward "[[:space:]@]" rcirc-prompt-end-marker t) - (1+ (point)) - rcirc-prompt-end-marker))) - (table (if (and (= beg rcirc-prompt-end-marker) - (eq (char-after beg) ?/)) - (delete-dups - (nconc (sort (copy-sequence rcirc-client-commands) - 'string-lessp) - (sort (copy-sequence rcirc-server-commands) - 'string-lessp))) - (rcirc-channel-nicks (rcirc-buffer-process) - rcirc-target)))) - (list beg (point) table)))) - -(defvar rcirc-completions nil) -(defvar rcirc-completion-start nil) - -(defun rcirc-complete () - "Cycle through completions from list of nicks in channel or IRC commands. -IRC command completion is performed only if `/' is the first input char." - (interactive) - (unless (rcirc-looking-at-input) - (error "Point not located after rcirc prompt")) - (if (eq last-command this-command) - (setq rcirc-completions - (append (cdr rcirc-completions) (list (car rcirc-completions)))) - (let ((completion-ignore-case t) - (table (rcirc-completion-at-point))) - (setq rcirc-completion-start (car table)) - (setq rcirc-completions - (and rcirc-completion-start - (all-completions (buffer-substring rcirc-completion-start - (cadr table)) - (nth 2 table)))))) - (let ((completion (car rcirc-completions))) - (when completion - (delete-region rcirc-completion-start (point)) - (insert - (cond - ((= (aref completion 0) ?/) (concat completion " ")) - ((= rcirc-completion-start rcirc-prompt-end-marker) - (format rcirc-nick-completion-format completion)) - (t completion)))))) - -(defun set-rcirc-decode-coding-system (coding-system) - "Set the decode coding system used in this channel." - (interactive "zCoding system for incoming messages: ") - (setq-local rcirc-decode-coding-system coding-system)) - -(defun set-rcirc-encode-coding-system (coding-system) - "Set the encode coding system used in this channel." - (interactive "zCoding system for outgoing messages: ") - (setq-local rcirc-encode-coding-system coding-system)) - -(defvar rcirc-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "RET") 'rcirc-send-input) - (define-key map (kbd "M-p") 'rcirc-insert-prev-input) - (define-key map (kbd "M-n") 'rcirc-insert-next-input) - (define-key map (kbd "TAB") 'rcirc-complete) - (define-key map (kbd "C-c C-b") 'rcirc-browse-url) - (define-key map (kbd "C-c C-c") 'rcirc-edit-multiline) - (define-key map (kbd "C-c C-j") 'rcirc-cmd-join) - (define-key map (kbd "C-c C-k") 'rcirc-cmd-kick) - (define-key map (kbd "C-c C-l") 'rcirc-toggle-low-priority) - (define-key map (kbd "C-c C-d") 'rcirc-cmd-mode) - (define-key map (kbd "C-c C-m") 'rcirc-cmd-msg) - (define-key map (kbd "C-c C-r") 'rcirc-cmd-nick) ; rename - (define-key map (kbd "C-c C-o") 'rcirc-omit-mode) - (define-key map (kbd "C-c C-p") 'rcirc-cmd-part) - (define-key map (kbd "C-c C-q") 'rcirc-cmd-query) - (define-key map (kbd "C-c C-t") 'rcirc-cmd-topic) - (define-key map (kbd "C-c C-n") 'rcirc-cmd-names) - (define-key map (kbd "C-c C-w") 'rcirc-cmd-whois) - (define-key map (kbd "C-c C-x") 'rcirc-cmd-quit) - (define-key map (kbd "C-c TAB") ; C-i - 'rcirc-toggle-ignore-buffer-activity) - (define-key map (kbd "C-c C-s") 'rcirc-switch-to-server-buffer) - (define-key map (kbd "C-c C-a") 'rcirc-jump-to-first-unread-line) - map) - "Keymap for rcirc mode.") - -(defvar rcirc-short-buffer-name nil - "Generated abbreviation to use to indicate buffer activity.") - -(defvar rcirc-mode-hook nil - "Hook run when setting up rcirc buffer.") - -(defvar rcirc-last-post-time nil) - -(defvar rcirc-log-alist nil - "Alist of lines to log to disk when `rcirc-log-flag' is non-nil. -Each element looks like (FILENAME . TEXT).") - -(defvar rcirc-current-line 0 - "The current number of responses printed in this channel. -This number is independent of the number of lines in the buffer.") - -(defun rcirc-mode (process target) - ;; FIXME: Use define-derived-mode. - "Major mode for IRC channel buffers. - -\\{rcirc-mode-map}" - (kill-all-local-variables) - (use-local-map rcirc-mode-map) - (setq mode-name "rcirc") - (setq major-mode 'rcirc-mode) - (setq mode-line-process nil) - - (setq-local rcirc-input-ring - ;; If rcirc-input-ring is already a ring with desired - ;; size do not re-initialize. - (if (and (ring-p rcirc-input-ring) - (= (ring-size rcirc-input-ring) - rcirc-input-ring-size)) - rcirc-input-ring - (make-ring rcirc-input-ring-size))) - (setq-local rcirc-server-buffer (process-buffer process)) - (setq-local rcirc-target target) - (setq-local rcirc-topic nil) - (setq-local rcirc-last-post-time (current-time)) - (setq-local fill-paragraph-function 'rcirc-fill-paragraph) - (setq-local rcirc-recent-quit-alist nil) - (setq-local rcirc-current-line 0) - (setq-local rcirc-last-connect-time (current-time)) - - (use-hard-newlines t) - (setq-local rcirc-short-buffer-name nil) - (setq-local rcirc-urls nil) - - ;; setup for omitting responses - (setq buffer-invisibility-spec '()) - (setq buffer-display-table (make-display-table)) - (set-display-table-slot buffer-display-table 4 - (let ((glyph (make-glyph-code - ?. 'font-lock-keyword-face))) - (make-vector 3 glyph))) - - (dolist (i rcirc-coding-system-alist) - (let ((chan (if (consp (car i)) (caar i) (car i))) - (serv (if (consp (car i)) (cdar i) ""))) - (when (and (string-match chan (or target "")) - (string-match serv (rcirc-server-name process))) - (setq-local rcirc-decode-coding-system - (if (consp (cdr i)) (cadr i) (cdr i))) - (setq-local rcirc-encode-coding-system - (if (consp (cdr i)) (cddr i) (cdr i)))))) - - ;; setup the prompt and markers - (setq-local rcirc-prompt-start-marker (point-max-marker)) - (setq-local rcirc-prompt-end-marker (point-max-marker)) - (rcirc-update-prompt) - (goto-char rcirc-prompt-end-marker) - - (setq-local overlay-arrow-position (make-marker)) - - ;; if the user changes the major mode or kills the buffer, there is - ;; cleanup work to do - (add-hook 'change-major-mode-hook 'rcirc-change-major-mode-hook nil t) - (add-hook 'kill-buffer-hook 'rcirc-kill-buffer-hook nil t) - - ;; add to buffer list, and update buffer abbrevs - (when target ; skip server buffer - (let ((buffer (current-buffer))) - (with-rcirc-process-buffer process - (setq rcirc-buffer-alist (cons (cons target buffer) - rcirc-buffer-alist)))) - (rcirc-update-short-buffer-names)) - - (add-hook 'completion-at-point-functions - 'rcirc-completion-at-point nil 'local) - - (run-mode-hooks 'rcirc-mode-hook)) - -(defun rcirc-update-prompt (&optional all) - "Reset the prompt string in the current buffer. - -If ALL is non-nil, update prompts in all IRC buffers." - (if all - (mapc (lambda (process) - (mapc (lambda (buffer) - (with-current-buffer buffer - (rcirc-update-prompt))) - (with-rcirc-process-buffer process - (mapcar 'cdr rcirc-buffer-alist)))) - (rcirc-process-list)) - (let ((inhibit-read-only t) - (prompt (or rcirc-prompt ""))) - (mapc (lambda (rep) - (setq prompt - (replace-regexp-in-string (car rep) (cdr rep) prompt))) - (list (cons "%n" (rcirc-buffer-nick)) - (cons "%s" (with-rcirc-server-buffer rcirc-server-name)) - (cons "%t" (or rcirc-target "")))) - (save-excursion - (delete-region rcirc-prompt-start-marker rcirc-prompt-end-marker) - (goto-char rcirc-prompt-start-marker) - (let ((start (point))) - (insert-before-markers prompt) - (set-marker rcirc-prompt-start-marker start) - (when (not (zerop (- rcirc-prompt-end-marker - rcirc-prompt-start-marker))) - (add-text-properties rcirc-prompt-start-marker - rcirc-prompt-end-marker - (list 'face 'rcirc-prompt - 'read-only t 'field t - 'front-sticky t 'rear-nonsticky t)))))))) - -(defun rcirc-set-changed (option value) - "Set OPTION to VALUE and do updates after a customization change." - (set-default option value) - (cond ((eq option 'rcirc-prompt) - (rcirc-update-prompt 'all)) - (t - (error "Bad option %s" option)))) - -(defun rcirc-channel-p (target) - "Return t if TARGET is a channel name." - (and target - (not (zerop (length target))) - (or (eq (aref target 0) ?#) - (eq (aref target 0) ?&)))) - -(defcustom rcirc-log-directory "~/.emacs.d/rcirc-log" - "Directory to keep IRC logfiles." - :type 'directory - :group 'rcirc) - -(defcustom rcirc-log-flag nil - "Non-nil means log IRC activity to disk. -Logfiles are kept in `rcirc-log-directory'." - :type 'boolean - :group 'rcirc) - -(defun rcirc-kill-buffer-hook () - "Part the channel when killing an rcirc buffer. - -If `rcirc-kill-channel-buffers' is non-nil and the killed buffer -is a server buffer, kills all of the channel buffers associated -with it." - (when (eq major-mode 'rcirc-mode) - (when (and rcirc-log-flag - rcirc-log-directory) - (rcirc-log-write)) - (rcirc-clean-up-buffer "Killed buffer") - (when (and rcirc-buffer-alist ;; it's a server buffer - rcirc-kill-channel-buffers) - (dolist (channel rcirc-buffer-alist) - (kill-buffer (cdr channel)))))) - -(defun rcirc-change-major-mode-hook () - "Part the channel when changing the major-mode." - (rcirc-clean-up-buffer "Changed major mode")) - -(defun rcirc-clean-up-buffer (reason) - (let ((buffer (current-buffer))) - (rcirc-clear-activity buffer) - (when (and (rcirc-buffer-process) - (rcirc--connection-open-p (rcirc-buffer-process))) - (with-rcirc-server-buffer - (setq rcirc-buffer-alist - (rassq-delete-all buffer rcirc-buffer-alist))) - (rcirc-update-short-buffer-names) - (if (rcirc-channel-p rcirc-target) - (rcirc-send-string (rcirc-buffer-process) - (concat "PART " rcirc-target " :" reason)) - (when rcirc-target - (rcirc-remove-nick-channel (rcirc-buffer-process) - (rcirc-buffer-nick) - rcirc-target)))) - (setq rcirc-target nil))) - -(defun rcirc-generate-new-buffer-name (process target) - "Return a buffer name based on PROCESS and TARGET. -This is used for the initial name given to IRC buffers." - (substring-no-properties - (if target - (concat target "@" (process-name process)) - (concat "*" (process-name process) "*")))) - -(defun rcirc-get-buffer (process target &optional server) - "Return the buffer associated with the PROCESS and TARGET. - -If optional argument SERVER is non-nil, return the server buffer -if there is no existing buffer for TARGET, otherwise return nil." - (with-rcirc-process-buffer process - (if (null target) - (current-buffer) - (let ((buffer (cdr (assoc-string target rcirc-buffer-alist t)))) - (or buffer (when server (current-buffer))))))) - -(defun rcirc-get-buffer-create (process target) - "Return the buffer associated with the PROCESS and TARGET. -Create the buffer if it doesn't exist." - (let ((buffer (rcirc-get-buffer process target))) - (if (and buffer (buffer-live-p buffer)) - (with-current-buffer buffer - (when (not rcirc-target) - (setq rcirc-target target)) - buffer) - ;; create the buffer - (with-rcirc-process-buffer process - (let ((new-buffer (get-buffer-create - (rcirc-generate-new-buffer-name process target)))) - (with-current-buffer new-buffer - (rcirc-mode process target) - (rcirc-put-nick-channel process (rcirc-nick process) target - rcirc-current-line)) - new-buffer))))) - -(defun rcirc-send-input () - "Send input to target associated with the current buffer." - (interactive) - (if (< (point) rcirc-prompt-end-marker) - ;; copy the line down to the input area - (progn - (forward-line 0) - (let ((start (if (eq (point) (point-min)) - (point) - (if (get-text-property (1- (point)) 'hard) - (point) - (previous-single-property-change (point) 'hard)))) - (end (next-single-property-change (1+ (point)) 'hard))) - (goto-char (point-max)) - (insert (replace-regexp-in-string - "\n\\s-+" " " - (buffer-substring-no-properties start end))))) - ;; process input - (goto-char (point-max)) - (when (not (equal 0 (- (point) rcirc-prompt-end-marker))) - ;; delete a trailing newline - (when (eq (point) (point-at-bol)) - (delete-char -1)) - (let ((input (buffer-substring-no-properties - rcirc-prompt-end-marker (point)))) - (dolist (line (split-string input "\n")) - (rcirc-process-input-line line)) - ;; add to input-ring - (save-excursion - (ring-insert rcirc-input-ring input) - (setq rcirc-input-ring-index 0)))))) - -(defun rcirc-fill-paragraph (&optional justify) - (interactive "P") - (when (> (point) rcirc-prompt-end-marker) - (save-restriction - (narrow-to-region rcirc-prompt-end-marker (point-max)) - (let ((fill-column rcirc-max-message-length)) - (fill-region (point-min) (point-max) justify))))) - -(defun rcirc-process-input-line (line) - (if (string-match "^/\\([^ ]+\\) ?\\(.*\\)$" line) - (rcirc-process-command (match-string 1 line) - (match-string 2 line) - line) - (rcirc-process-message line))) - -(defun rcirc-process-message (line) - (if (not rcirc-target) - (message "Not joined (no target)") - (delete-region rcirc-prompt-end-marker (point)) - (rcirc-send-message (rcirc-buffer-process) rcirc-target line) - (setq rcirc-last-post-time (current-time)))) - -(defun rcirc-process-command (command args line) - (if (eq (aref command 0) ?/) - ;; "//text" will send "/text" as a message - (rcirc-process-message (substring line 1)) - (let ((fun (intern-soft (concat "rcirc-cmd-" command))) - (process (rcirc-buffer-process))) - (newline) - (with-current-buffer (current-buffer) - (delete-region rcirc-prompt-end-marker (point)) - (if (string= command "me") - (rcirc-print process (rcirc-buffer-nick) - "ACTION" rcirc-target args) - (rcirc-print process (rcirc-buffer-nick) - "COMMAND" rcirc-target line)) - (set-marker rcirc-prompt-end-marker (point)) - (if (fboundp fun) - (funcall fun args process rcirc-target) - (rcirc-send-string process - (concat command " :" args))))))) - -(defvar rcirc-parent-buffer nil) -(make-variable-buffer-local 'rcirc-parent-buffer) -(put 'rcirc-parent-buffer 'permanent-local t) -(defvar rcirc-window-configuration nil) -(defun rcirc-edit-multiline () - "Move current edit to a dedicated buffer." - (interactive) - (let ((pos (1+ (- (point) rcirc-prompt-end-marker)))) - (goto-char (point-max)) - (let ((text (buffer-substring-no-properties rcirc-prompt-end-marker - (point))) - (parent (buffer-name))) - (delete-region rcirc-prompt-end-marker (point)) - (setq rcirc-window-configuration (current-window-configuration)) - (pop-to-buffer (concat "*multiline " parent "*")) - (funcall rcirc-multiline-major-mode) - (rcirc-multiline-minor-mode 1) - (setq rcirc-parent-buffer parent) - (insert text) - (and (> pos 0) (goto-char pos)) - (message "Type C-c C-c to return text to %s, or C-c C-k to cancel" parent)))) - -(defvar rcirc-multiline-minor-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-c C-c") 'rcirc-multiline-minor-submit) - (define-key map (kbd "C-x C-s") 'rcirc-multiline-minor-submit) - (define-key map (kbd "C-c C-k") 'rcirc-multiline-minor-cancel) - (define-key map (kbd "ESC ESC ESC") 'rcirc-multiline-minor-cancel) - map) - "Keymap for multiline mode in rcirc.") - -(define-minor-mode rcirc-multiline-minor-mode - "Minor mode for editing multiple lines in rcirc. -With a prefix argument ARG, enable the mode if ARG is positive, -and disable it otherwise. If called from Lisp, enable the mode -if ARG is omitted or nil." - :init-value nil - :lighter " rcirc-mline" - :keymap rcirc-multiline-minor-mode-map - :global nil - :group 'rcirc - (setq fill-column rcirc-max-message-length)) - -(defun rcirc-multiline-minor-submit () - "Send the text in buffer back to parent buffer." - (interactive) - (untabify (point-min) (point-max)) - (let ((text (buffer-substring (point-min) (point-max))) - (buffer (current-buffer)) - (pos (point))) - (set-buffer rcirc-parent-buffer) - (goto-char (point-max)) - (insert text) - (kill-buffer buffer) - (set-window-configuration rcirc-window-configuration) - (goto-char (+ rcirc-prompt-end-marker (1- pos))))) - -(defun rcirc-multiline-minor-cancel () - "Cancel the multiline edit." - (interactive) - (kill-buffer (current-buffer)) - (set-window-configuration rcirc-window-configuration)) - -(defun rcirc-any-buffer (process) - "Return a buffer for PROCESS, either the one selected or the process buffer." - (if rcirc-always-use-server-buffer-flag - (process-buffer process) - (let ((buffer (window-buffer))) - (if (and buffer - (with-current-buffer buffer - (and (eq major-mode 'rcirc-mode) - (eq (rcirc-buffer-process) process)))) - buffer - (process-buffer process))))) - -(defcustom rcirc-response-formats - '(("PRIVMSG" . "<%N> %m") - ("NOTICE" . "-%N- %m") - ("ACTION" . "[%N %m]") - ("COMMAND" . "%m") - ("ERROR" . "%fw!!! %m") - (t . "%fp*** %fs%n %r %m")) - "An alist of formats used for printing responses. -The format is looked up using the response-type as a key; -if no match is found, the default entry (with a key of t) is used. - -The entry's value part should be a string, which is inserted with -the of the following escape sequences replaced by the described values: - - %m The message text - %n The sender's nick - %N The sender's nick (with face `rcirc-my-nick' or `rcirc-other-nick') - %r The response-type - %t The target - %fw Following text uses the face `font-lock-warning-face' - %fp Following text uses the face `rcirc-server-prefix' - %fs Following text uses the face `rcirc-server' - %f[FACE] Following text uses the face FACE - %f- Following text uses the default face - %% A literal `%' character" - :type '(alist :key-type (choice (string :tag "Type") - (const :tag "Default" t)) - :value-type string) - :group 'rcirc) - -(defun rcirc-format-response-string (process sender response target text) - "Return a nicely-formatted response string, incorporating TEXT -\(and perhaps other arguments). The specific formatting used -is found by looking up RESPONSE in `rcirc-response-formats'." - (with-temp-buffer - (insert (or (cdr (assoc response rcirc-response-formats)) - (cdr (assq t rcirc-response-formats)))) - (goto-char (point-min)) - (let ((start (point-min)) - (sender (if (or (not sender) - (string= (rcirc-server-name process) sender)) - "" - sender)) - face) - (while (re-search-forward "%\\(\\(f\\(.\\)\\)\\|\\(.\\)\\)" nil t) - (rcirc-add-face start (match-beginning 0) face) - (setq start (match-beginning 0)) - (replace-match - (cl-case (aref (match-string 1) 0) - (?f (setq face - (cl-case (string-to-char (match-string 3)) - (?w 'font-lock-warning-face) - (?p 'rcirc-server-prefix) - (?s 'rcirc-server) - (t nil))) - "") - (?n sender) - (?N (let ((my-nick (rcirc-nick process))) - (save-match-data - (with-syntax-table rcirc-nick-syntax-table - (rcirc-facify sender - (cond ((string= sender my-nick) - 'rcirc-my-nick) - ((and rcirc-bright-nicks - (string-match - (regexp-opt rcirc-bright-nicks - 'words) - sender)) - 'rcirc-bright-nick) - ((and rcirc-dim-nicks - (string-match - (regexp-opt rcirc-dim-nicks - 'words) - sender)) - 'rcirc-dim-nick) - (t - 'rcirc-other-nick))))))) - (?m (propertize text 'rcirc-text text)) - (?r response) - (?t (or target "")) - (t (concat "UNKNOWN CODE:" (match-string 0)))) - t t nil 0) - (rcirc-add-face (match-beginning 0) (match-end 0) face)) - (rcirc-add-face start (match-beginning 0) face)) - (buffer-substring (point-min) (point-max)))) - -(defun rcirc-target-buffer (process sender response target _text) - "Return a buffer to print the server response." - (cl-assert (not (bufferp target))) - (with-rcirc-process-buffer process - (cond ((not target) - (rcirc-any-buffer process)) - ((not (rcirc-channel-p target)) - ;; message from another user - (if (or (string= response "PRIVMSG") - (string= response "ACTION")) - (rcirc-get-buffer-create process (if (string= sender rcirc-nick) - target - sender)) - (rcirc-get-buffer process target t))) - ((or (rcirc-get-buffer process target) - (rcirc-any-buffer process)))))) - -(defvar rcirc-activity-types nil) -(make-variable-buffer-local 'rcirc-activity-types) -(defvar rcirc-last-sender nil) -(make-variable-buffer-local 'rcirc-last-sender) - -(defcustom rcirc-omit-threshold 100 - "Number of lines since last activity from a nick before `rcirc-omit-responses' are omitted." - :type 'integer - :group 'rcirc) - -(defcustom rcirc-log-process-buffers nil - "Non-nil if rcirc process buffers should be logged to disk." - :group 'rcirc - :type 'boolean - :version "24.1") - -(defun rcirc-last-quit-line (process nick target) - "Return the line number where NICK left TARGET. -Returns nil if the information is not recorded." - (let ((chanbuf (rcirc-get-buffer process target))) - (when chanbuf - (cdr (assoc-string nick (with-current-buffer chanbuf - rcirc-recent-quit-alist)))))) - -(defun rcirc-last-line (process nick target) - "Return the line from the last activity from NICK in TARGET." - (let ((line (or (cdr (assoc-string target - (gethash nick (with-rcirc-server-buffer - rcirc-nick-table)) t)) - (rcirc-last-quit-line process nick target)))) - (if line - line - ;;(message "line is nil for %s in %s" nick target) - nil))) - -(defun rcirc-elapsed-lines (process nick target) - "Return the number of lines since activity from NICK in TARGET." - (let ((last-activity-line (rcirc-last-line process nick target))) - (when (and last-activity-line - (> last-activity-line 0)) - (- rcirc-current-line last-activity-line)))) - -(defvar rcirc-markup-text-functions - '(rcirc-markup-attributes - rcirc-markup-my-nick - rcirc-markup-urls - rcirc-markup-keywords - rcirc-markup-bright-nicks) - - "List of functions used to manipulate text before it is printed. - -Each function takes two arguments, SENDER, and RESPONSE. The -buffer is narrowed with the text to be printed and the point is -at the beginning of the `rcirc-text' propertized text.") - -(defun rcirc-print (process sender response target text &optional activity) - "Print TEXT in the buffer associated with TARGET. -Format based on SENDER and RESPONSE. If ACTIVITY is non-nil, -record activity." - (or text (setq text "")) - (unless (and (or (member sender rcirc-ignore-list) - (member (with-syntax-table rcirc-nick-syntax-table - (when (string-match "^\\([^/]\\w*\\)[:,]" text) - (match-string 1 text))) - rcirc-ignore-list)) - ;; do not ignore if we sent the message - (not (string= sender (rcirc-nick process)))) - (let* ((buffer (rcirc-target-buffer process sender response target text)) - (inhibit-read-only t)) - (with-current-buffer buffer - (let ((moving (= (point) rcirc-prompt-end-marker)) - (old-point (point-marker)) - (fill-start (marker-position rcirc-prompt-start-marker))) - - (setq text (decode-coding-string text rcirc-decode-coding-system)) - (unless (string= sender (rcirc-nick process)) - ;; mark the line with overlay arrow - (unless (or (marker-position overlay-arrow-position) - (get-buffer-window (current-buffer)) - (member response rcirc-omit-responses)) - (set-marker overlay-arrow-position - (marker-position rcirc-prompt-start-marker)))) - - ;; temporarily set the marker insertion-type because - ;; insert-before-markers results in hidden text in new buffers - (goto-char rcirc-prompt-start-marker) - (set-marker-insertion-type rcirc-prompt-start-marker t) - (set-marker-insertion-type rcirc-prompt-end-marker t) - - (let ((start (point))) - (insert (rcirc-format-response-string process sender response nil - text) - (propertize "\n" 'hard t)) - - ;; squeeze spaces out of text before rcirc-text - (fill-region fill-start - (1- (or (next-single-property-change fill-start - 'rcirc-text) - rcirc-prompt-end-marker))) - - ;; run markup functions - (save-excursion - (save-restriction - (narrow-to-region start rcirc-prompt-start-marker) - (goto-char (or (next-single-property-change start 'rcirc-text) - (point))) - (when (rcirc-buffer-process) - (save-excursion (rcirc-markup-timestamp sender response)) - (dolist (fn rcirc-markup-text-functions) - (save-excursion (funcall fn sender response))) - (when rcirc-fill-flag - (save-excursion (rcirc-markup-fill sender response)))) - - (when rcirc-read-only-flag - (add-text-properties (point-min) (point-max) - '(read-only t front-sticky t)))) - ;; make text omittable - (let ((last-activity-lines (rcirc-elapsed-lines process sender target))) - (if (and (not (string= (rcirc-nick process) sender)) - (member response rcirc-omit-responses) - (or (not last-activity-lines) - (< rcirc-omit-threshold last-activity-lines))) - (put-text-property (1- start) (1- rcirc-prompt-start-marker) - 'invisible 'rcirc-omit) - ;; otherwise increment the line count - (setq rcirc-current-line (1+ rcirc-current-line)))))) - - (set-marker-insertion-type rcirc-prompt-start-marker nil) - (set-marker-insertion-type rcirc-prompt-end-marker nil) - - ;; truncate buffer if it is very long - (save-excursion - (when (and rcirc-buffer-maximum-lines - (> rcirc-buffer-maximum-lines 0) - (= (forward-line (- rcirc-buffer-maximum-lines)) 0)) - (delete-region (point-min) (point)))) - - ;; set the window point for buffers show in windows - (walk-windows (lambda (w) - (when (and (not (eq (selected-window) w)) - (eq (current-buffer) - (window-buffer w)) - (>= (window-point w) - rcirc-prompt-end-marker)) - (set-window-point w (point-max)))) - nil t) - - ;; restore the point - (goto-char (if moving rcirc-prompt-end-marker old-point)) - - ;; keep window on bottom line if it was already there - (when rcirc-scroll-show-maximum-output - (let ((window (get-buffer-window))) - (when window - (with-selected-window window - (when (eq major-mode 'rcirc-mode) - (when (<= (- (window-height) - (count-screen-lines (window-point) - (window-start)) - 1) - 0) - (recenter -1))))))) - - ;; flush undo (can we do something smarter here?) - (buffer-disable-undo) - (buffer-enable-undo)) - - ;; record mode line activity - (when (and activity - (not rcirc-ignore-buffer-activity-flag) - (not (and rcirc-dim-nicks sender - (string-match (regexp-opt rcirc-dim-nicks) sender) - (rcirc-channel-p target)))) - (rcirc-record-activity (current-buffer) - (when (not (rcirc-channel-p rcirc-target)) - 'nick))) - - (when (and rcirc-log-flag - (or target - rcirc-log-process-buffers)) - (rcirc-log process sender response target text)) - - (sit-for 0) ; displayed text before hook - (run-hook-with-args 'rcirc-print-functions - process sender response target text))))) - -(defun rcirc-generate-log-filename (process target) - (if target - (rcirc-generate-new-buffer-name process target) - (process-name process))) - -(defcustom rcirc-log-filename-function 'rcirc-generate-log-filename - "A function to generate the filename used by rcirc's logging facility. - -It is called with two arguments, PROCESS and TARGET (see -`rcirc-generate-new-buffer-name' for their meaning), and should -return the filename, or nil if no logging is desired for this -session. - -If the returned filename is absolute (`file-name-absolute-p' -returns t), then it is used as-is, otherwise the resulting file -is put into `rcirc-log-directory'. - -The filename is then cleaned using `convert-standard-filename' to -guarantee valid filenames for the current OS." - :group 'rcirc - :type 'function) - -(defun rcirc-log (process sender response target text) - "Record line in `rcirc-log', to be later written to disk." - (let ((filename (funcall rcirc-log-filename-function process target))) - (unless (null filename) - (let ((cell (assoc-string filename rcirc-log-alist)) - (line (concat (format-time-string rcirc-time-format) - (substring-no-properties - (rcirc-format-response-string process sender - response target text)) - "\n"))) - (if cell - (setcdr cell (concat (cdr cell) line)) - (setq rcirc-log-alist - (cons (cons filename line) rcirc-log-alist))))))) - -(defun rcirc-log-write () - "Flush `rcirc-log-alist' data to disk. - -Log data is written to `rcirc-log-directory', except for -log-files with absolute names (see `rcirc-log-filename-function')." - (dolist (cell rcirc-log-alist) - (let ((filename (convert-standard-filename - (expand-file-name (car cell) - rcirc-log-directory))) - (coding-system-for-write 'utf-8)) - (make-directory (file-name-directory filename) t) - (with-temp-buffer - (insert (cdr cell)) - (write-region (point-min) (point-max) filename t 'quiet)))) - (setq rcirc-log-alist nil)) - -(defun rcirc-view-log-file () - "View logfile corresponding to the current buffer." - (interactive) - (find-file-other-window - (expand-file-name (funcall rcirc-log-filename-function - (rcirc-buffer-process) rcirc-target) - rcirc-log-directory))) - -(defun rcirc-join-channels (process channels) - "Join CHANNELS." - (save-window-excursion - (dolist (channel channels) - (with-rcirc-process-buffer process - (rcirc-cmd-join channel process))))) - -;;; nick management -(defvar rcirc-nick-prefix-chars "~&@%+") -(defun rcirc-user-nick (user) - "Return the nick from USER. Remove any non-nick junk." - (save-match-data - (if (string-match (concat "^[" rcirc-nick-prefix-chars - "]?\\([^! ]+\\)!?") (or user "")) - (match-string 1 user) - user))) - -(defun rcirc-nick-channels (process nick) - "Return list of channels for NICK." - (with-rcirc-process-buffer process - (mapcar (lambda (x) (car x)) - (gethash nick rcirc-nick-table)))) - -(defun rcirc-put-nick-channel (process nick channel &optional line) - "Add CHANNEL to list associated with NICK. -Update the associated linestamp if LINE is non-nil. - -If the record doesn't exist, and LINE is nil, set the linestamp -to zero." - (let ((nick (rcirc-user-nick nick))) - (with-rcirc-process-buffer process - (let* ((chans (gethash nick rcirc-nick-table)) - (record (assoc-string channel chans t))) - (if record - (when line (setcdr record line)) - (puthash nick (cons (cons channel (or line 0)) - chans) - rcirc-nick-table)))))) - -(defun rcirc-nick-remove (process nick) - "Remove NICK from table." - (with-rcirc-process-buffer process - (remhash nick rcirc-nick-table))) - -(defun rcirc-remove-nick-channel (process nick channel) - "Remove the CHANNEL from list associated with NICK." - (with-rcirc-process-buffer process - (let* ((chans (gethash nick rcirc-nick-table)) - (newchans - ;; instead of assoc-string-delete-all: - (let ((record (assoc-string channel chans t))) - (when record - (setcar record 'delete) - (assq-delete-all 'delete chans))))) - (if newchans - (puthash nick newchans rcirc-nick-table) - (remhash nick rcirc-nick-table))))) - -(defun rcirc-channel-nicks (process target) - "Return the list of nicks associated with TARGET sorted by last activity." - (when target - (if (rcirc-channel-p target) - (with-rcirc-process-buffer process - (let (nicks) - (maphash - (lambda (k v) - (let ((record (assoc-string target v t))) - (if record - (setq nicks (cons (cons k (cdr record)) nicks))))) - rcirc-nick-table) - (mapcar (lambda (x) (car x)) - (sort nicks (lambda (x y) - (let ((lx (or (cdr x) 0)) - (ly (or (cdr y) 0))) - (< ly lx))))))) - (list target)))) - -(defun rcirc-ignore-update-automatic (nick) - "Remove NICK from `rcirc-ignore-list' -if NICK is also on `rcirc-ignore-list-automatic'." - (when (member nick rcirc-ignore-list-automatic) - (setq rcirc-ignore-list-automatic - (delete nick rcirc-ignore-list-automatic) - rcirc-ignore-list - (delete nick rcirc-ignore-list)))) - -(defun rcirc-nickname< (s1 s2) - "Return t if IRC nickname S1 is less than S2, and nil otherwise. -Operator nicknames (@) are considered less than voiced -nicknames (+). Any other nicknames are greater than voiced -nicknames. The comparison is case-insensitive." - (setq s1 (downcase s1) - s2 (downcase s2)) - (let* ((s1-op (eq ?@ (string-to-char s1))) - (s2-op (eq ?@ (string-to-char s2)))) - (if s1-op - (if s2-op - (string< (substring s1 1) (substring s2 1)) - t) - (if s2-op - nil - (string< s1 s2))))) - -(defun rcirc-sort-nicknames-join (input sep) - "Return a string of sorted nicknames. -INPUT is a string containing nicknames separated by SEP. -This function does not alter the INPUT string." - (let* ((parts (split-string input sep t)) - (sorted (sort parts 'rcirc-nickname<))) - (mapconcat 'identity sorted sep))) - -;;; activity tracking -(defvar rcirc-track-minor-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-c C-@") 'rcirc-next-active-buffer) - (define-key map (kbd "C-c C-SPC") 'rcirc-next-active-buffer) - map) - "Keymap for rcirc track minor mode.") - -;;;###autoload -(define-minor-mode rcirc-track-minor-mode - "Global minor mode for tracking activity in rcirc buffers. -With a prefix argument ARG, enable the mode if ARG is positive, -and disable it otherwise. If called from Lisp, enable the mode -if ARG is omitted or nil." - :init-value nil - :lighter "" - :keymap rcirc-track-minor-mode-map - :global t - :group 'rcirc - (or global-mode-string (setq global-mode-string '(""))) - ;; toggle the mode-line channel indicator - (if rcirc-track-minor-mode - (progn - (and (not (memq 'rcirc-activity-string global-mode-string)) - (setq global-mode-string - (append global-mode-string '(rcirc-activity-string)))) - (add-hook 'window-configuration-change-hook - 'rcirc-window-configuration-change)) - (setq global-mode-string - (delete 'rcirc-activity-string global-mode-string)) - (remove-hook 'window-configuration-change-hook - 'rcirc-window-configuration-change))) - -(or (assq 'rcirc-ignore-buffer-activity-flag minor-mode-alist) - (setq minor-mode-alist - (cons '(rcirc-ignore-buffer-activity-flag " Ignore") minor-mode-alist))) -(or (assq 'rcirc-low-priority-flag minor-mode-alist) - (setq minor-mode-alist - (cons '(rcirc-low-priority-flag " LowPri") minor-mode-alist))) - -(defun rcirc-toggle-ignore-buffer-activity () - "Toggle the value of `rcirc-ignore-buffer-activity-flag'." - (interactive) - (setq rcirc-ignore-buffer-activity-flag - (not rcirc-ignore-buffer-activity-flag)) - (message (if rcirc-ignore-buffer-activity-flag - "Ignore activity in this buffer" - "Notice activity in this buffer")) - (force-mode-line-update)) - -(defun rcirc-toggle-low-priority () - "Toggle the value of `rcirc-low-priority-flag'." - (interactive) - (setq rcirc-low-priority-flag - (not rcirc-low-priority-flag)) - (message (if rcirc-low-priority-flag - "Activity in this buffer is low priority" - "Activity in this buffer is normal priority")) - (force-mode-line-update)) - -(defun rcirc-switch-to-server-buffer () - "Switch to the server buffer associated with current channel buffer." - (interactive) - (unless (buffer-live-p rcirc-server-buffer) - (error "No such buffer")) - (switch-to-buffer rcirc-server-buffer)) - -(defun rcirc-jump-to-first-unread-line () - "Move the point to the first unread line in this buffer." - (interactive) - (if (marker-position overlay-arrow-position) - (goto-char overlay-arrow-position) - (message "No unread messages"))) - -(defun rcirc-bury-buffers () - "Bury all RCIRC buffers." - (interactive) - (dolist (buf (buffer-list)) - (when (eq 'rcirc-mode (with-current-buffer buf major-mode)) - (bury-buffer buf) ; buffers not shown - (quit-windows-on buf)))) ; buffers shown in a window - -(defun rcirc-next-active-buffer (arg) - "Switch to the next rcirc buffer with activity. -With prefix ARG, go to the next low priority buffer with activity." - (interactive "P") - (let* ((pair (rcirc-split-activity rcirc-activity)) - (lopri (car pair)) - (hipri (cdr pair))) - (if (or (and (not arg) hipri) - (and arg lopri)) - (progn - (switch-to-buffer (car (if arg lopri hipri))) - (when (> (point) rcirc-prompt-start-marker) - (recenter -1))) - (rcirc-bury-buffers) - (message "No IRC activity.%s" - (if lopri - (concat - " Type C-u " (key-description (this-command-keys)) - " for low priority activity.") - ""))))) - -(define-obsolete-variable-alias 'rcirc-activity-hooks - 'rcirc-activity-functions "24.3") -(defvar rcirc-activity-functions nil - "Hook to be run when there is channel activity. - -Functions are called with a single argument, the buffer with the -activity. Only run if the buffer is not visible and -`rcirc-ignore-buffer-activity-flag' is non-nil.") - -(defun rcirc-record-activity (buffer &optional type) - "Record BUFFER activity with TYPE." - (with-current-buffer buffer - (let ((old-activity rcirc-activity) - (old-types rcirc-activity-types)) - (when (not (get-buffer-window (current-buffer) t)) - (setq rcirc-activity - (sort (if (memq (current-buffer) rcirc-activity) rcirc-activity - (cons (current-buffer) rcirc-activity)) - (lambda (b1 b2) - (let ((t1 (with-current-buffer b1 rcirc-last-post-time)) - (t2 (with-current-buffer b2 rcirc-last-post-time))) - (time-less-p t2 t1))))) - (cl-pushnew type rcirc-activity-types) - (unless (and (equal rcirc-activity old-activity) - (member type old-types)) - (rcirc-update-activity-string))))) - (run-hook-with-args 'rcirc-activity-functions buffer)) - -(defun rcirc-clear-activity (buffer) - "Clear the BUFFER activity." - (setq rcirc-activity (remove buffer rcirc-activity)) - (with-current-buffer buffer - (setq rcirc-activity-types nil))) - -(defun rcirc-clear-unread (buffer) - "Erase the last read message arrow from BUFFER." - (when (buffer-live-p buffer) - (with-current-buffer buffer - (set-marker overlay-arrow-position nil)))) - -(defun rcirc-split-activity (activity) - "Return a cons cell with ACTIVITY split into (lopri . hipri)." - (let (lopri hipri) - (dolist (buf activity) - (with-current-buffer buf - (if (and rcirc-low-priority-flag - (not (member 'nick rcirc-activity-types))) - (push buf lopri) - (push buf hipri)))) - (cons (nreverse lopri) (nreverse hipri)))) - -(defvar rcirc-update-activity-string-hook nil - "Hook run whenever the activity string is updated.") - -;; TODO: add mouse properties -(defun rcirc-update-activity-string () - "Update mode-line string." - (let* ((pair (rcirc-split-activity rcirc-activity)) - (lopri (car pair)) - (hipri (cdr pair))) - (setq rcirc-activity-string - (cond ((or hipri lopri) - (concat (and hipri "[") - (rcirc-activity-string hipri) - (and hipri lopri ",") - (and lopri - (concat "(" - (rcirc-activity-string lopri) - ")")) - (and hipri "]"))) - ((not (null (rcirc-process-list))) - "[]") - (t "[]"))) - (run-hooks 'rcirc-update-activity-string-hook))) - -(defun rcirc-activity-string (buffers) - (mapconcat (lambda (b) - (let ((s (substring-no-properties (rcirc-short-buffer-name b)))) - (with-current-buffer b - (dolist (type rcirc-activity-types) - (rcirc-add-face 0 (length s) - (cl-case type - (nick 'rcirc-track-nick) - (keyword 'rcirc-track-keyword)) - s))) - s)) - buffers ",")) - -(defun rcirc-short-buffer-name (buffer) - "Return a short name for BUFFER to use in the mode line indicator." - (with-current-buffer buffer - (or rcirc-short-buffer-name (buffer-name)))) - -(defun rcirc-visible-buffers () - "Return a list of the visible buffers that are in rcirc-mode." - (let (acc) - (walk-windows (lambda (w) - (with-current-buffer (window-buffer w) - (when (eq major-mode 'rcirc-mode) - (push (current-buffer) acc))))) - acc)) - -(defvar rcirc-visible-buffers nil) -(defun rcirc-window-configuration-change () - (unless (minibuffer-window-active-p (minibuffer-window)) - ;; delay this until command has finished to make sure window is - ;; actually visible before clearing activity - (add-hook 'post-command-hook 'rcirc-window-configuration-change-1))) - -(defun rcirc-window-configuration-change-1 () - ;; clear activity and overlay arrows - (let* ((old-activity rcirc-activity) - (hidden-buffers rcirc-visible-buffers)) - - (setq rcirc-visible-buffers (rcirc-visible-buffers)) - - (dolist (vbuf rcirc-visible-buffers) - (setq hidden-buffers (delq vbuf hidden-buffers)) - ;; clear activity for all visible buffers - (rcirc-clear-activity vbuf)) - - ;; clear unread arrow from recently hidden buffers - (dolist (hbuf hidden-buffers) - (rcirc-clear-unread hbuf)) - - ;; remove any killed buffers from list - (setq rcirc-activity - (delq nil (mapcar (lambda (buf) (when (buffer-live-p buf) buf)) - rcirc-activity))) - ;; update the mode-line string - (unless (equal old-activity rcirc-activity) - (rcirc-update-activity-string))) - - (remove-hook 'post-command-hook 'rcirc-window-configuration-change-1)) - - -;;; buffer name abbreviation -(defun rcirc-update-short-buffer-names () - (let ((bufalist - (apply 'append (mapcar (lambda (process) - (with-rcirc-process-buffer process - rcirc-buffer-alist)) - (rcirc-process-list))))) - (dolist (i (rcirc-abbreviate bufalist)) - (when (buffer-live-p (cdr i)) - (with-current-buffer (cdr i) - (setq rcirc-short-buffer-name (car i))))))) - -(defun rcirc-abbreviate (pairs) - (apply 'append (mapcar 'rcirc-rebuild-tree (rcirc-make-trees pairs)))) - -(defun rcirc-rebuild-tree (tree &optional acc) - (let ((ch (char-to-string (car tree)))) - (dolist (x (cdr tree)) - (if (listp x) - (setq acc (append acc - (mapcar (lambda (y) - (cons (concat ch (car y)) - (cdr y))) - (rcirc-rebuild-tree x)))) - (setq acc (cons (cons ch x) acc)))) - acc)) - -(defun rcirc-make-trees (pairs) - (let (alist) - (mapc (lambda (pair) - (if (consp pair) - (let* ((str (car pair)) - (data (cdr pair)) - (char (unless (zerop (length str)) - (aref str 0))) - (rest (unless (zerop (length str)) - (substring str 1))) - (part (if char (assq char alist)))) - (if part - ;; existing partition - (setcdr part (cons (cons rest data) (cdr part))) - ;; new partition - (setq alist (cons (if char - (list char (cons rest data)) - data) - alist)))) - (setq alist (cons pair alist)))) - pairs) - ;; recurse into cdrs of alist - (mapc (lambda (x) - (when (and (listp x) (listp (cadr x))) - (setcdr x (if (> (length (cdr x)) 1) - (rcirc-make-trees (cdr x)) - (setcdr x (list (cl-cdadr x))))))) - alist))) - -;;; /commands these are called with 3 args: PROCESS, TARGET, which is -;; the current buffer/channel/user, and ARGS, which is a string -;; containing the text following the /cmd. - -(defmacro defun-rcirc-command (command argument docstring interactive-form - &rest body) - "Define a command." - `(progn - (add-to-list 'rcirc-client-commands ,(concat "/" (symbol-name command))) - (defun ,(intern (concat "rcirc-cmd-" (symbol-name command))) - (,@argument &optional process target) - ,(concat docstring "\n\nNote: If PROCESS or TARGET are nil, the values given" - "\nby `rcirc-buffer-process' and `rcirc-target' will be used.") - ,interactive-form - (let ((process (or process (rcirc-buffer-process))) - (target (or target rcirc-target))) - (ignore target) ; mark `target' variable as ignorable - ,@body)))) - -(defun-rcirc-command msg (message) - "Send private MESSAGE to TARGET." - (interactive "i") - (if (null message) - (progn - (setq target (completing-read "Message nick: " - (with-rcirc-server-buffer - rcirc-nick-table))) - (when (> (length target) 0) - (setq message (read-string (format "Message %s: " target))) - (when (> (length message) 0) - (rcirc-send-message process target message)))) - (if (not (string-match "\\([^ ]+\\) \\(.+\\)" message)) - (message "Not enough args, or something.") - (setq target (match-string 1 message) - message (match-string 2 message)) - (rcirc-send-message process target message)))) - -(defun-rcirc-command query (nick) - "Open a private chat buffer to NICK." - (interactive (list (completing-read "Query nick: " - (with-rcirc-server-buffer rcirc-nick-table)))) - (let ((existing-buffer (rcirc-get-buffer process nick))) - (switch-to-buffer (or existing-buffer - (rcirc-get-buffer-create process nick))) - (when (not existing-buffer) - (rcirc-cmd-whois nick)))) - -(defun-rcirc-command join (channels) - "Join CHANNELS. -CHANNELS is a comma- or space-separated string of channel names." - (interactive "sJoin channels: ") - (let* ((split-channels (split-string channels "[ ,]" t)) - (buffers (mapcar (lambda (ch) - (rcirc-get-buffer-create process ch)) - split-channels)) - (channels (mapconcat 'identity split-channels ","))) - (rcirc-send-string process (concat "JOIN " channels)) - (when (not (eq (selected-window) (minibuffer-window))) - (dolist (b buffers) ;; order the new channel buffers in the buffer list - (switch-to-buffer b))))) - -(defun-rcirc-command invite (nick-channel) - "Invite NICK to CHANNEL." - (interactive (list - (concat - (completing-read "Invite nick: " - (with-rcirc-server-buffer rcirc-nick-table)) - " " - (read-string "Channel: ")))) - (rcirc-send-string process (concat "INVITE " nick-channel))) - -;; TODO: /part #channel reason, or consider removing #channel altogether -(defun-rcirc-command part (channel) - "Part CHANNEL." - (interactive "sPart channel: ") - (let ((channel (if (> (length channel) 0) channel target))) - (rcirc-send-string process (concat "PART " channel " :" rcirc-id-string)))) - -(defun-rcirc-command quit (reason) - "Send a quit message to server with REASON." - (interactive "sQuit reason: ") - (rcirc-send-string process (concat "QUIT :" - (if (not (zerop (length reason))) - reason - rcirc-id-string)))) - -(defun-rcirc-command reconnect (_) - "Reconnect to current server." - (interactive "i") - (with-rcirc-server-buffer - (cond - (rcirc-connecting (message "Already connecting")) - ((process-live-p process) (message "Server process is alive")) - (t (let ((conn-info rcirc-connection-info)) - (setf (nth 5 conn-info) - (cl-remove-if-not #'rcirc-channel-p - (mapcar #'car rcirc-buffer-alist))) - (apply #'rcirc-connect conn-info)))))) - -(defun-rcirc-command nick (nick) - "Change nick to NICK." - (interactive "i") - (when (null nick) - (setq nick (read-string "New nick: " (rcirc-nick process)))) - (rcirc-send-string process (concat "NICK " nick))) - -(defun-rcirc-command names (channel) - "Display list of names in CHANNEL or in current channel if CHANNEL is nil. -If called interactively, prompt for a channel when prefix arg is supplied." - (interactive "P") - (if (called-interactively-p 'interactive) - (if channel - (setq channel (read-string "List names in channel: " target)))) - (let ((channel (if (> (length channel) 0) - channel - target))) - (rcirc-send-string process (concat "NAMES " channel)))) - -(defun-rcirc-command topic (topic) - "List TOPIC for the TARGET channel. -With a prefix arg, prompt for new topic." - (interactive "P") - (if (and (called-interactively-p 'interactive) topic) - (setq topic (read-string "New Topic: " rcirc-topic))) - (rcirc-send-string process (concat "TOPIC " target - (when (> (length topic) 0) - (concat " :" topic))))) - -(defun-rcirc-command whois (nick) - "Request information from server about NICK." - (interactive (list - (completing-read "Whois: " - (with-rcirc-server-buffer rcirc-nick-table)))) - (rcirc-send-string process (concat "WHOIS " nick))) - -(defun-rcirc-command mode (args) - "Set mode with ARGS." - (interactive (list (concat (read-string "Mode nick or channel: ") - " " (read-string "Mode: ")))) - (rcirc-send-string process (concat "MODE " args))) - -(defun-rcirc-command list (channels) - "Request information on CHANNELS from server." - (interactive "sList Channels: ") - (rcirc-send-string process (concat "LIST " channels))) - -(defun-rcirc-command oper (args) - "Send operator command to server." - (interactive "sOper args: ") - (rcirc-send-string process (concat "OPER " args))) - -(defun-rcirc-command quote (message) - "Send MESSAGE literally to server." - (interactive "sServer message: ") - (rcirc-send-string process message)) - -(defun-rcirc-command kick (arg) - "Kick NICK from current channel." - (interactive (list - (concat (completing-read "Kick nick: " - (rcirc-channel-nicks - (rcirc-buffer-process) - rcirc-target)) - (read-from-minibuffer "Kick reason: ")))) - (let* ((arglist (split-string arg)) - (argstring (concat (car arglist) " :" - (mapconcat 'identity (cdr arglist) " ")))) - (rcirc-send-string process (concat "KICK " target " " argstring)))) - -(defun rcirc-cmd-ctcp (args &optional process _target) - (if (string-match "^\\([^ ]+\\)\\s-+\\(.+\\)$" args) - (let* ((target (match-string 1 args)) - (request (upcase (match-string 2 args))) - (function (intern-soft (concat "rcirc-ctcp-sender-" request)))) - (if (fboundp function) ;; use special function if available - (funcall function process target request) - (rcirc-send-ctcp process target request))) - (rcirc-print process (rcirc-nick process) "ERROR" nil - "usage: /ctcp NICK REQUEST"))) - -(defun rcirc-ctcp-sender-PING (process target _request) - "Send a CTCP PING message to TARGET." - (let ((timestamp (format-time-string "%s"))) - (rcirc-send-ctcp process target "PING" timestamp))) - -(defun rcirc-cmd-me (args &optional process target) - (rcirc-send-ctcp process target "ACTION" args)) - -(defun rcirc-add-or-remove (set &rest elements) - (dolist (elt elements) - (if (and elt (not (string= "" elt))) - (setq set (if (member-ignore-case elt set) - (delete elt set) - (cons elt set))))) - set) - -(defun-rcirc-command ignore (nick) - "Manage the ignore list. -Ignore NICK, unignore NICK if already ignored, or list ignored -nicks when no NICK is given. When listing ignored nicks, the -ones added to the list automatically are marked with an asterisk." - (interactive "sToggle ignoring of nick: ") - (setq rcirc-ignore-list - (apply #'rcirc-add-or-remove rcirc-ignore-list - (split-string nick nil t))) - (rcirc-print process nil "IGNORE" target - (mapconcat - (lambda (nick) - (concat nick - (if (member nick rcirc-ignore-list-automatic) - "*" ""))) - rcirc-ignore-list " "))) - -(defun-rcirc-command bright (nick) - "Manage the bright nick list." - (interactive "sToggle emphasis of nick: ") - (setq rcirc-bright-nicks - (apply #'rcirc-add-or-remove rcirc-bright-nicks - (split-string nick nil t))) - (rcirc-print process nil "BRIGHT" target - (mapconcat 'identity rcirc-bright-nicks " "))) - -(defun-rcirc-command dim (nick) - "Manage the dim nick list." - (interactive "sToggle deemphasis of nick: ") - (setq rcirc-dim-nicks - (apply #'rcirc-add-or-remove rcirc-dim-nicks - (split-string nick nil t))) - (rcirc-print process nil "DIM" target - (mapconcat 'identity rcirc-dim-nicks " "))) - -(defun-rcirc-command keyword (keyword) - "Manage the keyword list. -Mark KEYWORD, unmark KEYWORD if already marked, or list marked -keywords when no KEYWORD is given." - (interactive "sToggle highlighting of keyword: ") - (setq rcirc-keywords - (apply #'rcirc-add-or-remove rcirc-keywords - (split-string keyword nil t))) - (rcirc-print process nil "KEYWORD" target - (mapconcat 'identity rcirc-keywords " "))) - - -(defun rcirc-add-face (start end name &optional object) - "Add face NAME to the face text property of the text from START to END." - (when name - (let ((pos start) - next prop) - (while (< pos end) - (setq prop (get-text-property pos 'font-lock-face object) - next (next-single-property-change pos 'font-lock-face object end)) - (unless (member name (get-text-property pos 'font-lock-face object)) - (add-text-properties pos next - (list 'font-lock-face (cons name prop)) object)) - (setq pos next))))) - -(defun rcirc-facify (string face) - "Return a copy of STRING with FACE property added." - (let ((string (or string ""))) - (rcirc-add-face 0 (length string) face string) - string)) - -(defvar rcirc-url-regexp - (concat - "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|" - "nntp\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)" - "\\(//[-a-z0-9_.]+:[0-9]*\\)?" - (if (string-match "[[:digit:]]" "1") ;; Support POSIX? - (let ((chars "-a-z0-9_=#$@~%&*+\\/[:word:]") - (punct "!?:;.,")) - (concat - "\\(?:" - ;; Match paired parentheses, e.g. in Wikipedia URLs: - "[" chars punct "]+" "(" "[" chars punct "]+" "[" chars "]*)" "[" chars "]" - "\\|" - "[" chars punct "]+" "[" chars "]" - "\\)")) - (concat ;; XEmacs 21.4 doesn't support POSIX. - "\\([-a-z0-9_=!?#$@~%&*+\\/:;.,]\\|\\w\\)+" - "\\([-a-z0-9_=#$@~%&*+\\/]\\|\\w\\)")) - "\\)") - "Regexp matching URLs. Set to nil to disable URL features in rcirc.") - -;; cf cl-remove-if-not -(defun rcirc-condition-filter (condp lst) - "Remove all items not satisfying condition CONDP in list LST. -CONDP is a function that takes a list element as argument and returns -non-nil if that element should be included. Returns a new list." - (delq nil (mapcar (lambda (x) (and (funcall condp x) x)) lst))) - -(defun rcirc-browse-url (&optional arg) - "Prompt for URL to browse based on URLs in buffer before point. - -If ARG is given, opens the URL in a new browser window." - (interactive "P") - (let* ((point (point)) - (filtered (rcirc-condition-filter - (lambda (x) (>= point (cdr x))) - rcirc-urls)) - (completions (mapcar (lambda (x) (car x)) filtered)) - (defaults (mapcar (lambda (x) (car x)) filtered))) - (browse-url (completing-read "Rcirc browse-url: " - completions nil nil (car defaults) nil defaults) - arg))) - -(defun rcirc-markup-timestamp (_sender _response) - (goto-char (point-min)) - (insert (rcirc-facify (format-time-string rcirc-time-format - (let ((time rcirc-last-message-time)) - (when time (setq rcirc-last-message-time nil)) - time)) - 'rcirc-timestamp))) - -(defun rcirc-markup-attributes (_sender _response) - (while (re-search-forward "\\([\C-b\C-_\C-v]\\).*?\\(\\1\\|\C-o\\)" nil t) - (rcirc-add-face (match-beginning 0) (match-end 0) - (cl-case (char-after (match-beginning 1)) - (?\C-b 'bold) - (?\C-v 'italic) - (?\C-_ 'underline))) - ;; keep the ^O since it could terminate other attributes - (when (not (eq ?\C-o (char-before (match-end 2)))) - (delete-region (match-beginning 2) (match-end 2))) - (delete-region (match-beginning 1) (match-end 1)) - (goto-char (match-beginning 1))) - ;; remove the ^O characters now - (goto-char (point-min)) - (while (re-search-forward "\C-o+" nil t) - (delete-region (match-beginning 0) (match-end 0)))) - -(defun rcirc-markup-my-nick (_sender response) - (with-syntax-table rcirc-nick-syntax-table - (while (re-search-forward (concat "\\b" - (regexp-quote (rcirc-nick - (rcirc-buffer-process))) - "\\b") - nil t) - (rcirc-add-face (match-beginning 0) (match-end 0) - 'rcirc-nick-in-message) - (when (string= response "PRIVMSG") - (rcirc-add-face (point-min) (point-max) - 'rcirc-nick-in-message-full-line) - (rcirc-record-activity (current-buffer) 'nick))))) - -(defun rcirc-markup-urls (_sender _response) - (while (and rcirc-url-regexp ;; nil means disable URL catching - (re-search-forward rcirc-url-regexp nil t)) - (let* ((start (match-beginning 0)) - (end (match-end 0)) - (url (match-string-no-properties 0)) - (link-text (buffer-substring-no-properties start end))) - ;; Add a button for the URL. Note that we use `make-text-button', - ;; rather than `make-button', as text-buttons are much faster in - ;; large buffers. - (make-text-button start end - 'face 'rcirc-url - 'follow-link t - 'rcirc-url url - 'action (lambda (button) - (browse-url (button-get button 'rcirc-url)))) - ;; record the url if it is not already the latest stored url - (when (not (string= link-text (caar rcirc-urls))) - (push (cons link-text start) rcirc-urls))))) - -(defun rcirc-markup-keywords (sender response) - (when (and (string= response "PRIVMSG") - (not (string= sender (rcirc-nick (rcirc-buffer-process))))) - (let* ((target (or rcirc-target "")) - (keywords (delq nil (mapcar (lambda (keyword) - (when (not (string-match keyword - target)) - keyword)) - rcirc-keywords)))) - (when keywords - (while (re-search-forward (regexp-opt keywords 'words) nil t) - (rcirc-add-face (match-beginning 0) (match-end 0) 'rcirc-keyword) - (rcirc-record-activity (current-buffer) 'keyword)))))) - -(defun rcirc-markup-bright-nicks (_sender response) - (when (and rcirc-bright-nicks - (string= response "NAMES")) - (with-syntax-table rcirc-nick-syntax-table - (while (re-search-forward (regexp-opt rcirc-bright-nicks 'words) nil t) - (rcirc-add-face (match-beginning 0) (match-end 0) - 'rcirc-bright-nick))))) - -(defun rcirc-markup-fill (_sender response) - (when (not (string= response "372")) ; /motd - (let ((fill-prefix - (or rcirc-fill-prefix - (make-string (- (point) (line-beginning-position)) ?\s))) - (fill-column (- (cond ((null rcirc-fill-column) fill-column) - ((functionp rcirc-fill-column) - (funcall rcirc-fill-column)) - (t rcirc-fill-column)) - ;; make sure ... doesn't cause line wrapping - 3))) - (fill-region (point) (point-max) nil t)))) - -;;; handlers -;; these are called with the server PROCESS, the SENDER, which is a -;; server or a user, depending on the command, the ARGS, which is a -;; list of strings, and the TEXT, which is the original server text, -;; verbatim -(defun rcirc-handler-001 (process sender args text) - (rcirc-handler-generic process "001" sender args text) - (with-rcirc-process-buffer process - (setq rcirc-connecting nil) - (rcirc-reschedule-timeout process) - (setq rcirc-server-name sender) - (setq rcirc-nick (car args)) - (rcirc-update-prompt) - (if rcirc-auto-authenticate-flag - (if (and rcirc-authenticate-before-join - ;; We have to ensure that there's an authentication - ;; entry for that server. Else, - ;; rcirc-authenticated-hook won't be triggered, and - ;; autojoin won't happen at all. - (let (auth-required) - (dolist (s rcirc-authinfo auth-required) - (when (string-match (car s) rcirc-server-name) - (setq auth-required t))))) - (progn - (add-hook 'rcirc-authenticated-hook 'rcirc-join-channels-post-auth t t) - (rcirc-authenticate)) - (rcirc-authenticate) - (rcirc-join-channels process rcirc-startup-channels)) - (rcirc-join-channels process rcirc-startup-channels)))) - -(defun rcirc-join-channels-post-auth (process) - "Join `rcirc-startup-channels' after authenticating." - (with-rcirc-process-buffer process - (rcirc-join-channels process rcirc-startup-channels))) - -(defun rcirc-handler-PRIVMSG (process sender args text) - (rcirc-check-auth-status process sender args text) - (let ((target (if (rcirc-channel-p (car args)) - (car args) - sender)) - (message (or (cadr args) ""))) - (if (string-match "^\C-a\\(.*\\)\C-a$" message) - (rcirc-handler-CTCP process target sender (match-string 1 message)) - (rcirc-print process sender "PRIVMSG" target message t)) - ;; update nick linestamp - (with-current-buffer (rcirc-get-buffer process target t) - (rcirc-put-nick-channel process sender target rcirc-current-line)))) - -(defun rcirc-handler-NOTICE (process sender args text) - (rcirc-check-auth-status process sender args text) - (let ((target (car args)) - (message (cadr args))) - (if (string-match "^\C-a\\(.*\\)\C-a$" message) - (rcirc-handler-CTCP-response process target sender - (match-string 1 message)) - (rcirc-print process sender "NOTICE" - (cond ((rcirc-channel-p target) - target) - ;;; -ChanServ- [#gnu] Welcome... - ((string-match "\\[\\(#[^] ]+\\)\\]" message) - (match-string 1 message)) - (sender - (if (string= sender (rcirc-server-name process)) - nil ; server notice - sender))) - message t)))) - -(defun rcirc-check-auth-status (process sender args _text) - "Check if the user just authenticated. -If authenticated, runs `rcirc-authenticated-hook' with PROCESS as -the only argument." - (with-rcirc-process-buffer process - (when (and (not rcirc-user-authenticated) - rcirc-authenticate-before-join - rcirc-auto-authenticate-flag) - (let ((target (car args)) - (message (cadr args))) - (when (or - (and ;; nickserv - (string= sender "NickServ") - (string= target rcirc-nick) - (member message - (list - (format "You are now identified for \C-b%s\C-b." rcirc-nick) - (format "You are successfully identified as \C-b%s\C-b." rcirc-nick) - "Password accepted - you are now recognized." - ))) - (and ;; quakenet - (string= sender "Q") - (string= target rcirc-nick) - (string-match "\\`You are now logged in as .+\\.\\'" message))) - (setq rcirc-user-authenticated t) - (run-hook-with-args 'rcirc-authenticated-hook process) - (remove-hook 'rcirc-authenticated-hook 'rcirc-join-channels-post-auth t)))))) - -(defun rcirc-handler-WALLOPS (process sender args _text) - (rcirc-print process sender "WALLOPS" sender (car args) t)) - -(defun rcirc-handler-JOIN (process sender args _text) - (let ((channel (car args))) - (with-current-buffer (rcirc-get-buffer-create process channel) - ;; when recently rejoining, restore the linestamp - (rcirc-put-nick-channel process sender channel - (let ((last-activity-lines - (rcirc-elapsed-lines process sender channel))) - (when (and last-activity-lines - (< last-activity-lines rcirc-omit-threshold)) - (rcirc-last-line process sender channel)))) - ;; reset mode-line-process in case joining a channel with an - ;; already open buffer (after getting kicked e.g.) - (setq mode-line-process nil)) - - (rcirc-print process sender "JOIN" channel "") - - ;; print in private chat buffer if it exists - (when (rcirc-get-buffer (rcirc-buffer-process) sender) - (rcirc-print process sender "JOIN" sender channel)))) - -;; PART and KICK are handled the same way -(defun rcirc-handler-PART-or-KICK (process _response channel _sender nick _args) - (rcirc-ignore-update-automatic nick) - (if (not (string= nick (rcirc-nick process))) - ;; this is someone else leaving - (progn - (rcirc-maybe-remember-nick-quit process nick channel) - (rcirc-remove-nick-channel process nick channel)) - ;; this is us leaving - (mapc (lambda (n) - (rcirc-remove-nick-channel process n channel)) - (rcirc-channel-nicks process channel)) - - ;; if the buffer is still around, make it inactive - (let ((buffer (rcirc-get-buffer process channel))) - (when buffer - (rcirc-disconnect-buffer buffer))))) - -(defun rcirc-handler-PART (process sender args _text) - (let* ((channel (car args)) - (reason (cadr args)) - (message (concat channel " " reason))) - (rcirc-print process sender "PART" channel message) - ;; print in private chat buffer if it exists - (when (rcirc-get-buffer (rcirc-buffer-process) sender) - (rcirc-print process sender "PART" sender message)) - - (rcirc-handler-PART-or-KICK process "PART" channel sender sender reason))) - -(defun rcirc-handler-KICK (process sender args _text) - (let* ((channel (car args)) - (nick (cadr args)) - (reason (nth 2 args)) - (message (concat nick " " channel " " reason))) - (rcirc-print process sender "KICK" channel message t) - ;; print in private chat buffer if it exists - (when (rcirc-get-buffer (rcirc-buffer-process) nick) - (rcirc-print process sender "KICK" nick message)) - - (rcirc-handler-PART-or-KICK process "KICK" channel sender nick reason))) - -(defun rcirc-maybe-remember-nick-quit (process nick channel) - "Remember NICK as leaving CHANNEL if they recently spoke." - (let ((elapsed-lines (rcirc-elapsed-lines process nick channel))) - (when (and elapsed-lines - (< elapsed-lines rcirc-omit-threshold)) - (let ((buffer (rcirc-get-buffer process channel))) - (when buffer - (with-current-buffer buffer - (let ((record (assoc-string nick rcirc-recent-quit-alist t)) - (line (rcirc-last-line process nick channel))) - (if record - (setcdr record line) - (setq rcirc-recent-quit-alist - (cons (cons nick line) - rcirc-recent-quit-alist)))))))))) - -(defun rcirc-handler-QUIT (process sender args _text) - (rcirc-ignore-update-automatic sender) - (mapc (lambda (channel) - ;; broadcast quit message each channel - (rcirc-print process sender "QUIT" channel (apply 'concat args)) - ;; record nick in quit table if they recently spoke - (rcirc-maybe-remember-nick-quit process sender channel)) - (rcirc-nick-channels process sender)) - (rcirc-nick-remove process sender)) - -(defun rcirc-handler-NICK (process sender args _text) - (let* ((old-nick sender) - (new-nick (car args)) - (channels (rcirc-nick-channels process old-nick))) - ;; update list of ignored nicks - (rcirc-ignore-update-automatic old-nick) - (when (member old-nick rcirc-ignore-list) - (add-to-list 'rcirc-ignore-list new-nick) - (add-to-list 'rcirc-ignore-list-automatic new-nick)) - ;; print message to nick's channels - (dolist (target channels) - (rcirc-print process sender "NICK" target new-nick)) - ;; update private chat buffer, if it exists - (let ((chat-buffer (rcirc-get-buffer process old-nick))) - (when chat-buffer - (with-current-buffer chat-buffer - (rcirc-print process sender "NICK" old-nick new-nick) - (setq rcirc-target new-nick) - (rename-buffer (rcirc-generate-new-buffer-name process new-nick))))) - ;; remove old nick and add new one - (with-rcirc-process-buffer process - (let ((v (gethash old-nick rcirc-nick-table))) - (remhash old-nick rcirc-nick-table) - (puthash new-nick v rcirc-nick-table)) - ;; if this is our nick... - (when (string= old-nick rcirc-nick) - (setq rcirc-nick new-nick) - (rcirc-update-prompt t) - ;; reauthenticate - (when rcirc-auto-authenticate-flag (rcirc-authenticate)))))) - -(defun rcirc-handler-PING (process _sender args _text) - (rcirc-send-string process (concat "PONG :" (car args)))) - -(defun rcirc-handler-PONG (_process _sender _args _text) - ;; do nothing - ) - -(defun rcirc-handler-TOPIC (process sender args _text) - (let ((topic (cadr args))) - (rcirc-print process sender "TOPIC" (car args) topic) - (with-current-buffer (rcirc-get-buffer process (car args)) - (setq rcirc-topic topic)))) - -(defvar rcirc-nick-away-alist nil) -(defun rcirc-handler-301 (process _sender args text) - "RPL_AWAY" - (let* ((nick (cadr args)) - (rec (assoc-string nick rcirc-nick-away-alist)) - (away-message (nth 2 args))) - (when (or (not rec) - (not (string= (cdr rec) away-message))) - ;; away message has changed - (rcirc-handler-generic process "AWAY" nick (cdr args) text) - (if rec - (setcdr rec away-message) - (setq rcirc-nick-away-alist (cons (cons nick away-message) - rcirc-nick-away-alist)))))) - -(defun rcirc-handler-317 (process sender args _text) - "RPL_WHOISIDLE" - (let* ((nick (nth 1 args)) - (idle-secs (string-to-number (nth 2 args))) - (idle-string - (if (< idle-secs most-positive-fixnum) - (format-seconds "%yy %dd %hh %mm %z%ss" idle-secs) - "a very long time")) - (signon-time (seconds-to-time (string-to-number (nth 3 args)))) - (signon-string (format-time-string "%c" signon-time)) - (message (format "%s idle for %s, signed on %s" - nick idle-string signon-string))) - (rcirc-print process sender "317" nil message t))) - -(defun rcirc-handler-332 (process _sender args _text) - "RPL_TOPIC" - (let ((buffer (or (rcirc-get-buffer process (cadr args)) - (rcirc-get-temp-buffer-create process (cadr args))))) - (with-current-buffer buffer - (setq rcirc-topic (nth 2 args))))) - -(defun rcirc-handler-333 (process sender args _text) - "333 says who set the topic and when. -Not in rfc1459.txt" - (let ((buffer (or (rcirc-get-buffer process (cadr args)) - (rcirc-get-temp-buffer-create process (cadr args))))) - (with-current-buffer buffer - (let ((setter (nth 2 args)) - (time (current-time-string - (seconds-to-time - (string-to-number (cl-cadddr args)))))) - (rcirc-print process sender "TOPIC" (cadr args) - (format "%s (%s on %s)" rcirc-topic setter time)))))) - -(defun rcirc-handler-477 (process sender args _text) - "ERR_NOCHANMODES" - (rcirc-print process sender "477" (cadr args) (nth 2 args))) - -(defun rcirc-handler-MODE (process sender args _text) - (let ((target (car args)) - (msg (mapconcat 'identity (cdr args) " "))) - (rcirc-print process sender "MODE" - (if (string= target (rcirc-nick process)) - nil - target) - msg) - - ;; print in private chat buffers if they exist - (mapc (lambda (nick) - (when (rcirc-get-buffer process nick) - (rcirc-print process sender "MODE" nick msg))) - (cddr args)))) - -(defun rcirc-get-temp-buffer-create (process channel) - "Return a buffer based on PROCESS and CHANNEL." - (let ((tmpnam (concat " " (downcase channel) "TMP" (process-name process)))) - (get-buffer-create tmpnam))) - -(defun rcirc-handler-353 (process _sender args _text) - "RPL_NAMREPLY" - (let ((channel (nth 2 args)) - (names (or (nth 3 args) ""))) - (mapc (lambda (nick) - (rcirc-put-nick-channel process nick channel)) - (split-string names " " t)) - ;; create a temporary buffer to insert the names into - ;; rcirc-handler-366 (RPL_ENDOFNAMES) will handle it - (with-current-buffer (rcirc-get-temp-buffer-create process channel) - (goto-char (point-max)) - (insert (car (last args)) " ")))) - -(defun rcirc-handler-366 (process sender args _text) - "RPL_ENDOFNAMES" - (let* ((channel (cadr args)) - (buffer (rcirc-get-temp-buffer-create process channel))) - (with-current-buffer buffer - (rcirc-print process sender "NAMES" channel - (let ((content (buffer-substring (point-min) (point-max)))) - (rcirc-sort-nicknames-join content " ")))) - (kill-buffer buffer))) - -(defun rcirc-handler-433 (process sender args text) - "ERR_NICKNAMEINUSE" - (rcirc-handler-generic process "433" sender args text) - (let* ((new-nick (concat (cadr args) "`"))) - (with-rcirc-process-buffer process - (rcirc-cmd-nick new-nick nil process)))) - -(defun rcirc-authenticate () - "Send authentication to process associated with current buffer. -Passwords are stored in `rcirc-authinfo' (which see)." - (interactive) - (with-rcirc-server-buffer - (dolist (i rcirc-authinfo) - (let ((process (rcirc-buffer-process)) - (server (car i)) - (nick (nth 2 i)) - (method (cadr i)) - (args (cl-cdddr i))) - (when (and (string-match server rcirc-server)) - (if (and (memq method '(nickserv chanserv bitlbee)) - (string-match nick rcirc-nick)) - ;; the following methods rely on the user's nickname. - (cl-case method - (nickserv - (rcirc-send-privmsg - process - (or (cadr args) "NickServ") - (concat "IDENTIFY " (car args)))) - (chanserv - (rcirc-send-privmsg - process - "ChanServ" - (format "IDENTIFY %s %s" (car args) (cadr args)))) - (bitlbee - (rcirc-send-privmsg - process - "&bitlbee" - (concat "IDENTIFY " (car args))))) - ;; quakenet authentication doesn't rely on the user's nickname. - ;; the variable `nick' here represents the Q account name. - (when (eq method 'quakenet) - (rcirc-send-privmsg - process - "Q@CServe.quakenet.org" - (format "AUTH %s %s" nick (car args)))))))))) - -(defun rcirc-handler-INVITE (process sender args _text) - (rcirc-print process sender "INVITE" nil (mapconcat 'identity args " ") t)) - -(defun rcirc-handler-ERROR (process sender args _text) - (rcirc-print process sender "ERROR" nil (mapconcat 'identity args " "))) - -(defun rcirc-handler-CTCP (process target sender text) - (if (string-match "^\\([^ ]+\\) *\\(.*\\)$" text) - (let* ((request (upcase (match-string 1 text))) - (args (match-string 2 text)) - (handler (intern-soft (concat "rcirc-handler-ctcp-" request)))) - (if (not (fboundp handler)) - (rcirc-print process sender "ERROR" target - (format "%s sent unsupported ctcp: %s" sender text) - t) - (funcall handler process target sender args) - (unless (or (string= request "ACTION") - (string= request "KEEPALIVE")) - (rcirc-print process sender "CTCP" target - (format "%s" text) t)))))) - -(defun rcirc-handler-ctcp-VERSION (process _target sender _args) - (rcirc-send-string process - (concat "NOTICE " sender - " :\C-aVERSION " rcirc-id-string - "\C-a"))) - -(defun rcirc-handler-ctcp-ACTION (process target sender args) - (rcirc-print process sender "ACTION" target args t)) - -(defun rcirc-handler-ctcp-TIME (process _target sender _args) - (rcirc-send-string process - (concat "NOTICE " sender - " :\C-aTIME " (current-time-string) "\C-a"))) - -(defun rcirc-handler-CTCP-response (process _target sender message) - (rcirc-print process sender "CTCP" nil message t)) - -(defun rcirc-handler-CAP (process _sender args _text) - (when (equal (cadr args) "LS") - (rcirc-send-string process "CAP REQ :server-time")) - - (when (or (equal (cadr args) "ACK") - (equal (cadr args) "NAK")) - ;; Capability negotiation is best-effort here, I know that my - ;; servers support server-time and thus we end negotiation - ;; immediately. - (rcirc-send-string process "CAP END"))) - -(defgroup rcirc-faces nil - "Faces for rcirc." - :group 'rcirc - :group 'faces) - -(defface rcirc-my-nick ; font-lock-function-name-face - '((((class color) (min-colors 88) (background light)) :foreground "Blue1") - (((class color) (min-colors 88) (background dark)) :foreground "LightSkyBlue") - (((class color) (min-colors 16) (background light)) :foreground "Blue") - (((class color) (min-colors 16) (background dark)) :foreground "LightSkyBlue") - (((class color) (min-colors 8)) :foreground "blue" :weight bold) - (t :inverse-video t :weight bold)) - "Rcirc face for my messages." - :group 'rcirc-faces) - -(defface rcirc-other-nick ; font-lock-variable-name-face - '((((class grayscale) (background light)) - :foreground "Gray90" :weight bold :slant italic) - (((class grayscale) (background dark)) - :foreground "DimGray" :weight bold :slant italic) - (((class color) (min-colors 88) (background light)) :foreground "DarkGoldenrod") - (((class color) (min-colors 88) (background dark)) :foreground "LightGoldenrod") - (((class color) (min-colors 16) (background light)) :foreground "DarkGoldenrod") - (((class color) (min-colors 16) (background dark)) :foreground "LightGoldenrod") - (((class color) (min-colors 8)) :foreground "yellow" :weight light) - (t :weight bold :slant italic)) - "Rcirc face for other users' messages." - :group 'rcirc-faces) - -(defface rcirc-bright-nick - '((((class grayscale) (background light)) - :foreground "LightGray" :weight bold :underline t) - (((class grayscale) (background dark)) - :foreground "Gray50" :weight bold :underline t) - (((class color) (min-colors 88) (background light)) :foreground "CadetBlue") - (((class color) (min-colors 88) (background dark)) :foreground "Aquamarine") - (((class color) (min-colors 16) (background light)) :foreground "CadetBlue") - (((class color) (min-colors 16) (background dark)) :foreground "Aquamarine") - (((class color) (min-colors 8)) :foreground "magenta") - (t :weight bold :underline t)) - "Rcirc face for nicks matched by `rcirc-bright-nicks'." - :group 'rcirc-faces) - -(defface rcirc-dim-nick - '((t :inherit default)) - "Rcirc face for nicks in `rcirc-dim-nicks'." - :group 'rcirc-faces) - -(defface rcirc-server ; font-lock-comment-face - '((((class grayscale) (background light)) - :foreground "DimGray" :weight bold :slant italic) - (((class grayscale) (background dark)) - :foreground "LightGray" :weight bold :slant italic) - (((class color) (min-colors 88) (background light)) - :foreground "Firebrick") - (((class color) (min-colors 88) (background dark)) - :foreground "chocolate1") - (((class color) (min-colors 16) (background light)) - :foreground "red") - (((class color) (min-colors 16) (background dark)) - :foreground "red1") - (((class color) (min-colors 8) (background light))) - (((class color) (min-colors 8) (background dark))) - (t :weight bold :slant italic)) - "Rcirc face for server messages." - :group 'rcirc-faces) - -(defface rcirc-server-prefix ; font-lock-comment-delimiter-face - '((default :inherit rcirc-server) - (((class grayscale))) - (((class color) (min-colors 16))) - (((class color) (min-colors 8) (background light)) - :foreground "red") - (((class color) (min-colors 8) (background dark)) - :foreground "red1")) - "Rcirc face for server prefixes." - :group 'rcirc-faces) - -(defface rcirc-timestamp - '((t :inherit default)) - "Rcirc face for timestamps." - :group 'rcirc-faces) - -(defface rcirc-nick-in-message ; font-lock-keyword-face - '((((class grayscale) (background light)) :foreground "LightGray" :weight bold) - (((class grayscale) (background dark)) :foreground "DimGray" :weight bold) - (((class color) (min-colors 88) (background light)) :foreground "Purple") - (((class color) (min-colors 88) (background dark)) :foreground "Cyan1") - (((class color) (min-colors 16) (background light)) :foreground "Purple") - (((class color) (min-colors 16) (background dark)) :foreground "Cyan") - (((class color) (min-colors 8)) :foreground "cyan" :weight bold) - (t :weight bold)) - "Rcirc face for instances of your nick within messages." - :group 'rcirc-faces) - -(defface rcirc-nick-in-message-full-line '((t :weight bold)) - "Rcirc face for emphasizing the entire message when your nick is mentioned." - :group 'rcirc-faces) - -(defface rcirc-prompt ; comint-highlight-prompt - '((((min-colors 88) (background dark)) :foreground "cyan1") - (((background dark)) :foreground "cyan") - (t :foreground "dark blue")) - "Rcirc face for prompts." - :group 'rcirc-faces) - -(defface rcirc-track-nick - '((((type tty)) :inherit default) - (t :inverse-video t)) - "Rcirc face used in the mode-line when your nick is mentioned." - :group 'rcirc-faces) - -(defface rcirc-track-keyword '((t :weight bold)) - "Rcirc face used in the mode-line when keywords are mentioned." - :group 'rcirc-faces) - -(defface rcirc-url '((t :weight bold)) - "Rcirc face used to highlight urls." - :group 'rcirc-faces) - -(defface rcirc-keyword '((t :inherit highlight)) - "Rcirc face used to highlight keywords." - :group 'rcirc-faces) - - -;; When using M-x flyspell-mode, only check words after the prompt -(put 'rcirc-mode 'flyspell-mode-predicate 'rcirc-looking-at-input) -(defun rcirc-looking-at-input () - "Returns true if point is past the input marker." - (>= (point) rcirc-prompt-end-marker)) - - -(provide 'rcirc) - -;;; rcirc.el ends here diff --git a/third_party/exwm/.elpaignore b/third_party/exwm/.elpaignore deleted file mode 100644 index f0f644ee0..000000000 --- a/third_party/exwm/.elpaignore +++ /dev/null @@ -1,2 +0,0 @@ -LICENSE -README.md diff --git a/third_party/exwm/.gitignore b/third_party/exwm/.gitignore deleted file mode 100644 index 9e4b0ee5b..000000000 --- a/third_party/exwm/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.elc -*-pkg.el -*-autoloads.el diff --git a/third_party/exwm/LICENSE b/third_party/exwm/LICENSE deleted file mode 100644 index 9cecc1d46..000000000 --- a/third_party/exwm/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {one line to give the program's name and a brief idea of what it does.} - Copyright (C) {year} {name of author} - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - {project} Copyright (C) {year} {fullname} - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/third_party/exwm/README.md b/third_party/exwm/README.md deleted file mode 100644 index 6d7e0dd1f..000000000 --- a/third_party/exwm/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Emacs X Window Manager - -EXWM (Emacs X Window Manager) is a full-featured tiling X window manager -for Emacs built on top of [XELB](https://github.com/ch11ng/xelb). -It features: -+ Fully keyboard-driven operations -+ Hybrid layout modes (tiling & stacking) -+ Dynamic workspace support -+ ICCCM/EWMH compliance -+ (Optional) RandR (multi-monitor) support -+ (Optional) Builtin system tray -+ (Optional) Builtin input method - -Please check out the -[screenshots](https://github.com/ch11ng/exwm/wiki/Screenshots) -to get an overview of what EXWM is capable of, -and the [user guide](https://github.com/ch11ng/exwm/wiki) -for a detailed explanation of its usage. - -**Note**: If you install EXWM from source, it's recommended to install -XELB also from source (otherwise install both from GNU ELPA). diff --git a/third_party/exwm/default.nix b/third_party/exwm/default.nix deleted file mode 100644 index 6daee882f..000000000 --- a/third_party/exwm/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ depot, pkgs, lib, ... }: - -# special dance for overriding this into the fixed-point of emacs -# packages, but having it be separately buildable. - -pkgs.emacsPackages.callPackage - ({ trivialBuild, xelb }: trivialBuild { - pname = "depot-exwm"; - version = "canon"; - src = ./.; - - packageRequires = [ xelb ]; - }) -{ } diff --git a/third_party/exwm/exwm-background.el b/third_party/exwm/exwm-background.el deleted file mode 100644 index fa663d8fe..000000000 --- a/third_party/exwm/exwm-background.el +++ /dev/null @@ -1,199 +0,0 @@ -;;; exwm-background.el --- X Background Module for EXWM -*- lexical-binding: t -*- - -;; Copyright (C) 2022-2024 Free Software Foundation, Inc. - -;; Author: Steven Allen - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module adds X background color setting support to EXWM. - -;; To use this module, load and enable it as follows: -;; (require 'exwm-background) -;; (exwm-background-enable) -;; -;; By default, this will apply the theme's background color. However, that -;; color can be customized via the `exwm-background-color' setting. - -;;; Code: - -(require 'exwm-core) - -(defcustom exwm-background-color nil - "Background color for Xorg." - :type '(choice - (color :tag "Background Color") - (const :tag "Default" nil)) - :group 'exwm - :initialize #'custom-initialize-default - :set (lambda (symbol value) - (set-default-toplevel-value symbol value) - (exwm-background--update))) - -(defconst exwm-background--properties '("_XROOTPMAP_ID" "_XSETROOT_ID" "ESETROOT_PMAP_ID") - "The background properties to set. -We can't need to set these so that compositing window managers -can correctly display the background color.") - -(defvar exwm-background--connection nil - "The X connection used for setting the background. -We use a separate connection as other background-setting tools -may kill this connection when they replace it.") - -(defvar exwm-background--pixmap nil - "Cached background pixmap.") - -(defvar exwm-background--atoms nil - "Cached background atoms.") - -(defun exwm-background--update (&rest _) - "Update the EXWM background." - - ;; Always reconnect as any tool that sets the background may have disconnected us (to force X to - ;; free resources). - (exwm-background--connect) - - (let ((gc (xcb:generate-id exwm-background--connection)) - (color (exwm--color->pixel (or exwm-background-color - (face-background 'default))))) - ;; Fill the pixmap. - (xcb:+request exwm-background--connection - (make-instance 'xcb:CreateGC - :cid gc :drawable exwm-background--pixmap - :value-mask (logior xcb:GC:Foreground - xcb:GC:GraphicsExposures) - :foreground color - :graphics-exposures 0)) - - (xcb:+request exwm-background--connection - (make-instance 'xcb:PolyFillRectangle - :gc gc :drawable exwm-background--pixmap - :rectangles - (list - (make-instance - 'xcb:RECTANGLE - :x 0 :y 0 :width 1 :height 1)))) - (xcb:+request exwm-background--connection (make-instance 'xcb:FreeGC :gc gc))) - - ;; Reapply it to force an update (also clobber anyone else who may have set it). - (xcb:+request exwm-background--connection - (make-instance 'xcb:ChangeWindowAttributes - :window exwm--root - :value-mask xcb:CW:BackPixmap - :background-pixmap exwm-background--pixmap)) - - (let (old) - ;; Collect old pixmaps so we can kill other background clients (all the background setting tools - ;; seem to do this). - (dolist (atom exwm-background--atoms) - (when-let* ((reply (xcb:+request-unchecked+reply exwm-background--connection - (make-instance 'xcb:GetProperty - :delete 0 - :window exwm--root - :property atom - :type xcb:Atom:PIXMAP - :long-offset 0 - :long-length 1))) - (value (vconcat (slot-value reply 'value))) - ((length= value 4)) - (pixmap (funcall (if xcb:lsb #'xcb:-unpack-u4-lsb #'xcb:-unpack-u4) - value 0)) - ((not (or (= pixmap exwm-background--pixmap) - (member pixmap old))))) - (push pixmap old))) - - ;; Change the background. - (dolist (atom exwm-background--atoms) - (xcb:+request exwm-background--connection - (make-instance 'xcb:ChangeProperty - :window exwm--root - :property atom - :type xcb:Atom:PIXMAP - :format 32 - :mode xcb:PropMode:Replace - :data-len 1 - :data - (funcall (if xcb:lsb - #'xcb:-pack-u4-lsb - #'xcb:-pack-u4) - exwm-background--pixmap)))) - - ;; Kill the old background clients. - (dolist (pixmap old) - (xcb:+request exwm-background--connection - (make-instance 'xcb:KillClient :resource pixmap)))) - - (xcb:flush exwm-background--connection)) - -(defun exwm-background--connected-p () - (and exwm-background--connection - (process-live-p (slot-value exwm-background--connection 'process)))) - -(defun exwm-background--connect () - (unless (exwm-background--connected-p) - (setq exwm-background--connection (xcb:connect)) - ;;prevent query message on exit - (set-process-query-on-exit-flag (slot-value exwm-background--connection 'process) nil) - - ;; Intern the background property atoms. - (setq exwm-background--atoms - (mapcar - (lambda (prop) (exwm--intern-atom prop exwm-background--connection)) - exwm-background--properties)) - - ;; Create the pixmap. - (setq exwm-background--pixmap (xcb:generate-id exwm-background--connection)) - (xcb:+request exwm-background--connection - (make-instance 'xcb:CreatePixmap - :depth - (slot-value - (xcb:+request-unchecked+reply exwm-background--connection - (make-instance 'xcb:GetGeometry :drawable exwm--root)) - 'depth) - :pid exwm-background--pixmap - :drawable exwm--root - :width 1 :height 1)))) - -(defun exwm-background--init () - "Initialize background module." - (exwm--log) - (add-hook 'enable-theme-functions 'exwm-background--update) - (add-hook 'disable-theme-functions 'exwm-background--update) - (exwm-background--update)) - -(defun exwm-background--exit () - "Uninitialize the background module." - (exwm--log) - (remove-hook 'enable-theme-functions 'exwm-background--update) - (remove-hook 'disable-theme-functions 'exwm-background--update) - (when (and exwm-background--connection - (slot-value exwm-background--connection 'connected)) - (xcb:disconnect exwm-background--connection)) - (setq exwm-background--pixmap nil - exwm-background--connection nil - exwm-background--atoms nil)) - -(defun exwm-background-enable () - "Enable background support for EXWM." - (exwm--log) - (add-hook 'exwm-init-hook #'exwm-background--init) - (add-hook 'exwm-exit-hook #'exwm-background--exit)) - -(provide 'exwm-background) - -;;; exwm-background.el ends here diff --git a/third_party/exwm/exwm-config.el b/third_party/exwm/exwm-config.el deleted file mode 100644 index a9f21e9c8..000000000 --- a/third_party/exwm/exwm-config.el +++ /dev/null @@ -1,131 +0,0 @@ -;;; exwm-config.el --- Predefined configurations -*- lexical-binding: t -*- - -;; Copyright (C) 2015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module contains typical (yet minimal) configurations of EXWM. - -;;; Code: - -(require 'exwm) -(require 'ido) - -(define-obsolete-function-alias 'exwm-config-default - #'exwm-config-example "27.1") - -(defun exwm-config-example () - "Default configuration of EXWM." - ;; Set the initial workspace number. - (unless (get 'exwm-workspace-number 'saved-value) - (setq exwm-workspace-number 4)) - ;; Make class name the buffer name - (add-hook 'exwm-update-class-hook - (lambda () - (exwm-workspace-rename-buffer exwm-class-name))) - ;; Global keybindings. - (unless (get 'exwm-input-global-keys 'saved-value) - (setq exwm-input-global-keys - `( - ;; 's-r': Reset (to line-mode). - ([?\s-r] . exwm-reset) - ;; 's-w': Switch workspace. - ([?\s-w] . exwm-workspace-switch) - ;; 's-&': Launch application. - ([?\s-&] . (lambda (command) - (interactive (list (read-shell-command "$ "))) - (start-process-shell-command command nil command))) - ;; 's-N': Switch to certain workspace. - ,@(mapcar (lambda (i) - `(,(kbd (format "s-%d" i)) . - (lambda () - (interactive) - (exwm-workspace-switch-create ,i)))) - (number-sequence 0 9))))) - ;; Line-editing shortcuts - (unless (get 'exwm-input-simulation-keys 'saved-value) - (setq exwm-input-simulation-keys - '(([?\C-b] . [left]) - ([?\C-f] . [right]) - ([?\C-p] . [up]) - ([?\C-n] . [down]) - ([?\C-a] . [home]) - ([?\C-e] . [end]) - ([?\M-v] . [prior]) - ([?\C-v] . [next]) - ([?\C-d] . [delete]) - ([?\C-k] . [S-end delete])))) - ;; Enable EXWM - (exwm-enable) - ;; Configure Ido - (exwm-config-ido) - ;; Other configurations - (exwm-config-misc)) - -(defun exwm-config--fix/ido-buffer-window-other-frame () - "Fix `ido-buffer-window-other-frame'." - (defalias 'exwm-config-ido-buffer-window-other-frame - (symbol-function #'ido-buffer-window-other-frame)) - (defun ido-buffer-window-other-frame (buffer) - "This is a version redefined by EXWM. - -You can find the original one at `exwm-config-ido-buffer-window-other-frame'." - (with-current-buffer (window-buffer (selected-window)) - (if (and (derived-mode-p 'exwm-mode) - exwm--floating-frame) - ;; Switch from a floating frame. - (with-current-buffer buffer - (if (and (derived-mode-p 'exwm-mode) - exwm--floating-frame - (eq exwm--frame exwm-workspace--current)) - ;; Switch to another floating frame. - (frame-root-window exwm--floating-frame) - ;; Do not switch if the buffer is not on the current workspace. - (or (get-buffer-window buffer exwm-workspace--current) - (selected-window)))) - (with-current-buffer buffer - (when (derived-mode-p 'exwm-mode) - (if (eq exwm--frame exwm-workspace--current) - (when exwm--floating-frame - ;; Switch to a floating frame on the current workspace. - (frame-selected-window exwm--floating-frame)) - ;; Do not switch to exwm-mode buffers on other workspace (which - ;; won't work unless `exwm-layout-show-all-buffers' is set) - (unless exwm-layout-show-all-buffers - (selected-window))))))))) - -(defun exwm-config-ido () - "Configure Ido to work with EXWM." - (ido-mode 1) - (add-hook 'exwm-init-hook #'exwm-config--fix/ido-buffer-window-other-frame)) - -(defun exwm-config-misc () - "Other configurations." - ;; Make more room - (menu-bar-mode -1) - (tool-bar-mode -1) - (scroll-bar-mode -1) - (fringe-mode 1)) - - - -(provide 'exwm-config) - -;;; exwm-config.el ends here diff --git a/third_party/exwm/exwm-core.el b/third_party/exwm/exwm-core.el deleted file mode 100644 index a7fdfce71..000000000 --- a/third_party/exwm/exwm-core.el +++ /dev/null @@ -1,415 +0,0 @@ -;;; exwm-core.el --- Core definitions -*- lexical-binding: t -*- - -;; Copyright (C) 2015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module includes core definitions of variables, macros, functions, etc -;; shared by various other modules. - -;;; Code: - -(require 'kmacro) - -(require 'xcb) -(require 'xcb-icccm) -(require 'xcb-ewmh) -(require 'xcb-debug) - -(defgroup exwm-debug nil - "Debugging." - :group 'exwm) - -(defcustom exwm-debug-log-time-function #'exwm-debug-log-uptime - "Function used for generating timestamps in `exwm-debug' logs. - -Here are some predefined candidates: -`exwm-debug-log-uptime': Display the uptime of this Emacs instance. -`exwm-debug-log-time': Display time of day. -`nil': Disable timestamp." - :type `(choice (const :tag "Emacs uptime" ,#'exwm-debug-log-uptime) - (const :tag "Time of day" ,#'exwm-debug-log-time) - (const :tag "Off" nil) - (function :tag "Other")) - :set (lambda (symbol value) - (set-default symbol value) - ;; Also change the format for XELB to make logs consistent - ;; (as they share the same buffer). - (setq xcb-debug:log-time-function value))) - -(defalias 'exwm-debug-log-uptime 'xcb-debug:log-uptime - "Add uptime to `exwm-debug' logs.") - -(defalias 'exwm-debug-log-time 'xcb-debug:log-time - "Add time of day to `exwm-debug' logs.") - -(defvar exwm--connection nil "X connection.") - -(defvar exwm--terminal nil - "Terminal corresponding to `exwm--connection'.") - -(defvar exwm--wmsn-window nil - "An X window owning the WM_S0 selection.") - -(defvar exwm--wmsn-acquire-timeout 3 - "Number of seconds to wait for other window managers to release the selection.") - -(defvar exwm--guide-window nil - "An X window separating workspaces and X windows.") - -(defvar exwm--id-buffer-alist nil "Alist of ( . ).") - -(defvar exwm--root nil "Root window.") - -(defvar exwm-input--global-prefix-keys) -(defvar exwm-input--simulation-keys) -(defvar exwm-input-line-mode-passthrough) -(defvar exwm-input-prefix-keys) -(defvar exwm-workspace--list) -(declare-function exwm-input--fake-key "exwm-input.el" (event)) -(declare-function exwm-input--on-KeyPress-line-mode "exwm-input.el" - (key-press raw-data)) -(declare-function exwm-floating-hide "exwm-floating.el") -(declare-function exwm-floating-toggle-floating "exwm-floating.el") -(declare-function exwm-input-release-keyboard "exwm-input.el") -(declare-function exwm-input-send-next-key "exwm-input.el" (times)) -(declare-function exwm-layout-set-fullscreen "exwm-layout.el" (&optional id)) -(declare-function exwm-layout-toggle-mode-line "exwm-layout.el") -(declare-function exwm-manage--kill-buffer-query-function "exwm-manage.el") -(declare-function exwm-workspace-move-window "exwm-workspace.el" - (frame-or-index &optional id)) -(declare-function exwm-workspace-switch "exwm-workspace.el" - (frame-or-index &optional force)) - -(define-minor-mode exwm-debug - "Debug-logging enabled if non-nil." - :global t - :group 'exwm-debug) - -(defmacro exwm--debug (&rest forms) - "Evaluate FORMS if mode `exwm-debug' is active." - (when exwm-debug `(progn ,@forms))) - -(defmacro exwm--log (&optional format-string &rest objects) - "Emit a message prepending the name of the function being executed. - -FORMAT-STRING is a string specifying the message to output, as in -`format'. The OBJECTS arguments specify the substitutions." - (unless format-string (setq format-string "")) - `(when exwm-debug - (xcb-debug:message ,(concat "%s%s:\t" format-string "\n") - (if exwm-debug-log-time-function - (funcall exwm-debug-log-time-function) - "") - (xcb-debug:compile-time-function-name) - ,@objects) - nil)) - -(defsubst exwm--id->buffer (id) - "X window ID => Emacs buffer." - (declare (indent defun)) - (cdr (assoc id exwm--id-buffer-alist))) - -(defsubst exwm--buffer->id (buffer) - "Emacs buffer BUFFER => X window ID." - (declare (indent defun)) - (car (rassoc buffer exwm--id-buffer-alist))) - -(defun exwm--lock (&rest _args) - "Lock (disable all events)." - (exwm--log) - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window exwm--root - :value-mask xcb:CW:EventMask - :event-mask xcb:EventMask:NoEvent)) - (xcb:flush exwm--connection)) - -(defun exwm--unlock (&rest _args) - "Unlock (enable all events)." - (exwm--log) - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window exwm--root - :value-mask xcb:CW:EventMask - :event-mask (eval-when-compile - (logior xcb:EventMask:SubstructureRedirect - xcb:EventMask:StructureNotify)))) - (xcb:flush exwm--connection)) - -(defun exwm--set-geometry (xwin x y width height) - "Set the geometry of X window XWIN to WIDTHxHEIGHT+X+Y. - -Nil can be passed as placeholder." - (exwm--log "Setting #x%x to %sx%s+%s+%s" xwin width height x y) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window xwin - :value-mask (logior (if x xcb:ConfigWindow:X 0) - (if y xcb:ConfigWindow:Y 0) - (if width xcb:ConfigWindow:Width 0) - (if height xcb:ConfigWindow:Height 0)) - :x x :y y :width width :height height))) - -(defun exwm--intern-atom (atom &optional conn) - "Intern X11 ATOM. -If CONN is non-nil, use it instead of the value of the variable -`exwm--connection'." - (slot-value (xcb:+request-unchecked+reply (or conn exwm--connection) - (make-instance 'xcb:InternAtom - :only-if-exists 0 - :name-len (length atom) - :name atom)) - 'atom)) - -(defmacro exwm--defer (secs function &rest args) - "Defer the execution of FUNCTION. - -The action is to call FUNCTION with arguments ARGS. If Emacs is not idle, -defer the action until Emacs is idle. Otherwise, defer the action until at -least SECS seconds later." - `(run-with-idle-timer (+ (float-time (or (current-idle-time) - (seconds-to-time (- ,secs)))) - ,secs) - nil - ,function - ,@args)) - -(defsubst exwm--terminal-p (&optional frame) - "Return t when FRAME's terminal is EXWM's terminal. -If FRAME is null, use selected frame." - (declare (indent defun)) - (eq exwm--terminal (frame-terminal frame))) - -(defun exwm--get-client-event-mask () - "Return event mask set on all managed windows." - (logior xcb:EventMask:StructureNotify - xcb:EventMask:PropertyChange - (if mouse-autoselect-window - xcb:EventMask:EnterWindow 0))) - -(defun exwm--color->pixel (color) - "Convert COLOR to PIXEL (index in TrueColor colormap)." - (when (and color - (eq (x-display-visual-class) 'true-color)) - (let ((rgb (color-values color))) - (logior (ash (ash (pop rgb) -8) 16) - (ash (ash (pop rgb) -8) 8) - (ash (pop rgb) -8))))) - -(defun exwm--get-visual-depth-colormap (conn id) - "Get visual, depth and colormap from X window ID. -Return a three element list with the respective results. - -If CONN is non-nil, use it instead of the value of the variable -`exwm--connection'." - (let (ret-visual ret-depth ret-colormap) - (with-slots (visual colormap) - (xcb:+request-unchecked+reply conn - (make-instance 'xcb:GetWindowAttributes :window id)) - (setq ret-visual visual) - (setq ret-colormap colormap)) - (with-slots (depth) - (xcb:+request-unchecked+reply conn - (make-instance 'xcb:GetGeometry :drawable id)) - (setq ret-depth depth)) - (list ret-visual ret-depth ret-colormap))) - -(defun exwm--mode-name () - "Mode name string used in `exwm-mode' buffers." - (let ((name "EXWM")) - (if (cl-some (lambda (i) (frame-parameter i 'exwm-urgency)) - exwm-workspace--list) - (propertize name 'face 'font-lock-warning-face) - name))) - -;; Internal variables -(defvar-local exwm--id nil) ;window ID -(defvar-local exwm--configurations nil) ;initial configurations. -(defvar-local exwm--frame nil) ;workspace frame -(defvar-local exwm--floating-frame nil) ;floating frame -(defvar-local exwm--mode-line-format nil) ;save mode-line-format -(defvar-local exwm--floating-frame-position nil) ;set when hidden. -(defvar-local exwm--fixed-size nil) ;fixed size -(defvar-local exwm--selected-input-mode 'line-mode - "Input mode as selected by the user. -One of `line-mode' or `char-mode'.") -(defvar-local exwm--input-mode 'line-mode - "Actual input mode, i.e. whether mouse and keyboard are grabbed.") -;; Properties -(defvar-local exwm--desktop nil "_NET_WM_DESKTOP.") -(defvar-local exwm-window-type nil "_NET_WM_WINDOW_TYPE.") -(defvar-local exwm--geometry nil) -(defvar-local exwm-class-name nil "Class name in WM_CLASS.") -(defvar-local exwm-instance-name nil "Instance name in WM_CLASS.") -(defvar-local exwm-title nil "Window title (either _NET_WM_NAME or WM_NAME).") -(defvar-local exwm--title-is-utf8 nil) -(defvar-local exwm-transient-for nil "WM_TRANSIENT_FOR.") -(defvar-local exwm--protocols nil) -(defvar-local exwm-state xcb:icccm:WM_STATE:NormalState "WM_STATE.") -(defvar-local exwm--ewmh-state nil "_NET_WM_STATE.") -;; _NET_WM_NORMAL_HINTS -(defvar-local exwm--normal-hints-x nil) -(defvar-local exwm--normal-hints-y nil) -(defvar-local exwm--normal-hints-width nil) -(defvar-local exwm--normal-hints-height nil) -(defvar-local exwm--normal-hints-min-width nil) -(defvar-local exwm--normal-hints-min-height nil) -(defvar-local exwm--normal-hints-max-width nil) -(defvar-local exwm--normal-hints-max-height nil) -;; (defvar-local exwm--normal-hints-win-gravity nil) -;; WM_HINTS -(defvar-local exwm--hints-input nil) -(defvar-local exwm--hints-urgency nil) -;; _MOTIF_WM_HINTS -(defvar-local exwm--mwm-hints-decorations t) - -(defvar exwm-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "\C-c\C-d\C-l" #'xcb-debug:clear) - (define-key map "\C-c\C-d\C-m" #'xcb-debug:mark) - (define-key map "\C-c\C-d\C-t" #'exwm-debug) - (define-key map "\C-c\C-f" #'exwm-layout-set-fullscreen) - (define-key map "\C-c\C-h" #'exwm-floating-hide) - (define-key map "\C-c\C-k" #'exwm-input-release-keyboard) - (define-key map "\C-c\C-m" #'exwm-workspace-move-window) - (define-key map "\C-c\C-q" #'exwm-input-send-next-key) - (define-key map "\C-c\C-t\C-f" #'exwm-floating-toggle-floating) - (define-key map "\C-c\C-t\C-m" #'exwm-layout-toggle-mode-line) - map) - "Keymap for `exwm-mode'.") - -(defvar exwm--kmacro-map - (let ((map (make-sparse-keymap))) - (define-key map [t] - (lambda () - (interactive) - (cond - ((or exwm-input-line-mode-passthrough - ;; Do not test `exwm-input--during-command'. - (active-minibuffer-window) - (memq last-input-event exwm-input--global-prefix-keys) - (memq last-input-event exwm-input-prefix-keys) - (lookup-key exwm-mode-map (vector last-input-event)) - (gethash last-input-event exwm-input--simulation-keys)) - (set-transient-map (make-composed-keymap (list exwm-mode-map - global-map))) - (push last-input-event unread-command-events)) - (t - (exwm-input--fake-key last-input-event))))) - map) - "Keymap used when executing keyboard macros.") - -;; This menu mainly acts as an reminder for users. Thus it should be as -;; detailed as possible, even some entries do not make much sense here. -;; Also, inactive entries should be disabled rather than hidden. -(easy-menu-define exwm-mode-menu exwm-mode-map - "Menu for `exwm-mode'." - `("EXWM" - "---" - "*General*" - "---" - ["Toggle floating" exwm-floating-toggle-floating] - ["Toggle fullscreen mode" exwm-layout-toggle-fullscreen] - ["Hide window" exwm-floating-hide exwm--floating-frame] - ["Close window" (kill-buffer (current-buffer))] - - "---" - "*Resizing*" - "---" - ["Toggle mode-line" exwm-layout-toggle-mode-line] - ["Enlarge window vertically" exwm-layout-enlarge-window] - ["Enlarge window horizontally" exwm-layout-enlarge-window-horizontally] - ["Shrink window vertically" exwm-layout-shrink-window] - ["Shrink window horizontally" exwm-layout-shrink-window-horizontally] - - "---" - "*Keyboard*" - "---" - ["Toggle keyboard mode" exwm-input-toggle-keyboard] - ["Send key" exwm-input-send-next-key (eq exwm--input-mode 'line-mode)] - ;; This is merely a reference. - ("Send simulation key" :filter - ,(lambda (&rest _args) - (let (result) - (maphash - (lambda (key value) - (when (sequencep key) - (setq result (append result - `([,(format "Send '%s'" - (key-description value)) - ,(lambda () - (interactive) - (mapc #'exwm-input--fake-key value)) - :keys ,(key-description key)]))))) - exwm-input--simulation-keys) - result))) - - ["Define global binding" exwm-input-set-key] - - "---" - "*Workspace*" - "---" - ["Add workspace" exwm-workspace-add] - ["Delete current workspace" exwm-workspace-delete] - ["Move workspace to" exwm-workspace-move] - ["Swap workspaces" exwm-workspace-swap] - ["Move X window to" exwm-workspace-move-window] - ["Move X window from" exwm-workspace-switch-to-buffer] - ["Toggle minibuffer" exwm-workspace-toggle-minibuffer] - ["Switch workspace" exwm-workspace-switch] - ;; Place this entry at bottom to avoid selecting others by accident. - ("Switch to" :filter - ,(lambda (&rest _args) - (mapcar (lambda (i) - `[,(format "Workspace %d" i) - ,(lambda () - (interactive) - (exwm-workspace-switch i)) - (/= ,i exwm-workspace-current-index)]) - (number-sequence 0 (1- (length exwm-workspace--list)))))))) - -(define-derived-mode exwm-mode nil "EXWM" - "Major mode for managing X windows. - -\\{exwm-mode-map}" - :interactive nil :abbrev-table nil :syntax-table nil - ;; Change major-mode is not allowed - (add-hook 'change-major-mode-hook #'kill-buffer nil t) - ;; Kill buffer -> close window - (add-hook 'kill-buffer-query-functions - #'exwm-manage--kill-buffer-query-function nil t) - ;; Redirect events when executing keyboard macros. - (push `(executing-kbd-macro . ,exwm--kmacro-map) - minor-mode-overriding-map-alist) - (setq mode-name '(:eval (exwm--mode-name)) - buffer-read-only t - cursor-type nil - left-margin-width nil - right-margin-width nil - left-fringe-width 0 - right-fringe-width 0 - vertical-scroll-bar nil)) - - - -(provide 'exwm-core) - -;;; exwm-core.el ends here diff --git a/third_party/exwm/exwm-floating.el b/third_party/exwm/exwm-floating.el deleted file mode 100644 index 574a78f01..000000000 --- a/third_party/exwm/exwm-floating.el +++ /dev/null @@ -1,780 +0,0 @@ -;;; exwm-floating.el --- Floating Module for EXWM -*- lexical-binding: t -*- - -;; Copyright (C) 2015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module deals with the conversion between floating and non-floating -;; states and implements moving/resizing operations on floating windows. - -;;; Code: - -(require 'xcb-cursor) -(require 'exwm-core) - -(defgroup exwm-floating nil - "Floating." - :group 'exwm) - -(defcustom exwm-floating-setup-hook nil - "Normal hook run when an X window has been made floating. -This hook runs in the context of the corresponding buffer." - :type 'hook) - -(defcustom exwm-floating-exit-hook nil - "Normal hook run when an X window has exited floating state. -This hook runs in the context of the corresponding buffer." - :type 'hook) - -(defcustom exwm-floating-border-color "navy" - "Border color of floating windows." - :type 'color - :initialize #'custom-initialize-default - :set (lambda (symbol value) - (set-default symbol value) - ;; Change border color for all floating X windows. - (when exwm--connection - (let ((border-pixel (exwm--color->pixel value))) - (when border-pixel - (dolist (pair exwm--id-buffer-alist) - (with-current-buffer (cdr pair) - (when exwm--floating-frame - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window - (frame-parameter exwm--floating-frame - 'exwm-container) - :value-mask xcb:CW:BorderPixel - :border-pixel border-pixel))))) - (xcb:flush exwm--connection)))))) - -(defcustom exwm-floating-border-width 1 - "Border width of floating windows." - :type `(integer - :validate ,(lambda (widget) - (when (< (widget-value widget) 0) - (widget-put widget :error "Border width is at least 0") - widget))) - :initialize #'custom-initialize-default - :set (lambda (symbol value) - (let ((delta (- value exwm-floating-border-width)) - container) - (set-default symbol value) - ;; Change border width for all floating X windows. - (dolist (pair exwm--id-buffer-alist) - (with-current-buffer (cdr pair) - (when exwm--floating-frame - (setq container (frame-parameter exwm--floating-frame - 'exwm-container)) - (with-slots (x y) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry - :drawable container)) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window container - :value-mask - (logior xcb:ConfigWindow:X - xcb:ConfigWindow:Y - xcb:ConfigWindow:BorderWidth) - :border-width value - :x (- x delta) - :y (- y delta))))))) - (when exwm--connection - (xcb:flush exwm--connection))))) - -;; Cursors for moving/resizing a window -(defvar exwm-floating--cursor-move nil) -(defvar exwm-floating--cursor-top-left nil) -(defvar exwm-floating--cursor-top nil) -(defvar exwm-floating--cursor-top-right nil) -(defvar exwm-floating--cursor-right nil) -(defvar exwm-floating--cursor-bottom-right nil) -(defvar exwm-floating--cursor-bottom nil) -(defvar exwm-floating--cursor-bottom-left nil) -(defvar exwm-floating--cursor-left nil) - -(defvar exwm-floating--moveresize-calculate nil - "Calculate move/resize parameters [buffer event-mask x y width height].") - -(defvar exwm-workspace--current) -(defvar exwm-workspace--frame-y-offset) -(defvar exwm-workspace--window-y-offset) -(declare-function exwm-layout--hide "exwm-layout.el" (id)) -(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id)) -(declare-function exwm-layout--refresh "exwm-layout.el" ()) -(declare-function exwm-layout--show "exwm-layout.el" (id &optional window)) -(declare-function exwm-workspace--position "exwm-workspace.el" (frame)) -(declare-function exwm-workspace--update-offsets "exwm-workspace.el" ()) -(declare-function exwm-workspace--workarea "exwm-workspace.el" (frame)) - -(defun exwm-floating--set-allowed-actions (id tilling) - "Set _NET_WM_ALLOWED_ACTIONS." - (exwm--log "#x%x" id) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_ALLOWED_ACTIONS - :window id - :data (if tilling - (vector xcb:Atom:_NET_WM_ACTION_MINIMIZE - xcb:Atom:_NET_WM_ACTION_FULLSCREEN - xcb:Atom:_NET_WM_ACTION_CHANGE_DESKTOP - xcb:Atom:_NET_WM_ACTION_CLOSE) - (vector xcb:Atom:_NET_WM_ACTION_MOVE - xcb:Atom:_NET_WM_ACTION_RESIZE - xcb:Atom:_NET_WM_ACTION_MINIMIZE - xcb:Atom:_NET_WM_ACTION_FULLSCREEN - xcb:Atom:_NET_WM_ACTION_CHANGE_DESKTOP - xcb:Atom:_NET_WM_ACTION_CLOSE))))) - -(defun exwm-floating--set-floating (id) - "Make window ID floating." - (let ((window (get-buffer-window (exwm--id->buffer id)))) - (when window - ;; Hide the non-floating X window first. - (set-window-buffer window (other-buffer nil t)))) - (let* ((original-frame (buffer-local-value 'exwm--frame - (exwm--id->buffer id))) - ;; Create new frame - (frame (with-current-buffer - (or (get-buffer "*scratch*") - (progn - (set-buffer-major-mode - (get-buffer-create "*scratch*")) - (get-buffer "*scratch*"))) - (make-frame - `((minibuffer . ,(minibuffer-window exwm--frame)) - (tab-bar-lines . 0) - (tab-bar-lines-keep-state . t) - (left . ,(* window-min-width -10000)) - (top . ,(* window-min-height -10000)) - (width . ,window-min-width) - (height . ,window-min-height) - (unsplittable . t))))) ;and fix the size later - (outer-id (string-to-number (frame-parameter frame 'outer-window-id))) - (window-id (string-to-number (frame-parameter frame 'window-id))) - (frame-container (xcb:generate-id exwm--connection)) - (window (frame-first-window frame)) ;and it's the only window - (x (slot-value exwm--geometry 'x)) - (y (slot-value exwm--geometry 'y)) - (width (slot-value exwm--geometry 'width)) - (height (slot-value exwm--geometry 'height))) - ;; Force drawing menu-bar & tool-bar. - (redisplay t) - (exwm-workspace--update-offsets) - (exwm--log "Floating geometry (original): %dx%d%+d%+d" width height x y) - ;; Save frame parameters. - (set-frame-parameter frame 'exwm-outer-id outer-id) - (set-frame-parameter frame 'exwm-id window-id) - (set-frame-parameter frame 'exwm-container frame-container) - ;; Fix illegal parameters - ;; FIXME: check normal hints restrictions - (with-slots ((x* x) (y* y) (width* width) (height* height)) - (exwm-workspace--workarea original-frame) - ;; Center floating windows - (when (and (or (= x 0) (= x x*)) - (or (= y 0) (= y y*))) - (let ((buffer (exwm--id->buffer exwm-transient-for)) - window edges) - (when (and buffer (setq window (get-buffer-window buffer))) - (setq edges (window-inside-absolute-pixel-edges window)) - (unless (and (<= width (- (elt edges 2) (elt edges 0))) - (<= height (- (elt edges 3) (elt edges 1)))) - (setq edges nil))) - (if edges - ;; Put at the center of leading window - (setq x (+ x* (/ (- (elt edges 2) (elt edges 0) width) 2)) - y (+ y* (/ (- (elt edges 3) (elt edges 1) height) 2))) - ;; Put at the center of screen - (setq x (/ (- width* width) 2) - y (/ (- height* height) 2))))) - (if (> width width*) - ;; Too wide - (progn (setq x x* - width width*)) - ;; Invalid width - (when (= 0 width) (setq width (/ width* 2))) - ;; Make sure at least half of the window is visible - (unless (< x* (+ x (/ width 2)) (+ x* width*)) - (setq x (+ x* (/ (- width* width) 2))))) - (if (> height height*) - ;; Too tall - (setq y y* - height height*) - ;; Invalid height - (when (= 0 height) (setq height (/ height* 2))) - ;; Make sure at least half of the window is visible - (unless (< y* (+ y (/ height 2)) (+ y* height*)) - (setq y (+ y* (/ (- height* height) 2))))) - ;; The geometry can be overridden by user options. - (let ((x** (plist-get exwm--configurations 'x)) - (y** (plist-get exwm--configurations 'y)) - (width** (plist-get exwm--configurations 'width)) - (height** (plist-get exwm--configurations 'height))) - (if (integerp x**) - (setq x (+ x* x**)) - (when (and (floatp x**) - (>= 1 x** 0)) - (setq x (+ x* (round (* x** width*)))))) - (if (integerp y**) - (setq y (+ y* y**)) - (when (and (floatp y**) - (>= 1 y** 0)) - (setq y (+ y* (round (* y** height*)))))) - (if (integerp width**) - (setq width width**) - (when (and (floatp width**) - (> 1 width** 0)) - (setq width (max 1 (round (* width** width*)))))) - (if (integerp height**) - (setq height height**) - (when (and (floatp height**) - (> 1 height** 0)) - (setq height (max 1 (round (* height** height*)))))))) - (exwm--set-geometry id x y nil nil) - (xcb:flush exwm--connection) - (exwm--log "Floating geometry (corrected): %dx%d%+d%+d" width height x y) - ;; Fit frame to client - ;; It seems we have to make the frame invisible in order to resize it - ;; timely. - ;; The frame will be made visible by `select-frame-set-input-focus'. - (make-frame-invisible frame) - (let* ((edges (window-inside-pixel-edges window)) - (frame-width (+ width (- (frame-pixel-width frame) - (- (elt edges 2) (elt edges 0))))) - (frame-height (+ height (- (frame-pixel-height frame) - (- (elt edges 3) (elt edges 1))) - ;; Use `frame-outer-height' in the future. - exwm-workspace--frame-y-offset)) - (floating-mode-line (plist-get exwm--configurations - 'floating-mode-line)) - (floating-header-line (plist-get exwm--configurations - 'floating-header-line)) - (border-pixel (exwm--color->pixel exwm-floating-border-color))) - (if floating-mode-line - (setq exwm--mode-line-format (or exwm--mode-line-format - mode-line-format) - mode-line-format floating-mode-line) - (if (and (not (plist-member exwm--configurations 'floating-mode-line)) - exwm--mwm-hints-decorations) - (when exwm--mode-line-format - (setq mode-line-format exwm--mode-line-format)) - ;; The mode-line need to be hidden in floating mode. - (setq frame-height (- frame-height (window-mode-line-height - (frame-root-window frame))) - exwm--mode-line-format (or exwm--mode-line-format - mode-line-format) - mode-line-format nil))) - (if floating-header-line - (setq header-line-format floating-header-line) - (if (and (not (plist-member exwm--configurations - 'floating-header-line)) - exwm--mwm-hints-decorations) - (setq header-line-format nil) - ;; The header-line need to be hidden in floating mode. - (setq frame-height (- frame-height (window-header-line-height - (frame-root-window frame))) - header-line-format nil))) - (set-frame-size frame frame-width frame-height t) - ;; Create the frame container as the parent of the frame. - (xcb:+request exwm--connection - (make-instance 'xcb:CreateWindow - :depth 0 - :wid frame-container - :parent exwm--root - :x x - :y (- y exwm-workspace--window-y-offset) - :width width - :height height - :border-width - (with-current-buffer (exwm--id->buffer id) - (let ((border-witdh (plist-get exwm--configurations - 'border-width))) - (if (and (integerp border-witdh) - (>= border-witdh 0)) - border-witdh - exwm-floating-border-width))) - :class xcb:WindowClass:InputOutput - :visual 0 - :value-mask (logior xcb:CW:BackPixmap - (if border-pixel - xcb:CW:BorderPixel 0) - xcb:CW:OverrideRedirect) - :background-pixmap xcb:BackPixmap:ParentRelative - :border-pixel border-pixel - :override-redirect 1)) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window frame-container - :data - (format "EXWM floating frame container for 0x%x" id))) - ;; Map it. - (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow :window frame-container)) - ;; Put the X window right above this frame container. - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window id - :value-mask (logior xcb:ConfigWindow:Sibling - xcb:ConfigWindow:StackMode) - :sibling frame-container - :stack-mode xcb:StackMode:Above))) - ;; Reparent this frame to its container. - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window outer-id :parent frame-container :x 0 :y 0)) - (exwm-floating--set-allowed-actions id nil) - (xcb:flush exwm--connection) - ;; Set window/buffer - (with-current-buffer (exwm--id->buffer id) - (setq window-size-fixed exwm--fixed-size - exwm--floating-frame frame) - ;; Do the refresh manually. - (remove-hook 'window-configuration-change-hook #'exwm-layout--refresh) - (set-window-buffer window (current-buffer)) ;this changes current buffer - (add-hook 'window-configuration-change-hook #'exwm-layout--refresh) - (set-window-dedicated-p window t) - (exwm-layout--show id window)) - (with-current-buffer (exwm--id->buffer id) - (if (exwm-layout--iconic-state-p id) - ;; Hide iconic floating X windows. - (exwm-floating-hide) - (with-selected-frame exwm--frame - (exwm-layout--refresh))) - (select-frame-set-input-focus frame)) - ;; FIXME: Strangely, the Emacs frame can move itself at this point - ;; when there are left/top struts set. Force resetting its - ;; position seems working, but it'd better to figure out why. - ;; FIXME: This also happens in another case (#220) where the cause is - ;; still unclear. - (exwm--set-geometry outer-id 0 0 nil nil) - (xcb:flush exwm--connection)) - (with-current-buffer (exwm--id->buffer id) - (run-hooks 'exwm-floating-setup-hook)) - ;; Redraw the frame. - (redisplay t)) - -(defun exwm-floating--unset-floating (id) - "Make window ID non-floating." - (exwm--log "#x%x" id) - (let ((buffer (exwm--id->buffer id))) - (with-current-buffer buffer - (when exwm--floating-frame - ;; The X window is already mapped. - ;; Unmap the X window. - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window id :value-mask xcb:CW:EventMask - :event-mask xcb:EventMask:NoEvent)) - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow :window id)) - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window id :value-mask xcb:CW:EventMask - :event-mask (exwm--get-client-event-mask))) - ;; Reparent the floating frame back to the root window. - (let ((frame-id (frame-parameter exwm--floating-frame 'exwm-outer-id)) - (frame-container (frame-parameter exwm--floating-frame - 'exwm-container))) - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow :window frame-id)) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window frame-id - :parent exwm--root - :x 0 :y 0)) - ;; Also destroy its container. - (xcb:+request exwm--connection - (make-instance 'xcb:DestroyWindow :window frame-container)))) - ;; Place the X window just above the reference X window. - ;; (the stacking order won't change from now on). - ;; Also hide the possible floating border. - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window id - :value-mask (logior xcb:ConfigWindow:BorderWidth - xcb:ConfigWindow:Sibling - xcb:ConfigWindow:StackMode) - :border-width 0 - :sibling exwm--guide-window - :stack-mode xcb:StackMode:Above))) - (exwm-floating--set-allowed-actions id t) - (xcb:flush exwm--connection) - (with-current-buffer buffer - (when exwm--floating-frame ;from floating to non-floating - (set-window-dedicated-p (frame-first-window exwm--floating-frame) nil) - ;; Select a tiling window and delete the old frame. - (select-window (frame-selected-window exwm-workspace--current)) - (with-current-buffer buffer - (delete-frame exwm--floating-frame)))) - (with-current-buffer buffer - (setq window-size-fixed nil - exwm--floating-frame nil) - (if (not (plist-member exwm--configurations 'tiling-mode-line)) - (when exwm--mode-line-format - (setq mode-line-format exwm--mode-line-format)) - (setq exwm--mode-line-format (or exwm--mode-line-format - mode-line-format) - mode-line-format (plist-get exwm--configurations - 'tiling-mode-line))) - (if (not (plist-member exwm--configurations 'tiling-header-line)) - (setq header-line-format nil) - (setq header-line-format (plist-get exwm--configurations - 'tiling-header-line)))) - ;; Only show X windows in normal state. - (unless (exwm-layout--iconic-state-p) - (pop-to-buffer-same-window buffer))) - (with-current-buffer (exwm--id->buffer id) - (run-hooks 'exwm-floating-exit-hook))) - -;;;###autoload -(cl-defun exwm-floating-toggle-floating () - "Toggle the current window between floating and non-floating states." - (interactive) - (exwm--log) - (unless (derived-mode-p 'exwm-mode) - (cl-return-from exwm-floating-toggle-floating)) - (with-current-buffer (window-buffer) - (if exwm--floating-frame - (exwm-floating--unset-floating exwm--id) - (exwm-floating--set-floating exwm--id)))) - -;;;###autoload -(defun exwm-floating-hide () - "Hide the current floating X window (which would show again when selected)." - (interactive) - (exwm--log) - (when (and (derived-mode-p 'exwm-mode) - exwm--floating-frame) - (exwm-layout--hide exwm--id) - (select-frame-set-input-focus exwm-workspace--current))) - -(defun exwm-floating--start-moveresize (id &optional type) - "Start move/resize." - (exwm--log "#x%x" id) - (let ((buffer-or-id (or (exwm--id->buffer id) id)) - frame container-or-id x y width height cursor) - (if (bufferp buffer-or-id) - ;; Managed. - (with-current-buffer buffer-or-id - (setq frame exwm--floating-frame - container-or-id (frame-parameter exwm--floating-frame - 'exwm-container))) - ;; Unmanaged. - (setq container-or-id id)) - (when (and container-or-id - ;; Test if the pointer can be grabbed - (= xcb:GrabStatus:Success - (slot-value - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GrabPointer - :owner-events 0 - :grab-window container-or-id - :event-mask xcb:EventMask:NoEvent - :pointer-mode xcb:GrabMode:Async - :keyboard-mode xcb:GrabMode:Async - :confine-to xcb:Window:None - :cursor xcb:Cursor:None - :time xcb:Time:CurrentTime)) - 'status))) - (with-slots (root-x root-y win-x win-y) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:QueryPointer :window id)) - (if (not (bufferp buffer-or-id)) - ;; Unmanaged. - (unless (eq type xcb:ewmh:_NET_WM_MOVERESIZE_MOVE) - (with-slots ((width* width) - (height* height)) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry :drawable id)) - (setq width width* - height height*))) - ;; Managed. - (select-window (frame-first-window frame)) ;transfer input focus - (setq width (frame-pixel-width frame) - height (frame-pixel-height frame)) - (unless type - ;; Determine the resize type according to the pointer position - ;; Clicking the center 1/3 part to resize has no effect - (setq x (/ (* 3 win-x) (float width)) - y (/ (* 3 win-y) (float height)) - type (cond ((and (< x 1) (< y 1)) - xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_TOPLEFT) - ((and (> x 2) (< y 1)) - xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_TOPRIGHT) - ((and (> x 2) (> y 2)) - xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT) - ((and (< x 1) (> y 2)) - xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT) - ((> x 2) xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_RIGHT) - ((> y 2) xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_BOTTOM) - ((< x 1) xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_LEFT) - ((< y 1) xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_TOP))))) - (if (not type) - (exwm-floating--stop-moveresize) - (cond ((= type xcb:ewmh:_NET_WM_MOVERESIZE_MOVE) - (setq cursor exwm-floating--cursor-move - exwm-floating--moveresize-calculate - (lambda (x y) - (vector buffer-or-id - (eval-when-compile - (logior xcb:ConfigWindow:X - xcb:ConfigWindow:Y)) - (- x win-x) (- y win-y) 0 0)))) - ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_TOPLEFT) - (setq cursor exwm-floating--cursor-top-left - exwm-floating--moveresize-calculate - (lambda (x y) - (vector buffer-or-id - (eval-when-compile - (logior xcb:ConfigWindow:X - xcb:ConfigWindow:Y - xcb:ConfigWindow:Width - xcb:ConfigWindow:Height)) - (- x win-x) (- y win-y) - (- (+ root-x width) x) - (- (+ root-y height) y))))) - ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_TOP) - (setq cursor exwm-floating--cursor-top - exwm-floating--moveresize-calculate - (lambda (_x y) - (vector buffer-or-id - (eval-when-compile - (logior xcb:ConfigWindow:Y - xcb:ConfigWindow:Height)) - 0 (- y win-y) 0 (- (+ root-y height) y))))) - ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_TOPRIGHT) - (setq cursor exwm-floating--cursor-top-right - exwm-floating--moveresize-calculate - (lambda (x y) - (vector buffer-or-id - (eval-when-compile - (logior xcb:ConfigWindow:Y - xcb:ConfigWindow:Width - xcb:ConfigWindow:Height)) - 0 (- y win-y) (- x (- root-x width)) - (- (+ root-y height) y))))) - ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_RIGHT) - (setq cursor exwm-floating--cursor-right - exwm-floating--moveresize-calculate - (lambda (x _y) - (vector buffer-or-id - xcb:ConfigWindow:Width - 0 0 (- x (- root-x width)) 0)))) - ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT) - (setq cursor exwm-floating--cursor-bottom-right - exwm-floating--moveresize-calculate - (lambda (x y) - (vector buffer-or-id - (eval-when-compile - (logior xcb:ConfigWindow:Width - xcb:ConfigWindow:Height)) - 0 0 (- x (- root-x width)) - (- y (- root-y height)))))) - ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_BOTTOM) - (setq cursor exwm-floating--cursor-bottom - exwm-floating--moveresize-calculate - (lambda (_x y) - (vector buffer-or-id - xcb:ConfigWindow:Height - 0 0 0 (- y (- root-y height)))))) - ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT) - (setq cursor exwm-floating--cursor-bottom-left - exwm-floating--moveresize-calculate - (lambda (x y) - (vector buffer-or-id - (eval-when-compile - (logior xcb:ConfigWindow:X - xcb:ConfigWindow:Width - xcb:ConfigWindow:Height)) - (- x win-x) - 0 - (- (+ root-x width) x) - (- y (- root-y height)))))) - ((= type xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_LEFT) - (setq cursor exwm-floating--cursor-left - exwm-floating--moveresize-calculate - (lambda (x _y) - (vector buffer-or-id - (eval-when-compile - (logior xcb:ConfigWindow:X - xcb:ConfigWindow:Width)) - (- x win-x) 0 (- (+ root-x width) x) 0))))) - ;; Select events and change cursor (should always succeed) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GrabPointer - :owner-events 0 :grab-window container-or-id - :event-mask (eval-when-compile - (logior xcb:EventMask:ButtonRelease - xcb:EventMask:ButtonMotion)) - :pointer-mode xcb:GrabMode:Async - :keyboard-mode xcb:GrabMode:Async - :confine-to xcb:Window:None - :cursor cursor - :time xcb:Time:CurrentTime))))))) - -(defun exwm-floating--stop-moveresize (&rest _args) - "Stop move/resize." - (exwm--log) - (xcb:+request exwm--connection - (make-instance 'xcb:UngrabPointer :time xcb:Time:CurrentTime)) - (when exwm-floating--moveresize-calculate - (let (result buffer-or-id outer-id container-id) - (setq result (funcall exwm-floating--moveresize-calculate 0 0) - buffer-or-id (aref result 0)) - (when (bufferp buffer-or-id) - (with-current-buffer buffer-or-id - (setq outer-id (frame-parameter exwm--floating-frame 'exwm-outer-id) - container-id (frame-parameter exwm--floating-frame - 'exwm-container)) - (with-slots (x y width height border-width) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry - :drawable container-id)) - ;; Notify Emacs frame about this the position change. - (xcb:+request exwm--connection - (make-instance 'xcb:SendEvent - :propagate 0 - :destination outer-id - :event-mask xcb:EventMask:StructureNotify - :event - (xcb:marshal - (make-instance 'xcb:ConfigureNotify - :event outer-id - :window outer-id - :above-sibling xcb:Window:None - :x (+ x border-width) - :y (+ y border-width) - :width width - :height height - :border-width 0 - :override-redirect 0) - exwm--connection))) - (xcb:flush exwm--connection)) - (exwm-layout--show exwm--id - (frame-root-window exwm--floating-frame))))) - (setq exwm-floating--moveresize-calculate nil))) - -(defun exwm-floating--do-moveresize (data _synthetic) - "Perform move/resize." - (when exwm-floating--moveresize-calculate - (let* ((obj (make-instance 'xcb:MotionNotify)) - result value-mask x y width height buffer-or-id container-or-id) - (xcb:unmarshal obj data) - (setq result (funcall exwm-floating--moveresize-calculate - (slot-value obj 'root-x) (slot-value obj 'root-y)) - buffer-or-id (aref result 0) - value-mask (aref result 1) - x (aref result 2) - y (aref result 3) - width (max 1 (aref result 4)) - height (max 1 (aref result 5))) - (if (not (bufferp buffer-or-id)) - ;; Unmanaged. - (setq container-or-id buffer-or-id) - ;; Managed. - (setq container-or-id - (with-current-buffer buffer-or-id - (frame-parameter exwm--floating-frame 'exwm-container)) - x (- x exwm-floating-border-width) - ;; Use `frame-outer-height' in the future. - y (- y exwm-floating-border-width - exwm-workspace--window-y-offset) - height (+ height exwm-workspace--window-y-offset))) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window container-or-id - :value-mask (aref result 1) - :x x - :y y - :width width - :height height)) - (when (bufferp buffer-or-id) - ;; Managed. - (setq value-mask (logand value-mask (logior xcb:ConfigWindow:Width - xcb:ConfigWindow:Height))) - (when (/= 0 value-mask) - (with-current-buffer buffer-or-id - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm--floating-frame - 'exwm-outer-id) - :value-mask value-mask - :width width - :height height))))) - (xcb:flush exwm--connection)))) - -(defun exwm-floating-move (&optional delta-x delta-y) - "Move a floating window right by DELTA-X pixels and down by DELTA-Y pixels. - -Both DELTA-X and DELTA-Y default to 1. This command should be bound locally." - (exwm--log "delta-x: %s, delta-y: %s" delta-x delta-y) - (unless (and (derived-mode-p 'exwm-mode) exwm--floating-frame) - (user-error "[EXWM] `exwm-floating-move' is only for floating X windows")) - (unless delta-x (setq delta-x 1)) - (unless delta-y (setq delta-y 1)) - (unless (and (= 0 delta-x) (= 0 delta-y)) - (let* ((floating-container (frame-parameter exwm--floating-frame - 'exwm-container)) - (geometry (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry - :drawable floating-container))) - (edges (window-inside-absolute-pixel-edges))) - (with-slots (x y) geometry - (exwm--set-geometry floating-container - (+ x delta-x) (+ y delta-y) nil nil)) - (exwm--set-geometry exwm--id - (+ (pop edges) delta-x) - (+ (pop edges) delta-y) - nil nil)) - (xcb:flush exwm--connection))) - -(defun exwm-floating--init () - "Initialize floating module." - (exwm--log) - ;; Initialize cursors for moving/resizing a window - (xcb:cursor:init exwm--connection) - (setq exwm-floating--cursor-move - (xcb:cursor:load-cursor exwm--connection "fleur") - exwm-floating--cursor-top-left - (xcb:cursor:load-cursor exwm--connection "top_left_corner") - exwm-floating--cursor-top - (xcb:cursor:load-cursor exwm--connection "top_side") - exwm-floating--cursor-top-right - (xcb:cursor:load-cursor exwm--connection "top_right_corner") - exwm-floating--cursor-right - (xcb:cursor:load-cursor exwm--connection "right_side") - exwm-floating--cursor-bottom-right - (xcb:cursor:load-cursor exwm--connection "bottom_right_corner") - exwm-floating--cursor-bottom - (xcb:cursor:load-cursor exwm--connection "bottom_side") - exwm-floating--cursor-bottom-left - (xcb:cursor:load-cursor exwm--connection "bottom_left_corner") - exwm-floating--cursor-left - (xcb:cursor:load-cursor exwm--connection "left_side"))) - -(defun exwm-floating--exit () - "Exit the floating module." - (exwm--log)) - - - -(provide 'exwm-floating) - -;;; exwm-floating.el ends here diff --git a/third_party/exwm/exwm-input.el b/third_party/exwm/exwm-input.el deleted file mode 100644 index eac0ef6a3..000000000 --- a/third_party/exwm/exwm-input.el +++ /dev/null @@ -1,1248 +0,0 @@ -;;; exwm-input.el --- Input Module for EXWM -*- lexical-binding: t -*- - -;; Copyright (C) 2015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module deals with key/mouse matters, including: -;; + Input focus, -;; + Key/Button event handling, -;; + Key events filtering and simulation. - -;; Todo: -;; + Pointer simulation mode (e.g. 'C-c 1'/'C-c 2' for single/double click, -;; move with arrow keys). -;; + Simulation keys to mimic Emacs key bindings for text edit (redo, select, -;; cancel, clear, etc). Some of them are not present on common keyboard -;; (keycode = 0). May need to use XKB extension. - -;;; Code: - -(require 'xcb-keysyms) -(require 'exwm-core) - -(defgroup exwm-input nil - "Input." - :group 'exwm) - -(defcustom exwm-input-prefix-keys - '(?\C-x ?\C-u ?\C-h ?\M-x ?\M-` ?\M-& ?\M-:) - "List of prefix keys EXWM should forward to Emacs when in `line-mode'. - -The point is to make keys like `C-x C-f' forwarded to Emacs in `line-mode'. -There is no need to add prefix keys for global/simulation keys or those -defined in `exwm-mode-map' here." - :type '(repeat key-sequence) - :get (lambda (symbol) - (mapcar #'vector (default-value symbol))) - :set (lambda (symbol value) - (set symbol (mapcar (lambda (i) - (if (sequencep i) - (aref i 0) - i)) - value)))) - -(defcustom exwm-input-move-event 's-down-mouse-1 - "Emacs event to start moving a window." - :type 'key-sequence - :get (lambda (symbol) - (let ((value (default-value symbol))) - (if (mouse-event-p value) - value - (vector value)))) - :set (lambda (symbol value) - (set symbol (if (sequencep value) - (aref value 0) - value)))) - -(defcustom exwm-input-resize-event 's-down-mouse-3 - "Emacs event to start resizing a window." - :type 'key-sequence - :get (lambda (symbol) - (let ((value (default-value symbol))) - (if (mouse-event-p value) - value - (vector value)))) - :set (lambda (symbol value) - (set symbol (if (sequencep value) - (aref value 0) - value)))) - -(defcustom exwm-input-line-mode-passthrough nil - "Non-nil makes `line-mode' forward all events to Emacs." - :type 'boolean) - -;; Input focus update requests should be accumulated for a short time -;; interval so that only the last one need to be processed. This not -;; improves the overall performance, but avoids the problem of input -;; focus loop, which is a result of the interaction with Emacs frames. -;; -;; FIXME: The time interval is hard to decide and perhaps machine-dependent. -;; A value too small can cause redundant updates of input focus, -;; and even worse, dead loops. OTOH a large value would bring -;; laggy experience. -(defconst exwm-input--update-focus-interval 0.01 - "Time interval (in seconds) for accumulating input focus update requests.") - -(defconst exwm-input--passthrough-functions '(read-char - read-char-exclusive - read-key-sequence-vector - read-key-sequence - read-event) - "Low-level read functions that must be exempted from EXWM input handling.") - -(defvar exwm-input--during-command nil - "Indicate whether between `pre-command-hook' and `post-command-hook'.") - -(defvar exwm-input--global-keys nil "Global key bindings.") - -(defvar exwm-input--global-prefix-keys nil - "List of prefix keys of global key bindings.") - -(defvar exwm-input--line-mode-cache nil "Cache for incomplete key sequence.") - -(defvar exwm-input--local-simulation-keys nil - "Whether simulation keys are local.") - -(defvar exwm-input--simulation-keys nil "Simulation keys in `line-mode'.") - -(defvar exwm-input--skip-buffer-list-update nil - "Skip the upcoming `buffer-list-update'.") - -(defvar exwm-input--temp-line-mode nil - "Non-nil indicates it's in temporary line-mode for `char-mode'.") - -(defvar exwm-input--timestamp-atom nil) - -(defvar exwm-input--timestamp-callback nil) - -(defvar exwm-input--timestamp-window nil) - -(defvar exwm-input--update-focus-timer nil - "Timer for deferring the update of input focus.") - -(defvar exwm-input--update-focus-lock nil - "Lock for solving input focus update contention.") - -(defvar exwm-input--update-focus-window nil "The (Emacs) window to be focused. -This value should always be overwritten.") - -(defvar exwm-input--echo-area-timer nil "Timer for detecting echo area dirty.") - -(defvar exwm-input--event-hook nil - "Hook to run when EXWM receives an event.") - -(defvar exwm-input-input-mode-change-hook nil - "Hook to run when an input mode changes on an `exwm-mode' buffer. -Current buffer will be the `exwm-mode' buffer when this hook runs.") - -(defvar exwm-workspace--current) -(declare-function exwm-floating--do-moveresize "exwm-floating.el" - (data _synthetic)) -(declare-function exwm-floating--start-moveresize "exwm-floating.el" - (id &optional type)) -(declare-function exwm-floating--stop-moveresize "exwm-floating.el" - (&rest _args)) -(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id)) -(declare-function exwm-layout--show "exwm-layout.el" (id &optional window)) -(declare-function exwm-reset "exwm.el" ()) -(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el") -(declare-function exwm-workspace--workspace-p "exwm-workspace.el" (workspace)) -(declare-function exwm-workspace-switch "exwm-workspace.el" - (frame-or-index &optional force)) - -(defun exwm-input--set-focus (id) - "Set input focus to window ID in a proper way." - (let ((from (slot-value (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetInputFocus)) - 'focus)) - tree) - (if (or (exwm--id->buffer from) - (eq from id)) - (exwm--log "#x%x => #x%x" (or from 0) (or id 0)) - ;; Attempt to find the top-level X window for a 'focus proxy'. - (unless (= from xcb:Window:None) - (setq tree (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:QueryTree - :window from))) - (when tree - (setq from (slot-value tree 'parent)))) - (exwm--log "#x%x (corrected) => #x%x" (or from 0) (or id 0))) - (when (and (exwm--id->buffer id) - ;; Avoid redundant input focus transfer. - (not (eq from id))) - (with-current-buffer (exwm--id->buffer id) - (exwm-input--update-timestamp - (lambda (timestamp id send-input-focus wm-take-focus) - (when send-input-focus - (xcb:+request exwm--connection - (make-instance 'xcb:SetInputFocus - :revert-to xcb:InputFocus:Parent - :focus id - :time timestamp))) - (when wm-take-focus - (let ((event (make-instance 'xcb:icccm:WM_TAKE_FOCUS - :window id - :time timestamp))) - (setq event (xcb:marshal event exwm--connection)) - (xcb:+request exwm--connection - (make-instance 'xcb:icccm:SendEvent - :destination id - :event event)))) - (exwm-input--set-active-window id) - (xcb:flush exwm--connection)) - id - (or exwm--hints-input - (not (memq xcb:Atom:WM_TAKE_FOCUS exwm--protocols))) - (memq xcb:Atom:WM_TAKE_FOCUS exwm--protocols)))))) - -(defun exwm-input--update-timestamp (callback &rest args) - "Fetch the latest timestamp from the server and feed it to CALLBACK. - -ARGS are additional arguments to CALLBACK." - (setq exwm-input--timestamp-callback (cons callback args)) - (exwm--log) - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeProperty - :mode xcb:PropMode:Replace - :window exwm-input--timestamp-window - :property exwm-input--timestamp-atom - :type xcb:Atom:CARDINAL - :format 32 - :data-len 0 - :data nil)) - (xcb:flush exwm--connection)) - -(defun exwm-input--on-PropertyNotify (data _synthetic) - "Handle PropertyNotify events." - (exwm--log) - (when exwm-input--timestamp-callback - (let ((obj (make-instance 'xcb:PropertyNotify))) - (xcb:unmarshal obj data) - (when (= exwm-input--timestamp-window - (slot-value obj 'window)) - (apply (car exwm-input--timestamp-callback) - (slot-value obj 'time) - (cdr exwm-input--timestamp-callback)) - (setq exwm-input--timestamp-callback nil))))) - -(defvar exwm-input--last-enter-notify-position nil) - -(defun exwm-input--on-EnterNotify (data _synthetic) - "Handle EnterNotify events." - (let ((evt (make-instance 'xcb:EnterNotify)) - buffer window frame frame-xid edges fake-evt) - (xcb:unmarshal evt data) - (with-slots (time root event root-x root-y event-x event-y state) evt - (setq buffer (exwm--id->buffer event) - window (get-buffer-window buffer t)) - (exwm--log "buffer=%s; window=%s" buffer window) - (when (and buffer window (not (eq window (selected-window))) - (not (equal exwm-input--last-enter-notify-position - (vector root-x root-y)))) - (setq frame (window-frame window) - frame-xid (frame-parameter frame 'exwm-id)) - (unless (eq frame exwm-workspace--current) - (if (exwm-workspace--workspace-p frame) - ;; The X window is on another workspace. - (exwm-workspace-switch frame) - (with-current-buffer buffer - (when (and (derived-mode-p 'exwm-mode) - (not (eq exwm--frame exwm-workspace--current))) - ;; The floating X window is on another workspace. - (exwm-workspace-switch exwm--frame))))) - ;; Send a fake MotionNotify event to Emacs. - (setq edges (window-inside-pixel-edges window) - fake-evt (make-instance 'xcb:MotionNotify - :detail 0 - :time time - :root root - :event frame-xid - :child xcb:Window:None - :root-x root-x - :root-y root-y - :event-x (+ event-x (elt edges 0)) - :event-y (+ event-y (elt edges 1)) - :state state - :same-screen 1)) - (xcb:+request exwm--connection - (make-instance 'xcb:SendEvent - :propagate 0 - :destination frame-xid - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal fake-evt exwm--connection))) - (xcb:flush exwm--connection)) - (setq exwm-input--last-enter-notify-position (vector root-x root-y))))) - -(defun exwm-input--on-keysyms-update () - (exwm--log) - (let ((exwm-input--global-prefix-keys nil)) - (exwm-input--update-global-prefix-keys))) - -(defun exwm-input--on-buffer-list-update () - "Run in `buffer-list-update-hook' to track input focus." - (when (and ; this hook is called incesantly; place cheap tests on top - (not exwm-input--skip-buffer-list-update) - (exwm--terminal-p) ; skip other terminals, e.g. TTY client frames - (not (frame-parameter nil 'no-accept-focus))) - (exwm--log "current-buffer=%S selected-window=%S" - (current-buffer) (selected-window)) - (redirect-frame-focus (selected-frame) nil) - (setq exwm-input--update-focus-window (selected-window)) - (exwm-input--update-focus-defer))) - -(defun exwm-input--update-focus-defer () - "Schedule a deferred update to input focus. -Instead of immediately focusing the current window, it defers the focus change -until the selected window stops changing (debouncing input focus updates)." - (when exwm-input--update-focus-timer - (cancel-timer exwm-input--update-focus-timer)) - (setq exwm-input--update-focus-timer - ;; Attempt to accumulate successive events close enough. - (run-with-timer exwm-input--update-focus-interval - nil - #'exwm-input--update-focus-commit))) - -(defun exwm-input--update-focus-commit () - "Attempt to update the window focus. -If we're currently updating the window focus, re-schedule a focus update -attempt later." - (if exwm-input--update-focus-lock - (exwm-input--update-focus-defer) - (let ((exwm-input--update-focus-lock t)) - (exwm-input--update-focus exwm-input--update-focus-window)))) - -(defun exwm-input--update-focus (window) - "Update input focus to WINDOW." - (when (window-live-p window) - (exwm--log "focus-window=%s focus-buffer=%s" window (window-buffer window)) - (with-current-buffer (window-buffer window) - (if (derived-mode-p 'exwm-mode) - (if (not (eq exwm--frame exwm-workspace--current)) - (progn - (set-frame-parameter exwm--frame 'exwm-selected-window window) - (exwm--defer 0 #'exwm-workspace-switch exwm--frame)) - (exwm--log "Set focus on #x%x" exwm--id) - (when exwm--floating-frame - ;; Adjust stacking orders of the floating X window. - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window exwm--id - :value-mask xcb:ConfigWindow:StackMode - :stack-mode xcb:StackMode:TopIf)) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm--floating-frame - 'exwm-container) - :value-mask (logior - xcb:ConfigWindow:Sibling - xcb:ConfigWindow:StackMode) - :sibling exwm--id - :stack-mode xcb:StackMode:Below)) - ;; This floating X window might be hide by `exwm-floating-hide'. - (when (exwm-layout--iconic-state-p) - (exwm-layout--show exwm--id window)) - (xcb:flush exwm--connection)) - (exwm-input--set-focus exwm--id)) - (when (eq (selected-window) window) - (exwm--log "Focus on %s" window) - (if (and (exwm-workspace--workspace-p (selected-frame)) - (not (eq (selected-frame) exwm-workspace--current))) - ;; The focus is on another workspace (e.g. it got clicked) - ;; so switch to it. - (progn - (exwm--log "Switching to %s's workspace %s (%s)" - window - (window-frame window) - (selected-frame)) - (set-frame-parameter (selected-frame) 'exwm-selected-window - window) - (exwm--defer 0 #'exwm-workspace-switch (selected-frame))) - ;; The focus is still on the current workspace. - (if (not (and (exwm-workspace--minibuffer-own-frame-p) - (minibufferp))) - (x-focus-frame (window-frame window)) - ;; X input focus should be set on the previously selected - ;; frame. - (x-focus-frame (window-frame (minibuffer-window)))) - (exwm-input--set-active-window) - (xcb:flush exwm--connection))))))) - -(defun exwm-input--set-active-window (&optional id) - "Set _NET_ACTIVE_WINDOW." - (exwm--log) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_ACTIVE_WINDOW - :window exwm--root - :data (or id xcb:Window:None)))) - -(defun exwm-input--on-ButtonPress (data _synthetic) - "Handle ButtonPress event." - (let ((obj (make-instance 'xcb:ButtonPress)) - (mode xcb:Allow:SyncPointer) - button-event window buffer frame fake-last-command) - (xcb:unmarshal obj data) - (exwm--log "major-mode=%s buffer=%s" - major-mode (buffer-name (current-buffer))) - (with-slots (detail event state) obj - (setq button-event (xcb:keysyms:keysym->event exwm--connection - detail state) - buffer (exwm--id->buffer event) - window (get-buffer-window buffer t)) - (cond ((and (eq button-event exwm-input-move-event) - buffer - ;; Either an undecorated or a floating X window. - (with-current-buffer buffer - (or (not (derived-mode-p 'exwm-mode)) - exwm--floating-frame))) - ;; Move - (exwm-floating--start-moveresize - event xcb:ewmh:_NET_WM_MOVERESIZE_MOVE)) - ((and (eq button-event exwm-input-resize-event) - buffer - (with-current-buffer buffer - (or (not (derived-mode-p 'exwm-mode)) - exwm--floating-frame))) - ;; Resize - (exwm-floating--start-moveresize event)) - (buffer - ;; Click to focus - (setq fake-last-command t) - (unless (eq window (selected-window)) - (setq frame (window-frame window)) - (unless (eq frame exwm-workspace--current) - (if (exwm-workspace--workspace-p frame) - ;; The X window is on another workspace - (exwm-workspace-switch frame) - (with-current-buffer buffer - (when (and (derived-mode-p 'exwm-mode) - (not (eq exwm--frame - exwm-workspace--current))) - ;; The floating X window is on another workspace - (exwm-workspace-switch exwm--frame))))) - ;; It has been reported that the `window' may have be deleted - (if (window-live-p window) - (select-window window) - (setq window (get-buffer-window buffer t)) - (when window (select-window window)))) - ;; Also process keybindings. - (with-current-buffer buffer - (when (derived-mode-p 'exwm-mode) - (cl-case exwm--input-mode - (line-mode - (setq mode (exwm-input--on-ButtonPress-line-mode - buffer button-event))) - (char-mode - (setq mode (exwm-input--on-ButtonPress-char-mode))))))) - (t - ;; Replay this event by default. - (setq fake-last-command t) - (setq mode xcb:Allow:ReplayPointer))) - (when fake-last-command - (if buffer - (with-current-buffer buffer - (exwm-input--fake-last-command)) - (exwm-input--fake-last-command)))) - (xcb:+request exwm--connection - (make-instance 'xcb:AllowEvents :mode mode :time xcb:Time:CurrentTime)) - (xcb:flush exwm--connection)) - (run-hooks 'exwm-input--event-hook)) - -(defun exwm-input--on-KeyPress (data _synthetic) - "Handle KeyPress event." - (with-current-buffer (window-buffer (selected-window)) - (let ((obj (make-instance 'xcb:KeyPress))) - (xcb:unmarshal obj data) - (exwm--log "major-mode=%s buffer=%s" - major-mode (buffer-name (current-buffer))) - (if (derived-mode-p 'exwm-mode) - (cl-case exwm--input-mode - (line-mode - (exwm-input--on-KeyPress-line-mode obj data)) - (char-mode - (exwm-input--on-KeyPress-char-mode obj data))) - (exwm-input--on-KeyPress-char-mode obj))) - (run-hooks 'exwm-input--event-hook))) - -(defun exwm-input--on-CreateNotify (data _synthetic) - "Handle CreateNotify events." - (exwm--log) - (let ((evt (make-instance 'xcb:CreateNotify))) - (xcb:unmarshal evt data) - (with-slots (window) evt - (exwm-input--grab-global-prefix-keys window)))) - -(defun exwm-input--update-global-prefix-keys () - "Update `exwm-input--global-prefix-keys'." - (exwm--log) - (when exwm--connection - (let ((original exwm-input--global-prefix-keys)) - (setq exwm-input--global-prefix-keys nil) - (dolist (i exwm-input--global-keys) - (cl-pushnew (elt i 0) exwm-input--global-prefix-keys)) - (unless (equal original exwm-input--global-prefix-keys) - (apply #'exwm-input--grab-global-prefix-keys - (slot-value (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:QueryTree - :window exwm--root)) - 'children)))))) - -(defun exwm-input--grab-global-prefix-keys (&rest xwins) - (exwm--log) - (let ((req (make-instance 'xcb:GrabKey - :owner-events 0 - :grab-window nil - :modifiers nil - :key nil - :pointer-mode xcb:GrabMode:Async - :keyboard-mode xcb:GrabMode:Async)) - keysyms keycode alt-modifier) - (dolist (k exwm-input--global-prefix-keys) - (setq keysyms (xcb:keysyms:event->keysyms exwm--connection k)) - (if (not keysyms) - (warn "Key unavailable: %s" (key-description (vector k))) - (setq keycode (xcb:keysyms:keysym->keycode exwm--connection - (caar keysyms))) - (exwm--log "Grabbing key=%s (keysyms=%s keycode=%s)" - (single-key-description k) keysyms keycode) - (dolist (keysym keysyms) - (setf (slot-value req 'modifiers) (cdr keysym) - (slot-value req 'key) keycode) - ;; Also grab this key with num-lock mask set. - (when (and (/= 0 xcb:keysyms:num-lock-mask) - (= 0 (logand (cdr keysym) xcb:keysyms:num-lock-mask))) - (setf alt-modifier (logior (cdr keysym) - xcb:keysyms:num-lock-mask))) - (dolist (xwin xwins) - (setf (slot-value req 'grab-window) xwin) - (xcb:+request exwm--connection req) - (when alt-modifier - (setf (slot-value req 'modifiers) alt-modifier) - (xcb:+request exwm--connection req)))))) - (xcb:flush exwm--connection))) - -(defun exwm-input--set-key (key command) - (exwm--log "key: %s, command: %s" key command) - (global-set-key key command) - (cl-pushnew key exwm-input--global-keys)) - -(defcustom exwm-input-global-keys nil - "Global keys. - -It is an alist of the form (key . command), meaning giving KEY (a key -sequence) a global binding as COMMAND. - -Notes: -* Setting the value directly (rather than customizing it) after EXWM - finishes initialization has no effect." - :type '(alist :key-type key-sequence :value-type function) - :set (lambda (symbol value) - (when (boundp symbol) - (dolist (i (symbol-value symbol)) - (global-unset-key (car i)))) - (set symbol value) - (setq exwm-input--global-keys nil) - (dolist (i value) - (exwm-input--set-key (car i) (cdr i))) - (when exwm--connection - (exwm-input--update-global-prefix-keys)))) - -;;;###autoload -(defun exwm-input-set-key (key command) - "Set a global key binding. - -The new key binding only takes effect in real time when this command is -called interactively, and is lost when this session ends unless it's -specifically saved in the Customize interface for `exwm-input-global-keys'. - -In configuration you should customize or set `exwm-input-global-keys' -instead." - (interactive "KSet key globally: \nCSet key %s to command: ") - (exwm--log) - (setq exwm-input-global-keys (append exwm-input-global-keys - (list (cons key command)))) - (exwm-input--set-key key command) - (when (called-interactively-p 'any) - (exwm-input--update-global-prefix-keys))) - -(defsubst exwm-input--unread-event (event) - (declare (indent defun)) - (setq unread-command-events - (append unread-command-events `((t . ,event))))) - -(defun exwm-input--mimic-read-event (event) - "Process EVENT as if it were returned by `read-event'." - (exwm--log) - (unless (eq 0 extra-keyboard-modifiers) - (setq event (event-convert-list (append (event-modifiers - extra-keyboard-modifiers) - event)))) - (when (characterp event) - (let ((event* (when keyboard-translate-table - (aref keyboard-translate-table event)))) - (when event* - (setq event event*)))) - event) - -(cl-defun exwm-input--translate (key) - (let (translation) - (dolist (map (list input-decode-map - local-function-key-map - key-translation-map)) - (setq translation (lookup-key map key)) - (if (functionp translation) - (cl-return-from exwm-input--translate (funcall translation nil)) - (when (vectorp translation) - (cl-return-from exwm-input--translate translation))))) - key) - -(defun exwm-input--cache-event (event &optional temp-line-mode) - "Cache EVENT." - (exwm--log "%s" event) - (setq exwm-input--line-mode-cache - (vconcat exwm-input--line-mode-cache (vector event))) - ;; Attempt to translate this key sequence. - (setq exwm-input--line-mode-cache - (exwm-input--translate exwm-input--line-mode-cache)) - ;; When the key sequence is complete (not a keymap). - ;; Note that `exwm-input--line-mode-cache' might get translated to nil, for - ;; example 'mouse--down-1-maybe-follows-link' does this. - (if (and exwm-input--line-mode-cache - (keymapp (key-binding exwm-input--line-mode-cache))) - ;; Grab keyboard temporarily to intercept the complete key sequence. - (when temp-line-mode - (setq exwm-input--temp-line-mode t) - (exwm-input--grab-keyboard)) - (setq exwm-input--line-mode-cache nil) - (when exwm-input--temp-line-mode - (setq exwm-input--temp-line-mode nil) - (exwm-input--release-keyboard)))) - -(defun exwm-input--event-passthrough-p (event) - "Whether EVENT should be passed to Emacs. -Current buffer must be an `exwm-mode' buffer." - (or exwm-input-line-mode-passthrough - exwm-input--during-command - ;; Forward the event when there is an incomplete key - ;; sequence or when the minibuffer is active. - exwm-input--line-mode-cache - (eq (active-minibuffer-window) (selected-window)) - ;; - (memq event exwm-input--global-prefix-keys) - (memq event exwm-input-prefix-keys) - (when overriding-terminal-local-map - (lookup-key overriding-terminal-local-map - (vector event))) - (lookup-key (current-local-map) (vector event)) - (gethash event exwm-input--simulation-keys))) - -(defun exwm-input--noop (&rest _args) - "A placeholder command." - (interactive)) - -(defun exwm-input--fake-last-command () - "Fool some packages into thinking there is a change in the buffer." - (setq last-command #'exwm-input--noop) - ;; The Emacs manual says: - ;; > Quitting is suppressed while running pre-command-hook and - ;; > post-command-hook. If an error happens while executing one of these - ;; > hooks, it does not terminate execution of the hook; instead the error is - ;; > silenced and the function in which the error occurred is removed from the - ;; > hook. - ;; We supress errors but neither continue execution nor we remove from the - ;; hook. - (condition-case err - (run-hooks 'pre-command-hook) - ((error) - (exwm--log "Error occurred while running pre-command-hook: %s" - (error-message-string err)) - (xcb-debug:backtrace))) - (condition-case err - (run-hooks 'post-command-hook) - ((error) - (exwm--log "Error occurred while running post-command-hook: %s" - (error-message-string err)) - (xcb-debug:backtrace)))) - -(defun exwm-input--on-KeyPress-line-mode (key-press raw-data) - "Parse X KeyPress event to Emacs key event and then feed the command loop." - (with-slots (detail state) key-press - (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state)) - event raw-event mode) - (exwm--log "%s" keysym) - (when (and (/= 0 (car keysym)) - (setq raw-event (xcb:keysyms:keysym->event - exwm--connection (car keysym) - (logand state (lognot (cdr keysym))))) - (setq event (exwm-input--mimic-read-event raw-event)) - (exwm-input--event-passthrough-p event)) - (setq mode xcb:Allow:AsyncKeyboard) - (exwm-input--cache-event event) - (exwm-input--unread-event raw-event)) - (unless mode - (if (= 0 (logand #x6000 state)) ;Check the 13~14 bits. - ;; Not an XKB state; just replay it. - (setq mode xcb:Allow:ReplayKeyboard) - ;; An XKB state; sent it with SendEvent. - ;; FIXME: Can this also be replayed? - ;; FIXME: KeyRelease events are lost. - (setq mode xcb:Allow:AsyncKeyboard) - (xcb:+request exwm--connection - (make-instance 'xcb:SendEvent - :propagate 0 - :destination (slot-value key-press 'event) - :event-mask xcb:EventMask:NoEvent - :event raw-data))) - (when event - (if (not defining-kbd-macro) - (exwm-input--fake-last-command) - ;; Make Emacs aware of this event when defining keyboard macros. - (set-transient-map `(keymap (t . ,#'exwm-input--noop))) - (exwm-input--unread-event event)))) - (xcb:+request exwm--connection - (make-instance 'xcb:AllowEvents - :mode mode - :time xcb:Time:CurrentTime)) - (xcb:flush exwm--connection)))) - -(defun exwm-input--on-KeyPress-char-mode (key-press &optional _raw-data) - "Handle KeyPress event in `char-mode'." - (with-slots (detail state) key-press - (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state)) - event raw-event) - (exwm--log "%s" keysym) - (when (and (/= 0 (car keysym)) - (setq raw-event (xcb:keysyms:keysym->event - exwm--connection (car keysym) - (logand state (lognot (cdr keysym))))) - (setq event (exwm-input--mimic-read-event raw-event))) - (if (not (derived-mode-p 'exwm-mode)) - (exwm-input--unread-event raw-event) - (exwm-input--cache-event event t) - (exwm-input--unread-event raw-event))))) - (xcb:+request exwm--connection - (make-instance 'xcb:AllowEvents - :mode xcb:Allow:AsyncKeyboard - :time xcb:Time:CurrentTime)) - (xcb:flush exwm--connection)) - -(defun exwm-input--on-ButtonPress-line-mode (buffer button-event) - "Handle button events in line mode. -BUFFER is the `exwm-mode' buffer the event was generated -on. BUTTON-EVENT is the X event converted into an Emacs event. - -The return value is used as event_mode to release the original -button event." - (with-current-buffer buffer - (let ((read-event (exwm-input--mimic-read-event button-event))) - (exwm--log "%s" read-event) - (if (and read-event - (exwm-input--event-passthrough-p read-event)) - ;; The event should be forwarded to emacs - (progn - (exwm-input--cache-event read-event) - (exwm-input--unread-event button-event) - xcb:Allow:SyncPointer) - ;; The event should be replayed - xcb:Allow:ReplayPointer)))) - -(defun exwm-input--on-ButtonPress-char-mode () - "Handle button events in `char-mode'. -The return value is used as event_mode to release the original -button event." - (exwm--log) - xcb:Allow:ReplayPointer) - -(defun exwm-input--update-mode-line (id) - "Update the propertized `mode-line-process' for window ID." - (exwm--log "#x%x" id) - (let (help-echo cmd mode) - (with-current-buffer (exwm--id->buffer id) - (cl-case exwm--input-mode - (line-mode - (setq mode "line" - help-echo "mouse-1: Switch to char-mode" - cmd (lambda () - (interactive) - (exwm-input-release-keyboard id)))) - (char-mode - (setq mode "char" - help-echo "mouse-1: Switch to line-mode" - cmd (lambda () - (interactive) - (exwm-input-grab-keyboard id))))) - (setq mode-line-process - `(": " - (:propertize ,mode - help-echo ,help-echo - mouse-face mode-line-highlight - local-map - (keymap - (mode-line - keymap - (down-mouse-1 . ,cmd)))))) - (force-mode-line-update)))) - -(defun exwm-input--grab-keyboard (&optional id) - "Grab all key events on window ID." - (unless id (setq id (exwm--buffer->id (window-buffer)))) - (when id - (exwm--log "id=#x%x" id) - (when (xcb:+request-checked+request-check exwm--connection - (make-instance 'xcb:GrabKey - :owner-events 0 - :grab-window id - :modifiers xcb:ModMask:Any - :key xcb:Grab:Any - :pointer-mode xcb:GrabMode:Async - :keyboard-mode xcb:GrabMode:Sync)) - (exwm--log "Failed to grab keyboard for #x%x" id)) - (let ((buffer (exwm--id->buffer id))) - (when buffer - (with-current-buffer buffer - (setq exwm--input-mode 'line-mode) - (run-hooks 'exwm-input-input-mode-change-hook)))))) - -(defun exwm-input--release-keyboard (&optional id) - "Ungrab all key events on window ID." - (unless id (setq id (exwm--buffer->id (window-buffer)))) - (when id - (exwm--log "id=#x%x" id) - (when (xcb:+request-checked+request-check exwm--connection - (make-instance 'xcb:UngrabKey - :key xcb:Grab:Any - :grab-window id - :modifiers xcb:ModMask:Any)) - (exwm--log "Failed to release keyboard for #x%x" id)) - (exwm-input--grab-global-prefix-keys id) - (let ((buffer (exwm--id->buffer id))) - (when buffer - (with-current-buffer buffer - (setq exwm--input-mode 'char-mode) - (run-hooks 'exwm-input-input-mode-change-hook)))))) - -;;;###autoload -(defun exwm-input-grab-keyboard (&optional id) - "Switch to `line-mode'." - (interactive (list (when (derived-mode-p 'exwm-mode) - (exwm--buffer->id (window-buffer))))) - (when id - (exwm--log "id=#x%x" id) - (setq exwm--selected-input-mode 'line-mode) - (exwm-input--grab-keyboard id) - (exwm-input--update-mode-line id))) - -;;;###autoload -(defun exwm-input-release-keyboard (&optional id) - "Switch to `char-mode`." - (interactive (list (when (derived-mode-p 'exwm-mode) - (exwm--buffer->id (window-buffer))))) - (when id - (exwm--log "id=#x%x" id) - (setq exwm--selected-input-mode 'char-mode) - (exwm-input--release-keyboard id) - (exwm-input--update-mode-line id))) - -;;;###autoload -(defun exwm-input-toggle-keyboard (&optional id) - "Toggle between `line-mode' and `char-mode'." - (interactive (list (when (derived-mode-p 'exwm-mode) - (exwm--buffer->id (window-buffer))))) - (when id - (exwm--log "id=#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (cl-case exwm--input-mode - (line-mode - (exwm-input-release-keyboard id)) - (char-mode - (exwm-reset)))))) - -(defun exwm-input--fake-key (event) - "Fake a key event equivalent to Emacs event EVENT." - (let* ((keysyms (xcb:keysyms:event->keysyms exwm--connection event)) - keycode id) - (when (= 0 (caar keysyms)) - (user-error "[EXWM] Invalid key: %s" (single-key-description event))) - (setq keycode (xcb:keysyms:keysym->keycode exwm--connection - (caar keysyms))) - (when (/= 0 keycode) - (setq id (exwm--buffer->id (window-buffer (selected-window)))) - (exwm--log "id=#x%x event=%s keycode" id event keycode) - (dolist (class '(xcb:KeyPress xcb:KeyRelease)) - (xcb:+request exwm--connection - (make-instance 'xcb:SendEvent - :propagate 0 :destination id - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal - (make-instance class - :detail keycode - :time xcb:Time:CurrentTime - :root exwm--root :event id - :child 0 - :root-x 0 :root-y 0 - :event-x 0 :event-y 0 - :state (cdar keysyms) - :same-screen 1) - exwm--connection))))) - (xcb:flush exwm--connection))) - -;;;###autoload -(cl-defun exwm-input-send-next-key (times &optional end-key) - "Send next key to client window. - -EXWM will prompt for the key to send. This command can be prefixed to send -multiple keys. If END-KEY is non-nil, stop sending keys if it's pressed." - (interactive "p") - (exwm--log) - (unless (derived-mode-p 'exwm-mode) - (cl-return-from exwm-input-send-next-key)) - (when (> times 12) (setq times 12)) - (let (key keys) - (dotimes (i times) - ;; Skip events not from keyboard - (let ((exwm-input-line-mode-passthrough t)) - (catch 'break - (while t - (setq key (read-key (format "Send key: %s (%d/%d) %s" - (key-description keys) - (1+ i) times - (if end-key - (concat "To exit, press: " - (key-description - (list end-key))) - "")))) - (unless (listp key) (throw 'break nil))))) - (setq keys (vconcat keys (vector key))) - (when (eq key end-key) (cl-return-from exwm-input-send-next-key)) - (exwm-input--fake-key key)))) - -(defun exwm-input--set-simulation-keys (simulation-keys &optional no-refresh) - "Set simulation keys." - (exwm--log "%s" simulation-keys) - (unless no-refresh - ;; Unbind simulation keys. - (let ((hash (buffer-local-value 'exwm-input--simulation-keys - (current-buffer)))) - (when (hash-table-p hash) - (maphash (lambda (key _value) - (when (sequencep key) - (if exwm-input--local-simulation-keys - (local-unset-key key) - (define-key exwm-mode-map key nil)))) - hash))) - ;; Abandon the old hash table. - (setq exwm-input--simulation-keys (make-hash-table :test #'equal))) - (dolist (i simulation-keys) - (let ((original (vconcat (car i))) - (simulated (cdr i))) - (setq simulated (if (sequencep simulated) - (append simulated nil) - (list simulated))) - ;; The key stored is a key sequence (vector). - ;; The value stored is a list of key events. - (puthash original simulated exwm-input--simulation-keys) - ;; Also mark the prefix key as used. - (puthash (aref original 0) t exwm-input--simulation-keys))) - ;; Update keymaps. - (maphash (lambda (key _value) - (when (sequencep key) - (if exwm-input--local-simulation-keys - (local-set-key key #'exwm-input-send-simulation-key) - (define-key exwm-mode-map key - #'exwm-input-send-simulation-key)))) - exwm-input--simulation-keys)) - -(defcustom exwm-input-simulation-keys nil - "Simulation keys. - -It is an alist of the form (original-key . simulated-key), where both -original-key and simulated-key are key sequences. Original-key is what you -type to an X window in `line-mode' which then gets translated to simulated-key -by EXWM and forwarded to the X window. - -Notes: -* Setting the value directly (rather than customizing it) after EXWM - finishes initialization has no effect. -* Original-keys consist of multiple key events are only supported in Emacs - 26.2 and later. -* A minority of applications do not accept simulated keys by default. It's - required to customize them to accept events sent by SendEvent. -* The predefined examples in the Customize interface are not guaranteed to - work for all applications. This can be tweaked on a per application basis - with `exwm-input-set-local-simulation-keys'." - :type '(alist :key-type (key-sequence :tag "Original") - :value-type (choice (key-sequence :tag "User-defined") - (key-sequence :tag "Move left" [left]) - (key-sequence :tag "Move right" [right]) - (key-sequence :tag "Move up" [up]) - (key-sequence :tag "Move down" [down]) - (key-sequence :tag "Move to BOL" [home]) - (key-sequence :tag "Move to EOL" [end]) - (key-sequence :tag "Page up" [prior]) - (key-sequence :tag "Page down" [next]) - (key-sequence :tag "Copy" [C-c]) - (key-sequence :tag "Paste" [C-v]) - (key-sequence :tag "Delete" [delete]) - (key-sequence :tag "Delete to EOL" - [S-end delete]))) - :set (lambda (symbol value) - (set symbol value) - (exwm-input--set-simulation-keys value))) - -(defcustom exwm-input-pre-post-command-blacklist '(exit-minibuffer - abort-recursive-edit - minibuffer-keyboard-quit) - "Commands impossible to detect with `post-command-hook'." - :type '(repeat function)) - -(cl-defun exwm-input--read-keys (prompt stop-key) - (let ((cursor-in-echo-area t) - keys key) - (while (not (eq key stop-key)) - (setq key (read-key (format "%s (terminate with %s): %s" - prompt - (key-description (vector stop-key)) - (key-description keys))) - keys (vconcat keys (vector key)))) - (when (> (length keys) 1) - (substring keys 0 -1)))) - -;;;###autoload -(defun exwm-input-set-simulation-key (original-key simulated-key) - "Set a simulation key. - -The simulation key takes effect in real time, but is lost when this session -ends unless it's specifically saved in the Customize interface for -`exwm-input-simulation-keys'." - (interactive - (let (original simulated) - (setq original (exwm-input--read-keys "Translate from" ?\C-g)) - (when original - (setq simulated (exwm-input--read-keys - (format "Translate from %s to" - (key-description original)) - ?\C-g))) - (list original simulated))) - (exwm--log "original: %s, simulated: %s" original-key simulated-key) - (when (and original-key simulated-key) - (let ((entry `((,original-key . ,simulated-key)))) - (setq exwm-input-simulation-keys (append exwm-input-simulation-keys - entry)) - (exwm-input--set-simulation-keys entry t)))) - -(defun exwm-input--unset-simulation-keys () - "Clear simulation keys and key bindings defined." - (exwm--log) - (when (hash-table-p exwm-input--simulation-keys) - (maphash (lambda (key _value) - (when (sequencep key) - (define-key exwm-mode-map key nil))) - exwm-input--simulation-keys) - (clrhash exwm-input--simulation-keys))) - -(defun exwm-input-set-local-simulation-keys (simulation-keys) - "Set buffer-local simulation keys. - -SIMULATION-KEYS is an alist of the form (original-key . simulated-key), -where both ORIGINAL-KEY and SIMULATED-KEY are key sequences." - (exwm--log) - (make-local-variable 'exwm-input--simulation-keys) - (use-local-map (copy-keymap exwm-mode-map)) - (let ((exwm-input--local-simulation-keys t)) - (exwm-input--set-simulation-keys simulation-keys))) - -;;;###autoload -(cl-defun exwm-input-send-simulation-key (times) - "Fake a key event according to the last input key sequence." - (interactive "p") - (exwm--log) - (unless (derived-mode-p 'exwm-mode) - (cl-return-from exwm-input-send-simulation-key)) - (let ((keys (gethash (this-single-command-keys) - exwm-input--simulation-keys))) - (dotimes (_ times) - (dolist (key keys) - (exwm-input--fake-key key))))) - -;;;###autoload -(defmacro exwm-input-invoke-factory (keys) - "Make a command that invokes KEYS when called. - -One use is to access the keymap bound to KEYS (as prefix keys) in `char-mode'." - (let* ((keys (kbd keys)) - (description (key-description keys))) - `(defun ,(intern (concat "exwm-input--invoke--" description)) () - ,(format "Invoke `%s'." description) - (interactive) - (mapc (lambda (key) - (exwm-input--cache-event key t) - (exwm-input--unread-event key)) - ',(listify-key-sequence keys))))) - -(defun exwm-input--on-pre-command () - "Run in `pre-command-hook'." - (unless (or (eq this-command #'exwm-input--noop) - (memq this-command exwm-input-pre-post-command-blacklist)) - (setq exwm-input--during-command t))) - -(defun exwm-input--on-post-command () - "Run in `post-command-hook'." - (unless (eq this-command #'exwm-input--noop) - (setq exwm-input--during-command nil))) - -(defun exwm-input--on-minibuffer-setup () - "Run in `minibuffer-setup-hook' to grab keyboard if necessary." - (let* ((window (or (minibuffer-selected-window) ; minibuffer-setup-hook - (selected-window))) ; echo-area-clear-hook - (frame (window-frame window))) - (when (exwm--terminal-p frame) - (with-current-buffer (window-buffer window) - (when (and (derived-mode-p 'exwm-mode) - (eq exwm--selected-input-mode 'char-mode)) - (exwm--log "Grab #x%x window=%s frame=%s" exwm--id window frame) - (exwm-input--grab-keyboard exwm--id)))))) - -(defun exwm-input--on-minibuffer-exit () - "Run in `minibuffer-exit-hook' to release keyboard if necessary." - (let* ((window (or (minibuffer-selected-window) ; minibuffer-setup-hook - (selected-window))) ; echo-area-clear-hook - (frame (window-frame window))) - (when (exwm--terminal-p frame) - (with-current-buffer (window-buffer window) - (when (and (derived-mode-p 'exwm-mode) - (eq exwm--selected-input-mode 'char-mode) - (eq exwm--input-mode 'line-mode)) - (exwm--log "Release #x%x window=%s frame=%s" exwm--id window frame) - (exwm-input--release-keyboard exwm--id)))))) - -(defun exwm-input--on-echo-area-dirty () - "Run when new message arrives to grab keyboard if necessary." - (when (and cursor-in-echo-area - (not (active-minibuffer-window))) - (exwm--log) - (exwm-input--on-minibuffer-setup))) - -(defun exwm-input--on-echo-area-clear () - "Run in `echo-area-clear-hook' to release keyboard if necessary." - (unless (current-message) - (exwm--log) - (exwm-input--on-minibuffer-exit))) - -(defun exwm-input--call-with-passthrough (function &rest args) - "Bind `exwm-input-line-mode-passthrough' and call FUNCTION with ARGS." - (let ((exwm-input-line-mode-passthrough t)) - (apply function args))) - -(defun exwm-input--init () - "Initialize the keyboard module." - (exwm--log) - ;; Refresh keyboard mapping - (xcb:keysyms:init exwm--connection #'exwm-input--on-keysyms-update) - ;; Create the X window and intern the atom used to fetch timestamp. - (setq exwm-input--timestamp-window (xcb:generate-id exwm--connection)) - (xcb:+request exwm--connection - (make-instance 'xcb:CreateWindow - :depth 0 - :wid exwm-input--timestamp-window - :parent exwm--root - :x -1 - :y -1 - :width 1 - :height 1 - :border-width 0 - :class xcb:WindowClass:CopyFromParent - :visual 0 - :value-mask xcb:CW:EventMask - :event-mask xcb:EventMask:PropertyChange)) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window exwm-input--timestamp-window - :data "EXWM: exwm-input--timestamp-window")) - (setq exwm-input--timestamp-atom (exwm--intern-atom "_TIME")) - ;; Initialize global keys. - (dolist (i exwm-input-global-keys) - (exwm-input--set-key (car i) (cdr i))) - ;; Initialize simulation keys. - (when exwm-input-simulation-keys - (exwm-input--set-simulation-keys exwm-input-simulation-keys)) - ;; Attach event listeners - (xcb:+event exwm--connection 'xcb:PropertyNotify - #'exwm-input--on-PropertyNotify) - (xcb:+event exwm--connection 'xcb:CreateNotify #'exwm-input--on-CreateNotify) - (xcb:+event exwm--connection 'xcb:KeyPress #'exwm-input--on-KeyPress) - (xcb:+event exwm--connection 'xcb:ButtonPress #'exwm-input--on-ButtonPress) - (xcb:+event exwm--connection 'xcb:ButtonRelease - #'exwm-floating--stop-moveresize) - (xcb:+event exwm--connection 'xcb:MotionNotify - #'exwm-floating--do-moveresize) - (when mouse-autoselect-window - (xcb:+event exwm--connection 'xcb:EnterNotify - #'exwm-input--on-EnterNotify)) - ;; Control `exwm-input--during-command' - (add-hook 'pre-command-hook #'exwm-input--on-pre-command) - (add-hook 'post-command-hook #'exwm-input--on-post-command) - ;; Grab/Release keyboard when minibuffer/echo becomes active/inactive. - (add-hook 'minibuffer-setup-hook #'exwm-input--on-minibuffer-setup) - (add-hook 'minibuffer-exit-hook #'exwm-input--on-minibuffer-exit) - (setq exwm-input--echo-area-timer - (run-with-idle-timer 0 t #'exwm-input--on-echo-area-dirty)) - (add-hook 'echo-area-clear-hook #'exwm-input--on-echo-area-clear) - ;; Update focus when buffer list updates - (add-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update) - - (dolist (fun exwm-input--passthrough-functions) - (advice-add fun :around #'exwm-input--call-with-passthrough))) - -(defun exwm-input--post-init () - "The second stage in the initialization of the input module." - (exwm--log) - (exwm-input--update-global-prefix-keys)) - -(defun exwm-input--exit () - "Exit the input module." - (exwm--log) - (dolist (fun exwm-input--passthrough-functions) - (advice-remove fun #'exwm-input--call-with-passthrough)) - (exwm-input--unset-simulation-keys) - (remove-hook 'pre-command-hook #'exwm-input--on-pre-command) - (remove-hook 'post-command-hook #'exwm-input--on-post-command) - (remove-hook 'minibuffer-setup-hook #'exwm-input--on-minibuffer-setup) - (remove-hook 'minibuffer-exit-hook #'exwm-input--on-minibuffer-exit) - (when exwm-input--echo-area-timer - (cancel-timer exwm-input--echo-area-timer) - (setq exwm-input--echo-area-timer nil)) - (remove-hook 'echo-area-clear-hook #'exwm-input--on-echo-area-clear) - (remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update) - (when exwm-input--update-focus-timer - (cancel-timer exwm-input--update-focus-timer)) - ;; Make input focus working even without a WM. - (when (slot-value exwm--connection 'connected) - (xcb:+request exwm--connection - (make-instance 'xcb:SetInputFocus - :revert-to xcb:InputFocus:PointerRoot - :focus exwm--root - :time xcb:Time:CurrentTime)) - (xcb:flush exwm--connection))) - - - -(provide 'exwm-input) - -;;; exwm-input.el ends here diff --git a/third_party/exwm/exwm-layout.el b/third_party/exwm/exwm-layout.el deleted file mode 100644 index 83421b2e9..000000000 --- a/third_party/exwm/exwm-layout.el +++ /dev/null @@ -1,628 +0,0 @@ -;;; exwm-layout.el --- Layout Module for EXWM -*- lexical-binding: t -*- - -;; Copyright (C) 2015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module is responsible for keeping X client window properly displayed. - -;;; Code: - -(require 'exwm-core) - -(defgroup exwm-layout nil - "Layout." - :group 'exwm) - -(defcustom exwm-layout-auto-iconify t - "Non-nil to automatically iconify unused X windows when possible." - :type 'boolean) - -(defcustom exwm-layout-show-all-buffers nil - "Non-nil to allow switching to buffers on other workspaces." - :type 'boolean) - -(defconst exwm-layout--floating-hidden-position -101 - "Where to place hidden floating X windows.") - -(defvar exwm-layout--other-buffer-exclude-buffers nil - "List of buffers that should not be selected by `other-buffer'.") - -(defvar exwm-layout--other-buffer-exclude-exwm-mode-buffers nil - "When non-nil, prevent EXWM buffers from being selected by `other-buffer'.") - -(defvar exwm-layout--timer nil "Timer used to track echo area changes.") - -(defvar exwm-workspace--current) -(defvar exwm-workspace--frame-y-offset) -(declare-function exwm-input--release-keyboard "exwm-input.el") -(declare-function exwm-input--grab-keyboard "exwm-input.el") -(declare-function exwm-input-grab-keyboard "exwm-input.el") -(declare-function exwm-workspace--active-p "exwm-workspace.el" (frame)) -(declare-function exwm-workspace--get-geometry "exwm-workspace.el" (frame)) -(declare-function exwm-workspace--minibuffer-own-frame-p "exwm-workspace.el") -(declare-function exwm-workspace--workspace-p "exwm-workspace.el" - (workspace)) -(declare-function exwm-workspace-move-window "exwm-workspace.el" - (frame-or-index &optional id)) - -(defun exwm-layout--set-state (id state) - "Set WM_STATE of X window ID to STATE." - (exwm--log "id=#x%x" id) - (xcb:+request exwm--connection - (make-instance 'xcb:icccm:set-WM_STATE - :window id :state state :icon xcb:Window:None)) - (with-current-buffer (exwm--id->buffer id) - (setq exwm-state state))) - -(defun exwm-layout--iconic-state-p (&optional id) - "Check whether X window ID is in iconic state." - (= xcb:icccm:WM_STATE:IconicState - (if id - (buffer-local-value 'exwm-state (exwm--id->buffer id)) - exwm-state))) - -(defun exwm-layout--set-ewmh-state (id) - "Set _NET_WM_STATE of X window ID to the value of variable `exwm--ewmh-state'." - (with-current-buffer (exwm--id->buffer id) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_STATE - :window exwm--id - :data exwm--ewmh-state)))) - -(defun exwm-layout--fullscreen-p () - "Check whether current `exwm-mode' buffer is in fullscreen state." - (when (derived-mode-p 'exwm-mode) - (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state))) - -(defun exwm-layout--auto-iconify () - "Helper function to iconify unused X windows. -See variable `exwm-layout-auto-iconify'." - (when (and exwm-layout-auto-iconify - (not exwm-transient-for)) - (let ((xwin exwm--id) - (state exwm-state)) - (dolist (pair exwm--id-buffer-alist) - (with-current-buffer (cdr pair) - (when (and exwm--floating-frame - (eq exwm-transient-for xwin) - (not (eq exwm-state state))) - (if (eq state xcb:icccm:WM_STATE:NormalState) - (exwm-layout--refresh-floating exwm--floating-frame) - (exwm-layout--hide exwm--id)))))))) - -(defun exwm-layout--show (id &optional window) - "Show window ID exactly fit in the Emacs window WINDOW." - (exwm--log "Show #x%x in %s" id window) - (let* ((edges (window-inside-absolute-pixel-edges window)) - (x (pop edges)) - (y (pop edges)) - (width (- (pop edges) x)) - (height (- (pop edges) y)) - frame-x frame-y frame-width frame-height) - (with-current-buffer (exwm--id->buffer id) - (when exwm--floating-frame - (setq frame-width (frame-pixel-width exwm--floating-frame) - frame-height (+ (frame-pixel-height exwm--floating-frame) - ;; Use `frame-outer-height' in the future. - exwm-workspace--frame-y-offset)) - (when exwm--floating-frame-position - (setq frame-x (elt exwm--floating-frame-position 0) - frame-y (elt exwm--floating-frame-position 1) - x (+ x frame-x (- exwm-layout--floating-hidden-position)) - y (+ y frame-y (- exwm-layout--floating-hidden-position))) - (setq exwm--floating-frame-position nil)) - (exwm--set-geometry (frame-parameter exwm--floating-frame - 'exwm-container) - frame-x frame-y frame-width frame-height)) - (when (exwm-layout--fullscreen-p) - (with-slots ((x* x) - (y* y) - (width* width) - (height* height)) - (exwm-workspace--get-geometry exwm--frame) - (setq x x* - y y* - width width* - height height*))) - (exwm--set-geometry id x y width height) - (xcb:+request exwm--connection (make-instance 'xcb:MapWindow :window id)) - (exwm-layout--set-state id xcb:icccm:WM_STATE:NormalState) - (setq exwm--ewmh-state - (delq xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state)) - (exwm-layout--set-ewmh-state id) - (exwm-layout--auto-iconify))) - (xcb:flush exwm--connection)) - -(defun exwm-layout--hide (id) - "Hide window ID." - (with-current-buffer (exwm--id->buffer id) - (unless (or (exwm-layout--iconic-state-p) - (and exwm--floating-frame - exwm--desktop - (= 4294967295. exwm--desktop))) - (exwm--log "Hide #x%x" id) - (when exwm--floating-frame - (let* ((container (frame-parameter exwm--floating-frame - 'exwm-container)) - (geometry (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry - :drawable container)))) - (setq exwm--floating-frame-position - (vector (slot-value geometry 'x) (slot-value geometry 'y))) - (exwm--set-geometry container exwm-layout--floating-hidden-position - exwm-layout--floating-hidden-position - 1 - 1))) - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window id :value-mask xcb:CW:EventMask - :event-mask xcb:EventMask:NoEvent)) - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow :window id)) - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window id :value-mask xcb:CW:EventMask - :event-mask (exwm--get-client-event-mask))) - (exwm-layout--set-state id xcb:icccm:WM_STATE:IconicState) - (cl-pushnew xcb:Atom:_NET_WM_STATE_HIDDEN exwm--ewmh-state) - (exwm-layout--set-ewmh-state id) - (exwm-layout--auto-iconify) - (xcb:flush exwm--connection)))) - -;;;###autoload -(cl-defun exwm-layout-set-fullscreen (&optional id) - "Make window ID fullscreen." - (interactive) - (exwm--log "id=#x%x" (or id 0)) - (unless (and (or id (derived-mode-p 'exwm-mode)) - (not (exwm-layout--fullscreen-p))) - (cl-return-from exwm-layout-set-fullscreen)) - (with-current-buffer (if id (exwm--id->buffer id) (window-buffer)) - ;; Expand the X window to fill the whole screen. - (with-slots (x y width height) (exwm-workspace--get-geometry exwm--frame) - (exwm--set-geometry exwm--id x y width height)) - ;; Raise the X window. - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window exwm--id - :value-mask (logior xcb:ConfigWindow:BorderWidth - xcb:ConfigWindow:StackMode) - :border-width 0 - :stack-mode xcb:StackMode:Above)) - (cl-pushnew xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state) - (exwm-layout--set-ewmh-state exwm--id) - (xcb:flush exwm--connection) - (set-window-dedicated-p (get-buffer-window) t) - (exwm-input--release-keyboard exwm--id))) - -;;;###autoload -(cl-defun exwm-layout-unset-fullscreen (&optional id) - "Restore X window ID from fullscreen state." - (interactive) - (exwm--log "id=#x%x" (or id 0)) - (unless (and (or id (derived-mode-p 'exwm-mode)) - (exwm-layout--fullscreen-p)) - (cl-return-from exwm-layout-unset-fullscreen)) - (with-current-buffer (if id (exwm--id->buffer id) (window-buffer)) - ;; `exwm-layout--show' relies on `exwm--ewmh-state' to decide whether to - ;; fullscreen the window. - (setq exwm--ewmh-state - (delq xcb:Atom:_NET_WM_STATE_FULLSCREEN exwm--ewmh-state)) - (exwm-layout--set-ewmh-state exwm--id) - (if exwm--floating-frame - (exwm-layout--show exwm--id (frame-root-window exwm--floating-frame)) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window exwm--id - :value-mask (logior xcb:ConfigWindow:Sibling - xcb:ConfigWindow:StackMode) - :sibling exwm--guide-window - :stack-mode xcb:StackMode:Above)) - (let ((window (get-buffer-window nil t))) - (when window - (exwm-layout--show exwm--id window)))) - (xcb:flush exwm--connection) - (set-window-dedicated-p (get-buffer-window) nil) - (when (eq 'line-mode exwm--selected-input-mode) - (exwm-input--grab-keyboard exwm--id)))) - -;;;###autoload -(cl-defun exwm-layout-toggle-fullscreen (&optional id) - "Toggle fullscreen mode of X window ID." - (interactive (list (exwm--buffer->id (window-buffer)))) - (exwm--log "id=#x%x" (or id 0)) - (unless (or id (derived-mode-p 'exwm-mode)) - (cl-return-from exwm-layout-toggle-fullscreen)) - (when id - (with-current-buffer (exwm--id->buffer id) - (if (exwm-layout--fullscreen-p) - (exwm-layout-unset-fullscreen id) - (exwm-layout-set-fullscreen id))))) - -(defun exwm-layout--other-buffer-predicate (buffer) - "Return non-nil when the BUFFER may be displayed in selected frame. - -Prevents EXWM-mode buffers already being displayed on some other window from -being selected. - -Should be set as `buffer-predicate' frame parameter for all -frames. Used by `other-buffer'. - -When variable `exwm-layout--other-buffer-exclude-exwm-mode-buffers' -is t EXWM buffers are never selected by `other-buffer'. - -When variable `exwm-layout--other-buffer-exclude-buffers' is a -list of buffers, EXWM buffers belonging to that list are never -selected by `other-buffer'." - (or (not (with-current-buffer buffer (derived-mode-p 'exwm-mode))) - (and (not exwm-layout--other-buffer-exclude-exwm-mode-buffers) - (not (memq buffer exwm-layout--other-buffer-exclude-buffers)) - ;; Do not select if already shown in some window. - (not (get-buffer-window buffer t))))) - -(defun exwm-layout--set-client-list-stacking () - "Set _NET_CLIENT_LIST_STACKING." - (exwm--log) - (let (id clients-floating clients clients-iconic clients-other) - (dolist (pair exwm--id-buffer-alist) - (setq id (car pair)) - (with-current-buffer (cdr pair) - (if (eq exwm--frame exwm-workspace--current) - (if exwm--floating-frame - ;; A floating X window on the current workspace. - (setq clients-floating (cons id clients-floating)) - (if (get-buffer-window (cdr pair) exwm-workspace--current) - ;; A normal tilling X window on the current workspace. - (setq clients (cons id clients)) - ;; An iconic tilling X window on the current workspace. - (setq clients-iconic (cons id clients-iconic)))) - ;; X window on other workspaces. - (setq clients-other (cons id clients-other))))) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_CLIENT_LIST_STACKING - :window exwm--root - :data (vconcat (append clients-other clients-iconic - clients clients-floating)))))) - -(defun exwm-layout--refresh (&optional frame) - "Refresh layout of FRAME. -If FRAME is nil, refresh layout of selected frame." - ;; `window-size-change-functions' sets this argument while - ;; `window-configuration-change-hook' makes the frame selected. - (unless frame - (setq frame (selected-frame))) - (exwm--log "frame=%s" frame) - (if (not (exwm-workspace--workspace-p frame)) - (if (frame-parameter frame 'exwm-outer-id) - (exwm-layout--refresh-floating frame) - (exwm-layout--refresh-other frame)) - (exwm-layout--refresh-workspace frame))) - -(defun exwm-layout--refresh-floating (frame) - "Refresh floating frame FRAME." - (exwm--log "Refresh floating %s" frame) - (let ((window (frame-first-window frame))) - (with-current-buffer (window-buffer window) - (when (and (derived-mode-p 'exwm-mode) - ;; It may be a buffer waiting to be killed. - (exwm--id->buffer exwm--id)) - (exwm--log "Refresh floating window #x%x" exwm--id) - (if (exwm-workspace--active-p exwm--frame) - (exwm-layout--show exwm--id window) - (exwm-layout--hide exwm--id)))))) - -(defun exwm-layout--refresh-other (frame) - "Refresh client or nox frame FRAME." - ;; Other frames (e.g. terminal/graphical frame of emacsclient) - ;; We shall bury all `exwm-mode' buffers in this case - (exwm--log "Refresh other %s" frame) - (let ((windows (window-list frame 'nomini)) ;exclude minibuffer - (exwm-layout--other-buffer-exclude-exwm-mode-buffers t)) - (dolist (window windows) - (with-current-buffer (window-buffer window) - (when (derived-mode-p 'exwm-mode) - (if (window-prev-buffers window) - (switch-to-prev-buffer window) - (switch-to-next-buffer window))))))) - -(defun exwm-layout--refresh-workspace (frame) - "Refresh workspace frame FRAME." - (exwm--log "Refresh workspace %s" frame) - ;; Workspaces other than the active one can also be refreshed (RandR) - (let (covered-buffers ;EXWM-buffers covered by a new X window. - vacated-windows) ;Windows previously displaying EXWM-buffers. - (dolist (pair exwm--id-buffer-alist) - (with-current-buffer (cdr pair) - (when (and (not exwm--floating-frame) ;exclude floating X windows - (or exwm-layout-show-all-buffers - ;; Exclude X windows on other workspaces - (eq frame exwm--frame))) - (let (;; List of windows in current frame displaying the `exwm-mode' - ;; buffers. - (windows (get-buffer-window-list (current-buffer) 'nomini - frame))) - (if (not windows) - (when (eq frame exwm--frame) - ;; Hide it if it was being shown in this workspace. - (exwm-layout--hide exwm--id)) - (let ((window (car windows))) - (if (eq frame exwm--frame) - ;; Show it if `frame' is active, hide otherwise. - (if (exwm-workspace--active-p frame) - (exwm-layout--show exwm--id window) - (exwm-layout--hide exwm--id)) - ;; It was last shown in other workspace; move it here. - (exwm-workspace-move-window frame exwm--id)) - ;; Vacate any other windows (in any workspace) showing this - ;; `exwm-mode' buffer. - (setq vacated-windows - (append vacated-windows (remove - window - (get-buffer-window-list - (current-buffer) 'nomini t)))) - ;; Note any `exwm-mode' buffer is being covered by another - ;; `exwm-mode' buffer. We want to avoid that `exwm-mode' - ;; buffer to be reappear in any of the vacated windows. - (let ((prev-buffer (car-safe - (car-safe (window-prev-buffers window))))) - (and - prev-buffer - (with-current-buffer prev-buffer - (derived-mode-p 'exwm-mode)) - (push prev-buffer covered-buffers))))))))) - ;; Set some sensible buffer to vacated windows. - (let ((exwm-layout--other-buffer-exclude-buffers covered-buffers)) - (dolist (window vacated-windows) - (if (window-prev-buffers window) - (switch-to-prev-buffer window) - (switch-to-next-buffer window)))) - ;; Make sure windows floating / on other workspaces are excluded - (let ((exwm-layout--other-buffer-exclude-exwm-mode-buffers t)) - (dolist (window (window-list frame 'nomini)) - (with-current-buffer (window-buffer window) - (when (and (derived-mode-p 'exwm-mode) - (or exwm--floating-frame (not (eq frame exwm--frame)))) - (if (window-prev-buffers window) - (switch-to-prev-buffer window) - (switch-to-next-buffer window)))))) - (exwm-layout--set-client-list-stacking) - (xcb:flush exwm--connection))) - -(defun exwm-layout--on-minibuffer-setup () - "Refresh layout when minibuffer grows." - (exwm--log) - ;; Only when active minibuffer's frame is an EXWM frame. - (let* ((mini-window (active-minibuffer-window)) - (frame (window-frame mini-window))) - (when (exwm-workspace--workspace-p frame) - (exwm--defer 0 (lambda () - (when (< 1 (window-height mini-window)) - (exwm-layout--refresh frame))))))) - -(defun exwm-layout--on-echo-area-change (&optional dirty) - "Run when message arrives or in `echo-area-clear-hook' to refresh layout. -If DIRTY is non-nil, refresh layout immediately." - (let ((frame (window-frame (active-minibuffer-window))) - (msg (current-message))) - ;; Check whether the frame where current window's minibuffer resides (not - ;; current window's frame for floating windows!) must be adjusted. - (when (and msg - (exwm-workspace--workspace-p frame) - (or (cl-position ?\n msg) - (> (length msg) (frame-width frame)))) - (exwm--log) - (if dirty - (exwm-layout--refresh exwm-workspace--current) - (exwm--defer 0 #'exwm-layout--refresh exwm-workspace--current))))) - -;;;###autoload -(defun exwm-layout-enlarge-window (delta &optional horizontal) - "Make the selected window DELTA pixels taller. - -If no argument is given, make the selected window one pixel taller. If the -optional argument HORIZONTAL is non-nil, make selected window DELTA pixels -wider. If DELTA is negative, shrink selected window by -DELTA pixels. - -Normal hints are checked and regarded if the selected window is displaying an -`exwm-mode' buffer. However, this may violate the normal hints set on other X -windows." - (interactive "p") - (exwm--log) - (cond - ((zerop delta)) ;no operation - ((window-minibuffer-p)) ;avoid resize minibuffer-window - ((not (and (derived-mode-p 'exwm-mode) exwm--floating-frame)) - ;; Resize on tiling layout - (unless (= 0 (window-resizable nil delta horizontal nil t)) ;not resizable - (let ((window-resize-pixelwise t)) - (window-resize nil delta horizontal nil t)))) - ;; Resize on floating layout - (exwm--fixed-size) ;fixed size - (horizontal - (let* ((width (frame-pixel-width)) - (edges (window-inside-pixel-edges)) - (inner-width (- (elt edges 2) (elt edges 0))) - (margin (- width inner-width))) - (if (> delta 0) - (if (not exwm--normal-hints-max-width) - (cl-incf width delta) - (if (>= inner-width exwm--normal-hints-max-width) - (setq width nil) - (setq width (min (+ exwm--normal-hints-max-width margin) - (+ width delta))))) - (if (not exwm--normal-hints-min-width) - (cl-incf width delta) - (if (<= inner-width exwm--normal-hints-min-width) - (setq width nil) - (setq width (max (+ exwm--normal-hints-min-width margin) - (+ width delta)))))) - (when (and width (> width 0)) - (setf (slot-value exwm--geometry 'width) width) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm--floating-frame - 'exwm-outer-id) - :value-mask xcb:ConfigWindow:Width - :width width)) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm--floating-frame - 'exwm-container) - :value-mask xcb:ConfigWindow:Width - :width width)) - (xcb:flush exwm--connection)))) - (t - (let* ((height (+ (frame-pixel-height) exwm-workspace--frame-y-offset)) - (edges (window-inside-pixel-edges)) - (inner-height (- (elt edges 3) (elt edges 1))) - (margin (- height inner-height))) - (if (> delta 0) - (if (not exwm--normal-hints-max-height) - (cl-incf height delta) - (if (>= inner-height exwm--normal-hints-max-height) - (setq height nil) - (setq height (min (+ exwm--normal-hints-max-height margin) - (+ height delta))))) - (if (not exwm--normal-hints-min-height) - (cl-incf height delta) - (if (<= inner-height exwm--normal-hints-min-height) - (setq height nil) - (setq height (max (+ exwm--normal-hints-min-height margin) - (+ height delta)))))) - (when (and height (> height 0)) - (setf (slot-value exwm--geometry 'height) height) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm--floating-frame - 'exwm-outer-id) - :value-mask xcb:ConfigWindow:Height - :height height)) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm--floating-frame - 'exwm-container) - :value-mask xcb:ConfigWindow:Height - :height height)) - (xcb:flush exwm--connection)))))) - -;;;###autoload -(defun exwm-layout-enlarge-window-horizontally (delta) - "Make the selected window DELTA pixels wider. - -See also `exwm-layout-enlarge-window'." - (interactive "p") - (exwm--log "%s" delta) - (exwm-layout-enlarge-window delta t)) - -;;;###autoload -(defun exwm-layout-shrink-window (delta) - "Make the selected window DELTA pixels lower. - -See also `exwm-layout-enlarge-window'." - (interactive "p") - (exwm--log "%s" delta) - (exwm-layout-enlarge-window (- delta))) - -;;;###autoload -(defun exwm-layout-shrink-window-horizontally (delta) - "Make the selected window DELTA pixels narrower. - -See also `exwm-layout-enlarge-window'." - (interactive "p") - (exwm--log "%s" delta) - (exwm-layout-enlarge-window (- delta) t)) - -;;;###autoload -(defun exwm-layout-hide-mode-line () - "Hide mode-line." - (interactive) - (exwm--log) - (when (and (derived-mode-p 'exwm-mode) mode-line-format) - (let (mode-line-height) - (when exwm--floating-frame - (setq mode-line-height (window-mode-line-height - (frame-root-window exwm--floating-frame)))) - (setq exwm--mode-line-format mode-line-format - mode-line-format nil) - (if (not exwm--floating-frame) - (exwm-layout--show exwm--id) - (set-frame-height exwm--floating-frame - (- (frame-pixel-height exwm--floating-frame) - mode-line-height) - nil t))))) - -;;;###autoload -(defun exwm-layout-show-mode-line () - "Show mode-line." - (interactive) - (exwm--log) - (when (and (derived-mode-p 'exwm-mode) (not mode-line-format)) - (setq mode-line-format exwm--mode-line-format - exwm--mode-line-format nil) - (if (not exwm--floating-frame) - (exwm-layout--show exwm--id) - (set-frame-height exwm--floating-frame - (+ (frame-pixel-height exwm--floating-frame) - (window-mode-line-height (frame-root-window - exwm--floating-frame))) - nil t) - (call-interactively #'exwm-input-grab-keyboard)) - (force-mode-line-update))) - -;;;###autoload -(defun exwm-layout-toggle-mode-line () - "Toggle the display of mode-line." - (interactive) - (exwm--log) - (when (derived-mode-p 'exwm-mode) - (if mode-line-format - (exwm-layout-hide-mode-line) - (exwm-layout-show-mode-line)))) - -(defun exwm-layout--init () - "Initialize layout module." - ;; Auto refresh layout - (exwm--log) - (add-hook 'window-configuration-change-hook #'exwm-layout--refresh) - (add-hook 'window-size-change-functions #'exwm-layout--refresh) - (unless (exwm-workspace--minibuffer-own-frame-p) - ;; Refresh when minibuffer grows - (add-hook 'minibuffer-setup-hook #'exwm-layout--on-minibuffer-setup t) - (setq exwm-layout--timer - (run-with-idle-timer 0 t #'exwm-layout--on-echo-area-change t)) - (add-hook 'echo-area-clear-hook #'exwm-layout--on-echo-area-change))) - -(defun exwm-layout--exit () - "Exit the layout module." - (exwm--log) - (remove-hook 'window-configuration-change-hook #'exwm-layout--refresh) - (remove-hook 'window-size-change-functions #'exwm-layout--refresh) - (remove-hook 'minibuffer-setup-hook #'exwm-layout--on-minibuffer-setup) - (when exwm-layout--timer - (cancel-timer exwm-layout--timer) - (setq exwm-layout--timer nil)) - (remove-hook 'echo-area-clear-hook #'exwm-layout--on-echo-area-change)) - - - -(provide 'exwm-layout) - -;;; exwm-layout.el ends here diff --git a/third_party/exwm/exwm-manage.el b/third_party/exwm/exwm-manage.el deleted file mode 100644 index ab66e298a..000000000 --- a/third_party/exwm/exwm-manage.el +++ /dev/null @@ -1,833 +0,0 @@ -;;; exwm-manage.el --- Window Management Module for -*- lexical-binding: t -*- -;;; EXWM - -;; Copyright (C) 2015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This is the fundamental module of EXWM that deals with window management. - -;;; Code: - -(require 'exwm-core) - -(defgroup exwm-manage nil - "Manage." - :group 'exwm) - -(defcustom exwm-manage-finish-hook nil - "Normal hook run after a window is just managed. -This hook runs in the context of the corresponding `exwm-mode' buffer." - :type 'hook) - -(defcustom exwm-manage-force-tiling nil - "Non-nil to force managing all X windows in tiling layout. -You can still make the X windows floating afterwards." - :type 'boolean) - -(defcustom exwm-manage-ping-timeout 3 - "Seconds to wait before killing a client." - :type 'integer) - -(defcustom exwm-manage-configurations nil - "Per-application configurations. - -Configuration options allow to override various default behaviors of EXWM -and only take effect when they are present. Note for certain options -specifying nil is not exactly the same as leaving them out. Currently -possible choices: -* floating: Force floating (non-nil) or tiling (nil) on startup. -* x/y/width/height: Override the initial geometry (floating X window only). -* border-width: Override the border width (only visible when floating). -* fullscreen: Force full screen (non-nil) on startup. -* floating-mode-line: `mode-line-format' used when floating. -* tiling-mode-line: `mode-line-format' used when tiling. -* floating-header-line: `header-line-format' used when floating. -* tiling-header-line: `header-line-format' used when tiling. -* char-mode: Force char-mode (non-nil) on startup. -* prefix-keys: `exwm-input-prefix-keys' local to this X window. -* simulation-keys: `exwm-input-simulation-keys' local to this X window. -* workspace: The initial workspace. -* managed: Force to manage (non-nil) or not manage (nil) the X window. - -For each X window managed for the first time, matching criteria (sexps) are -evaluated sequentially and the first configuration with a non-nil matching -criterion would be applied. Apart from generic forms, one would typically -want to match against EXWM internal variables such as `exwm-title', -`exwm-class-name' and `exwm-instance-name'." - :type '(alist :key-type (sexp :tag "Matching criterion" nil) - :value-type - (plist :tag "Configurations" - :options - (((const :tag "Floating" floating) boolean) - ((const :tag "X" x) number) - ((const :tag "Y" y) number) - ((const :tag "Width" width) number) - ((const :tag "Height" height) number) - ((const :tag "Border width" border-width) integer) - ((const :tag "Fullscreen" fullscreen) boolean) - ((const :tag "Floating mode-line" floating-mode-line) - sexp) - ((const :tag "Tiling mode-line" tiling-mode-line) sexp) - ((const :tag "Floating header-line" - floating-header-line) - sexp) - ((const :tag "Tiling header-line" tiling-header-line) - sexp) - ((const :tag "Char-mode" char-mode) boolean) - ((const :tag "Prefix keys" prefix-keys) - (repeat key-sequence)) - ((const :tag "Simulation keys" simulation-keys) - (alist :key-type (key-sequence :tag "From") - :value-type (key-sequence :tag "To"))) - ((const :tag "Workspace" workspace) integer) - ((const :tag "Managed" managed) boolean) - ;; For forward compatibility. - ((other) sexp)))) - ;; TODO: This is admittedly ugly. We'd be better off with an event type. - :get (lambda (symbol) - (mapcar (lambda (pair) - (let* ((match (car pair)) - (config (cdr pair)) - (prefix-keys (plist-get config 'prefix-keys))) - (when prefix-keys - (setq config (copy-tree config) - config (plist-put config 'prefix-keys - (mapcar (lambda (i) - (if (sequencep i) - i - (vector i))) - prefix-keys)))) - (cons match config))) - (default-value symbol))) - :set (lambda (symbol value) - (set symbol - (mapcar (lambda (pair) - (let* ((match (car pair)) - (config (cdr pair)) - (prefix-keys (plist-get config 'prefix-keys))) - (when prefix-keys - (setq config (copy-tree config) - config (plist-put config 'prefix-keys - (mapcar (lambda (i) - (if (sequencep i) - (aref i 0) - i)) - prefix-keys)))) - (cons match config))) - value)))) - -;; FIXME: Make the following values as small as possible. -(defconst exwm-manage--height-delta-min 5) -(defconst exwm-manage--width-delta-min 5) - -;; The _MOTIF_WM_HINTS atom (see for more details) -;; It's currently only used in 'exwm-manage' module -(defvar exwm-manage--_MOTIF_WM_HINTS nil "_MOTIF_WM_HINTS atom.") - -(defvar exwm-manage--desktop nil "The desktop X window.") - -(defvar exwm-manage--frame-outer-id-list nil - "List of window-outer-id's of all frames.") - -(defvar exwm-manage--ping-lock nil - "Non-nil indicates EXWM is pinging a window.") - -(defvar exwm-input--skip-buffer-list-update) -(defvar exwm-input-prefix-keys) -(defvar exwm-workspace--current) -(defvar exwm-workspace--id-struts-alist) -(defvar exwm-workspace--list) -(defvar exwm-workspace--switch-history-outdated) -(defvar exwm-workspace-current-index) -(declare-function exwm--update-class "exwm.el" (id &optional force)) -(declare-function exwm--update-hints "exwm.el" (id &optional force)) -(declare-function exwm--update-normal-hints "exwm.el" (id &optional force)) -(declare-function exwm--update-protocols "exwm.el" (id &optional force)) -(declare-function exwm--update-struts "exwm.el" (id)) -(declare-function exwm--update-title "exwm.el" (id)) -(declare-function exwm--update-transient-for "exwm.el" (id &optional force)) -(declare-function exwm--update-desktop "exwm.el" (id &optional force)) -(declare-function exwm--update-window-type "exwm.el" (id &optional force)) -(declare-function exwm-floating--set-floating "exwm-floating.el" (id)) -(declare-function exwm-floating--unset-floating "exwm-floating.el" (id)) -(declare-function exwm-input-grab-keyboard "exwm-input.el" (&optional id)) -(declare-function exwm-input-release-keyboard "exwm-input.el" (&optional id)) -(declare-function exwm-input-set-local-simulation-keys "exwm-input.el") -(declare-function exwm-layout--fullscreen-p "exwm-layout.el" ()) -(declare-function exwm-layout--iconic-state-p "exwm-layout.el" (&optional id)) -(declare-function exwm-layout-set-fullscreen "exwm-layout.el" (&optional id)) -(declare-function exwm-workspace--get-geometry "exwm-workspace.el" (frame)) -(declare-function exwm-workspace--position "exwm-workspace.el" (frame)) -(declare-function exwm-workspace--set-fullscreen "exwm-workspace.el" (frame)) -(declare-function exwm-workspace--update-struts "exwm-workspace.el" ()) -(declare-function exwm-workspace--update-workareas "exwm-workspace.el" ()) -(declare-function exwm-workspace--workarea "exwm-workspace.el" (frame)) - -(defun exwm-manage--update-geometry (id &optional force) - "Update geometry of X window ID. -Override current geometry if FORCE is non-nil." - (exwm--log "id=#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (and exwm--geometry (not force)) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry :drawable id)))) - (setq exwm--geometry - (or reply - ;; Provide a reasonable fallback value. - (make-instance 'xcb:RECTANGLE - :x 0 - :y 0 - :width (/ (x-display-pixel-width) 2) - :height (/ (x-display-pixel-height) 2)))))))) - -(defun exwm-manage--update-ewmh-state (id) - "Update _NET_WM_STATE of X window ID." - (exwm--log "id=#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless exwm--ewmh-state - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:ewmh:get-_NET_WM_STATE - :window id)))) - (when reply - (setq exwm--ewmh-state (append (slot-value reply 'value) nil))))))) - -(defun exwm-manage--update-mwm-hints (id &optional force) - "Update _MOTIF_WM_HINTS of X window ID. -Override current hinds if FORCE is non-nil." - (exwm--log "id=#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (and (not exwm--mwm-hints-decorations) (not force)) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:icccm:-GetProperty - :window id - :property exwm-manage--_MOTIF_WM_HINTS - :type exwm-manage--_MOTIF_WM_HINTS - :long-length 5)))) - (when reply - ;; Check MotifWmHints.decorations. - (with-slots (value) reply - (setq value (append value nil)) - (when (and value - ;; See for fields definitions. - (/= 0 (logand - (elt value 0) ;MotifWmHints.flags - 2)) ;MWM_HINTS_DECORATIONS - (= 0 - (elt value 2))) ;MotifWmHints.decorations - (setq exwm--mwm-hints-decorations nil)))))))) - -(defun exwm-manage--update-default-directory (id) - "Update the `default-directory' of X window ID. -Sets the `default-directory' of the EXWM buffer associated with X window to -match its current working directory. - -This only works when procfs is mounted, which may not be the case on some BSDs." - (with-current-buffer (exwm--id->buffer id) - (if-let* ((response (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:ewmh:get-_NET_WM_PID - :window id))) - (pid (slot-value response 'value)) - (cwd (file-symlink-p (format "/proc/%d/cwd" pid))) - ((file-accessible-directory-p cwd))) - (setq default-directory (file-name-as-directory cwd)) - (setq default-directory (expand-file-name "~/"))))) - - -(defun exwm-manage--set-client-list () - "Set _NET_CLIENT_LIST." - (exwm--log) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_CLIENT_LIST - :window exwm--root - :data (vconcat (mapcar #'car exwm--id-buffer-alist))))) - -(cl-defun exwm-manage--get-configurations () - "Retrieve configurations for this buffer." - (exwm--log) - (when (derived-mode-p 'exwm-mode) - (dolist (i exwm-manage-configurations) - (save-current-buffer - (when (with-demoted-errors "Problematic configuration: %S" - (eval (car i) t)) - (cl-return-from exwm-manage--get-configurations (cdr i))))))) - -(defun exwm-manage--manage-window (id) - "Manage window ID." - (exwm--log "Try to manage #x%x" id) - (catch 'return - ;; Ensure it's alive - (when (xcb:+request-checked+request-check exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window id :value-mask xcb:CW:EventMask - :event-mask (exwm--get-client-event-mask))) - (throw 'return 'dead)) - ;; Add this X window to save-set. - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeSaveSet - :mode xcb:SetMode:Insert - :window id)) - (with-current-buffer (let ((exwm-input--skip-buffer-list-update t)) - (generate-new-buffer "*EXWM*")) - ;; Keep the oldest X window first. - (setq exwm--id-buffer-alist - (nconc exwm--id-buffer-alist `((,id . ,(current-buffer))))) - (exwm-mode) - (setq exwm--id id - exwm--frame exwm-workspace--current) - (exwm--update-window-type id) - (exwm--update-class id) - (exwm--update-transient-for id) - (exwm--update-normal-hints id) - (exwm--update-hints id) - (exwm-manage--update-geometry id) - (exwm-manage--update-mwm-hints id) - (exwm--update-title id) - (exwm--update-protocols id) - (setq exwm--configurations (exwm-manage--get-configurations)) - ;; OverrideRedirect is not checked here. - (when (and - ;; The user has specified to manage it. - (not (plist-get exwm--configurations 'managed)) - (or - ;; The user has specified not to manage it. - (plist-member exwm--configurations 'managed) - ;; This is not a type of X window we can manage. - (and exwm-window-type - (not (cl-intersection - exwm-window-type - (list xcb:Atom:_NET_WM_WINDOW_TYPE_UTILITY - xcb:Atom:_NET_WM_WINDOW_TYPE_DIALOG - xcb:Atom:_NET_WM_WINDOW_TYPE_NORMAL)))) - ;; Check the _MOTIF_WM_HINTS property to not manage floating X - ;; windows without decoration. - (and (not exwm--mwm-hints-decorations) - (not exwm--hints-input) - ;; Floating windows only - (or exwm-transient-for exwm--fixed-size - (memq xcb:Atom:_NET_WM_WINDOW_TYPE_UTILITY - exwm-window-type) - (memq xcb:Atom:_NET_WM_WINDOW_TYPE_DIALOG - exwm-window-type))))) - (exwm--log "No need to manage #x%x" id) - ;; Update struts. - (when (memq xcb:Atom:_NET_WM_WINDOW_TYPE_DOCK exwm-window-type) - (exwm--update-struts id)) - ;; Remove all events - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window id :value-mask xcb:CW:EventMask - :event-mask - (if (memq xcb:Atom:_NET_WM_WINDOW_TYPE_DOCK - exwm-window-type) - ;; Listen for PropertyChange (struts) and - ;; UnmapNotify/DestroyNotify event of the dock. - (exwm--get-client-event-mask) - xcb:EventMask:NoEvent))) - ;; The window needs to be mapped - (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow :window id)) - (with-slots (x y width height) exwm--geometry - ;; Center window of type _NET_WM_WINDOW_TYPE_SPLASH - (when (memq xcb:Atom:_NET_WM_WINDOW_TYPE_SPLASH exwm-window-type) - (with-slots ((x* x) (y* y) (width* width) (height* height)) - (exwm-workspace--workarea exwm--frame) - (exwm--set-geometry id - (+ x* (/ (- width* width) 2)) - (+ y* (/ (- height* height) 2)) - nil - nil)))) - ;; Check for desktop. - (when (memq xcb:Atom:_NET_WM_WINDOW_TYPE_DESKTOP exwm-window-type) - ;; There should be only one desktop X window. - (setq exwm-manage--desktop id) - ;; Put it at bottom. - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window id - :value-mask xcb:ConfigWindow:StackMode - :stack-mode xcb:StackMode:Below))) - (xcb:flush exwm--connection) - (setq exwm--id-buffer-alist (assq-delete-all id exwm--id-buffer-alist)) - (let ((kill-buffer-query-functions nil) - (exwm-input--skip-buffer-list-update t)) - (kill-buffer (current-buffer))) - (throw 'return 'ignored)) - (let ((index (plist-get exwm--configurations 'workspace))) - (when (and index (< index (length exwm-workspace--list))) - (setq exwm--frame (elt exwm-workspace--list index)))) - ;; Manage the window - (exwm--log "Manage #x%x" id) - (xcb:+request exwm--connection ;remove border - (make-instance 'xcb:ConfigureWindow - :window id :value-mask xcb:ConfigWindow:BorderWidth - :border-width 0)) - (dolist (button ;grab buttons to set focus / move / resize - (list xcb:ButtonIndex:1 xcb:ButtonIndex:2 xcb:ButtonIndex:3)) - (xcb:+request exwm--connection - (make-instance 'xcb:GrabButton - :owner-events 0 :grab-window id - :event-mask xcb:EventMask:ButtonPress - :pointer-mode xcb:GrabMode:Sync - :keyboard-mode xcb:GrabMode:Async - :confine-to xcb:Window:None :cursor xcb:Cursor:None - :button button :modifiers xcb:ModMask:Any))) - (exwm-manage--set-client-list) - (xcb:flush exwm--connection) - (if (plist-member exwm--configurations 'floating) - ;; User has specified whether it should be floating. - (if (plist-get exwm--configurations 'floating) - (exwm-floating--set-floating id) - (with-selected-window (frame-selected-window exwm--frame) - (exwm-floating--unset-floating id))) - ;; Try to determine if it should be floating. - (if (and (not exwm-manage-force-tiling) - (or exwm-transient-for exwm--fixed-size - (memq xcb:Atom:_NET_WM_WINDOW_TYPE_UTILITY - exwm-window-type) - (memq xcb:Atom:_NET_WM_WINDOW_TYPE_DIALOG - exwm-window-type))) - (exwm-floating--set-floating id) - (with-selected-window (frame-selected-window exwm--frame) - (exwm-floating--unset-floating id)))) - (if (plist-get exwm--configurations 'char-mode) - (exwm-input-release-keyboard id) - (exwm-input-grab-keyboard id)) - (when-let ((simulation-keys (plist-get exwm--configurations 'simulation-keys))) - (exwm-input-set-local-simulation-keys simulation-keys)) - (when-let ((prefix-keys (plist-get exwm--configurations 'prefix-keys))) - (setq-local exwm-input-prefix-keys prefix-keys)) - (setq exwm-workspace--switch-history-outdated t) - (exwm--update-desktop id) - (exwm-manage--update-ewmh-state id) - (exwm-manage--update-default-directory id) - (when (or (plist-get exwm--configurations 'fullscreen) - (exwm-layout--fullscreen-p)) - (setq exwm--ewmh-state (delq xcb:Atom:_NET_WM_STATE_FULLSCREEN - exwm--ewmh-state)) - (exwm-layout-set-fullscreen id)) - (run-hooks 'exwm-manage-finish-hook)))) - -(defun exwm-manage--unmanage-window (id &optional withdraw-only) - "Unmanage window ID. - -If WITHDRAW-ONLY is non-nil, the X window will be properly placed back to the -root window. Set WITHDRAW-ONLY to `quit' if this functions is used when window -manager is shutting down." - (let ((buffer (exwm--id->buffer id))) - (exwm--log "Unmanage #x%x (buffer: %s, widthdraw: %s)" - id buffer withdraw-only) - (setq exwm--id-buffer-alist (assq-delete-all id exwm--id-buffer-alist)) - ;; Update workspaces when a dock is destroyed. - (when (and (null withdraw-only) - (assq id exwm-workspace--id-struts-alist)) - (setq exwm-workspace--id-struts-alist - (assq-delete-all id exwm-workspace--id-struts-alist)) - (exwm-workspace--update-struts) - (exwm-workspace--update-workareas) - (dolist (f exwm-workspace--list) - (exwm-workspace--set-fullscreen f))) - (when (and (buffer-live-p buffer) - ;; Invoked from `exwm-manage--exit' upon disconnection. - (slot-value exwm--connection 'connected)) - (with-current-buffer buffer - ;; Unmap the X window. - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow :window id)) - ;; - (setq exwm-workspace--switch-history-outdated t) - ;; - (when withdraw-only - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window id :value-mask xcb:CW:EventMask - :event-mask xcb:EventMask:NoEvent)) - ;; Delete WM_STATE property - (xcb:+request exwm--connection - (make-instance 'xcb:DeleteProperty - :window id :property xcb:Atom:WM_STATE)) - (cond - ((eq withdraw-only 'quit) - ;; Remap the window when exiting. - (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow :window id))) - (t - ;; Remove _NET_WM_DESKTOP. - (xcb:+request exwm--connection - (make-instance 'xcb:DeleteProperty - :window id - :property xcb:Atom:_NET_WM_DESKTOP))))) - (when exwm--floating-frame - ;; Unmap the floating frame before destroying its container. - (let ((window (frame-parameter exwm--floating-frame 'exwm-outer-id)) - (container (frame-parameter exwm--floating-frame - 'exwm-container))) - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow :window window)) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window window :parent exwm--root :x 0 :y 0)) - (xcb:+request exwm--connection - (make-instance 'xcb:DestroyWindow :window container)))) - (when (exwm-layout--fullscreen-p) - (let ((window (get-buffer-window))) - (when window - (set-window-dedicated-p window nil)))) - (exwm-manage--set-client-list) - (xcb:flush exwm--connection)) - (let ((kill-buffer-func - (lambda (buffer) - (when (buffer-local-value 'exwm--floating-frame buffer) - (select-window - (frame-selected-window exwm-workspace--current))) - (with-current-buffer buffer - (let ((kill-buffer-query-functions nil)) - (kill-buffer buffer)))))) - (exwm--defer 0 kill-buffer-func buffer) - (when (active-minibuffer-window) - (exit-minibuffer)))))) - -(defun exwm-manage--scan () - "Search for existing windows and try to manage them." - (exwm--log) - (let* ((tree (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:QueryTree - :window exwm--root))) - reply) - (dolist (i (slot-value tree 'children)) - (setq reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetWindowAttributes - :window i))) - ;; It's possible the X window has been destroyed. - (when reply - (with-slots (override-redirect map-state) reply - (when (and (= 0 override-redirect) - (= xcb:MapState:Viewable map-state)) - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow - :window i)) - (xcb:flush exwm--connection) - (exwm-manage--manage-window i))))))) - -(defun exwm-manage--kill-buffer-query-function () - "Run in `kill-buffer-query-functions'." - (exwm--log "id=#x%x; buffer=%s" (or exwm--id 0) (current-buffer)) - (catch 'return - (when (or (not exwm--connection) - (not (slot-value exwm--connection 'connected))) - (throw 'return t)) - (when (or (not exwm--id) - (xcb:+request-checked+request-check exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window exwm--id - :value-mask xcb:CW:EventMask - :event-mask (exwm--get-client-event-mask)))) - ;; The X window is no longer alive so just close the buffer. - (when exwm--floating-frame - (let ((window (frame-parameter exwm--floating-frame 'exwm-outer-id)) - (container (frame-parameter exwm--floating-frame - 'exwm-container))) - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow :window window)) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window window - :parent exwm--root - :x 0 :y 0)) - (xcb:+request exwm--connection - (make-instance 'xcb:DestroyWindow - :window container)))) - (xcb:flush exwm--connection) - (throw 'return t)) - (unless (memq xcb:Atom:WM_DELETE_WINDOW exwm--protocols) - ;; The X window does not support WM_DELETE_WINDOW; destroy it. - (xcb:+request exwm--connection - (make-instance 'xcb:DestroyWindow :window exwm--id)) - (xcb:flush exwm--connection) - ;; Wait for DestroyNotify event. - (throw 'return nil)) - (let ((id exwm--id)) - ;; Try to close the X window with WM_DELETE_WINDOW client message. - (xcb:+request exwm--connection - (make-instance 'xcb:icccm:SendEvent - :destination id - :event (xcb:marshal - (make-instance 'xcb:icccm:WM_DELETE_WINDOW - :window id) - exwm--connection))) - (xcb:flush exwm--connection) - ;; - (unless (memq xcb:Atom:_NET_WM_PING exwm--protocols) - ;; For X windows without _NET_WM_PING support, we'd better just - ;; wait for DestroyNotify events. - (throw 'return nil)) - ;; Try to determine if the X window is dead with _NET_WM_PING. - (setq exwm-manage--ping-lock t) - (xcb:+request exwm--connection - (make-instance 'xcb:SendEvent - :propagate 0 - :destination id - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal - (make-instance 'xcb:ewmh:_NET_WM_PING - :window id - :timestamp 0 - :client-window id) - exwm--connection))) - (xcb:flush exwm--connection) - (with-timeout (exwm-manage-ping-timeout - (if (y-or-n-p (format "'%s' is not responding. \ -Would you like to kill it? " - (buffer-name))) - (progn (exwm-manage--kill-client id) - ;; Kill the unresponsive X window and - ;; wait for DestroyNotify event. - (throw 'return nil)) - ;; Give up. - (throw 'return nil))) - (while (and exwm-manage--ping-lock - (exwm--id->buffer id)) ;may have been destroyed. - (accept-process-output nil 0.1)) - ;; Give up. - (throw 'return nil))))) - -(defun exwm-manage--kill-client (&optional id) - "Kill X client ID. -If ID is nil, kill X window corresponding to current buffer." - (unless id (setq id (exwm--buffer->id (current-buffer)))) - (exwm--log "id=#x%x" id) - (let* ((response (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:ewmh:get-_NET_WM_PID :window id))) - (pid (and response (slot-value response 'value))) - (request (make-instance 'xcb:KillClient :resource id))) - (if (not pid) - (xcb:+request exwm--connection request) - ;; What if the PID is fake/wrong? - (signal-process pid 'SIGKILL) - ;; Ensure it's dead - (run-with-timer exwm-manage-ping-timeout nil - (lambda () - (xcb:+request exwm--connection request)))) - (xcb:flush exwm--connection))) - -(defun exwm-manage--add-frame (frame) - "Run in `after-make-frame-functions'. -FRAME is the newly created frame." - (exwm--log "frame=%s" frame) - (when (display-graphic-p frame) - (push (string-to-number (frame-parameter frame 'outer-window-id)) - exwm-manage--frame-outer-id-list))) - -(defun exwm-manage--remove-frame (frame) - "Run in `delete-frame-functions'. -FRAME is the frame to be deleted." - (exwm--log "frame=%s" frame) - (when (display-graphic-p frame) - (setq exwm-manage--frame-outer-id-list - (delq (string-to-number (frame-parameter frame 'outer-window-id)) - exwm-manage--frame-outer-id-list)))) - -(defun exwm-manage--on-ConfigureRequest (data _synthetic) - "Handle ConfigureRequest event. -DATA contains unmarshalled ConfigureRequest event data." - (exwm--log) - (let ((obj (make-instance 'xcb:ConfigureRequest)) - buffer edges width-delta height-delta) - (xcb:unmarshal obj data) - (with-slots (window x y width height - border-width sibling stack-mode value-mask) - obj - (exwm--log "#x%x (#x%x) @%dx%d%+d%+d; \ -border-width: %d; sibling: #x%x; stack-mode: %d" - window value-mask width height x y - border-width sibling stack-mode) - (if (and (setq buffer (exwm--id->buffer window)) - (with-current-buffer buffer - (or (exwm-layout--fullscreen-p) - ;; Make sure it's a floating X window wanting to resize - ;; itself. - (or (not exwm--floating-frame) - (progn - (setq edges - (window-inside-pixel-edges - (get-buffer-window buffer t)) - width-delta (- width (- (elt edges 2) - (elt edges 0))) - height-delta (- height (- (elt edges 3) - (elt edges 1)))) - ;; We cannot do resizing precisely for now. - (and (if (= 0 (logand value-mask - xcb:ConfigWindow:Width)) - t - (< (abs width-delta) - exwm-manage--width-delta-min)) - (if (= 0 (logand value-mask - xcb:ConfigWindow:Height)) - t - (< (abs height-delta) - exwm-manage--height-delta-min)))))))) - ;; Send client message for managed windows - (with-current-buffer buffer - (setq edges - (if (exwm-layout--fullscreen-p) - (with-slots (x y width height) - (exwm-workspace--get-geometry exwm--frame) - (list x y width height)) - (window-inside-absolute-pixel-edges - (get-buffer-window buffer t)))) - (exwm--log "Reply with ConfigureNotify (edges): %s" edges) - (xcb:+request exwm--connection - (make-instance 'xcb:SendEvent - :propagate 0 :destination window - :event-mask xcb:EventMask:StructureNotify - :event (xcb:marshal - (make-instance - 'xcb:ConfigureNotify - :event window :window window - :above-sibling xcb:Window:None - :x (elt edges 0) :y (elt edges 1) - :width (- (elt edges 2) (elt edges 0)) - :height (- (elt edges 3) (elt edges 1)) - :border-width 0 :override-redirect 0) - exwm--connection)))) - (if buffer - (with-current-buffer buffer - (exwm--log "ConfigureWindow (resize floating X window)") - (exwm--set-geometry (frame-parameter exwm--floating-frame - 'exwm-outer-id) - nil - nil - (+ (frame-pixel-width exwm--floating-frame) - width-delta) - (+ (frame-pixel-height exwm--floating-frame) - height-delta))) - (exwm--log "ConfigureWindow (preserve geometry)") - ;; Configure the unmanaged window. - ;; But Emacs frames should be excluded. Generally we don't - ;; receive ConfigureRequest events from Emacs frames since we - ;; have set OverrideRedirect on them, but this is not true for - ;; Lucid build (as of 25.1). - (unless (memq window exwm-manage--frame-outer-id-list) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window window - :value-mask value-mask - :x x :y y :width width :height height - :border-width border-width - :sibling sibling - :stack-mode stack-mode))))))) - (xcb:flush exwm--connection)) - -(defun exwm-manage--on-MapRequest (data _synthetic) - "Handle MapRequest event. -DATA contains unmarshalled MapRequest event data." - (let ((obj (make-instance 'xcb:MapRequest))) - (xcb:unmarshal obj data) - (with-slots (parent window) obj - (exwm--log "id=#x%x parent=#x%x" window parent) - (if (assoc window exwm--id-buffer-alist) - (with-current-buffer (exwm--id->buffer window) - (if (exwm-layout--iconic-state-p) - ;; State change: iconic => normal. - (when (eq exwm--frame exwm-workspace--current) - (pop-to-buffer-same-window (current-buffer))) - (exwm--log "#x%x is already managed" window))) - (if (/= exwm--root parent) - (progn (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow :window window)) - (xcb:flush exwm--connection)) - (exwm--log "#x%x" window) - (exwm-manage--manage-window window)))))) - -(defun exwm-manage--on-UnmapNotify (data _synthetic) - "Handle UnmapNotify event. -DATA contains unmarshalled UnmapNotify event data." - (let ((obj (make-instance 'xcb:UnmapNotify))) - (xcb:unmarshal obj data) - (with-slots (window) obj - (exwm--log "id=#x%x" window) - (exwm-manage--unmanage-window window t)))) - -(defun exwm-manage--on-MapNotify (data _synthetic) - "Handle MapNotify event. -DATA contains unmarshalled MapNotify event data." - (let ((obj (make-instance 'xcb:MapNotify))) - (xcb:unmarshal obj data) - (with-slots (window) obj - (when (assoc window exwm--id-buffer-alist) - (exwm--log "id=#x%x" window) - ;; With this we ensure that a "window hierarchy change" happens after - ;; mapping the window, as some servers (XQuartz) do not generate it. - (with-current-buffer (exwm--id->buffer window) - (if exwm--floating-frame - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window window - :value-mask xcb:ConfigWindow:StackMode - :stack-mode xcb:StackMode:Above)) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window window - :value-mask (logior xcb:ConfigWindow:Sibling - xcb:ConfigWindow:StackMode) - :sibling exwm--guide-window - :stack-mode xcb:StackMode:Above)))) - (xcb:flush exwm--connection))))) - -(defun exwm-manage--on-DestroyNotify (data synthetic) - "Handle DestroyNotify event. -DATA contains unmarshalled DestroyNotify event data. -SYNTHETIC indicates whether the event is a synthetic event." - (unless synthetic - (exwm--log) - (let ((obj (make-instance 'xcb:DestroyNotify))) - (xcb:unmarshal obj data) - (exwm--log "#x%x" (slot-value obj 'window)) - (exwm-manage--unmanage-window (slot-value obj 'window))))) - -(defun exwm-manage--init () - "Initialize manage module." - ;; Intern _MOTIF_WM_HINTS - (exwm--log) - (setq exwm-manage--_MOTIF_WM_HINTS (exwm--intern-atom "_MOTIF_WM_HINTS")) - (add-hook 'after-make-frame-functions #'exwm-manage--add-frame) - (add-hook 'delete-frame-functions #'exwm-manage--remove-frame) - (xcb:+event exwm--connection 'xcb:ConfigureRequest - #'exwm-manage--on-ConfigureRequest) - (xcb:+event exwm--connection 'xcb:MapRequest #'exwm-manage--on-MapRequest) - (xcb:+event exwm--connection 'xcb:UnmapNotify #'exwm-manage--on-UnmapNotify) - (xcb:+event exwm--connection 'xcb:MapNotify #'exwm-manage--on-MapNotify) - (xcb:+event exwm--connection 'xcb:DestroyNotify - #'exwm-manage--on-DestroyNotify)) - -(defun exwm-manage--exit () - "Exit the manage module." - (exwm--log) - (dolist (pair exwm--id-buffer-alist) - (exwm-manage--unmanage-window (car pair) 'quit)) - (remove-hook 'after-make-frame-functions #'exwm-manage--add-frame) - (remove-hook 'delete-frame-functions #'exwm-manage--remove-frame) - (setq exwm-manage--_MOTIF_WM_HINTS nil)) - - - -(provide 'exwm-manage) - -;;; exwm-manage.el ends here diff --git a/third_party/exwm/exwm-randr.el b/third_party/exwm/exwm-randr.el deleted file mode 100644 index 7f0e50559..000000000 --- a/third_party/exwm/exwm-randr.el +++ /dev/null @@ -1,369 +0,0 @@ -;;; exwm-randr.el --- RandR Module for EXWM -*- lexical-binding: t -*- - -;; Copyright (C) 2015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module adds RandR support for EXWM. Currently it requires external -;; tools such as xrandr(1) to properly configure RandR first. This -;; dependency may be removed in the future, but more work is needed before -;; that. - -;; To use this module, load, enable it and configure -;; `exwm-randr-workspace-monitor-plist' and `exwm-randr-screen-change-hook' -;; as follows: -;; -;; (require 'exwm-randr) -;; (setq exwm-randr-workspace-monitor-plist '(0 "VGA1")) -;; (add-hook 'exwm-randr-screen-change-hook -;; (lambda () -;; (start-process-shell-command -;; "xrandr" nil "xrandr --output VGA1 --left-of LVDS1 --auto"))) -;; (exwm-randr-enable) -;; -;; With above lines, workspace 0 should be assigned to the output named "VGA1", -;; staying at the left of other workspaces on the output "LVDS1". Please refer -;; to xrandr(1) for the configuration of RandR. - -;; References: -;; + RandR (http://www.x.org/archive/X11R7.7/doc/randrproto/randrproto.txt) - -;;; Code: - -(require 'xcb-randr) - -(require 'exwm-core) -(require 'exwm-workspace) - -(declare-function x-get-atom-name "C source code" (VALUE &optional FRAME)) - -(defgroup exwm-randr nil - "RandR." - :group 'exwm) - -(defcustom exwm-randr-refresh-hook nil - "Normal hook run when the RandR module just refreshed." - :type 'hook) - -(defcustom exwm-randr-screen-change-hook nil - "Normal hook run when screen changes." - :type 'hook) - -(defcustom exwm-randr-workspace-monitor-plist nil - "Plist mapping workspaces to monitors. - -In RandR 1.5 a monitor is a rectangle region decoupled from the physical -size of screens, and can be identified with `xrandr --listmonitors' (name of -the primary monitor is prefixed with an `*'). When no monitor is created it -automatically fallback to RandR 1.2 output which represents the physical -screen size. RandR 1.5 monitors can be created with `xrandr --setmonitor'. -For example, to split an output (`LVDS-1') of size 1280x800 into two -side-by-side monitors one could invoke (the digits after `/' are size in mm) - - xrandr --setmonitor *LVDS-1-L 640/135x800/163+0+0 LVDS-1 - xrandr --setmonitor LVDS-1-R 640/135x800/163+640+0 none - -If a monitor is not active, the workspaces mapped to it are displayed on the -primary monitor until it becomes active (if ever). Unspecified workspaces -are all mapped to the primary monitor. For example, with the following -setting workspace other than 1 and 3 would always be displayed on the -primary monitor where workspace 1 and 3 would be displayed on their -corresponding monitors whenever the monitors are active. - - \\='(1 \"HDMI-1\" 3 \"DP-1\")" - :type '(plist :key-type integer :value-type string)) - -(defvar exwm-randr--last-timestamp 0 "Used for debouncing events.") - -(defvar exwm-randr--prev-screen-change-seqnum nil - "The most recent ScreenChangeNotify sequence number.") - -(defvar exwm-randr--compatibility-mode nil - "Non-nil when the server does not support RandR 1.5 protocol.") - -(defun exwm-randr--get-monitors () - "Get RandR 1.5 monitors." - (exwm--log) - (let (monitor-name geometry monitor-geometry-alist primary-monitor) - (with-slots (timestamp monitors) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:randr:GetMonitors - :window exwm--root - :get-active 1)) - (when (> timestamp exwm-randr--last-timestamp) - (setq exwm-randr--last-timestamp timestamp)) - (dolist (monitor monitors) - (with-slots (name primary x y width height) monitor - (setq monitor-name (x-get-atom-name name) - geometry (make-instance 'xcb:RECTANGLE - :x x - :y y - :width width - :height height) - monitor-geometry-alist (cons (cons monitor-name geometry) - monitor-geometry-alist)) - (exwm--log "%s: %sx%s+%s+%s" monitor-name x y width height) - ;; Save primary monitor when available (fallback to the first one). - (when (or (/= 0 primary) - (not primary-monitor)) - (setq primary-monitor monitor-name))))) - (exwm--log "Primary monitor: %s" primary-monitor) - (list primary-monitor monitor-geometry-alist - (exwm-randr--get-monitor-alias primary-monitor - monitor-geometry-alist)))) - -(defun exwm-randr--get-outputs () - "Get RandR 1.2 outputs. - -Only used when RandR 1.5 is not supported by the server." - (exwm--log) - (let (output-name geometry output-geometry-alist primary-output) - (with-slots (config-timestamp outputs) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:randr:GetScreenResourcesCurrent - :window exwm--root)) - (when (> config-timestamp exwm-randr--last-timestamp) - (setq exwm-randr--last-timestamp config-timestamp)) - (dolist (output outputs) - (with-slots (crtc connection name) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:randr:GetOutputInfo - :output output - :config-timestamp config-timestamp)) - (when (and (= connection xcb:randr:Connection:Connected) - (/= crtc 0)) - (with-slots (x y width height) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:randr:GetCrtcInfo - :crtc crtc - :config-timestamp config-timestamp)) - (setq output-name (decode-coding-string - (apply #'unibyte-string name) 'utf-8) - geometry (make-instance 'xcb:RECTANGLE - :x x - :y y - :width width - :height height) - output-geometry-alist (cons (cons output-name geometry) - output-geometry-alist)) - (exwm--log "%s: %sx%s+%s+%s" output-name x y width height) - ;; The primary output is the first one. - (unless primary-output - (setq primary-output output-name))))))) - (exwm--log "Primary output: %s" primary-output) - (list primary-output output-geometry-alist - (exwm-randr--get-monitor-alias primary-output - output-geometry-alist)))) - -(defun exwm-randr--get-monitor-alias (primary-monitor monitor-geometry-alist) - "Generate monitor aliases using PRIMARY-MONITOR MONITOR-GEOMETRY-ALIST. - -In a mirroring setup some monitors overlap and should be treated as one." - (let (monitor-position-alist monitor-alias-alist monitor-name geometry) - (setq monitor-position-alist (with-slots (x y) - (cdr (assoc primary-monitor - monitor-geometry-alist)) - (list (cons primary-monitor (vector x y))))) - (setq monitor-alias-alist (list (cons primary-monitor primary-monitor))) - (dolist (pair monitor-geometry-alist) - (setq monitor-name (car pair) - geometry (cdr pair)) - (unless (assoc monitor-name monitor-alias-alist) - (let* ((position (vector (slot-value geometry 'x) - (slot-value geometry 'y))) - (alias (car (rassoc position monitor-position-alist)))) - (if alias - (setq monitor-alias-alist (cons (cons monitor-name alias) - monitor-alias-alist)) - (setq monitor-position-alist (cons (cons monitor-name position) - monitor-position-alist) - monitor-alias-alist (cons (cons monitor-name monitor-name) - monitor-alias-alist)))))) - monitor-alias-alist)) - -;;;###autoload -(defun exwm-randr-refresh () - "Refresh workspaces according to the updated RandR info." - (interactive) - (exwm--log) - (let* ((result (if exwm-randr--compatibility-mode - (exwm-randr--get-outputs) - (exwm-randr--get-monitors))) - (primary-monitor (elt result 0)) - (monitor-geometry-alist (elt result 1)) - (monitor-alias-alist (elt result 2)) - container-monitor-alist container-frame-alist) - (when (and primary-monitor monitor-geometry-alist) - (when exwm-workspace--fullscreen-frame-count - ;; Not all workspaces are fullscreen; reset this counter. - (setq exwm-workspace--fullscreen-frame-count 0)) - (dotimes (i (exwm-workspace--count)) - (let* ((monitor (plist-get exwm-randr-workspace-monitor-plist i)) - (geometry (cdr (assoc monitor monitor-geometry-alist))) - (frame (elt exwm-workspace--list i)) - (container (frame-parameter frame 'exwm-container))) - (if geometry - ;; Unify monitor names in case it's a mirroring setup. - (setq monitor (cdr (assoc monitor monitor-alias-alist))) - ;; Missing monitors fallback to the primary one. - (setq monitor primary-monitor - geometry (cdr (assoc primary-monitor - monitor-geometry-alist)))) - (setq container-monitor-alist (nconc - `((,container . ,(intern monitor))) - container-monitor-alist) - container-frame-alist (nconc `((,container . ,frame)) - container-frame-alist)) - (set-frame-parameter frame 'exwm-randr-monitor monitor) - (set-frame-parameter frame 'exwm-geometry geometry))) - ;; Update workareas. - (exwm-workspace--update-workareas) - ;; Resize workspace. - (dolist (f exwm-workspace--list) - (exwm-workspace--set-fullscreen f)) - (xcb:flush exwm--connection) - ;; Raise the minibuffer if it's active. - (when (and (active-minibuffer-window) - (exwm-workspace--minibuffer-own-frame-p)) - (exwm-workspace--show-minibuffer)) - ;; Set _NET_DESKTOP_GEOMETRY. - (exwm-workspace--set-desktop-geometry) - ;; Update active/inactive workspaces. - (dolist (w exwm-workspace--list) - (exwm-workspace--set-active w nil)) - ;; Mark the workspace on the top of each monitor as active. - (dolist (xwin - (reverse - (slot-value (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:QueryTree - :window exwm--root)) - 'children))) - (let ((monitor (cdr (assq xwin container-monitor-alist)))) - (when monitor - (setq container-monitor-alist - (rassq-delete-all monitor container-monitor-alist)) - (exwm-workspace--set-active (cdr (assq xwin container-frame-alist)) - t)))) - (xcb:flush exwm--connection) - (run-hooks 'exwm-randr-refresh-hook)))) - -(defun exwm-randr--on-ScreenChangeNotify (data _synthetic) - "Handle `ScreenChangeNotify' event. - -Run `exwm-randr-screen-change-hook' (usually user scripts to configure RandR)." - (exwm--log) - (let ((evt (make-instance 'xcb:randr:ScreenChangeNotify))) - (xcb:unmarshal evt data) - (let ((seqnum (slot-value evt '~sequence))) - (unless (equal seqnum exwm-randr--prev-screen-change-seqnum) - (setq exwm-randr--prev-screen-change-seqnum seqnum) - (run-hooks 'exwm-randr-screen-change-hook))))) - -(defun exwm-randr--on-Notify (data _synthetic) - "Handle `CrtcChangeNotify' and `OutputChangeNotify' events. - -Refresh when any CRTC/output changes." - (exwm--log) - (let ((evt (make-instance 'xcb:randr:Notify)) - notify) - (xcb:unmarshal evt data) - (with-slots (subCode u) evt - (cl-case subCode - (xcb:randr:Notify:CrtcChange - (setq notify (slot-value u 'cc))) - (xcb:randr:Notify:OutputChange - (setq notify (slot-value u 'oc)))) - (when notify - (with-slots (timestamp) notify - (when (> timestamp exwm-randr--last-timestamp) - (exwm-randr-refresh) - (setq exwm-randr--last-timestamp timestamp))))))) - -(defun exwm-randr--on-ConfigureNotify (data _synthetic) - "Handle `ConfigureNotify' event. - -Refresh when any RandR 1.5 monitor changes." - (exwm--log) - (let ((evt (make-instance 'xcb:ConfigureNotify))) - (xcb:unmarshal evt data) - (with-slots (window) evt - (when (eq window exwm--root) - (exwm-randr-refresh))))) - -(defun exwm-randr--init () - "Initialize RandR extension and EXWM RandR module." - (exwm--log) - (when (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:randr) - 'present)) - (error "[EXWM] RandR extension is not supported by the server")) - (with-slots (major-version minor-version) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:randr:QueryVersion - :major-version 1 :minor-version 5)) - (cond ((and (= major-version 1) (= minor-version 5)) - (setq exwm-randr--compatibility-mode nil)) - ((and (= major-version 1) (>= minor-version 2)) - (setq exwm-randr--compatibility-mode t)) - (t - (error "[EXWM] The server only support RandR version up to %d.%d" - major-version minor-version))) - ;; External monitor(s) may already be connected. - (run-hooks 'exwm-randr-screen-change-hook) - (exwm-randr-refresh) - ;; Listen for `ScreenChangeNotify' to notify external tools to - ;; configure RandR and `CrtcChangeNotify/OutputChangeNotify' to - ;; refresh the workspace layout. - (xcb:+event exwm--connection 'xcb:randr:ScreenChangeNotify - #'exwm-randr--on-ScreenChangeNotify) - (xcb:+event exwm--connection 'xcb:randr:Notify - #'exwm-randr--on-Notify) - (xcb:+event exwm--connection 'xcb:ConfigureNotify - #'exwm-randr--on-ConfigureNotify) - (xcb:+request exwm--connection - (make-instance 'xcb:randr:SelectInput - :window exwm--root - :enable (logior - xcb:randr:NotifyMask:ScreenChange - xcb:randr:NotifyMask:CrtcChange - xcb:randr:NotifyMask:OutputChange))) - (xcb:flush exwm--connection) - (add-hook 'exwm-workspace-list-change-hook #'exwm-randr-refresh)) - ;; Prevent frame parameters introduced by this module from being - ;; saved/restored. - (dolist (i '(exwm-randr-monitor)) - (unless (assq i frameset-filter-alist) - (push (cons i :never) frameset-filter-alist)))) - -(defun exwm-randr--exit () - "Exit the RandR module." - (exwm--log) - (remove-hook 'exwm-workspace-list-change-hook #'exwm-randr-refresh)) - -(defun exwm-randr-enable () - "Enable RandR support for EXWM." - (exwm--log) - (add-hook 'exwm-init-hook #'exwm-randr--init) - (add-hook 'exwm-exit-hook #'exwm-randr--exit)) - - - -(provide 'exwm-randr) - -;;; exwm-randr.el ends here diff --git a/third_party/exwm/exwm-systemtray.el b/third_party/exwm/exwm-systemtray.el deleted file mode 100644 index 2b4656815..000000000 --- a/third_party/exwm/exwm-systemtray.el +++ /dev/null @@ -1,692 +0,0 @@ -;;; exwm-systemtray.el --- System Tray Module for -*- lexical-binding: t -*- -;;; EXWM - -;; Copyright (C) 2016-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module adds system tray support for EXWM. - -;; To use this module, load and enable it as follows: -;; (require 'exwm-systemtray) -;; (exwm-systemtray-enable) - -;;; Code: - -(require 'xcb-ewmh) -(require 'xcb-icccm) -(require 'xcb-xembed) -(require 'xcb-systemtray) - -(require 'exwm-core) -(require 'exwm-workspace) - -(declare-function exwm-workspace--workarea "exwm-workspace.el" (frame)) - -(defclass exwm-systemtray--icon () - ((width :initarg :width) - (height :initarg :height) - (visible :initarg :visible)) - :documentation "Attributes of a system tray icon.") - -(defgroup exwm-systemtray nil - "System tray." - :group 'exwm) - -(defcustom exwm-systemtray-height nil - "System tray height. - -You shall use the default value if using auto-hide minibuffer." - :type 'integer) - -(defcustom exwm-systemtray-icon-gap 2 - "Gap between icons." - :type 'integer) - -(defvar exwm-systemtray--connection nil "The X connection.") - -(defvar exwm-systemtray--embedder-window nil "The embedder window.") -(defvar exwm-systemtray--embedder-window-depth nil - "The embedder window's depth.") - -(defcustom exwm-systemtray-background-color 'workspace-background - "Background color of systemtray. -This should be a color, the symbol `workspace-background' for the background -color of current workspace frame, or the symbol `transparent' for transparent -background. - -Transparent background is not yet supported when Emacs uses 32-bit depth -visual, as reported by `x-display-planes'. The X resource \"Emacs.visualClass: -TrueColor-24\" can be used to force Emacs to use 24-bit depth." - :type '(choice (const :tag "Transparent" transparent) - (const :tag "Frame background" workspace-background) - (color :tag "Color")) - :initialize #'custom-initialize-default - :set (lambda (symbol value) - (when (and (eq value 'transparent) - (not (exwm-systemtray--transparency-supported-p))) - (display-warning 'exwm-systemtray - "Transparent background is not supported yet when \ -using 32-bit depth. Using `workspace-background' instead.") - (setq value 'workspace-background)) - (set-default symbol value) - (when (and exwm-systemtray--connection - exwm-systemtray--embedder-window) - ;; Change the background color for embedder. - (exwm-systemtray--set-background-color) - ;; Unmap & map to take effect immediately. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:UnmapWindow - :window exwm-systemtray--embedder-window)) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:MapWindow - :window exwm-systemtray--embedder-window)) - (xcb:flush exwm-systemtray--connection)))) - -;; GTK icons require at least 16 pixels to show normally. -(defconst exwm-systemtray--icon-min-size 16 "Minimum icon size.") - -(defvar exwm-systemtray--list nil "The icon list.") - -(defvar exwm-systemtray--selection-owner-window nil - "The selection owner window.") - -(defvar xcb:Atom:_NET_SYSTEM_TRAY_S0) - -(defun exwm-systemtray--embed (icon) - "Embed an ICON." - (exwm--log "Try to embed #x%x" icon) - (let ((info (xcb:+request-unchecked+reply exwm-systemtray--connection - (make-instance 'xcb:xembed:get-_XEMBED_INFO - :window icon))) - width* height* visible) - (when info - (exwm--log "Embed #x%x" icon) - (with-slots (width height) - (xcb:+request-unchecked+reply exwm-systemtray--connection - (make-instance 'xcb:GetGeometry :drawable icon)) - (setq height* exwm-systemtray-height - width* (round (* width (/ (float height*) height)))) - (when (< width* exwm-systemtray--icon-min-size) - (setq width* exwm-systemtray--icon-min-size - height* (round (* height (/ (float width*) width))))) - (exwm--log "Resize from %dx%d to %dx%d" - width height width* height*)) - ;; Add this icon to save-set. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ChangeSaveSet - :mode xcb:SetMode:Insert - :window icon)) - ;; Reparent to the embedder. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ReparentWindow - :window icon - :parent exwm-systemtray--embedder-window - :x 0 - ;; Vertically centered. - :y (/ (- exwm-systemtray-height height*) 2))) - ;; Resize the icon. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ConfigureWindow - :window icon - :value-mask (logior xcb:ConfigWindow:Width - xcb:ConfigWindow:Height - xcb:ConfigWindow:BorderWidth) - :width width* - :height height* - :border-width 0)) - ;; Set event mask. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ChangeWindowAttributes - :window icon - :value-mask xcb:CW:EventMask - :event-mask (logior xcb:EventMask:ResizeRedirect - xcb:EventMask:KeyPress - xcb:EventMask:PropertyChange))) - ;; Grab all keys and forward them to Emacs frame. - (unless (exwm-workspace--minibuffer-own-frame-p) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:GrabKey - :owner-events 0 - :grab-window icon - :modifiers xcb:ModMask:Any - :key xcb:Grab:Any - :pointer-mode xcb:GrabMode:Async - :keyboard-mode xcb:GrabMode:Async))) - (setq visible (slot-value info 'flags)) - (if visible - (setq visible - (/= 0 (logand (slot-value info 'flags) xcb:xembed:MAPPED))) - ;; Default to visible. - (setq visible t)) - (when visible - (exwm--log "Map the window") - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:MapWindow :window icon))) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:xembed:SendEvent - :destination icon - :event - (xcb:marshal - (make-instance 'xcb:xembed:EMBEDDED-NOTIFY - :window icon - :time xcb:Time:CurrentTime - :embedder - exwm-systemtray--embedder-window - :version 0) - exwm-systemtray--connection))) - (push `(,icon . ,(make-instance 'exwm-systemtray--icon - :width width* - :height height* - :visible visible)) - exwm-systemtray--list) - (exwm-systemtray--refresh)))) - -(defun exwm-systemtray--unembed (icon) - "Unembed an ICON." - (exwm--log "Unembed #x%x" icon) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:UnmapWindow :window icon)) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ReparentWindow - :window icon - :parent exwm--root - :x 0 :y 0)) - (setq exwm-systemtray--list - (assq-delete-all icon exwm-systemtray--list)) - (exwm-systemtray--refresh)) - -(defun exwm-systemtray--refresh () - "Refresh the system tray." - (exwm--log) - ;; Make sure to redraw the embedder. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:UnmapWindow - :window exwm-systemtray--embedder-window)) - (let ((x exwm-systemtray-icon-gap) - map) - (dolist (pair exwm-systemtray--list) - (when (slot-value (cdr pair) 'visible) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ConfigureWindow - :window (car pair) - :value-mask xcb:ConfigWindow:X - :x x)) - (setq x (+ x (slot-value (cdr pair) 'width) - exwm-systemtray-icon-gap)) - (setq map t))) - (let ((workarea (exwm-workspace--workarea exwm-workspace-current-index))) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ConfigureWindow - :window exwm-systemtray--embedder-window - :value-mask (logior xcb:ConfigWindow:X - xcb:ConfigWindow:Width) - :x (- (slot-value workarea 'width) x) - :width x))) - (when map - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:MapWindow - :window exwm-systemtray--embedder-window)))) - (xcb:flush exwm-systemtray--connection)) - -(defun exwm-systemtray--refresh-background-color (&optional remap) - "Refresh background color after theme change or workspace switch. -If REMAP is not nil, map and unmap the embedder window so that the background is -redrawn." - ;; Only `workspace-background' is dependent on current theme and workspace. - (when (eq 'workspace-background exwm-systemtray-background-color) - (exwm-systemtray--set-background-color) - (when remap - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:UnmapWindow - :window exwm-systemtray--embedder-window)) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:MapWindow - :window exwm-systemtray--embedder-window)) - (xcb:flush exwm-systemtray--connection)))) - -(defun exwm-systemtray--set-background-color () - "Change the background color of the embedder. -The color is set according to `exwm-systemtray-background-color'. - -Note that this function does not change the current contents of the embedder -window; unmap & map are necessary for the background color to take effect." - (when (and exwm-systemtray--connection - exwm-systemtray--embedder-window) - (let* ((color (cl-case exwm-systemtray-background-color - ((transparent nil) ; nil means transparent as well - (if (exwm-systemtray--transparency-supported-p) - nil - (message "%s" "[EXWM] system tray does not support \ -`transparent' background; using `workspace-background' instead") - (face-background 'default exwm-workspace--current))) - (workspace-background - (face-background 'default exwm-workspace--current)) - (t exwm-systemtray-background-color))) - (background-pixel (exwm--color->pixel color))) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ChangeWindowAttributes - :window exwm-systemtray--embedder-window - ;; Either-or. A `background-pixel' of nil - ;; means simulate transparency. We use - ;; `xcb:CW:BackPixmap' together with - ;; `xcb:BackPixmap:ParentRelative' do that, - ;; but this only works when the parent - ;; window's visual (Emacs') has the same - ;; visual depth. - :value-mask (if background-pixel - xcb:CW:BackPixel - xcb:CW:BackPixmap) - ;; Due to the :value-mask above, - ;; :background-pixmap only takes effect when - ;; `transparent' is requested and supported - ;; (visual depth of Emacs and of system tray - ;; are equal). Setting - ;; `xcb:BackPixmap:ParentRelative' when - ;; that's not the case would produce an - ;; `xcb:Match' error. - :background-pixmap xcb:BackPixmap:ParentRelative - :background-pixel background-pixel))))) - -(defun exwm-systemtray--transparency-supported-p () - "Check whether transparent background is supported. -EXWM system tray supports transparency when the visual depth of the system tray -window matches that of Emacs. The visual depth of the system tray window is the -default visual depth of the display. - -Sections \"Visual and background pixmap handling\" and -\"_NET_SYSTEM_TRAY_VISUAL\" of the System Tray Protocol Specification -\(https://specifications.freedesktop.org/systemtray-spec/systemtray-spec-latest.html#visuals) -indicate how to support actual transparency." - (let ((planes (x-display-planes))) - (if exwm-systemtray--embedder-window-depth - (= planes exwm-systemtray--embedder-window-depth) - (<= planes 24)))) - -(defun exwm-systemtray--on-DestroyNotify (data _synthetic) - "Unembed icons on DestroyNotify. -Argument DATA contains the raw event data." - (exwm--log) - (let ((obj (make-instance 'xcb:DestroyNotify))) - (xcb:unmarshal obj data) - (with-slots (window) obj - (when (assoc window exwm-systemtray--list) - (exwm-systemtray--unembed window))))) - -(defun exwm-systemtray--on-ReparentNotify (data _synthetic) - "Unembed icons on ReparentNotify. -Argument DATA contains the raw event data." - (exwm--log) - (let ((obj (make-instance 'xcb:ReparentNotify))) - (xcb:unmarshal obj data) - (with-slots (window parent) obj - (when (and (/= parent exwm-systemtray--embedder-window) - (assoc window exwm-systemtray--list)) - (exwm-systemtray--unembed window))))) - -(defun exwm-systemtray--on-ResizeRequest (data _synthetic) - "Resize the tray icon on ResizeRequest. -Argument DATA contains the raw event data." - (exwm--log) - (let ((obj (make-instance 'xcb:ResizeRequest)) - attr) - (xcb:unmarshal obj data) - (with-slots (window width height) obj - (when (setq attr (cdr (assoc window exwm-systemtray--list))) - (with-slots ((width* width) - (height* height)) - attr - (setq height* exwm-systemtray-height - width* (round (* width (/ (float height*) height)))) - (when (< width* exwm-systemtray--icon-min-size) - (setq width* exwm-systemtray--icon-min-size - height* (round (* height (/ (float width*) width))))) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ConfigureWindow - :window window - :value-mask (logior xcb:ConfigWindow:Y - xcb:ConfigWindow:Width - xcb:ConfigWindow:Height) - ;; Vertically centered. - :y (/ (- exwm-systemtray-height height*) 2) - :width width* - :height height*))) - (exwm-systemtray--refresh))))) - -(defun exwm-systemtray--on-PropertyNotify (data _synthetic) - "Map/Unmap the tray icon on PropertyNotify. -Argument DATA contains the raw event data." - (exwm--log) - (let ((obj (make-instance 'xcb:PropertyNotify)) - attr info visible) - (xcb:unmarshal obj data) - (with-slots (window atom state) obj - (when (and (eq state xcb:Property:NewValue) - (eq atom xcb:Atom:_XEMBED_INFO) - (setq attr (cdr (assoc window exwm-systemtray--list)))) - (setq info (xcb:+request-unchecked+reply exwm-systemtray--connection - (make-instance 'xcb:xembed:get-_XEMBED_INFO - :window window))) - (when info - (setq visible (/= 0 (logand (slot-value info 'flags) - xcb:xembed:MAPPED))) - (exwm--log "#x%x visible? %s" window visible) - (if visible - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:MapWindow :window window)) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:UnmapWindow :window window))) - (setf (slot-value attr 'visible) visible) - (exwm-systemtray--refresh)))))) - -(defun exwm-systemtray--on-ClientMessage (data _synthetic) - "Handle client messages. -Argument DATA contains the raw event data." - (let ((obj (make-instance 'xcb:ClientMessage)) - opcode data32) - (xcb:unmarshal obj data) - (with-slots (window type data) obj - (when (eq type xcb:Atom:_NET_SYSTEM_TRAY_OPCODE) - (setq data32 (slot-value data 'data32) - opcode (elt data32 1)) - (exwm--log "opcode: %s" opcode) - (cond ((= opcode xcb:systemtray:opcode:REQUEST-DOCK) - (unless (assoc (elt data32 2) exwm-systemtray--list) - (exwm-systemtray--embed (elt data32 2)))) - ;; Not implemented (rarely used nowadays). - ((or (= opcode xcb:systemtray:opcode:BEGIN-MESSAGE) - (= opcode xcb:systemtray:opcode:CANCEL-MESSAGE))) - (t - (exwm--log "Unknown opcode message: %s" obj))))))) - -(defun exwm-systemtray--on-KeyPress (data _synthetic) - "Forward all KeyPress events to Emacs frame. -Argument DATA contains the raw event data." - (exwm--log) - ;; This function is only executed when there's no autohide minibuffer, - ;; a workspace frame has the input focus and the pointer is over a - ;; tray icon. - (let ((dest (frame-parameter (selected-frame) 'exwm-outer-id)) - (obj (make-instance 'xcb:KeyPress))) - (xcb:unmarshal obj data) - (setf (slot-value obj 'event) dest) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:SendEvent - :propagate 0 - :destination dest - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal obj exwm-systemtray--connection)))) - (xcb:flush exwm-systemtray--connection)) - -(defun exwm-systemtray--on-workspace-switch () - "Reparent/Refresh the system tray in `exwm-workspace-switch-hook'." - (exwm--log) - (unless (exwm-workspace--minibuffer-own-frame-p) - (exwm-workspace--update-offsets) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ReparentWindow - :window exwm-systemtray--embedder-window - :parent (string-to-number - (frame-parameter exwm-workspace--current - 'window-id)) - :x 0 - :y (- (slot-value (exwm-workspace--workarea - exwm-workspace-current-index) - 'height) - exwm-workspace--frame-y-offset - exwm-systemtray-height)))) - (exwm-systemtray--refresh-background-color) - (exwm-systemtray--refresh)) - -(defun exwm-systemtray--on-theme-change (_theme) - "Refresh system tray upon theme change." - (exwm-systemtray--refresh-background-color 'remap)) - -(defun exwm-systemtray--refresh-all () - "Reposition/Refresh the system tray." - (exwm--log) - (unless (exwm-workspace--minibuffer-own-frame-p) - (exwm-workspace--update-offsets) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ConfigureWindow - :window exwm-systemtray--embedder-window - :value-mask xcb:ConfigWindow:Y - :y (- (slot-value (exwm-workspace--workarea - exwm-workspace-current-index) - 'height) - exwm-workspace--frame-y-offset - exwm-systemtray-height)))) - (exwm-systemtray--refresh)) - -(cl-defun exwm-systemtray--init () - "Initialize system tray module." - (exwm--log) - (cl-assert (not exwm-systemtray--connection)) - (cl-assert (not exwm-systemtray--list)) - (cl-assert (not exwm-systemtray--selection-owner-window)) - (cl-assert (not exwm-systemtray--embedder-window)) - (unless exwm-systemtray-height - (setq exwm-systemtray-height (max exwm-systemtray--icon-min-size - (with-selected-window (minibuffer-window) - (line-pixel-height))))) - ;; Create a new connection. - (setq exwm-systemtray--connection (xcb:connect)) - (set-process-query-on-exit-flag (slot-value exwm-systemtray--connection - 'process) - nil) - ;; Initialize XELB modules. - (xcb:xembed:init exwm-systemtray--connection t) - (xcb:systemtray:init exwm-systemtray--connection t) - ;; Acquire the manager selection _NET_SYSTEM_TRAY_S0. - (with-slots (owner) - (xcb:+request-unchecked+reply exwm-systemtray--connection - (make-instance 'xcb:GetSelectionOwner - :selection xcb:Atom:_NET_SYSTEM_TRAY_S0)) - (when (/= owner xcb:Window:None) - (xcb:disconnect exwm-systemtray--connection) - (setq exwm-systemtray--connection nil) - (warn "[EXWM] Other system tray detected") - (cl-return-from exwm-systemtray--init))) - (let ((id (xcb:generate-id exwm-systemtray--connection))) - (setq exwm-systemtray--selection-owner-window id) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:CreateWindow - :depth 0 - :wid id - :parent exwm--root - :x 0 - :y 0 - :width 1 - :height 1 - :border-width 0 - :class xcb:WindowClass:InputOnly - :visual 0 - :value-mask xcb:CW:OverrideRedirect - :override-redirect 1)) - ;; Get the selection ownership. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:SetSelectionOwner - :owner id - :selection xcb:Atom:_NET_SYSTEM_TRAY_S0 - :time xcb:Time:CurrentTime)) - ;; Send a client message to announce the selection. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:SendEvent - :propagate 0 - :destination exwm--root - :event-mask xcb:EventMask:StructureNotify - :event (xcb:marshal - (make-instance 'xcb:icccm:-ManagerSelection - :window exwm--root - :time xcb:Time:CurrentTime - :selection - xcb:Atom:_NET_SYSTEM_TRAY_S0 - :owner id) - exwm-systemtray--connection))) - ;; Set _NET_WM_NAME. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window id - :data "EXWM: exwm-systemtray--selection-owner-window")) - ;; Set the _NET_SYSTEM_TRAY_ORIENTATION property. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:xembed:set-_NET_SYSTEM_TRAY_ORIENTATION - :window id - :data xcb:systemtray:ORIENTATION:HORZ))) - ;; Create the embedder. - (let ((id (xcb:generate-id exwm-systemtray--connection)) - frame parent embedder-depth embedder-visual embedder-colormap y) - (setq exwm-systemtray--embedder-window id) - (if (exwm-workspace--minibuffer-own-frame-p) - (setq frame exwm-workspace--minibuffer - y (if (>= (line-pixel-height) exwm-systemtray-height) - ;; Bottom aligned. - (- (line-pixel-height) exwm-systemtray-height) - ;; Vertically centered. - (/ (- (line-pixel-height) exwm-systemtray-height) 2))) - (exwm-workspace--update-offsets) - (setq frame exwm-workspace--current - ;; Bottom aligned. - y (- (slot-value (exwm-workspace--workarea - exwm-workspace-current-index) - 'height) - exwm-workspace--frame-y-offset - exwm-systemtray-height))) - (setq parent (string-to-number (frame-parameter frame 'window-id))) - ;; Use default depth, visual and colormap (from root window), instead of - ;; Emacs frame's. See Section "Visual and background pixmap handling" in - ;; "System Tray Protocol Specification 0.3". - (let* ((vdc (exwm--get-visual-depth-colormap exwm-systemtray--connection - exwm--root))) - (setq embedder-visual (car vdc)) - (setq embedder-depth (cadr vdc)) - (setq embedder-colormap (caddr vdc))) - ;; Note down the embedder window's depth. It will be used to check whether - ;; we can use xcb:BackPixmap:ParentRelative to emulate transparency. - (setq exwm-systemtray--embedder-window-depth embedder-depth) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:CreateWindow - :depth embedder-depth - :wid id - :parent parent - :x 0 - :y y - :width 1 - :height exwm-systemtray-height - :border-width 0 - :class xcb:WindowClass:InputOutput - :visual embedder-visual - :colormap embedder-colormap - :value-mask (logior xcb:CW:BorderPixel - xcb:CW:Colormap - xcb:CW:EventMask) - :border-pixel 0 - :event-mask xcb:EventMask:SubstructureNotify)) - (exwm-systemtray--set-background-color) - ;; Set _NET_WM_NAME. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window id - :data "EXWM: exwm-systemtray--embedder-window")) - ;; Set _NET_WM_WINDOW_TYPE. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ewmh:set-_NET_WM_WINDOW_TYPE - :window id - :data (vector xcb:Atom:_NET_WM_WINDOW_TYPE_DOCK))) - ;; Set _NET_SYSTEM_TRAY_VISUAL. - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:xembed:set-_NET_SYSTEM_TRAY_VISUAL - :window exwm-systemtray--selection-owner-window - :data embedder-visual))) - (xcb:flush exwm-systemtray--connection) - ;; Attach event listeners. - (xcb:+event exwm-systemtray--connection 'xcb:DestroyNotify - #'exwm-systemtray--on-DestroyNotify) - (xcb:+event exwm-systemtray--connection 'xcb:ReparentNotify - #'exwm-systemtray--on-ReparentNotify) - (xcb:+event exwm-systemtray--connection 'xcb:ResizeRequest - #'exwm-systemtray--on-ResizeRequest) - (xcb:+event exwm-systemtray--connection 'xcb:PropertyNotify - #'exwm-systemtray--on-PropertyNotify) - (xcb:+event exwm-systemtray--connection 'xcb:ClientMessage - #'exwm-systemtray--on-ClientMessage) - (unless (exwm-workspace--minibuffer-own-frame-p) - (xcb:+event exwm-systemtray--connection 'xcb:KeyPress - #'exwm-systemtray--on-KeyPress)) - ;; Add hook to move/reparent the embedder. - (add-hook 'exwm-workspace-switch-hook #'exwm-systemtray--on-workspace-switch) - (add-hook 'exwm-workspace--update-workareas-hook - #'exwm-systemtray--refresh-all) - ;; Add hook to update background colors. - (add-hook 'enable-theme-functions #'exwm-systemtray--on-theme-change) - (add-hook 'disable-theme-functions #'exwm-systemtray--on-theme-change) - (add-hook 'menu-bar-mode-hook #'exwm-systemtray--refresh-all) - (add-hook 'tool-bar-mode-hook #'exwm-systemtray--refresh-all) - (when (boundp 'exwm-randr-refresh-hook) - (add-hook 'exwm-randr-refresh-hook #'exwm-systemtray--refresh-all)) - ;; The struts can be updated already. - (when exwm-workspace--workareas - (exwm-systemtray--refresh-all))) - -(defun exwm-systemtray--exit () - "Exit the systemtray module." - (exwm--log) - (when exwm-systemtray--connection - (when (slot-value exwm-systemtray--connection 'connected) - ;; Hide & reparent out the embedder before disconnection to prevent - ;; embedded icons from being reparented to an Emacs frame (which is the - ;; parent of the embedder). - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:UnmapWindow - :window exwm-systemtray--embedder-window)) - (xcb:+request exwm-systemtray--connection - (make-instance 'xcb:ReparentWindow - :window exwm-systemtray--embedder-window - :parent exwm--root - :x 0 - :y 0)) - (xcb:disconnect exwm-systemtray--connection)) - (setq exwm-systemtray--connection nil - exwm-systemtray--list nil - exwm-systemtray--selection-owner-window nil - exwm-systemtray--embedder-window nil - exwm-systemtray--embedder-window-depth nil) - (remove-hook 'exwm-workspace-switch-hook - #'exwm-systemtray--on-workspace-switch) - (remove-hook 'exwm-workspace--update-workareas-hook - #'exwm-systemtray--refresh-all) - (remove-hook 'enable-theme-functions #'exwm-systemtray--on-theme-change) - (remove-hook 'disable-theme-functions #'exwm-systemtray--on-theme-change) - (remove-hook 'menu-bar-mode-hook #'exwm-systemtray--refresh-all) - (remove-hook 'tool-bar-mode-hook #'exwm-systemtray--refresh-all) - (when (boundp 'exwm-randr-refresh-hook) - (remove-hook 'exwm-randr-refresh-hook #'exwm-systemtray--refresh-all)))) - -(defun exwm-systemtray-enable () - "Enable system tray support for EXWM." - (exwm--log) - (add-hook 'exwm-init-hook #'exwm-systemtray--init) - (add-hook 'exwm-exit-hook #'exwm-systemtray--exit)) - - - -(provide 'exwm-systemtray) - -;;; exwm-systemtray.el ends here diff --git a/third_party/exwm/exwm-workspace.el b/third_party/exwm/exwm-workspace.el deleted file mode 100644 index 9337dc08a..000000000 --- a/third_party/exwm/exwm-workspace.el +++ /dev/null @@ -1,1766 +0,0 @@ -;;; exwm-workspace.el --- Workspace Module for EXWM -*- lexical-binding: t -*- - -;; Copyright (C) 1015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module adds workspace support for EXWM. - -;;; Code: - -(require 'server) - -(require 'exwm-core) - -(defgroup exwm-workspace nil - "Workspace." - :group 'exwm) - -(defcustom exwm-workspace-switch-hook nil - "Normal hook run after switching workspace." - :type 'hook) - -(defcustom exwm-workspace-list-change-hook nil - "Normal hook run when the workspace list is changed. -This happens when a workspace is added, deleted, moved, etc." - :type 'hook) - -(defcustom exwm-workspace-show-all-buffers nil - "Non-nil to show buffers on other workspaces." - :type 'boolean) - -(defcustom exwm-workspace-warp-cursor nil - "Non-nil to warp cursor automatically after workspace switch." - :type 'boolean) - -(defcustom exwm-workspace-number 1 - "Initial number of workspaces." - :type 'integer) - -(defcustom exwm-workspace-index-map #'number-to-string - "Function for mapping a workspace index to a string for display. - -By default `number-to-string' is applied which yields 0 1 2 ... ." - :type 'function) - -(defcustom exwm-workspace-minibuffer-position nil - "Position of the minibuffer frame. - -A restart is required for this change to take effect." - :type '(choice (const :tag "Bottom (fixed)" nil) - (const :tag "Bottom (auto-hide)" bottom) - (const :tag "Top (auto-hide)" top))) - -(defcustom exwm-workspace-display-echo-area-timeout 1 - "Timeout for displaying echo area." - :type 'integer) - -(defcustom exwm-workspace-switch-create-limit 10 - "Number of workspaces `exwm-workspace-switch-create' is allowed to create." - :type 'integer) - -(defvar exwm-workspace-current-index 0 "Index of current active workspace.") - -(defvar exwm-workspace--attached-minibuffer-height 0 - "Height (in pixel) of the attached minibuffer. - -If the minibuffer is detached, this value is 0.") - -(defvar exwm-workspace--create-silently nil - "When non-nil workspaces are created in the background (not switched to). - -Please manually run the hook `exwm-workspace-list-change-hook' afterwards.") - -(defvar exwm-workspace--current nil "Current active workspace.") - -(defvar exwm-workspace--display-echo-area-timer nil - "Timer for auto-hiding echo area.") - -(defvar exwm-workspace--id-struts-alist nil "Alist of X window and struts.") - -(defvar exwm-workspace--fullscreen-frame-count 0 - "Count the fullscreen workspace frames.") - -(defvar exwm-workspace--list nil "List of all workspaces (Emacs frames).") - -(defvar exwm-workspace--minibuffer nil - "The minibuffer frame shared among all frames.") - -(defvar exwm-workspace--original-handle-focus-in - (symbol-function #'handle-focus-in)) -(defvar exwm-workspace--original-handle-focus-out - (symbol-function #'handle-focus-out)) - -(defvar exwm-workspace--prompt-add-allowed nil - "Non-nil to allow adding workspace from the prompt.") - -(defvar exwm-workspace--prompt-delete-allowed nil - "Non-nil to allow deleting workspace from the prompt.") - -(defvar exwm-workspace--struts nil "Areas occupied by struts.") - -(defvar exwm-workspace--switch-history nil - "History for `read-from-minibuffer' to interactively switch workspace.") - -(defvar exwm-workspace--switch-history-outdated nil - "Non-nil to indicate `exwm-workspace--switch-history' is outdated.") - -(defvar exwm-workspace--timer nil "Timer used to track echo area changes.") - -(defvar exwm-workspace--update-workareas-hook nil - "Normal hook run when workareas get updated.") - -(defvar exwm-workspace--workareas nil "Workareas (struts excluded).") - -(defvar exwm-workspace--frame-y-offset 0 - "Offset between Emacs inner & outer frame in Y.") -(defvar exwm-workspace--window-y-offset 0 - "Offset between Emacs first window & outer frame in Y.") - -(defvar exwm-input--during-command) -(defvar exwm-input--event-hook) -(defvar exwm-layout-show-all-buffers) -(defvar exwm-manage--desktop) -(declare-function exwm-input--on-buffer-list-update "exwm-input.el" ()) -(declare-function exwm-layout--fullscreen-p "exwm-layout.el" ()) -(declare-function exwm-layout--hide "exwm-layout.el" (id)) -(declare-function exwm-layout--other-buffer-predicate "exwm-layout.el" - (buffer)) -(declare-function exwm-layout--refresh "exwm-layout.el") -(declare-function exwm-layout--show "exwm-layout.el" (id &optional window)) - -(defsubst exwm-workspace--position (frame) - "Retrieve index of given FRAME in workspace list. -NIL if FRAME is not a workspace." - (declare (indent defun)) - (cl-position frame exwm-workspace--list)) - -(defsubst exwm-workspace--count () - "Retrieve total number of workspaces." - (length exwm-workspace--list)) - -(defsubst exwm-workspace--workspace-p (frame) - "Return t if FRAME is a workspace." - (declare (indent defun)) - (memq frame exwm-workspace--list)) - -(defsubst exwm-workspace--workarea (frame) - "Return workarea corresponding to FRAME. -FRAME may be either a workspace frame or a workspace position." - (declare (indent defun)) - (elt exwm-workspace--workareas - (if (integerp frame) - frame - (exwm-workspace--position frame)))) - -(defvar exwm-workspace--switch-map nil - "Keymap used for interactively selecting workspace.") - -(defun exwm-workspace--init-switch-map () - "Initialize variable `exwm-workspace--switch-map'." - (let ((map (make-sparse-keymap))) - (define-key map [t] (lambda () (interactive))) - (define-key map "+" #'exwm-workspace--prompt-add) - (define-key map "-" #'exwm-workspace--prompt-delete) - (dotimes (i 10) - (define-key map (int-to-string i) - #'exwm-workspace--switch-map-nth-prefix)) - (unless (eq exwm-workspace-index-map #'number-to-string) - ;; Add extra (and possibly override) keys for selecting workspace. - (dotimes (i 10) - (let ((key (funcall exwm-workspace-index-map i))) - (when (and (stringp key) - (= (length key) 1) - (<= 0 (elt key 0) 127)) - (define-key map key - (lambda () - (interactive) - (exwm-workspace--switch-map-select-nth i))))))) - (define-key map "\C-a" (lambda () (interactive) (goto-history-element 1))) - (define-key map "\C-e" (lambda () - (interactive) - (goto-history-element (exwm-workspace--count)))) - (define-key map "\C-g" #'abort-recursive-edit) - (define-key map "\C-]" #'abort-recursive-edit) - (define-key map "\C-j" #'exit-minibuffer) - ;; (define-key map "\C-m" #'exit-minibuffer) ;not working - (define-key map [return] #'exit-minibuffer) - (define-key map " " #'exit-minibuffer) - (define-key map "\C-f" #'previous-history-element) - (define-key map "\C-b" #'next-history-element) - ;; Alternative keys - (define-key map [right] #'previous-history-element) - (define-key map [left] #'next-history-element) - (setq exwm-workspace--switch-map map))) - -(defun exwm-workspace--workspace-from-frame-or-index (frame-or-index) - "Retrieve the workspace frame from FRAME-OR-INDEX." - (cond - ((framep frame-or-index) - (unless (exwm-workspace--position frame-or-index) - (user-error "[EXWM] Frame is not a workspace %S" frame-or-index)) - frame-or-index) - ((integerp frame-or-index) - (unless (and (<= 0 frame-or-index) - (< frame-or-index (exwm-workspace--count))) - (user-error "[EXWM] Workspace index out of range: %d" frame-or-index)) - (elt exwm-workspace--list frame-or-index)) - (t (user-error "[EXWM] Invalid workspace: %s" frame-or-index)))) - -(defun exwm-workspace--prompt-for-workspace (&optional prompt) - "Prompt for a workspace, returning the workspace frame. -Show PROMPT to the user if non-nil." - (exwm-workspace--update-switch-history) - (let* ((current-idx (exwm-workspace--position exwm-workspace--current)) - (history-add-new-input nil) ;prevent modifying history - (history-idx (read-from-minibuffer - (or prompt "Workspace: ") - (elt exwm-workspace--switch-history current-idx) - exwm-workspace--switch-map nil - `(exwm-workspace--switch-history . ,(1+ current-idx)))) - (workspace-idx (cl-position history-idx exwm-workspace--switch-history - :test #'equal))) - (elt exwm-workspace--list workspace-idx))) - -(defun exwm-workspace--prompt-add () - "Add workspace from the prompt." - (interactive) - (when exwm-workspace--prompt-add-allowed - (let ((exwm-workspace--create-silently t)) - (make-frame) - (run-hooks 'exwm-workspace-list-change-hook)) - (exwm-workspace--update-switch-history) - (goto-history-element minibuffer-history-position))) - -(defun exwm-workspace--prompt-delete () - "Delete workspace from the prompt." - (interactive) - (when (and exwm-workspace--prompt-delete-allowed - (< 1 (exwm-workspace--count))) - (let ((frame (elt exwm-workspace--list (1- minibuffer-history-position)))) - (if (eq frame exwm-workspace--current) - ;; Abort the recursive minibuffer if deleting the current workspace. - (progn - (exwm--defer 0 #'delete-frame frame) - (abort-recursive-edit)) - (delete-frame frame) - (exwm-workspace--update-switch-history) - (goto-history-element (min minibuffer-history-position - (exwm-workspace--count))))))) - -(defun exwm-workspace--update-switch-history () - "Update the history for switching workspace to reflect the latest status." - (when exwm-workspace--switch-history-outdated - (setq exwm-workspace--switch-history-outdated nil) - (let* ((num (exwm-workspace--count)) - (sequence (number-sequence 0 (1- num))) - (not-empty (make-vector num nil))) - (dolist (i exwm--id-buffer-alist) - (with-current-buffer (cdr i) - (when exwm--frame - (setf (aref not-empty - (exwm-workspace--position exwm--frame)) - t)))) - (setq exwm-workspace--switch-history - (mapcar - (lambda (i) - (mapconcat - (lambda (j) - (format (if (= i j) "[%s]" " %s ") - (propertize - (apply exwm-workspace-index-map (list j)) - 'face - (cond ((frame-parameter (elt exwm-workspace--list j) - 'exwm-urgency) - '(:foreground "orange")) - ((aref not-empty j) '(:foreground "green")) - (t nil))))) - sequence "")) - sequence))))) - -;;;###autoload -(defun exwm-workspace--get-geometry (frame) - "Return the geometry of frame FRAME." - (or (frame-parameter frame 'exwm-geometry) - (make-instance 'xcb:RECTANGLE - :x 0 - :y 0 - :width (x-display-pixel-width) - :height (x-display-pixel-height)))) - -;;;###autoload -(defun exwm-workspace--current-height () - "Return the height of current workspace." - (let ((geometry (frame-parameter exwm-workspace--current 'exwm-geometry))) - (if geometry - (slot-value geometry 'height) - (x-display-pixel-height)))) - -;;;###autoload -(defun exwm-workspace--minibuffer-own-frame-p () - "Reports whether the minibuffer is displayed in its own frame." - (memq exwm-workspace-minibuffer-position '(top bottom))) - -(defun exwm-workspace--update-struts () - "Update `exwm-workspace--struts'." - (setq exwm-workspace--struts nil) - (let (struts struts*) - (dolist (pair exwm-workspace--id-struts-alist) - (setq struts (cdr pair)) - (when struts - (dotimes (i 4) - (when (/= 0 (aref struts i)) - (setq struts* - (vector (aref [left right top bottom] i) - (aref struts i) - (when (= 12 (length struts)) - (substring struts (+ 4 (* i 2)) (+ 6 (* i 2)))))) - (if (= 0 (mod i 2)) - ;; Make left/top processed first. - (push struts* exwm-workspace--struts) - (setq exwm-workspace--struts - (append exwm-workspace--struts (list struts*)))))))) - (exwm--log "%s" exwm-workspace--struts))) - -(defun exwm-workspace--update-workareas () - "Update `exwm-workspace--workareas'." - (let* ((root-width (x-display-pixel-width)) - (root-height (x-display-pixel-height)) - ;; Get workareas prior to struts. - (workareas (mapcar - (lambda (frame) - (if-let (rect (frame-parameter frame 'exwm-geometry)) - ;; Use the 'exwm-geometry' frame parameter if it - ;; exists. Make sure to clone it, will be modified - ;; below! - (clone rect) - ;; Fall back to use the screen size. - (make-instance 'xcb:RECTANGLE - :x 0 - :y 0 - :width root-width - :height root-height))) - exwm-workspace--list))) - ;; Exclude areas occupied by struts. - (dolist (struts exwm-workspace--struts) - (let* ((edge (aref struts 0)) - (size (aref struts 1)) - (position (aref struts 2)) - (beg (and position (aref position 0))) - (end (and position (aref position 1))) - delta) - (dolist (w workareas) - (with-slots (x y width height) w - (pcase edge - ;; Left and top are always processed first. - ('left - (setq delta (- size x)) - (when (and (< 0 delta) - (< delta width) - (or (not position) - (< (max beg y) - (min end (+ y height))))) - (cl-decf width delta) - (setf x size))) - ('right - (setq delta (- size (- root-width x width))) - (when (and (< 0 delta) - (< delta width) - (or (not position) - (< (max beg y) - (min end (+ y height))))) - (cl-decf width delta))) - ('top - (setq delta (- size y)) - (when (and (< 0 delta) - (< delta height) - (or (not position) - (< (max beg x) - (min end (+ x width))))) - (cl-decf height delta) - (setf y size))) - ('bottom - (setq delta (- size (- root-height y height))) - (when (and (< 0 delta) - (< delta height) - (or (not position) - (< (max beg x) - (min end (+ x width))))) - (cl-decf height delta)))))))) - ;; Save the result. - (setq exwm-workspace--workareas workareas) - (xcb:flush exwm--connection)) - (exwm--log "%s" exwm-workspace--workareas) - (run-hooks 'exwm-workspace--update-workareas-hook)) - -(defun exwm-workspace--update-offsets () - "Update `exwm-workspace--frame-y-offset'/`exwm-workspace--window-y-offset'." - (exwm--log) - (if (not (and exwm-workspace--list - (or menu-bar-mode tool-bar-mode))) - (setq exwm-workspace--frame-y-offset 0 - exwm-workspace--window-y-offset 0) - (redisplay t) - (let* ((frame (elt exwm-workspace--list 0)) - (edges (window-inside-absolute-pixel-edges (frame-first-window - frame)))) - (with-slots (y) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry - :drawable (frame-parameter frame - 'exwm-container))) - (with-slots ((y* y)) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry - :drawable (frame-parameter frame - 'exwm-outer-id))) - (with-slots ((y** y)) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry - :drawable (frame-parameter frame 'exwm-id))) - (setq exwm-workspace--frame-y-offset (- y** y*) - exwm-workspace--window-y-offset (- (elt edges 1) y)))))))) - -(defun exwm-workspace--set-active (frame active) - "Make frame FRAME active on its monitor. -ACTIVE indicates whether to set the frame active or inactive." - (exwm--log "active=%s; frame=%s" active frame) - (set-frame-parameter frame 'exwm-active active) - (if active - (exwm-workspace--set-fullscreen frame) - (exwm--set-geometry (frame-parameter frame 'exwm-container) nil nil 1 1)) - (exwm-layout--refresh frame) - (xcb:flush exwm--connection)) - -(defun exwm-workspace--active-p (frame) - "Return non-nil if FRAME is active." - (frame-parameter frame 'exwm-active)) - -(defun exwm-workspace--set-fullscreen (frame) - "Make frame FRAME fullscreen according to `exwm-workspace--workareas'." - (exwm--log "frame=%s" frame) - (let ((id (frame-parameter frame 'exwm-outer-id)) - (container (frame-parameter frame 'exwm-container))) - (with-slots (x y width height) - (exwm-workspace--workarea frame) - (exwm--log "x=%s; y=%s; w=%s; h=%s" x y width height) - (when (and (eq frame exwm-workspace--current) - (exwm-workspace--minibuffer-own-frame-p)) - (exwm-workspace--resize-minibuffer-frame)) - (if (exwm-workspace--active-p frame) - (exwm--set-geometry container x y width height) - (exwm--set-geometry container x y 1 1)) - (exwm--set-geometry id nil nil width height) - (xcb:flush exwm--connection))) - ;; This is only used for workspace initialization. - (when exwm-workspace--fullscreen-frame-count - (cl-incf exwm-workspace--fullscreen-frame-count))) - -(defun exwm-workspace--resize-minibuffer-frame () - "Resize minibuffer (and its container) to fit the size of workspace." - (cl-assert (exwm-workspace--minibuffer-own-frame-p)) - (let ((workarea (exwm-workspace--workarea exwm-workspace-current-index)) - (container (frame-parameter exwm-workspace--minibuffer - 'exwm-container)) - y width) - (setq y (if (eq exwm-workspace-minibuffer-position 'top) - (- (slot-value workarea 'y) - exwm-workspace--attached-minibuffer-height) - ;; Reset the frame size. - (set-frame-height exwm-workspace--minibuffer 1) - (redisplay) ;FIXME. - (+ (slot-value workarea 'y) (slot-value workarea 'height) - (- (frame-pixel-height exwm-workspace--minibuffer)) - exwm-workspace--attached-minibuffer-height)) - width (slot-value workarea 'width)) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window container - :value-mask (logior xcb:ConfigWindow:X - xcb:ConfigWindow:Y - xcb:ConfigWindow:Width - (if exwm-manage--desktop - xcb:ConfigWindow:Sibling - 0) - xcb:ConfigWindow:StackMode) - :x (slot-value workarea 'x) - :y y - :width width - :sibling exwm-manage--desktop - :stack-mode (if exwm-manage--desktop - xcb:StackMode:Above - xcb:StackMode:Below))) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm-workspace--minibuffer - 'exwm-outer-id) - :value-mask xcb:ConfigWindow:Width - :width width)) - (exwm--log "y: %s, width: %s" y width))) - -(defun exwm-workspace--switch-map-nth-prefix (&optional prefix-digits) - "Allow selecting a workspace by number. - -PREFIX-DIGITS is a list of the digits introduced so far." - (interactive) - (let* ((k (aref (substring (this-command-keys-vector) -1) 0)) - (d (- k ?0)) - ;; Convert prefix-digits to number. For example, '(2 1) to 120. - (o 1) - (pn (apply #'+ (mapcar (lambda (x) - (setq o (* 10 o)) - (* o x)) - prefix-digits))) - (n (+ pn d)) - prefix-length index-max index-length) - (if (or (= n 0) - (> n - (setq index-max (1- (exwm-workspace--count)))) - (>= (setq prefix-length (length prefix-digits)) - (setq index-length (floor (log index-max 10)))) - ;; Check if it's still possible to do a match. - (> (* n (expt 10 (- index-length prefix-length))) - index-max)) - (exwm-workspace--switch-map-select-nth n) - ;; Go ahead if there are enough digits to select any workspace. - (set-transient-map - (let ((map (make-sparse-keymap)) - (cmd (let ((digits (cons d prefix-digits))) - (lambda () - (interactive) - (exwm-workspace--switch-map-nth-prefix digits))))) - (dotimes (i 10) - (define-key map (int-to-string i) cmd)) - ;; Accept - (define-key map [return] - (lambda () - (interactive) - (exwm-workspace--switch-map-select-nth n))) - map))))) - -(defun exwm-workspace--switch-map-select-nth (n) - "Select Nth workspace." - (interactive) - (goto-history-element (1+ n)) - (exit-minibuffer)) - -;;;###autoload -(defun exwm-workspace-switch (frame-or-index &optional force) - "Switch to workspace FRAME-OR-INDEX (0-based). - -Query for the index if not specified when called interactively. Passing a -workspace frame as the first option or making use of the rest options are -for internal use only. - -When FORCE is true, allow switching to current workspace." - (interactive - (list - (cond - ((null current-prefix-arg) - (unless (and (derived-mode-p 'exwm-mode) - ;; The prompt is invisible in fullscreen mode. - (exwm-layout--fullscreen-p)) - (let ((exwm-workspace--prompt-add-allowed t) - (exwm-workspace--prompt-delete-allowed t)) - (exwm-workspace--prompt-for-workspace "Switch to [+/-]: ")))) - ((and (integerp current-prefix-arg) - (<= 0 current-prefix-arg (exwm-workspace--count))) - current-prefix-arg) - (t 0)))) - (exwm--log) - (let* ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index)) - (old-frame exwm-workspace--current) - (index (exwm-workspace--position frame)) - (window (frame-parameter frame 'exwm-selected-window))) - (when (or force (not (eq frame exwm-workspace--current))) - (unless (window-live-p window) - (setq window (frame-selected-window frame))) - (when (and (not (eq frame old-frame)) - (frame-live-p old-frame)) - (with-selected-frame old-frame - (funcall exwm-workspace--original-handle-focus-out - (list 'focus-out frame)))) - ;; Raise this frame. - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter frame 'exwm-container) - :value-mask (logior xcb:ConfigWindow:Sibling - xcb:ConfigWindow:StackMode) - :sibling exwm--guide-window - :stack-mode xcb:StackMode:Below)) - (setq exwm-workspace--current frame - exwm-workspace-current-index index) - (unless (exwm-workspace--workspace-p (selected-frame)) - ;; Save the floating frame window selected on the previous workspace. - (set-frame-parameter (buffer-local-value 'exwm--frame (window-buffer)) - 'exwm-selected-window (selected-window))) - ;; Show/Hide X windows. - (let ((monitor-old (frame-parameter old-frame 'exwm-randr-monitor)) - (monitor-new (frame-parameter frame 'exwm-randr-monitor)) - (active-old (exwm-workspace--active-p old-frame)) - (active-new (exwm-workspace--active-p frame)) - workspaces-to-hide) - (cond - ((not active-old) - (exwm-workspace--set-active frame t)) - ((equal monitor-old monitor-new) - (exwm-workspace--set-active frame t) - (unless (eq frame old-frame) - (exwm-workspace--set-active old-frame nil) - (setq workspaces-to-hide (list old-frame)))) - (active-new) - (t - (dolist (w exwm-workspace--list) - (when (and (exwm-workspace--active-p w) - (equal monitor-new - (frame-parameter w 'exwm-randr-monitor))) - (exwm-workspace--set-active w nil) - (setq workspaces-to-hide (append workspaces-to-hide (list w))))) - (exwm-workspace--set-active frame t))) - (dolist (i exwm--id-buffer-alist) - (with-current-buffer (cdr i) - (if (memq exwm--frame workspaces-to-hide) - (exwm-layout--hide exwm--id) - (when (eq frame exwm--frame) - (let ((window (get-buffer-window nil t))) - (when window - (exwm-layout--show exwm--id window)))))))) - (select-window window) - (x-focus-frame (window-frame window)) ;The real input focus. - (set-frame-parameter frame 'exwm-selected-window nil) - (if (exwm-workspace--minibuffer-own-frame-p) - ;; Resize the minibuffer frame. - (exwm-workspace--resize-minibuffer-frame) - ;; Set a default minibuffer frame. - (setq default-minibuffer-frame frame)) - ;; Hide windows in other workspaces by preprending a space - (unless exwm-workspace-show-all-buffers - (dolist (i exwm--id-buffer-alist) - (with-current-buffer (cdr i) - (let ((name (replace-regexp-in-string "^\\s-*" "" - (buffer-name)))) - (exwm-workspace-rename-buffer (if (eq frame exwm--frame) - name - (concat " " name))))))) - ;; Update demands attention flag - (set-frame-parameter frame 'exwm-urgency nil) - ;; Update switch workspace history - (setq exwm-workspace--switch-history-outdated t) - ;; Set _NET_CURRENT_DESKTOP - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_CURRENT_DESKTOP - :window exwm--root :data index)) - (xcb:flush exwm--connection)) - (when exwm-workspace-warp-cursor - (with-slots (win-x win-y) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:QueryPointer - :window (frame-parameter frame - 'exwm-outer-id))) - (when (or (< win-x 0) - (< win-y 0) - (> win-x (frame-pixel-width frame)) - (> win-y (frame-pixel-height frame))) - (xcb:+request exwm--connection - (make-instance 'xcb:WarpPointer - :src-window xcb:Window:None - :dst-window (frame-parameter frame - 'exwm-outer-id) - :src-x 0 - :src-y 0 - :src-width 0 - :src-height 0 - :dst-x (/ (frame-pixel-width frame) 2) - :dst-y (/ (frame-pixel-height frame) 2))) - (xcb:flush exwm--connection)))) - (funcall exwm-workspace--original-handle-focus-in (list 'focus-in frame)) - (run-hooks 'exwm-workspace-switch-hook))) - -;;;###autoload -(defun exwm-workspace-switch-create (frame-or-index) - "Switch to workspace FRAME-OR-INDEX creating it first non-existent. - -Passing a workspace frame as the first option is for internal use only." - (interactive - (list - (cond - ((integerp current-prefix-arg) - current-prefix-arg) - (t 0)))) - (unless frame-or-index - (setq frame-or-index 0)) - (exwm--log "%s" frame-or-index) - (if (or (framep frame-or-index) - (< frame-or-index (exwm-workspace--count))) - (exwm-workspace-switch frame-or-index) - (let ((exwm-workspace--create-silently t)) - (dotimes (_ (min exwm-workspace-switch-create-limit - (1+ (- frame-or-index - (exwm-workspace--count))))) - (make-frame)) - (run-hooks 'exwm-workspace-list-change-hook)) - (exwm-workspace-switch frame-or-index))) - -;;;###autoload -(defun exwm-workspace-swap (workspace1 workspace2) - "Interchange position of WORKSPACE1 with that of WORKSPACE2." - (interactive - (unless (and (derived-mode-p 'exwm-mode) - ;; The prompt is invisible in fullscreen mode. - (exwm-layout--fullscreen-p)) - (let (w1 w2) - (let ((exwm-workspace--prompt-add-allowed t) - (exwm-workspace--prompt-delete-allowed t)) - (setq w1 (exwm-workspace--prompt-for-workspace - "Pick a workspace [+/-]: "))) - (setq w2 (exwm-workspace--prompt-for-workspace - (format "Swap workspace %d with: " - (exwm-workspace--position w1)))) - (list w1 w2)))) - (exwm--log) - (let ((pos1 (exwm-workspace--position workspace1)) - (pos2 (exwm-workspace--position workspace2))) - (if (or (not pos1) (not pos2) (= pos1 pos2)) - (user-error "[EXWM] Cannot swap %s and %s" workspace1 workspace2) - (setf (elt exwm-workspace--list pos1) workspace2) - (setf (elt exwm-workspace--list pos2) workspace1) - ;; Update the _NET_WM_DESKTOP property of each X window affected. - (dolist (pair exwm--id-buffer-alist) - (when (memq (buffer-local-value 'exwm--frame (cdr pair)) - (list workspace1 workspace2)) - (exwm-workspace--set-desktop (car pair)))) - (xcb:flush exwm--connection) - (when (memq exwm-workspace--current (list workspace1 workspace2)) - ;; With the current workspace involved, lots of stuffs need refresh. - (set-frame-parameter exwm-workspace--current 'exwm-selected-window - (selected-window)) - (exwm-workspace-switch exwm-workspace--current t)) - (run-hooks 'exwm-workspace-list-change-hook)))) - -;;;###autoload -(defun exwm-workspace-move (workspace nth) - "Move WORKSPACE to the NTH position. - -When called interactively, prompt for a workspace and move current one just -before it." - (interactive - (cond - ((null current-prefix-arg) - (unless (and (derived-mode-p 'exwm-mode) - ;; The prompt is invisible in fullscreen mode. - (exwm-layout--fullscreen-p)) - (list exwm-workspace--current - (exwm-workspace--position - (exwm-workspace--prompt-for-workspace "Move workspace to: "))))) - ((and (integerp current-prefix-arg) - (<= 0 current-prefix-arg (exwm-workspace--count))) - (list exwm-workspace--current current-prefix-arg)) - (t (list exwm-workspace--current 0)))) - (exwm--log) - (let ((pos (exwm-workspace--position workspace)) - flag start end index) - (if (= nth pos) - (user-error "[EXWM] Cannot move to same position") - ;; Set if the current workspace is involved. - (setq flag (or (eq workspace exwm-workspace--current) - (eq (elt exwm-workspace--list nth) - exwm-workspace--current))) - ;; Do the move. - (with-no-warnings ;For Emacs 24. - (pop (nthcdr pos exwm-workspace--list))) - (push workspace (nthcdr nth exwm-workspace--list)) - ;; Update the _NET_WM_DESKTOP property of each X window affected. - (setq start (min pos nth) - end (max pos nth)) - (dolist (pair exwm--id-buffer-alist) - (setq index (exwm-workspace--position - (buffer-local-value 'exwm--frame (cdr pair)))) - (unless (or (< index start) (> index end)) - (exwm-workspace--set-desktop (car pair)))) - (when flag - ;; With the current workspace involved, lots of stuffs need refresh. - (set-frame-parameter exwm-workspace--current 'exwm-selected-window - (selected-window)) - (exwm-workspace-switch exwm-workspace--current t)) - (run-hooks 'exwm-workspace-list-change-hook)))) - -;;;###autoload -(defun exwm-workspace-add (&optional index) - "Add a workspace as the INDEX-th workspace, or the last one if INDEX is nil. - -INDEX must not exceed the current number of workspaces." - (interactive) - (exwm--log "%s" index) - (if (and index - ;; No need to move if it's the last one. - (< index (exwm-workspace--count))) - (exwm-workspace-move (make-frame) index) - (make-frame))) - -;;;###autoload -(defun exwm-workspace-delete (&optional frame-or-index) - "Delete the workspace FRAME-OR-INDEX." - (interactive) - (exwm--log "%s" frame-or-index) - (when (< 1 (exwm-workspace--count)) - (let ((frame (if frame-or-index - (exwm-workspace--workspace-from-frame-or-index - frame-or-index) - exwm-workspace--current))) - (delete-frame frame)))) - -(defun exwm-workspace--set-desktop (id) - "Set _NET_WM_DESKTOP for X window ID." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (let ((desktop (exwm-workspace--position exwm--frame))) - (setq exwm--desktop desktop) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_DESKTOP - :window id - :data desktop))))) - -;;;###autoload -(cl-defun exwm-workspace-move-window (frame-or-index &optional id) - "Move window ID to workspace FRAME-OR-INDEX." - (interactive (list - (cond - ((null current-prefix-arg) - (let ((exwm-workspace--prompt-add-allowed t) - (exwm-workspace--prompt-delete-allowed t)) - (exwm-workspace--prompt-for-workspace "Move to [+/-]: "))) - ((and (integerp current-prefix-arg) - (<= 0 current-prefix-arg (exwm-workspace--count))) - current-prefix-arg) - (t 0)))) - (let ((frame (exwm-workspace--workspace-from-frame-or-index frame-or-index)) - old-frame container) - (unless id (setq id (exwm--buffer->id (window-buffer)))) - (unless id - (cl-return-from exwm-workspace-move-window)) - (exwm--log "Moving #x%x to %s" id frame-or-index) - (with-current-buffer (exwm--id->buffer id) - (unless (eq exwm--frame frame) - (unless exwm-workspace-show-all-buffers - (let ((name (replace-regexp-in-string "^\\s-*" "" (buffer-name)))) - (exwm-workspace-rename-buffer - (if (eq frame exwm-workspace--current) - name - (concat " " name))))) - (setq old-frame exwm--frame - exwm--frame frame) - (if (not exwm--floating-frame) - ;; Tiling. - (if (get-buffer-window nil frame) - (when (eq frame exwm-workspace--current) - (exwm-layout--refresh frame)) - (set-window-buffer (get-buffer-window nil t) - (other-buffer nil t)) - (unless (eq frame exwm-workspace--current) - ;; Clear the 'exwm-selected-window' frame parameter. - (set-frame-parameter frame 'exwm-selected-window nil)) - (set-window-buffer (frame-selected-window frame) - (exwm--id->buffer id)) - (if (eq frame exwm-workspace--current) - (select-window (frame-selected-window frame)) - (unless (exwm-workspace--active-p frame) - (exwm-layout--hide id)))) - ;; Floating. - (setq container (frame-parameter exwm--floating-frame - 'exwm-container)) - (unless (equal (frame-parameter old-frame 'exwm-randr-monitor) - (frame-parameter frame 'exwm-randr-monitor)) - (with-slots (x y) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry - :drawable container)) - (with-slots ((x1 x) - (y1 y)) - (exwm-workspace--get-geometry old-frame) - (with-slots ((x2 x) - (y2 y)) - (exwm-workspace--get-geometry frame) - (setq x (+ x (- x2 x1)) - y (+ y (- y2 y1))))) - (exwm--set-geometry id x y nil nil) - (exwm--set-geometry container x y nil nil))) - (if (exwm-workspace--minibuffer-own-frame-p) - (if (eq frame exwm-workspace--current) - (select-window (frame-root-window exwm--floating-frame)) - (select-window (frame-selected-window exwm-workspace--current)) - (unless (exwm-workspace--active-p frame) - (exwm-layout--hide id))) - ;; The frame needs to be recreated since it won't use the - ;; minibuffer on the new workspace. - ;; The code is mostly copied from `exwm-floating--set-floating'. - (let* ((old-frame exwm--floating-frame) - (new-frame - (with-current-buffer - (or (get-buffer "*scratch*") - (progn - (set-buffer-major-mode - (get-buffer-create "*scratch*")) - (get-buffer "*scratch*"))) - (make-frame - `((minibuffer . ,(minibuffer-window frame)) - (left . ,(* window-min-width -100)) - (top . ,(* window-min-height -100)) - (width . ,window-min-width) - (height . ,window-min-height) - (unsplittable . t))))) - (outer-id (string-to-number - (frame-parameter new-frame - 'outer-window-id))) - (window-id (string-to-number - (frame-parameter new-frame 'window-id))) - (window (frame-root-window new-frame))) - (set-frame-parameter new-frame 'exwm-outer-id outer-id) - (set-frame-parameter new-frame 'exwm-id window-id) - (set-frame-parameter new-frame 'exwm-container container) - (make-frame-invisible new-frame) - (set-frame-size new-frame - (frame-pixel-width old-frame) - (frame-pixel-height old-frame) - t) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window outer-id - :parent container - :x 0 :y 0)) - (xcb:flush exwm--connection) - (with-current-buffer (exwm--id->buffer id) - (setq window-size-fixed nil - exwm--floating-frame new-frame) - (set-window-dedicated-p (frame-root-window old-frame) nil) - (remove-hook 'window-configuration-change-hook - #'exwm-layout--refresh) - (set-window-buffer window (current-buffer)) - (add-hook 'window-configuration-change-hook - #'exwm-layout--refresh) - (set-window-dedicated-p window t)) - ;; Select a tiling window and delete the old frame. - (select-window (frame-selected-window exwm-workspace--current)) - (delete-frame old-frame) - ;; The rest is the same. - (make-frame-visible new-frame) - (exwm--set-geometry outer-id 0 0 nil nil) - (xcb:flush exwm--connection) - (redisplay) - (if (eq frame exwm-workspace--current) - (with-current-buffer (exwm--id->buffer id) - (select-window (frame-root-window exwm--floating-frame))) - (unless (exwm-workspace--active-p frame) - (exwm-layout--hide id))))) - ;; Update the 'exwm-selected-window' frame parameter. - (when (not (eq frame exwm-workspace--current)) - (with-current-buffer (exwm--id->buffer id) - (set-frame-parameter frame 'exwm-selected-window - (frame-root-window - exwm--floating-frame))))) - ;; Set _NET_WM_DESKTOP. - (exwm-workspace--set-desktop id) - (xcb:flush exwm--connection))) - (setq exwm-workspace--switch-history-outdated t))) - -;;;###autoload -(defun exwm-workspace-switch-to-buffer (buffer-or-name) - "Make selected window display BUFFER-OR-NAME." - (interactive - (let ((inhibit-quit t)) - ;; Show all buffers - (unless exwm-workspace-show-all-buffers - (dolist (pair exwm--id-buffer-alist) - (with-current-buffer (cdr pair) - (when (= ?\s (aref (buffer-name) 0)) - (let ((buffer-list-update-hook - (remq #'exwm-input--on-buffer-list-update - buffer-list-update-hook))) - (rename-buffer (substring (buffer-name) 1))))))) - (prog1 - (with-local-quit - (list (get-buffer (read-buffer-to-switch "Switch to buffer: ")))) - ;; Hide buffers on other workspaces - (unless exwm-workspace-show-all-buffers - (dolist (pair exwm--id-buffer-alist) - (with-current-buffer (cdr pair) - (unless (or (eq exwm--frame exwm-workspace--current) - (= ?\s (aref (buffer-name) 0))) - (let ((buffer-list-update-hook - (remq #'exwm-input--on-buffer-list-update - buffer-list-update-hook))) - (rename-buffer (concat " " (buffer-name))))))))))) - (exwm--log) - (when buffer-or-name - (with-current-buffer buffer-or-name - (if (derived-mode-p 'exwm-mode) - ;; EXWM buffer. - (if (eq exwm--frame exwm-workspace--current) - ;; On the current workspace. - (if (not exwm--floating-frame) - (switch-to-buffer buffer-or-name) - ;; Select the floating frame. - (select-frame-set-input-focus exwm--floating-frame) - (select-window (frame-root-window exwm--floating-frame))) - ;; On another workspace. - (if exwm-layout-show-all-buffers - (exwm-workspace-move-window exwm-workspace--current - exwm--id) - (let ((window (get-buffer-window buffer-or-name exwm--frame))) - (if window - (set-frame-parameter exwm--frame - 'exwm-selected-window window) - (set-window-buffer (frame-selected-window exwm--frame) - buffer-or-name))) - (exwm-workspace-switch exwm--frame))) - ;; Ordinary buffer. - (switch-to-buffer buffer-or-name))))) - -(defun exwm-workspace-rename-buffer (newname) - "Rename current buffer to NEWNAME." - (let ((hidden (= ?\s (aref newname 0))) - (basename (replace-regexp-in-string "<[0-9]+>$" "" newname)) - (counter 1) - tmp) - (when hidden (setq basename (substring basename 1))) - (setq newname basename) - (while (and (setq tmp (or (get-buffer newname) - (get-buffer (concat " " newname)))) - (not (eq tmp (current-buffer)))) - (setq newname (format "%s<%d>" basename (cl-incf counter)))) - (let ((buffer-list-update-hook - (remq #'exwm-input--on-buffer-list-update - buffer-list-update-hook))) - (rename-buffer (concat (and hidden " ") newname))))) - -(defun exwm-workspace--x-create-frame (orig-x-create-frame params) - "Set override-redirect on the frame created by `x-create-frame'. -ORIG-X-CREATE-FRAME is the advised function `x-create-frame'. -PARAMS are the original arguments." - (exwm--log) - (let ((frame (funcall orig-x-create-frame params))) - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window (string-to-number - (frame-parameter frame 'outer-window-id)) - :value-mask xcb:CW:OverrideRedirect - :override-redirect 1)) - (xcb:flush exwm--connection) - frame)) - -(defsubst exwm-workspace--minibuffer-attached-p () - "Return non-nil if the minibuffer is attached. - -Please check `exwm-workspace--minibuffer-own-frame-p' first." - (assq (frame-parameter exwm-workspace--minibuffer 'exwm-container) - exwm-workspace--id-struts-alist)) - -;;;###autoload -(defun exwm-workspace-attach-minibuffer () - "Attach the minibuffer making it always visible." - (interactive) - (exwm--log) - (when (and (exwm-workspace--minibuffer-own-frame-p) - (not (exwm-workspace--minibuffer-attached-p))) - ;; Reset the frame size. - (set-frame-height exwm-workspace--minibuffer 1) - (redisplay) ;FIXME. - (setq exwm-workspace--attached-minibuffer-height - (frame-pixel-height exwm-workspace--minibuffer)) - (exwm-workspace--show-minibuffer) - (let ((container (frame-parameter exwm-workspace--minibuffer - 'exwm-container))) - (push (cons container - (if (eq exwm-workspace-minibuffer-position 'top) - (vector 0 0 exwm-workspace--attached-minibuffer-height 0) - (vector 0 0 0 exwm-workspace--attached-minibuffer-height))) - exwm-workspace--id-struts-alist) - (exwm-workspace--update-struts) - (exwm-workspace--update-workareas) - (dolist (f exwm-workspace--list) - (exwm-workspace--set-fullscreen f))))) - -;;;###autoload -(defun exwm-workspace-detach-minibuffer () - "Detach the minibuffer so that it automatically hides." - (interactive) - (exwm--log) - (when (and (exwm-workspace--minibuffer-own-frame-p) - (exwm-workspace--minibuffer-attached-p)) - (setq exwm-workspace--attached-minibuffer-height 0) - (let ((container (frame-parameter exwm-workspace--minibuffer - 'exwm-container))) - (setq exwm-workspace--id-struts-alist - (assq-delete-all container exwm-workspace--id-struts-alist)) - (exwm-workspace--update-struts) - (exwm-workspace--update-workareas) - (dolist (f exwm-workspace--list) - (exwm-workspace--set-fullscreen f)) - (exwm-workspace--hide-minibuffer)))) - -;;;###autoload -(defun exwm-workspace-toggle-minibuffer () - "Attach the minibuffer if it's detached, or detach it if it's attached." - (interactive) - (exwm--log) - (when (exwm-workspace--minibuffer-own-frame-p) - (if (exwm-workspace--minibuffer-attached-p) - (exwm-workspace-detach-minibuffer) - (exwm-workspace-attach-minibuffer)))) - -(defun exwm-workspace--update-minibuffer-height (&optional echo-area) - "Update the minibuffer frame height. -When ECHO-AREA is non-nil, take the size of the echo area into -account when calculating the height." - (when (exwm--terminal-p) - (let ((height - (with-current-buffer - (window-buffer (minibuffer-window exwm-workspace--minibuffer)) - (max 1 - (if echo-area - (let ((width (frame-width exwm-workspace--minibuffer)) - (result 0)) - (mapc (lambda (i) - (setq result - (+ result - (ceiling (1+ (length i)) width)))) - (split-string (or (current-message) "") "\n")) - result) - (count-screen-lines)))))) - (when (and (integerp max-mini-window-height) - (> height max-mini-window-height)) - (setq height max-mini-window-height)) - (exwm--log "%s" height) - (set-frame-height exwm-workspace--minibuffer height)))) - -(defun exwm-workspace--on-ConfigureNotify (data _synthetic) - "Adjust the container to fit the minibuffer frame. -DATA contains unmarshalled ConfigureNotify event data." - (let ((obj (make-instance 'xcb:ConfigureNotify)) y) - (xcb:unmarshal obj data) - (with-slots (window height) obj - (when (eq (frame-parameter exwm-workspace--minibuffer 'exwm-outer-id) - window) - (exwm--log) - (when (and (floatp max-mini-window-height) - (> height (* max-mini-window-height - (exwm-workspace--current-height)))) - (setq height (floor - (* max-mini-window-height - (exwm-workspace--current-height)))) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window window - :value-mask xcb:ConfigWindow:Height - :height height))) - (when (/= (exwm-workspace--count) (length exwm-workspace--workareas)) - ;; There is a chance the workareas are not updated timely. - (exwm-workspace--update-workareas)) - (with-slots ((y* y) (height* height)) - (exwm-workspace--workarea exwm-workspace-current-index) - (setq y (if (eq exwm-workspace-minibuffer-position 'top) - (- y* - exwm-workspace--attached-minibuffer-height) - (+ y* height* (- height) - exwm-workspace--attached-minibuffer-height)))) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm-workspace--minibuffer - 'exwm-container) - :value-mask (logior xcb:ConfigWindow:Y - xcb:ConfigWindow:Height) - :y y - :height height)) - (xcb:flush exwm--connection))))) - -(defun exwm-workspace--display-buffer (buffer alist) - "Display BUFFER as if the current workspace were selected. -ALIST is an action alist, as accepted by function `display-buffer'." - ;; Only when the floating minibuffer frame is selected. - ;; This also protect this functions from being recursively called. - (when (eq (selected-frame) exwm-workspace--minibuffer) - (with-selected-frame exwm-workspace--current - (display-buffer buffer alist)))) - -(defun exwm-workspace--show-minibuffer () - "Show the minibuffer frame." - (exwm--log) - ;; Cancel pending timer. - (when exwm-workspace--display-echo-area-timer - (cancel-timer exwm-workspace--display-echo-area-timer) - (setq exwm-workspace--display-echo-area-timer nil)) - ;; Show the minibuffer frame. - (unless (exwm-workspace--minibuffer-attached-p) - (exwm--set-geometry (frame-parameter exwm-workspace--minibuffer - 'exwm-container) - nil nil - (frame-pixel-width exwm-workspace--minibuffer) - (frame-pixel-height exwm-workspace--minibuffer))) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm-workspace--minibuffer - 'exwm-container) - :value-mask xcb:ConfigWindow:StackMode - :stack-mode xcb:StackMode:Above)) - (xcb:flush exwm--connection)) - -(defun exwm-workspace--hide-minibuffer () - "Hide the minibuffer frame." - (exwm--log) - ;; Hide the minibuffer frame. - (if (exwm-workspace--minibuffer-attached-p) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window (frame-parameter exwm-workspace--minibuffer - 'exwm-container) - :value-mask (logior (if exwm-manage--desktop - xcb:ConfigWindow:Sibling - 0) - xcb:ConfigWindow:StackMode) - :sibling exwm-manage--desktop - :stack-mode (if exwm-manage--desktop - xcb:StackMode:Above - xcb:StackMode:Below))) - (exwm--set-geometry (frame-parameter exwm-workspace--minibuffer - 'exwm-container) - nil nil 1 1)) - (xcb:flush exwm--connection)) - -(defun exwm-workspace--on-minibuffer-setup () - "Run in `minibuffer-setup-hook' to show the minibuffer and its container." - (exwm--log) - (when (and (= 1 (minibuffer-depth)) - (exwm--terminal-p)) - (add-hook 'post-command-hook #'exwm-workspace--update-minibuffer-height) - (exwm-workspace--show-minibuffer)) - ;; FIXME: This is a temporary fix for the *Completions* buffer not - ;; being correctly fitted by its displaying window. As with - ;; `exwm-workspace--display-buffer', the problem is caused by - ;; the fact that the minibuffer (rather than the workspace) - ;; frame is the 'selected frame'. `get-buffer-window' will - ;; fail to retrieve the correct window. It's likely there are - ;; other related issues. - ;; This is not required by Emacs 24. - (let ((window (get-buffer-window "*Completions*" exwm-workspace--current))) - (when window - (fit-window-to-buffer window) - (window-preserve-size window)))) - -(defun exwm-workspace--on-minibuffer-exit () - "Run in `minibuffer-exit-hook' to hide the minibuffer container." - (exwm--log) - (when (and (= 1 (minibuffer-depth)) - (exwm--terminal-p)) - (remove-hook 'post-command-hook #'exwm-workspace--update-minibuffer-height) - (exwm-workspace--hide-minibuffer))) - -(defun exwm-workspace--on-echo-area-dirty () - "Run when new message arrives to show the echo area and its container." - (when (and (not (active-minibuffer-window)) - (or (current-message) - cursor-in-echo-area) - (exwm--terminal-p)) - (exwm-workspace--update-minibuffer-height t) - (exwm-workspace--show-minibuffer) - (unless (or (not exwm-workspace-display-echo-area-timeout) - exwm-input--during-command ;e.g. read-event - input-method-use-echo-area) - (setq exwm-workspace--display-echo-area-timer - (run-with-timer exwm-workspace-display-echo-area-timeout nil - #'exwm-workspace--echo-area-maybe-clear))))) - -(defun exwm-workspace--echo-area-maybe-clear () - "Eventually clear the echo area container." - (exwm--log) - (if (not (current-message)) - (exwm-workspace--on-echo-area-clear) - ;; Reschedule. - (cancel-timer exwm-workspace--display-echo-area-timer) - (setq exwm-workspace--display-echo-area-timer - (run-with-timer exwm-workspace-display-echo-area-timeout nil - #'exwm-workspace--echo-area-maybe-clear)))) - -(defun exwm-workspace--on-echo-area-clear () - "Run in `echo-area-clear-hook' to hide echo area container." - (when (exwm--terminal-p) - (unless (active-minibuffer-window) - (exwm-workspace--hide-minibuffer)) - (when exwm-workspace--display-echo-area-timer - (cancel-timer exwm-workspace--display-echo-area-timer) - (setq exwm-workspace--display-echo-area-timer nil)))) - -(defun exwm-workspace--set-desktop-geometry () - "Set _NET_DESKTOP_GEOMETRY." - (exwm--log) - ;; We don't support large desktop so it's the same with screen size. - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_DESKTOP_GEOMETRY - :window exwm--root - :width (x-display-pixel-width) - :height (x-display-pixel-height)))) - -(defun exwm-workspace--add-frame-as-workspace (frame) - "Configure frame FRAME to be treated as a workspace." - (exwm--log "%s" frame) - (setq exwm-workspace--list (nconc exwm-workspace--list (list frame))) - (let ((outer-id (string-to-number (frame-parameter frame - 'outer-window-id))) - (window-id (string-to-number (frame-parameter frame 'window-id))) - (container (xcb:generate-id exwm--connection)) - frame-colormap frame-visual frame-depth) - ;; Save window IDs - (set-frame-parameter frame 'exwm-outer-id outer-id) - (set-frame-parameter frame 'exwm-id window-id) - (set-frame-parameter frame 'exwm-container container) - ;; Copy RandR frame parameters from the first workspace to - ;; prevent potential problems. The values do not matter here as - ;; they'll be updated by the RandR module later. - (let ((w (car exwm-workspace--list))) - (dolist (param '(exwm-randr-monitor - exwm-geometry)) - (set-frame-parameter frame param (frame-parameter w param)))) - ;; Support transparency on the container X window when the Emacs frame - ;; does. Note that in addition to setting the visual, colormap and depth - ;; we must also reset the `:border-pixmap', as its default value is - ;; relative to the parent window, which might have a different depth. - (let* ((vdc (exwm--get-visual-depth-colormap exwm--connection outer-id))) - (setq frame-visual (car vdc)) - (setq frame-depth (cadr vdc)) - (setq frame-colormap (caddr vdc))) - (xcb:+request exwm--connection - (make-instance 'xcb:CreateWindow - :depth frame-depth - :wid container - :parent exwm--root - :x -1 - :y -1 - :width 1 - :height 1 - :border-width 0 - :class xcb:WindowClass:InputOutput - :visual frame-visual - :value-mask (logior xcb:CW:BackPixmap - xcb:CW:BorderPixel - xcb:CW:Colormap - xcb:CW:OverrideRedirect) - :background-pixmap xcb:BackPixmap:None - :border-pixel 0 - :colormap frame-colormap - :override-redirect 1)) - (xcb:+request exwm--connection - (make-instance 'xcb:ConfigureWindow - :window container - :value-mask xcb:ConfigWindow:StackMode - :stack-mode xcb:StackMode:Below)) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window container - :data - (format "EXWM workspace %d frame container" - (exwm-workspace--position frame)))) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window outer-id :parent container :x 0 :y 0)) - (xcb:+request exwm--connection - (make-instance 'xcb:icccm:set-WM_STATE - :window outer-id - :state xcb:icccm:WM_STATE:NormalState - :icon xcb:Window:None)) - (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow :window container))) - (xcb:flush exwm--connection) - ;; Delay making the workspace fullscreen until Emacs becomes idle - (exwm--defer 0 #'exwm-workspace--fullscreen-workspace frame) - ;; Update EWMH properties. - (exwm-workspace--update-ewmh-props) - (if exwm-workspace--create-silently - (setq exwm-workspace--switch-history-outdated t) - (let ((original-index exwm-workspace-current-index)) - (exwm-workspace-switch frame t) - (message "Created %s as workspace %d; switched from %d" - frame exwm-workspace-current-index original-index)) - (run-hooks 'exwm-workspace-list-change-hook))) - -(defun exwm-workspace--get-next-workspace (frame) - "Return the next workspace if workspace FRAME were removed. -Return nil if FRAME is the only workspace." - (let* ((index (exwm-workspace--position frame)) - (lastp (= index (1- (exwm-workspace--count)))) - (nextw (elt exwm-workspace--list (+ index (if lastp -1 +1))))) - (unless (eq frame nextw) - nextw))) - -(defun exwm-workspace--remove-frame-as-workspace (frame &optional quit) - "Stop treating FRAME as a workspace. -When QUIT is non-nil cleanup avoid communicating with the X server." - ;; TODO: restore all frame parameters (e.g. exwm-workspace, buffer-predicate, - ;; etc) - (exwm--log "Removing frame `%s' as workspace" frame) - (unless quit - (let* ((next-frame (exwm-workspace--get-next-workspace frame)) - (following-frames (cdr (memq frame exwm-workspace--list)))) - ;; Need to remove the workspace from the list for the correct calculation of - ;; indexes below. - (setq exwm-workspace--list (delete frame exwm-workspace--list)) - ;; Move the windows to the next workspace and switch to it. - (unless next-frame - ;; The user managed to delete the last workspace, so create a new one. - (exwm--log "Last workspace deleted; create a new one") - (let ((exwm-workspace--create-silently t)) - (setq next-frame (make-frame)))) - (dolist (pair exwm--id-buffer-alist) - (let ((other-frame (buffer-local-value 'exwm--frame (cdr pair)))) - ;; Move X windows to next-frame. - (when (eq other-frame frame) - (exwm-workspace-move-window next-frame (car pair))) - ;; Update the _NET_WM_DESKTOP property of each following X window. - (when (memq other-frame following-frames) - (exwm-workspace--set-desktop (car pair))))) - ;; If the current workspace is deleted, switch to next one. - (when (eq frame exwm-workspace--current) - (exwm-workspace-switch next-frame)))) - ;; Reparent out the frame. - (let ((outer-id (frame-parameter frame 'exwm-outer-id))) - (xcb:+request exwm--connection - (make-instance 'xcb:UnmapWindow - :window outer-id)) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window outer-id - :parent exwm--root - :x 0 - :y 0)) - ;; Reset the override-redirect. - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window outer-id - :value-mask xcb:CW:OverrideRedirect - :override-redirect 0)) - ;; Remove fullscreen state. - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_STATE - :window outer-id - :data nil)) - (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow - :window outer-id))) - ;; Destroy the container. - (xcb:+request exwm--connection - (make-instance 'xcb:DestroyWindow - :window (frame-parameter frame 'exwm-container))) - (xcb:flush exwm--connection) - ;; Update EWMH properties. - (exwm-workspace--update-ewmh-props) - ;; Update switch history. - (unless quit - (setq exwm-workspace--switch-history-outdated t) - (run-hooks 'exwm-workspace-list-change-hook))) - -(defun exwm-workspace--on-delete-frame (frame) - "Hook run upon `delete-frame' removing FRAME as a workspace." - (cond - ((not (exwm-workspace--workspace-p frame)) - (exwm--log "Frame `%s' is not a workspace" frame)) - (t - (exwm-workspace--remove-frame-as-workspace frame)))) - -(defun exwm-workspace--fullscreen-workspace (frame) - "Make workspace FRAME fullscreen. -Called from a timer." - (when (frame-live-p frame) - (set-frame-parameter frame 'fullscreen 'fullboth))) - -(defun exwm-workspace--on-after-make-frame (frame) - "Hook run upon `make-frame' that configures FRAME as a workspace." - (cond - ((exwm-workspace--workspace-p frame) - (exwm--log "Frame `%s' is already a workspace" frame)) - ((not (display-graphic-p frame)) - (exwm--log "Frame `%s' is not graphical" frame)) - ((not (eq (frame-terminal) exwm--terminal)) - (exwm--log "Frame `%s' is on a different terminal (%S instead of %S)" - frame - (frame-terminal frame) - exwm--terminal)) - ((not (string-equal - (replace-regexp-in-string "\\.0$" "" - (slot-value exwm--connection 'display)) - (replace-regexp-in-string "\\.0$" "" - (frame-parameter frame 'display)))) - (exwm--log "Frame `%s' is on a different DISPLAY (%S instead of %S)" - frame - (frame-parameter frame 'display) - (slot-value exwm--connection 'display))) - ((frame-parameter frame 'unsplittable) - ;; We create floating frames with the "unsplittable" parameter set. - ;; Though it may not be a floating frame, we won't treat an - ;; unsplittable frame as a workspace anyway. - (exwm--log "Frame `%s' is floating" frame)) - (t - (exwm--log "Adding frame `%s' as workspace" frame) - (exwm-workspace--add-frame-as-workspace frame)))) - -(defun exwm-workspace--update-ewmh-props () - "Update EWMH properties to match the workspace list." - (exwm--log) - (let ((num-workspaces (exwm-workspace--count))) - ;; Avoid setting 0 desktops. - (when (= 0 num-workspaces) - (setq num-workspaces 1)) - ;; Set _NET_NUMBER_OF_DESKTOPS. - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_NUMBER_OF_DESKTOPS - :window exwm--root :data num-workspaces)) - ;; Set _NET_DESKTOP_GEOMETRY. - (exwm-workspace--set-desktop-geometry) - ;; Update workareas. - (exwm-workspace--update-workareas)) - (xcb:flush exwm--connection)) - -(defun exwm-workspace--modify-all-x-frames-parameters (new-x-parameters) - "Modifies `window-system-default-frame-alist' for the X Window System. -NEW-X-PARAMETERS is an alist of frame parameters, merged into current -`window-system-default-frame-alist' for the X Window System. The parameters are -applied to all subsequently created X frames." - (exwm--log) - ;; The parameters are modified in place; take current - ;; ones or insert a new X-specific list. - (let ((x-parameters (or (assq 'x window-system-default-frame-alist) - (let ((new-x-parameters '(x))) - (push new-x-parameters - window-system-default-frame-alist) - new-x-parameters)))) - (setf (cdr x-parameters) - (append new-x-parameters (cdr x-parameters))))) - -(defun exwm-workspace--handle-focus-in (_orig-func _event) - "Replacement for `handle-focus-in'." - (interactive "e")) - -(defun exwm-workspace--handle-focus-out (_orig-func _event) - "Replacement for `handle-focus-out'." - (interactive "e")) - -(defun exwm-workspace--init-minibuffer-frame () - "Initialize minibuffer-only frame." - (exwm--log) - ;; Initialize workspaces without minibuffers. - (setq exwm-workspace--minibuffer - (make-frame '((window-system . x) (minibuffer . only) - (left . 10000) (right . 10000) - (width . 1) (height . 1)))) - ;; This is the only usable minibuffer frame. - (setq default-minibuffer-frame exwm-workspace--minibuffer) - (exwm-workspace--modify-all-x-frames-parameters - '((minibuffer . nil))) - (let ((outer-id (string-to-number - (frame-parameter exwm-workspace--minibuffer - 'outer-window-id))) - (window-id (string-to-number - (frame-parameter exwm-workspace--minibuffer - 'window-id))) - (container (xcb:generate-id exwm--connection))) - (set-frame-parameter exwm-workspace--minibuffer - 'exwm-outer-id outer-id) - (set-frame-parameter exwm-workspace--minibuffer 'exwm-id window-id) - (set-frame-parameter exwm-workspace--minibuffer 'exwm-container - container) - (xcb:+request exwm--connection - (make-instance 'xcb:CreateWindow - :depth 0 - :wid container - :parent exwm--root - :x 0 - :y 0 - :width 1 - :height 1 - :border-width 0 - :class xcb:WindowClass:InputOutput - :visual 0 - :value-mask (logior xcb:CW:BackPixmap - xcb:CW:OverrideRedirect) - :background-pixmap xcb:BackPixmap:ParentRelative - :override-redirect 1)) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window container - :data "EXWM minibuffer container")) - ;; Reparent the minibuffer frame to the container. - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window outer-id :parent container :x 0 :y 0)) - ;; Map the container. - (xcb:+request exwm--connection - (make-instance 'xcb:MapWindow - :window container)) - ;; Attach event listener for monitoring the frame - (xcb:+request exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window outer-id - :value-mask xcb:CW:EventMask - :event-mask xcb:EventMask:StructureNotify)) - (xcb:+event exwm--connection 'xcb:ConfigureNotify - #'exwm-workspace--on-ConfigureNotify)) - ;; Show/hide minibuffer / echo area when they're active/inactive. - (add-hook 'minibuffer-setup-hook #'exwm-workspace--on-minibuffer-setup) - (add-hook 'minibuffer-exit-hook #'exwm-workspace--on-minibuffer-exit) - (setq exwm-workspace--timer - (run-with-idle-timer 0 t #'exwm-workspace--on-echo-area-dirty)) - (add-hook 'echo-area-clear-hook #'exwm-workspace--on-echo-area-clear) - ;; The default behavior of `display-buffer' (indirectly called by - ;; `minibuffer-completion-help') is not correct here. - (cl-pushnew '(exwm-workspace--display-buffer) display-buffer-alist - :test #'equal)) - -(defun exwm-workspace--exit-minibuffer-frame () - "Cleanup minibuffer-only frame." - (exwm--log) - ;; Only on minibuffer-frame. - (remove-hook 'minibuffer-setup-hook #'exwm-workspace--on-minibuffer-setup) - (remove-hook 'minibuffer-exit-hook #'exwm-workspace--on-minibuffer-exit) - (remove-hook 'echo-area-clear-hook #'exwm-workspace--on-echo-area-clear) - (when exwm-workspace--display-echo-area-timer - (cancel-timer exwm-workspace--display-echo-area-timer)) - (when exwm-workspace--timer - (cancel-timer exwm-workspace--timer) - (setq exwm-workspace--timer nil)) - (setq display-buffer-alist - (cl-delete '(exwm-workspace--display-buffer) display-buffer-alist - :test #'equal)) - (setq default-minibuffer-frame nil) - (when (frame-live-p exwm-workspace--minibuffer) ; might be already dead - (let ((id (frame-parameter exwm-workspace--minibuffer 'exwm-outer-id))) - (when (and exwm-workspace--minibuffer id - ;; Invoked from `exwm-manage--exit' upon disconnection. - (slot-value exwm--connection 'connected)) - (xcb:+request exwm--connection - (make-instance 'xcb:ReparentWindow - :window id - :parent exwm--root - :x 0 - :y 0))) - (setq exwm-workspace--minibuffer nil)))) - -(defun exwm-workspace--init () - "Initialize workspace module." - (exwm--log) - (exwm-workspace--init-switch-map) - ;; Prevent unexpected exit - (setq exwm-workspace--fullscreen-frame-count 0) - (exwm-workspace--modify-all-x-frames-parameters - '((internal-border-width . 0))) - (let ((initial-workspaces (frame-list))) - (if (not (exwm-workspace--minibuffer-own-frame-p)) - ;; Initialize workspaces with minibuffers. - (when (< 1 (length initial-workspaces)) - ;; Exclude the initial frame. - (dolist (i initial-workspaces) - (unless (frame-parameter i 'window-id) - (setq initial-workspaces (delq i initial-workspaces)))) - (let ((f (car initial-workspaces))) - ;; Remove the possible internal border. - (set-frame-parameter f 'internal-border-width 0))) - (exwm-workspace--init-minibuffer-frame) - ;; Remove/hide existing frames. - (dolist (f initial-workspaces) - (when (eq 'x (framep f)) ;do not delete the initial frame. - (delete-frame f))) - ;; Recreate one frame with the external minibuffer set. - (setq initial-workspaces (list (make-frame '((window-system . x)))))) - ;; Prevent `other-buffer' from selecting already displayed EXWM buffers. - (modify-all-frames-parameters - '((buffer-predicate . exwm-layout--other-buffer-predicate))) - ;; Create remaining workspaces. - (dotimes (_ (- exwm-workspace-number (length initial-workspaces))) - (nconc initial-workspaces (list (make-frame '((window-system . x)))))) - ;; Configure workspaces - (let ((exwm-workspace--create-silently t)) - (dolist (i initial-workspaces) - (exwm-workspace--add-frame-as-workspace i)))) - (xcb:flush exwm--connection) - ;; We have to advice `x-create-frame' or every call to it would hang EXWM - (advice-add 'x-create-frame :around #'exwm-workspace--x-create-frame) - ;; We have to manually handle focus-in and focus-out events for Emacs - ;; frames. - (advice-add 'handle-focus-in :around #'exwm-workspace--handle-focus-in) - (advice-add 'handle-focus-out :around #'exwm-workspace--handle-focus-out) - ;; Make new frames create new workspaces. - (add-hook 'after-make-frame-functions - #'exwm-workspace--on-after-make-frame) - (add-hook 'delete-frame-functions #'exwm-workspace--on-delete-frame) - (when (exwm-workspace--minibuffer-own-frame-p) - (add-hook 'exwm-input--event-hook - #'exwm-workspace--on-echo-area-clear)) - ;; Switch to the first workspace - (exwm-workspace-switch 0 t) - ;; Prevent frame parameters introduced by this module from being - ;; saved/restored. - (dolist (i '(exwm-active exwm-outer-id exwm-id exwm-container exwm-geometry - exwm-selected-window exwm-urgency fullscreen)) - (unless (assq i frameset-filter-alist) - (push (cons i :never) frameset-filter-alist)))) - -(defun exwm-workspace--exit () - "Exit the workspace module." - (exwm--log) - (when (exwm-workspace--minibuffer-own-frame-p) - (exwm-workspace--exit-minibuffer-frame)) - (advice-remove 'x-create-frame #'exwm-workspace--x-create-frame) - (advice-remove 'handle-focus-in #'exwm-workspace--handle-focus-in) - (advice-remove 'handle-focus-out #'exwm-workspace--handle-focus-out) - (remove-hook 'after-make-frame-functions - #'exwm-workspace--on-after-make-frame) - (remove-hook 'delete-frame-functions - #'exwm-workspace--on-delete-frame) - (when (exwm-workspace--minibuffer-own-frame-p) - (remove-hook 'exwm-input--event-hook - #'exwm-workspace--on-echo-area-clear)) - ;; Hide & reparent out all frames (save-set can't be used here since - ;; X windows will be re-mapped). - (when (slot-value exwm--connection 'connected) - (dolist (i exwm-workspace--list) - (when (frame-live-p i) ; might be already dead - (exwm-workspace--remove-frame-as-workspace i 'quit) - (modify-frame-parameters i '((exwm-selected-window . nil) - (exwm-urgency . nil) - (exwm-outer-id . nil) - (exwm-id . nil) - (exwm-container . nil) - ;; (internal-border-width . nil) ; integerp - (fullscreen . nil) - (buffer-predicate . nil)))))) - ;; Don't let dead frames linger. - (setq exwm-workspace--current nil) - (setq exwm-workspace-current-index 0) - (setq exwm-workspace--list nil)) - -(defun exwm-workspace--post-init () - "The second stage in the initialization of the workspace module." - (exwm--log) - ;; Wait until all workspace frames are resized. - (with-timeout (1) - (while (< exwm-workspace--fullscreen-frame-count (exwm-workspace--count)) - (accept-process-output nil 0.1))) - (setq exwm-workspace--fullscreen-frame-count nil)) - - - -(provide 'exwm-workspace) - -;;; exwm-workspace.el ends here diff --git a/third_party/exwm/exwm-xim.el b/third_party/exwm/exwm-xim.el deleted file mode 100644 index 1f0c9c460..000000000 --- a/third_party/exwm/exwm-xim.el +++ /dev/null @@ -1,810 +0,0 @@ -;;; exwm-xim.el --- XIM Module for EXWM -*- lexical-binding: t -*- - -;; Copyright (C) 2019-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; This module adds XIM support for EXWM and allows sending characters -;; generated by any Emacs's builtin input method (info node `Input Methods') -;; to X windows. - -;; This module is essentially an X input method server utilizing Emacs as -;; its backend. It talks with X windows through the XIM protocol. The XIM -;; protocol is quite flexible by itself, stating that an implementation can -;; create network connections of various types as well as make use of an -;; existing X connection for communication, and that an IM server may -;; support multiple transport versions, various input styles and several -;; event flow modals, etc. Here we only make choices that are most popular -;; among other IM servers and more importantly, practical for Emacs to act -;; as an IM server: -;; -;; + Packets are transported on top of an X connection like most IMEs. -;; + Only transport version 0.0 (i.e. only-CM & Property-with-CM) is -;; supported (same as "IM Server Developers Kit", adopted by most IMEs). -;; + Only support static event flow, on-demand-synchronous method. -;; + Only "root-window" input style is supported. - -;; To use this module, first load and enable it as follows: -;; -;; (require 'exwm-xim) -;; (exwm-xim-enable) -;; -;; A keybinding for `toggle-input-method' is probably required to turn on & -;; off an input method (default to `default-input-method'). It's bound to -;; 'C-\' by default and can be made reachable when working with X windows: -;; -;; (push ?\C-\\ exwm-input-prefix-keys) -;; -;; It's also required (and error-prone) to setup environment variables to -;; make applications actually use this input method. Typically the -;; following lines should be inserted into '~/.xinitrc'. -;; -;; export XMODIFIERS=@im=exwm-xim -;; export GTK_IM_MODULE=xim -;; export QT_IM_MODULE=xim -;; export CLUTTER_IM_MODULE=xim - -;; References: -;; + XIM (http://www.x.org/releases/X11R7.6/doc/libX11/specs/XIM/xim.html) -;; + IMdkit (http://xorg.freedesktop.org/archive/unsupported/lib/IMdkit/) -;; + UIM (https://github.com/uim/uim) - -;;; Code: - -(require 'cl-lib) - -(require 'xcb-keysyms) -(require 'xcb-xim) - -(require 'exwm-core) -(require 'exwm-input) - -(defconst exwm-xim--locales - "@locale=\ -aa,af,ak,am,an,anp,ar,as,ast,ayc,az,be,bem,ber,bg,bhb,bho,bn,bo,br,brx,bs,byn,\ -ca,ce,cmn,crh,cs,csb,cv,cy,da,de,doi,dv,dz,el,en,es,et,eu,fa,ff,fi,fil,fo,fr,\ -fur,fy,ga,gd,gez,gl,gu,gv,ha,hak,he,hi,hne,hr,hsb,ht,hu,hy,ia,id,ig,ik,is,it,\ -iu,iw,ja,ka,kk,kl,km,kn,ko,kok,ks,ku,kw,ky,lb,lg,li,li,lij,lo,lt,lv,lzh,mag,\ -mai,mg,mhr,mi,mk,ml,mn,mni,mr,ms,mt,my,nan,nb,nds,ne,nhn,niu,nl,nn,nr,nso,oc,\ -om,or,os,pa,pa,pap,pl,ps,pt,quz,raj,ro,ru,rw,sa,sat,sc,sd,se,shs,si,sid,sk,sl,\ -so,sq,sr,ss,st,sv,sw,szl,ta,tcy,te,tg,th,the,ti,tig,tk,tl,tn,tr,ts,tt,ug,uk,\ -unm,ur,uz,ve,vi,wa,wae,wal,wo,xh,yi,yo,yue,zh,zu,\ -C,no" - "All supported locales (stolen from glibc).") - -(defconst exwm-xim--default-error - (make-instance 'xim:error - :im-id 0 - :ic-id 0 - :flag xim:error-flag:invalid-both - :error-code xim:error-code:bad-something - :length 0 - :type 0 - :detail nil) - "Default error returned to clients.") - -(defconst exwm-xim--default-im-attrs - (list (make-instance 'xim:XIMATTR - :id 0 - :type xim:ATTRIBUTE-VALUE-TYPE:xim-styles - :length (length xlib:XNQueryInputStyle) - :attribute xlib:XNQueryInputStyle)) - "Default IM attrs returned to clients.") - -(defconst exwm-xim--default-ic-attrs - (list (make-instance 'xim:XICATTR - :id 0 - :type xim:ATTRIBUTE-VALUE-TYPE:long-data - :length (length xlib:XNInputStyle) - :attribute xlib:XNInputStyle) - (make-instance 'xim:XICATTR - :id 1 - :type xim:ATTRIBUTE-VALUE-TYPE:window - :length (length xlib:XNClientWindow) - :attribute xlib:XNClientWindow) - ;; Required by e.g. xterm. - (make-instance 'xim:XICATTR - :id 2 - :type xim:ATTRIBUTE-VALUE-TYPE:window - :length (length xlib:XNFocusWindow) - :attribute xlib:XNFocusWindow)) - "Default IC attrs returned to clients.") - -(defconst exwm-xim--default-styles - (make-instance 'xim:XIMStyles - :number nil - :styles (list (logior xlib:XIMPreeditNothing - xlib:XIMStatusNothing))) - "Default styles: root-window, i.e. no preediting or status display support.") - -(defconst exwm-xim--default-attributes - (list (make-instance 'xim:XIMATTRIBUTE - :id 0 - :length nil - :value exwm-xim--default-styles)) - "Default IM/IC attributes returned to clients.") - -(defvar exwm-xim--conn nil - "The X connection for initiating other XIM connections.") -(defvar exwm-xim--event-xwin nil - "X window for initiating new XIM connections.") -(defvar exwm-xim--server-client-plist '(nil nil) - "Plist mapping server window to [X connection, client window, byte-order].") -(defvar exwm-xim--client-server-plist '(nil nil) - "Plist mapping client window to server window.") -(defvar exwm-xim--property-index 0 "For generating a unique property name.") -(defvar exwm-xim--im-id 0 "Last IM ID.") -(defvar exwm-xim--ic-id 0 "Last IC ID.") - -;; X11 atoms. -(defvar exwm-xim--@server nil) -(defvar exwm-xim--LOCALES nil) -(defvar exwm-xim--TRANSPORT nil) -(defvar exwm-xim--XIM_SERVERS nil) -(defvar exwm-xim--_XIM_PROTOCOL nil) -(defvar exwm-xim--_XIM_XCONNECT nil) - -(defvar exwm-xim-buffer-p nil - "Whether current buffer is used by exwm-xim.") -(make-variable-buffer-local 'exwm-xim-buffer-p) - -(defun exwm-xim--on-SelectionRequest (data _synthetic) - "Handle SelectionRequest events on IMS window. -DATA contains unmarshalled SelectionRequest event data. - -Such events would be received when clients query for LOCALES or TRANSPORT." - (exwm--log) - (let ((evt (make-instance 'xcb:SelectionRequest)) - value fake-event) - (xcb:unmarshal evt data) - (with-slots (time requestor selection target property) evt - (setq value (cond ((= target exwm-xim--LOCALES) - ;; Return supported locales. - exwm-xim--locales) - ((= target exwm-xim--TRANSPORT) - ;; Use XIM over an X connection. - "@transport=X/"))) - (when value - ;; Change the property. - (xcb:+request exwm-xim--conn - (make-instance 'xcb:ChangeProperty - :mode xcb:PropMode:Replace - :window requestor - :property property - :type target - :format 8 - :data-len (length value) - :data value)) - ;; Send a SelectionNotify event. - (setq fake-event (make-instance 'xcb:SelectionNotify - :time time - :requestor requestor - :selection selection - :target target - :property property)) - (xcb:+request exwm-xim--conn - (make-instance 'xcb:SendEvent - :propagate 0 - :destination requestor - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal fake-event exwm-xim--conn))) - (xcb:flush exwm-xim--conn))))) - -(cl-defun exwm-xim--on-ClientMessage-0 (data _synthetic) - "Handle ClientMessage event on IMS window (new connection). - -Such events would be received when clients request for _XIM_XCONNECT. -A new X connection and server window would be created to communicate with -this client." - (exwm--log) - (let ((evt (make-instance 'xcb:ClientMessage)) - conn client-xwin server-xwin) - (xcb:unmarshal evt data) - (with-slots (window type data) evt - (unless (= type exwm-xim--_XIM_XCONNECT) - ;; Only handle _XIM_XCONNECT. - (exwm--log "Ignore ClientMessage %s" type) - (cl-return-from exwm-xim--on-ClientMessage-0)) - (setq client-xwin (elt (slot-value data 'data32) 0) - ;; Create a new X connection and a new server window. - conn (xcb:connect) - server-xwin (xcb:generate-id conn)) - (set-process-query-on-exit-flag (slot-value conn 'process) nil) - ;; Store this client. - (plist-put exwm-xim--server-client-plist server-xwin - `[,conn ,client-xwin nil]) - (plist-put exwm-xim--client-server-plist client-xwin server-xwin) - ;; Select DestroyNotify events on this client window. - (xcb:+request exwm-xim--conn - (make-instance 'xcb:ChangeWindowAttributes - :window client-xwin - :value-mask xcb:CW:EventMask - :event-mask xcb:EventMask:StructureNotify)) - (xcb:flush exwm-xim--conn) - ;; Handle ClientMessage events from this new connection. - (xcb:+event conn 'xcb:ClientMessage #'exwm-xim--on-ClientMessage) - ;; Create a communication window. - (xcb:+request conn - (make-instance 'xcb:CreateWindow - :depth 0 - :wid server-xwin - :parent exwm--root - :x 0 - :y 0 - :width 1 - :height 1 - :border-width 0 - :class xcb:WindowClass:InputOutput - :visual 0 - :value-mask xcb:CW:OverrideRedirect - :override-redirect 1)) - (xcb:flush conn) - ;; Send connection establishment ClientMessage. - (setf window client-xwin - (slot-value data 'data32) `(,server-xwin 0 0 0 0)) - (slot-makeunbound data 'data8) - (slot-makeunbound data 'data16) - (xcb:+request exwm-xim--conn - (make-instance 'xcb:SendEvent - :propagate 0 - :destination client-xwin - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal evt exwm-xim--conn))) - (xcb:flush exwm-xim--conn)))) - -(cl-defun exwm-xim--on-ClientMessage (data _synthetic) - "Handle ClientMessage event on IMS communication window (request). - -Such events would be received when clients request for _XIM_PROTOCOL. -The actual XIM request is in client message data or a property." - (exwm--log) - (let ((evt (make-instance 'xcb:ClientMessage)) - conn client-xwin server-xwin) - (xcb:unmarshal evt data) - (with-slots (format window type data) evt - (unless (= type exwm-xim--_XIM_PROTOCOL) - (exwm--log "Ignore ClientMessage %s" type) - (cl-return-from exwm-xim--on-ClientMessage)) - (setq server-xwin window - conn (plist-get exwm-xim--server-client-plist server-xwin) - client-xwin (elt conn 1) - conn (elt conn 0)) - (cond ((= format 8) - ;; Data. - (exwm-xim--on-request (vconcat (slot-value data 'data8)) - conn client-xwin server-xwin)) - ((= format 32) - ;; Atom. - (with-slots (data32) data - (with-slots (value) - (xcb:+request-unchecked+reply conn - (make-instance 'xcb:GetProperty - :delete 1 - :window server-xwin - :property (elt data32 1) - :type xcb:GetPropertyType:Any - :long-offset 0 - :long-length (elt data32 0))) - (when (> (length value) 0) - (exwm-xim--on-request value conn client-xwin - server-xwin))))))))) - -(defun exwm-xim--on-request (data conn client-xwin server-xwin) - "Handle an XIM reuqest." - (exwm--log) - (let ((opcode (elt data 0)) - ;; Let-bind `xim:lsb' to make pack/unpack functions work correctly. - (xim:lsb (elt (plist-get exwm-xim--server-client-plist server-xwin) 2)) - req replies) - (cond ((= opcode xim:opcode:error) - (exwm--log "ERROR: %s" data)) - ((= opcode xim:opcode:connect) - (exwm--log "CONNECT") - (setq xim:lsb (= (elt data 4) xim:connect-byte-order:lsb-first)) - ;; Store byte-order. - (setf (elt (plist-get exwm-xim--server-client-plist server-xwin) 2) - xim:lsb) - (setq req (make-instance 'xim:connect)) - (xcb:unmarshal req data) - (if (and (= (slot-value req 'major-version) 1) - (= (slot-value req 'minor-version) 0) - ;; Do not support authentication. - (= (slot-value req 'number) 0)) - ;; Accept the connection. - (push (make-instance 'xim:connect-reply) replies) - ;; Deny it. - (push exwm-xim--default-error replies))) - ((memq opcode (list xim:opcode:auth-required - xim:opcode:auth-reply - xim:opcode:auth-next - xim:opcode:auth-ng)) - (exwm--log "AUTH: %d" opcode) - ;; Deny any attempt to make authentication. - (push exwm-xim--default-error replies)) - ((= opcode xim:opcode:disconnect) - (exwm--log "DISCONNECT") - ;; Gracefully disconnect from the client. - (exwm-xim--make-request (make-instance 'xim:disconnect-reply) - conn client-xwin) - ;; Destroy the communication window & connection. - (xcb:+request conn - (make-instance 'xcb:DestroyWindow - :window server-xwin)) - (xcb:disconnect conn) - ;; Clean up cache. - (cl-remf exwm-xim--server-client-plist server-xwin) - (cl-remf exwm-xim--client-server-plist client-xwin)) - ((= opcode xim:opcode:open) - (exwm--log "OPEN") - ;; Note: We make no check here. - (setq exwm-xim--im-id (if (< exwm-xim--im-id #xffff) - (1+ exwm-xim--im-id) - 1)) - (setq replies - (list - (make-instance 'xim:open-reply - :im-id exwm-xim--im-id - :im-attrs-length nil - :im-attrs exwm-xim--default-im-attrs - :ic-attrs-length nil - :ic-attrs exwm-xim--default-ic-attrs) - (make-instance 'xim:set-event-mask - :im-id exwm-xim--im-id - :ic-id 0 - ;; Static event flow. - :forward-event-mask xcb:EventMask:KeyPress - ;; on-demand-synchronous method. - :synchronous-event-mask - xcb:EventMask:NoEvent)))) - ((= opcode xim:opcode:close) - (exwm--log "CLOSE") - (setq req (make-instance 'xim:close)) - (xcb:unmarshal req data) - (push (make-instance 'xim:close-reply - :im-id (slot-value req 'im-id)) - replies)) - ((= opcode xim:opcode:trigger-notify) - (exwm--log "TRIGGER-NOTIFY") - ;; Only static event flow modal is supported. - (push exwm-xim--default-error replies)) - ((= opcode xim:opcode:encoding-negotiation) - (exwm--log "ENCODING-NEGOTIATION") - (setq req (make-instance 'xim:encoding-negotiation)) - (xcb:unmarshal req data) - (let ((index (cl-position "COMPOUND_TEXT" - (mapcar (lambda (i) (slot-value i 'name)) - (slot-value req 'names)) - :test #'equal))) - (unless index - ;; Fallback to portable character encoding (a subset of ASCII). - (setq index -1)) - (push (make-instance 'xim:encoding-negotiation-reply - :im-id (slot-value req 'im-id) - :category - xim:encoding-negotiation-reply-category:name - :index index) - replies))) - ((= opcode xim:opcode:query-extension) - (exwm--log "QUERY-EXTENSION") - (setq req (make-instance 'xim:query-extension)) - (xcb:unmarshal req data) - (push (make-instance 'xim:query-extension-reply - :im-id (slot-value req 'im-id) - ;; No extension support. - :length 0 - :extensions nil) - replies)) - ((= opcode xim:opcode:set-im-values) - (exwm--log "SET-IM-VALUES") - ;; There's only one possible input method attribute. - (setq req (make-instance 'xim:set-im-values)) - (xcb:unmarshal req data) - (push (make-instance 'xim:set-im-values-reply - :im-id (slot-value req 'im-id)) - replies)) - ((= opcode xim:opcode:get-im-values) - (exwm--log "GET-IM-VALUES") - (setq req (make-instance 'xim:get-im-values)) - (let (im-attributes-id) - (xcb:unmarshal req data) - (setq im-attributes-id (slot-value req 'im-attributes-id)) - (if (cl-notevery (lambda (i) (= i 0)) im-attributes-id) - ;; Only support one IM attributes. - (push (make-instance 'xim:error - :im-id (slot-value req 'im-id) - :ic-id 0 - :flag xim:error-flag:invalid-ic-id - :error-code xim:error-code:bad-something - :length 0 - :type 0 - :detail nil) - replies) - (push - (make-instance 'xim:get-im-values-reply - :im-id (slot-value req 'im-id) - :length nil - :im-attributes exwm-xim--default-attributes) - replies)))) - ((= opcode xim:opcode:create-ic) - (exwm--log "CREATE-IC") - (setq req (make-instance 'xim:create-ic)) - (xcb:unmarshal req data) - ;; Note: The ic-attributes slot is ignored. - (setq exwm-xim--ic-id (if (< exwm-xim--ic-id #xffff) - (1+ exwm-xim--ic-id) - 1)) - (push (make-instance 'xim:create-ic-reply - :im-id (slot-value req 'im-id) - :ic-id exwm-xim--ic-id) - replies)) - ((= opcode xim:opcode:destroy-ic) - (exwm--log "DESTROY-IC") - (setq req (make-instance 'xim:destroy-ic)) - (xcb:unmarshal req data) - (push (make-instance 'xim:destroy-ic-reply - :im-id (slot-value req 'im-id) - :ic-id (slot-value req 'ic-id)) - replies)) - ((= opcode xim:opcode:set-ic-values) - (exwm--log "SET-IC-VALUES") - (setq req (make-instance 'xim:set-ic-values)) - (xcb:unmarshal req data) - ;; We don't distinguish between input contexts. - (push (make-instance 'xim:set-ic-values-reply - :im-id (slot-value req 'im-id) - :ic-id (slot-value req 'ic-id)) - replies)) - ((= opcode xim:opcode:get-ic-values) - (exwm--log "GET-IC-VALUES") - (setq req (make-instance 'xim:get-ic-values)) - (xcb:unmarshal req data) - (push (make-instance 'xim:get-ic-values-reply - :im-id (slot-value req 'im-id) - :ic-id (slot-value req 'ic-id) - :length nil - :ic-attributes exwm-xim--default-attributes) - replies)) - ((= opcode xim:opcode:set-ic-focus) - (exwm--log "SET-IC-FOCUS") - ;; All input contexts are the same. - ) - ((= opcode xim:opcode:unset-ic-focus) - (exwm--log "UNSET-IC-FOCUS") - ;; All input contexts are the same. - ) - ((= opcode xim:opcode:forward-event) - (exwm--log "FORWARD-EVENT") - (setq req (make-instance 'xim:forward-event)) - (xcb:unmarshal req data) - (exwm-xim--handle-forward-event-request req xim:lsb conn - client-xwin)) - ((= opcode xim:opcode:sync) - (exwm--log "SYNC") - (setq req (make-instance 'xim:sync)) - (xcb:unmarshal req data) - (push (make-instance 'xim:sync-reply - :im-id (slot-value req 'im-id) - :ic-id (slot-value req 'ic-id)) - replies)) - ((= opcode xim:opcode:sync-reply) - (exwm--log "SYNC-REPLY")) - ((= opcode xim:opcode:reset-ic) - (exwm--log "RESET-IC") - ;; No context-specific data saved. - (setq req (make-instance 'xim:reset-ic)) - (xcb:unmarshal req data) - (push (make-instance 'xim:reset-ic-reply - :im-id (slot-value req 'im-id) - :ic-id (slot-value req 'ic-id) - :length 0 - :string "") - replies)) - ((memq opcode (list xim:opcode:str-conversion-reply - xim:opcode:preedit-start-reply - xim:opcode:preedit-caret-reply)) - (exwm--log "PREEDIT: %d" opcode) - ;; No preedit support. - (push exwm-xim--default-error replies)) - (t - (exwm--log "Bad protocol") - (push exwm-xim--default-error replies))) - ;; Actually send the replies. - (when replies - (mapc (lambda (reply) - (exwm-xim--make-request reply conn client-xwin)) - replies) - (xcb:flush conn)))) - -(defun exwm-xim--handle-forward-event-request (req lsb conn client-xwin) - (let ((im-func (with-current-buffer (window-buffer) - input-method-function)) - key-event keysym keysyms event result) - ;; Note: The flag slot is ignored. - ;; Do conversion in client's byte-order. - (let ((xcb:lsb lsb)) - (setq key-event (make-instance 'xcb:KeyPress)) - (xcb:unmarshal key-event (slot-value req 'event))) - (with-slots (detail state) key-event - (setq keysym (xcb:keysyms:keycode->keysym exwm-xim--conn detail - state)) - (when (/= (car keysym) 0) - (setq event (xcb:keysyms:keysym->event - exwm-xim--conn - (car keysym) - (logand state (lognot (cdr keysym))))))) - (while (or (slot-value req 'event) unread-command-events) - (unless (slot-value req 'event) - (setq event (pop unread-command-events)) - ;; Handle events in (t . EVENT) format. - (when (and (consp event) - (eq (car event) t)) - (setq event (cdr event)))) - (if (or (not im-func) - ;; `list' is the default method. - (eq im-func #'list) - (not event) - ;; Select only printable keys. - (not (integerp event)) (> #x20 event) (< #x7e event)) - ;; Either there is no active input method, or invalid key - ;; is detected. - (with-slots ((raw-event event) - im-id ic-id serial-number) - req - (if raw-event - (setq event raw-event) - (setq keysyms (xcb:keysyms:event->keysyms exwm-xim--conn event)) - (with-slots (detail state) key-event - (setf detail (xcb:keysyms:keysym->keycode exwm-xim--conn - (caar keysyms)) - state (cdar keysyms))) - (setq event (let ((xcb:lsb lsb)) - (xcb:marshal key-event conn)))) - (when event - (exwm-xim--make-request - (make-instance 'xim:forward-event - :im-id im-id - :ic-id ic-id - :flag xim:commit-flag:synchronous - :serial-number serial-number - :event event) - conn client-xwin))) - (when (eq exwm--selected-input-mode 'char-mode) - ;; Grab keyboard temporarily for char-mode. - (exwm-input--grab-keyboard)) - (unwind-protect - (with-temp-buffer - ;; This variable is used to test whether exwm-xim is enabled. - ;; Used by e.g. pyim-probe. - (setq-local exwm-xim-buffer-p t) - ;; Always show key strokes. - (let ((input-method-use-echo-area t) - (exwm-input-line-mode-passthrough t)) - (setq result (funcall im-func event)) - ;; Clear echo area for the input method. - (message nil) - ;; This also works for portable character encoding. - (setq result - (encode-coding-string (concat result) - 'compound-text-with-extensions)) - (exwm-xim--make-request - (make-instance 'xim:commit-x-lookup-chars - :im-id (slot-value req 'im-id) - :ic-id (slot-value req 'ic-id) - :flag (logior xim:commit-flag:synchronous - xim:commit-flag:x-lookup-chars) - :length (length result) - :string result) - conn client-xwin))) - (when (eq exwm--selected-input-mode 'char-mode) - (exwm-input--release-keyboard)))) - (xcb:flush conn) - (setf event nil - (slot-value req 'event) nil)))) - -(defun exwm-xim--make-request (req conn client-xwin) - "Make an XIM request REQ via connection CONN. - -CLIENT-XWIN would receive a ClientMessage event either telling the client -the request data or where to fetch the data." - (exwm--log) - (let ((data (xcb:marshal req)) - property format client-message-data client-message) - (if (<= (length data) 20) - ;; Send short requests directly with client messages. - (setq format 8 - ;; Pad to 20 bytes. - data (append data (make-list (- 20 (length data)) 0)) - client-message-data (make-instance 'xcb:ClientMessageData - :data8 data)) - ;; Send long requests with properties. - (setq property (exwm--intern-atom (format "_EXWM_XIM_%x" - exwm-xim--property-index))) - (cl-incf exwm-xim--property-index) - (xcb:+request conn - (make-instance 'xcb:ChangeProperty - :mode xcb:PropMode:Append - :window client-xwin - :property property - :type xcb:Atom:STRING - :format 8 - :data-len (length data) - :data data)) - ;; Also send a client message to notify the client about this property. - (setq format 32 - client-message-data (make-instance 'xcb:ClientMessageData - :data32 `(,(length data) - ,property - ;; Pad to 20 bytes. - 0 0 0)))) - ;; Send the client message. - (setq client-message (make-instance 'xcb:ClientMessage - :format format - :window client-xwin - :type exwm-xim--_XIM_PROTOCOL - :data client-message-data)) - (xcb:+request conn - (make-instance 'xcb:SendEvent - :propagate 0 - :destination client-xwin - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal client-message conn))))) - -(defun exwm-xim--on-DestroyNotify (data synthetic) - "Do cleanups on receiving DestroyNotify event. - -Such event would be received when the client window is destroyed." - (exwm--log) - (unless synthetic - (let ((evt (make-instance 'xcb:DestroyNotify)) - conn client-xwin server-xwin) - (xcb:unmarshal evt data) - (setq client-xwin (slot-value evt 'window) - server-xwin (plist-get exwm-xim--client-server-plist client-xwin)) - (when server-xwin - (setq conn (aref (plist-get exwm-xim--server-client-plist server-xwin) - 0)) - (cl-remf exwm-xim--server-client-plist server-xwin) - (cl-remf exwm-xim--client-server-plist client-xwin) - ;; Destroy the communication window & connection. - (xcb:+request conn - (make-instance 'xcb:DestroyWindow - :window server-xwin)) - (xcb:disconnect conn))))) - -(cl-defun exwm-xim--init () - "Initialize the XIM module." - (exwm--log) - (when exwm-xim--conn - (cl-return-from exwm-xim--init)) - ;; Initialize atoms. - (setq exwm-xim--@server (exwm--intern-atom "@server=exwm-xim") - exwm-xim--LOCALES (exwm--intern-atom "LOCALES") - exwm-xim--TRANSPORT (exwm--intern-atom "TRANSPORT") - exwm-xim--XIM_SERVERS (exwm--intern-atom "XIM_SERVERS") - exwm-xim--_XIM_PROTOCOL (exwm--intern-atom "_XIM_PROTOCOL") - exwm-xim--_XIM_XCONNECT (exwm--intern-atom "_XIM_XCONNECT")) - ;; Create a new connection and event window. - (setq exwm-xim--conn (xcb:connect) - exwm-xim--event-xwin (xcb:generate-id exwm-xim--conn)) - (set-process-query-on-exit-flag (slot-value exwm-xim--conn 'process) nil) - ;; Initialize xcb:keysyms module. - (xcb:keysyms:init exwm-xim--conn) - ;; Listen to SelectionRequest event for connection establishment. - (xcb:+event exwm-xim--conn 'xcb:SelectionRequest - #'exwm-xim--on-SelectionRequest) - ;; Listen to ClientMessage event on IMS window for new XIM connection. - (xcb:+event exwm-xim--conn 'xcb:ClientMessage #'exwm-xim--on-ClientMessage-0) - ;; Listen to DestroyNotify event to do cleanups. - (xcb:+event exwm-xim--conn 'xcb:DestroyNotify #'exwm-xim--on-DestroyNotify) - ;; Create the event window. - (xcb:+request exwm-xim--conn - (make-instance 'xcb:CreateWindow - :depth 0 - :wid exwm-xim--event-xwin - :parent exwm--root - :x 0 - :y 0 - :width 1 - :height 1 - :border-width 0 - :class xcb:WindowClass:InputOutput - :visual 0 - :value-mask xcb:CW:OverrideRedirect - :override-redirect 1)) - ;; Set the selection owner. - (xcb:+request exwm-xim--conn - (make-instance 'xcb:SetSelectionOwner - :owner exwm-xim--event-xwin - :selection exwm-xim--@server - :time xcb:Time:CurrentTime)) - ;; Set XIM_SERVERS property on the root window. - (xcb:+request exwm-xim--conn - (make-instance 'xcb:ChangeProperty - :mode xcb:PropMode:Prepend - :window exwm--root - :property exwm-xim--XIM_SERVERS - :type xcb:Atom:ATOM - :format 32 - :data-len 1 - :data (funcall (if xcb:lsb - #'xcb:-pack-u4-lsb - #'xcb:-pack-u4) - exwm-xim--@server))) - (xcb:flush exwm-xim--conn)) - -(cl-defun exwm-xim--exit () - "Exit the XIM module." - (exwm--log) - ;; Close IMS communication connections. - (mapc (lambda (i) - (when (vectorp i) - (when (slot-value (elt i 0) 'connected) - (xcb:disconnect (elt i 0))))) - exwm-xim--server-client-plist) - ;; Close the IMS connection. - (unless (and exwm-xim--conn - (slot-value exwm-xim--conn 'connected)) - (cl-return-from exwm-xim--exit)) - ;; Remove exwm-xim from XIM_SERVERS. - (let ((reply (xcb:+request-unchecked+reply exwm-xim--conn - (make-instance 'xcb:GetProperty - :delete 1 - :window exwm--root - :property exwm-xim--XIM_SERVERS - :type xcb:Atom:ATOM - :long-offset 0 - :long-length 1000))) - unpacked-reply pack unpack) - (unless reply - (cl-return-from exwm-xim--exit)) - (setq reply (slot-value reply 'value)) - (unless (> (length reply) 4) - (cl-return-from exwm-xim--exit)) - (setq reply (vconcat reply) - pack (if xcb:lsb #'xcb:-pack-u4-lsb #'xcb:-pack-u4) - unpack (if xcb:lsb #'xcb:-unpack-u4-lsb #'xcb:-unpack-u4)) - (dotimes (i (/ (length reply) 4)) - (push (funcall unpack reply (* i 4)) unpacked-reply)) - (setq unpacked-reply (delq exwm-xim--@server unpacked-reply) - reply (mapcar pack unpacked-reply)) - (xcb:+request exwm-xim--conn - (make-instance 'xcb:ChangeProperty - :mode xcb:PropMode:Replace - :window exwm--root - :property exwm-xim--XIM_SERVERS - :type xcb:Atom:ATOM - :format 32 - :data-len (length reply) - :data reply)) - (xcb:flush exwm-xim--conn)) - (xcb:disconnect exwm-xim--conn) - (setq exwm-xim--conn nil)) - -(defun exwm-xim-enable () - "Enable XIM support for EXWM." - (exwm--log) - (add-hook 'exwm-init-hook #'exwm-xim--init) - (add-hook 'exwm-exit-hook #'exwm-xim--exit)) - - - -(provide 'exwm-xim) - -;;; exwm-xim.el ends here diff --git a/third_party/exwm/exwm-xsettings.el b/third_party/exwm/exwm-xsettings.el deleted file mode 100644 index 596588b82..000000000 --- a/third_party/exwm/exwm-xsettings.el +++ /dev/null @@ -1,336 +0,0 @@ -;;; exwm-xsettings.el --- XSETTINGS Module for EXWM -*- lexical-binding: t -*- - -;; Copyright (C) 2022-2024 Free Software Foundation, Inc. - -;; Author: Steven Allen - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; Implements the XSETTINGS protocol, allowing Emacs to manage the system theme, -;; fonts, icons, etc. -;; -;; This package can be configured as follows: -;; -;; (require 'exwm-xsettings) -;; (setq exwm-xsettings-theme '("Adwaita" . "Adwaita-dark") ;; light/dark -;; exwm-xsettings `(("Xft/HintStyle" . "hintslight") -;; ("Xft/RGBA" . "rgb") -;; ("Xft/lcdfilter" . "lcddefault") -;; ("Xft/Antialias" . 1) -;; ;; DPI is in 1024ths of an inch, so this is a DPI of -;; ;; 144, equivalent to ;; a scaling factor of 1.5 -;; ;; (144 = 1.5 * 96). -;; ("Xft/DPI" . ,(* 144 1024)) -;; ("Xft/Hinting" . 1))) -;; (exwm-xsettings-enable) -;; -;; To modify these settings at runtime, customize them with -;; `custom-set-variables' or `setopt' (Emacs 29+). E.g., the following will -;; immediately change the icon theme to "Papirus" at runtime, even in running -;; applications: -;; -;; (setopt exwm-xsettings-icon-theme "Papirus") - -;;; Code: - -(require 'xcb-ewmh) -(require 'xcb-xsettings) -(require 'exwm-core) - -(defvar exwm-xsettings--connection nil) -(defvar exwm-xsettings--XSETTINGS_SETTINGS-atom nil) -(defvar exwm-xsettings--XSETTINGS_S0-atom nil) -(defvar exwm-xsettings--selection-owner-window nil) -(defvar exwm-xsettings--serial 0) - -(defun exwm-xsettings--rgba-match (_widget value) - "Return t if VALUE is a valid RGBA color." - (and (numberp value) (<= 0 value 1))) - -(defun exwm-xsettings--custom-set (symbol value) - "Setter used by `exwm-xsettings' customization options. - -SYMBOL is the setting being updated and VALUE is the new value." - (set-default-toplevel-value symbol value) - (exwm-xsettings--update-settings)) - -(defgroup exwm-xsettings nil - "XSETTINGS." - :group 'exwm) - -(defcustom exwm-xsettings nil - "Alist of custom XSETTINGS. -These settings take precedence over `exwm-xsettings-theme' and -`exwm-xsettings-icon-theme'." - :type '(alist :key-type (string :tag "Name") - :value-type (choice :tag "Value" - (string :tag "String") - (integer :tag "Integer") - (list :tag "Color" - (number :tag "Red" - :type-error - "This field should contain a number between 0 and 1." - :match exwm-xsettings--rgba-match) - (number :tag "Green" - :type-error - "This field should contain a number between 0 and 1." - :match exwm-xsettings--rgba-match) - (number :tag "Blue" - :type-error - "This field should contain a number between 0 and 1." - :match exwm-xsettings--rgba-match) - (number :tag "Alpha" - :type-error - "This field should contain a number between 0 and 1." - :match exwm-xsettings--rgba-match - :value 1.0)))) - :initialize #'custom-initialize-default - :set #'exwm-xsettings--custom-set) - -(defcustom exwm-xsettings-theme nil - "The system-wide theme." - :type '(choice (string :tag "Theme") - (cons (string :tag "Light Theme") - (string :tag "Dark Theme"))) - :initialize #'custom-initialize-default - :set #'exwm-xsettings--custom-set) - -(defcustom exwm-xsettings-icon-theme nil - "The system-wide icon theme." - :type '(choice (string :tag "Icon Theme") - (cons (string :tag "Light Icon Theme") - (string :tag "Dark Icon Theme"))) - :initialize #'custom-initialize-default - :set #'exwm-xsettings--custom-set) - -(defalias 'exwm-xsettings--color-dark-p - (if (eval-when-compile (< emacs-major-version 29)) - ;; Borrowed from Emacs 29. - (lambda (rgb) - "Whether RGB is more readable against white than black." - (unless (<= 0 (apply #'min rgb) (apply #'max rgb) 1) - (error "RGB components %S not in [0,1]" rgb)) - (let* ((r (expt (nth 0 rgb) 2.2)) - (g (expt (nth 1 rgb) 2.2)) - (b (expt (nth 2 rgb) 2.2)) - (y (+ (* r 0.2126) (* g 0.7152) (* b 0.0722)))) - (< y 0.325))) - 'color-dark-p)) - -(defun exwm-xsettings--pick-theme (theme) - "Pick a light or dark theme from the given THEME. -If THEME is a string, it's returned directly. -If THEME is a cons of (LIGHT . DARK), the appropriate theme is picked based on -the default face's background color." - (pcase theme - ((cl-type string) theme) - (`(,(cl-type string) . ,(cl-type string)) - (if (exwm-xsettings--color-dark-p (color-name-to-rgb (face-background 'default))) - (cdr theme) (car theme))) - (_ (error "Expected theme to be a string or a pair of strings")))) - -(defun exwm-xsettings--get-settings () - "Get the current settings. -Combines `exwm-xsettings', `exwm-xsettings-theme' (if set), and -`exwm-xsettings-icon-theme' (if set)." - (cl-remove-duplicates - (append - exwm-xsettings - (when exwm-xsettings-theme - (list (cons "Net/ThemeName" (exwm-xsettings--pick-theme exwm-xsettings-theme)))) - (when exwm-xsettings-icon-theme - (list (cons "Net/IconThemeName" (exwm-xsettings--pick-theme exwm-xsettings-icon-theme))))) - :key 'car - :test 'string=)) - -(defun exwm-xsettings--make-settings (settings serial) - "Construct a new settings object. -SETTINGS is an alist of key/value pairs. -SERIAL is a sequence number." - (make-instance 'xcb:xsettings:-Settings - :byte-order (if xcb:lsb 0 1) - :serial serial - :settings-len (length settings) - :settings - (mapcar - (lambda (prop) - (let* ((name (car prop)) - (value (cdr prop)) - (common (list :name name - :name-len (length name) - :last-change-serial serial))) - (pcase value - ((cl-type string) - (apply #'make-instance 'xcb:xsettings:-SETTING_STRING - :value-len (length value) - :value value - common)) - ((cl-type integer) - (apply #'make-instance 'xcb:xsettings:-SETTING_INTEGER - :value value common)) - ((and (cl-type list) (app length (or 3 4))) - ;; Convert from RGB(A) to 16bit integers. - (setq value (mapcar (lambda (x) (round (* x #xffff))) value)) - (apply #'make-instance 'xcb:xsettings:-SETTING_COLOR - :red (pop value) - :green (pop value) - :blue (pop value) - :alpha (or (pop value) #xffff))) - (_ (error "Setting value must be a string, integer, or length 3-4 list"))))) - settings))) - -(defun exwm-xsettings--update-settings () - "Update the xsettings." - (when exwm-xsettings--connection - (setq exwm-xsettings--serial (1+ exwm-xsettings--serial)) - (let* ((settings (exwm-xsettings--get-settings)) - (bytes (xcb:marshal (exwm-xsettings--make-settings settings exwm-xsettings--serial)))) - (xcb:+request exwm-xsettings--connection - (make-instance 'xcb:ChangeProperty - :mode xcb:PropMode:Replace - :window exwm-xsettings--selection-owner-window - :property exwm-xsettings--XSETTINGS_SETTINGS-atom - :type exwm-xsettings--XSETTINGS_SETTINGS-atom - :format 8 - :data-len (length bytes) - :data bytes))) - (xcb:flush exwm-xsettings--connection))) - -(defun exwm-xsettings--on-theme-change (&rest _) - "Called when the Emacs theme is changed." - ;; We only bother updating the xsettings if changing the theme could effect - ;; the settings. - (when (or (consp exwm-xsettings-theme) (consp exwm-xsettings-icon-theme)) - (exwm-xsettings--update-settings))) - -(defun exwm-xsettings--on-SelectionClear (_data _synthetic) - "Called when another xsettings daemon takes over." - (exwm--log "XSETTINGS manager has been replaced.") - (exwm-xsettings--exit)) - -(cl-defun exwm-xsettings--init () - "Initialize the XSETTINGS module." - (exwm--log) - - (cl-assert (not exwm-xsettings--connection)) - - ;; Connect - (setq exwm-xsettings--connection (xcb:connect)) - (set-process-query-on-exit-flag (slot-value exwm-xsettings--connection - 'process) - nil) - - ;; Intern the atoms. - (setq exwm-xsettings--XSETTINGS_SETTINGS-atom - (exwm--intern-atom "_XSETTINGS_SETTINGS" exwm-xsettings--connection) - - exwm-xsettings--XSETTINGS_S0-atom - (exwm--intern-atom "_XSETTINGS_S0" exwm-xsettings--connection)) - - ;; Detect running XSETTINGS managers. - (with-slots (owner) - (xcb:+request-unchecked+reply exwm-xsettings--connection - (make-instance 'xcb:GetSelectionOwner - :selection exwm-xsettings--XSETTINGS_S0-atom)) - (when (/= owner xcb:Window:None) - (xcb:disconnect exwm-xsettings--connection) - (setq exwm-xsettings--connection nil) - (warn "[EXWM] Other XSETTINGS manager detected") - (cl-return-from exwm-xsettings--init))) - - (let ((id(xcb:generate-id exwm-xsettings--connection))) - (setq exwm-xsettings--selection-owner-window id) - - ;; Create a settings window. - (xcb:+request exwm-xsettings--connection - (make-instance 'xcb:CreateWindow - :wid id - :parent exwm--root - :class xcb:WindowClass:InputOnly - :x 0 - :y 0 - :width 1 - :height 1 - :border-width 0 - :depth 0 - :visual 0 - :value-mask xcb:CW:OverrideRedirect - :override-redirect 1)) - - ;; Set _NET_WM_NAME. - (xcb:+request exwm-xsettings--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window id - :data "EXWM: exwm-xsettings--selection-owner-window")) - - ;; Apply the XSETTINGS properties. - (exwm-xsettings--update-settings) - - ;; Take ownership and notify. - (xcb:+request exwm-xsettings--connection - (make-instance 'xcb:SetSelectionOwner - :owner id - :selection exwm-xsettings--XSETTINGS_S0-atom - :time xcb:Time:CurrentTime)) - (xcb:+request exwm-xsettings--connection - (make-instance 'xcb:SendEvent - :propagate 0 - :destination exwm--root - :event-mask xcb:EventMask:StructureNotify - :event (xcb:marshal - (make-instance 'xcb:icccm:-ManagerSelection - :window exwm--root - :time xcb:Time:CurrentTime - :selection exwm-xsettings--XSETTINGS_S0-atom - :owner id) - exwm-xsettings--connection))) - - ;; Detect loss of XSETTINGS ownership. - (xcb:+event exwm-xsettings--connection 'xcb:SelectionClear - #'exwm-xsettings--on-SelectionClear) - - (xcb:flush exwm-xsettings--connection)) - - ;; Update the xsettings if/when the theme changes. - (add-hook 'enable-theme-functions #'exwm-xsettings--on-theme-change) - (add-hook 'disable-theme-functions #'exwm-xsettings--on-theme-change)) - -(defun exwm-xsettings--exit () - "Exit the XSETTINGS module." - (exwm--log) - - (when exwm-xsettings--connection - (remove-hook 'enable-theme-functions #'exwm-xsettings--on-theme-change) - (remove-hook 'disable-theme-functions #'exwm-xsettings--on-theme-change) - - (xcb:disconnect exwm-xsettings--connection) - - (setq exwm-xsettings--connection nil - exwm-xsettings--XSETTINGS_SETTINGS-atom nil - exwm-xsettings--XSETTINGS_S0-atom nil - exwm-xsettings--selection-owner-window nil))) - -(defun exwm-xsettings-enable () - "Enable xsettings support for EXWM." - (exwm--log) - (add-hook 'exwm-init-hook #'exwm-xsettings--init) - (add-hook 'exwm-exit-hook #'exwm-xsettings--exit)) - -(provide 'exwm-xsettings) - -;;; exwm-xsettings.el ends here diff --git a/third_party/exwm/exwm.el b/third_party/exwm/exwm.el deleted file mode 100644 index 1186a40f4..000000000 --- a/third_party/exwm/exwm.el +++ /dev/null @@ -1,1110 +0,0 @@ -;;; exwm.el --- Emacs X Window Manager -*- lexical-binding: t -*- - -;; Copyright (C) 2015-2024 Free Software Foundation, Inc. - -;; Author: Chris Feng -;; Maintainer: Adrián Medraño Calvo , Steven Allen , Daniel Mendler -;; Version: 0.30 -;; Package-Requires: ((emacs "27.1") (xelb "0.19")) -;; Keywords: unix -;; URL: https://github.com/emacs-exwm/exwm - -;; This file is part of GNU Emacs. - -;; GNU Emacs is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; GNU Emacs is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with GNU Emacs. If not, see . - -;;; Commentary: - -;; Overview -;; -------- -;; EXWM (Emacs X Window Manager) is a full-featured tiling X window manager -;; for Emacs built on top of [XELB](https://github.com/emacs-exwm/xelb). -;; It features: -;; + Fully keyboard-driven operations -;; + Hybrid layout modes (tiling & stacking) -;; + Dynamic workspace support -;; + ICCCM/EWMH compliance -;; Optional features: -;; + RandR (multi-monitor) support -;; + System tray -;; + Input method -;; + Background setting support -;; + XSETTINGS server - -;; Installation & configuration -;; ---------------------------- -;; Here are the minimal steps to get EXWM working: -;; 1. Install XELB and EXWM, and make sure they are in `load-path'. -;; 2. In '~/.emacs', add following lines (please modify accordingly): -;; -;; (require 'exwm) -;; (require 'exwm-config) -;; (exwm-config-example) -;; -;; 3. Link or copy the file 'xinitrc' to '~/.xinitrc'. -;; 4. Launch EXWM in a console (e.g. tty1) with -;; -;; xinit -- vt01 -;; -;; You should additionally hide the menu-bar, tool-bar, etc to increase the -;; usable space. Please check the wiki (https://github.com/emacs-exwm/exwm/wiki) -;; for more detailed instructions on installation, configuration, usage, etc. - -;; References: -;; + dwm (http://dwm.suckless.org/) -;; + i3 wm (https://i3wm.org/) -;; + Also see references within each required library. - -;;; Code: - -(require 'server) -(require 'exwm-core) -(require 'exwm-workspace) -(require 'exwm-layout) -(require 'exwm-floating) -(require 'exwm-manage) -(require 'exwm-input) - -(declare-function x-get-atom-name "C source code" (VALUE &optional FRAME)) - -(defgroup exwm nil - "Emacs X Window Manager." - :tag "EXWM" - :group 'applications - :prefix "exwm-") - -(defcustom exwm-init-hook nil - "Normal hook run when EXWM has just finished initialization." - :type 'hook) - -(defcustom exwm-exit-hook nil - "Normal hook run just before EXWM exits." - :type 'hook) - -(defcustom exwm-update-class-hook nil - "Normal hook run when window class is updated." - :type 'hook) - -(defcustom exwm-update-title-hook nil - "Normal hook run when window title is updated." - :type 'hook) - -(defcustom exwm-blocking-subrs - ;; `x-file-dialog' and `x-select-font' are missing on some Emacs builds, for - ;; example on the X11 Lucid build. - '(x-file-dialog x-popup-dialog x-select-font message-box message-or-box) - "Subrs (primitives) that would normally block EXWM." - :type '(repeat function)) - -(defcustom exwm-replace 'ask - "Whether to replace existing window manager." - :type '(radio (const :tag "Ask" ask) - (const :tag "Replace by default" t) - (const :tag "Do not replace" nil))) - -(defconst exwm--server-name "server-exwm" - "Name of the subordinate Emacs server.") - -(defvar exwm--server-timeout 1 - "Number of seconds to wait for the subordinate Emacs server to exit. -After this time, the server will be killed.") - -(defvar exwm--server-process nil "Process of the subordinate Emacs server.") - -(defun exwm-reset () - "Reset the state of the selected window (non-fullscreen, line-mode, etc)." - (interactive) - (exwm--log) - (with-current-buffer (window-buffer) - (when (derived-mode-p 'exwm-mode) - (when (exwm-layout--fullscreen-p) - (exwm-layout-unset-fullscreen)) - ;; Force refresh - (exwm-layout--refresh) - (call-interactively #'exwm-input-grab-keyboard)))) - -;;;###autoload -(defun exwm-restart () - "Restart EXWM." - (interactive) - (exwm--log) - (when (exwm--confirm-kill-emacs "Restart?" 'no-check) - (let* ((attr (process-attributes (emacs-pid))) - (args (cdr (assq 'args attr))) - (ppid (cdr (assq 'ppid attr))) - (pargs (cdr (assq 'args (process-attributes ppid))))) - (cond - ((= ppid 1) - ;; The parent is the init process. This probably means this - ;; instance is an emacsclient. Anyway, start a control instance - ;; to manage the subsequent ones. - (call-process (car command-line-args)) - (kill-emacs)) - ((string= args pargs) - ;; This is a subordinate instance. Return a magic number to - ;; inform the parent (control instance) to start another one. - (kill-emacs ?R)) - (t - ;; This is the control instance. Keep starting subordinate - ;; instances until told to exit. - ;; Run `server-force-stop' if it exists. - (run-hooks 'kill-emacs-hook) - (with-temp-buffer - (while (= ?R (shell-command-on-region (point) (point) args)))) - (kill-emacs)))))) - -(defun exwm--update-desktop (xwin) - "Update _NET_WM_DESKTOP. -Argument XWIN contains the X window of the `exwm-mode' buffer." - (exwm--log "#x%x" xwin) - (with-current-buffer (exwm--id->buffer xwin) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:ewmh:get-_NET_WM_DESKTOP - :window xwin))) - desktop) - (when reply - (setq desktop (slot-value reply 'value)) - (cond - ((and desktop (= desktop 4294967295.)) - (unless (or (not exwm--floating-frame) - (eq exwm--frame exwm-workspace--current) - (and exwm--desktop - (= desktop exwm--desktop))) - (exwm-layout--show xwin (frame-root-window exwm--floating-frame))) - (setq exwm--desktop desktop)) - ((and desktop - (< desktop (exwm-workspace--count)) - (if exwm--desktop - (/= desktop exwm--desktop) - (/= desktop (exwm-workspace--position exwm--frame)))) - (exwm-workspace-move-window desktop xwin)) - (t - (exwm-workspace--set-desktop xwin))))))) - -(defun exwm--update-window-type (id &optional force) - "Update `exwm-window-type' from _NET_WM_WINDOW_TYPE. -Argument ID contains the X window of the `exwm-mode' buffer. - -When FORCE is nil the update only takes place if -`exwm-window-type' is unset." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (and exwm-window-type (not force)) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:ewmh:get-_NET_WM_WINDOW_TYPE - :window id)))) - (when reply ;nil when destroyed - (setq exwm-window-type (append (slot-value reply 'value) nil))))))) - -(defun exwm--update-class (id &optional force) - "Update `exwm-instance-name' and `exwm-class' from WM_CLASS. -Argument ID contains the X window of the `exwm-mode' buffer. - -When FORCE is nil the update only takes place if any of -`exwm-instance-name' or `exwm-class' is unset." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (and exwm-instance-name exwm-class-name (not force)) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:icccm:get-WM_CLASS :window id)))) - (when reply ;nil when destroyed - (setq exwm-instance-name (slot-value reply 'instance-name) - exwm-class-name (slot-value reply 'class-name)) - (when (and exwm-instance-name exwm-class-name) - (run-hooks 'exwm-update-class-hook))))))) - -(defun exwm--update-utf8-title (id &optional force) - "Update `exwm-title' from _NET_WM_NAME. -Argument ID contains the X window of the `exwm-mode' buffer. - -When FORCE is nil the update only takes place if `exwm-title' is -unset." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (when (or force (not exwm-title)) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:ewmh:get-_NET_WM_NAME :window id)))) - (when reply ;nil when destroyed - (setq exwm-title (slot-value reply 'value)) - (when exwm-title - (setq exwm--title-is-utf8 t) - (run-hooks 'exwm-update-title-hook))))))) - -(defun exwm--update-ctext-title (id &optional force) - "Update `exwm-title' from WM_NAME. -Argument ID contains the X window of the `exwm-mode' buffer. - -When FORCE is nil the update only takes place if `exwm-title' is -unset." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (or exwm--title-is-utf8 - (and exwm-title (not force))) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:icccm:get-WM_NAME :window id)))) - (when reply ;nil when destroyed - (setq exwm-title (slot-value reply 'value)) - (when exwm-title - (run-hooks 'exwm-update-title-hook))))))) - -(defun exwm--update-title (id) - "Update _NET_WM_NAME or WM_NAME. -Argument ID contains the X window of the `exwm-mode' buffer." - (exwm--log "#x%x" id) - (exwm--update-utf8-title id) - (exwm--update-ctext-title id)) - -(defun exwm--update-transient-for (id &optional force) - "Update `exwm-transient-for' from WM_TRANSIENT_FOR. -Argument ID contains the X window of the `exwm-mode' buffer. - -When FORCE is nil the update only takes place if `exwm-title' is -unset." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (and exwm-transient-for (not force)) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:icccm:get-WM_TRANSIENT_FOR - :window id)))) - (when reply ;nil when destroyed - (setq exwm-transient-for (slot-value reply 'value))))))) - -(defun exwm--update-normal-hints (id &optional force) - "Update normal hints from WM_NORMAL_HINTS. -Argument ID contains the X window of the `exwm-mode' buffer. - -When FORCE is nil the update only takes place all of -`exwm--normal-hints-x exwm--normal-hints-y', -`exwm--normal-hints-width exwm--normal-hints-height', -`exwm--normal-hints-min-width exwm--normal-hints-min-height' and -`exwm--normal-hints-max-width exwm--normal-hints-max-height' are -unset." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (and (not force) - (or exwm--normal-hints-x exwm--normal-hints-y - exwm--normal-hints-width exwm--normal-hints-height - exwm--normal-hints-min-width exwm--normal-hints-min-height - exwm--normal-hints-max-width exwm--normal-hints-max-height - ;; FIXME: other fields - )) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:icccm:get-WM_NORMAL_HINTS - :window id)))) - (when (and reply (slot-value reply 'flags)) ;nil when destroyed - (with-slots (flags x y width height min-width min-height max-width - max-height base-width base-height ;; win-gravity - ) - reply - (unless (= 0 (logand flags xcb:icccm:WM_SIZE_HINTS:USPosition)) - (setq exwm--normal-hints-x x exwm--normal-hints-y y)) - (unless (= 0 (logand flags xcb:icccm:WM_SIZE_HINTS:USSize)) - (setq exwm--normal-hints-width width - exwm--normal-hints-height height)) - (unless (= 0 (logand flags xcb:icccm:WM_SIZE_HINTS:PMinSize)) - (setq exwm--normal-hints-min-width min-width - exwm--normal-hints-min-height min-height)) - (unless (= 0 (logand flags xcb:icccm:WM_SIZE_HINTS:PMaxSize)) - (setq exwm--normal-hints-max-width max-width - exwm--normal-hints-max-height max-height)) - (unless (or exwm--normal-hints-min-width - (= 0 (logand flags xcb:icccm:WM_SIZE_HINTS:PBaseSize))) - (setq exwm--normal-hints-min-width base-width - exwm--normal-hints-min-height base-height)) - ;; (unless (= 0 (logand flags xcb:icccm:WM_SIZE_HINTS:PWinGravity)) - ;; (setq exwm--normal-hints-win-gravity win-gravity)) - (setq exwm--fixed-size - (and exwm--normal-hints-min-width - exwm--normal-hints-min-height - exwm--normal-hints-max-width - exwm--normal-hints-max-height - (/= 0 exwm--normal-hints-min-width) - (/= 0 exwm--normal-hints-min-height) - (= exwm--normal-hints-min-width - exwm--normal-hints-max-width) - (= exwm--normal-hints-min-height - exwm--normal-hints-max-height))))))))) - -(defun exwm--update-hints (id &optional force) - "Update hints from WM_HINTS. -Argument ID contains the X window of the `exwm-mode' buffer. - -When FORCE is nil the update only takes place if both of -`exwm--hints-input' and `exwm--hints-urgency' are unset." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (and (not force) exwm--hints-input exwm--hints-urgency) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:icccm:get-WM_HINTS :window id)))) - (when (and reply (slot-value reply 'flags)) ;nil when destroyed - (with-slots (flags input initial-state) reply - (when flags - (unless (= 0 (logand flags xcb:icccm:WM_HINTS:InputHint)) - (setq exwm--hints-input (when input (= 1 input)))) - (unless (= 0 (logand flags xcb:icccm:WM_HINTS:StateHint)) - (setq exwm-state initial-state)) - (unless (= 0 (logand flags xcb:icccm:WM_HINTS:UrgencyHint)) - (setq exwm--hints-urgency t)))) - (when (and exwm--hints-urgency - (not (eq exwm--frame exwm-workspace--current))) - (unless (frame-parameter exwm--frame 'exwm-urgency) - (set-frame-parameter exwm--frame 'exwm-urgency t) - (setq exwm-workspace--switch-history-outdated t)))))))) - -(defun exwm--update-protocols (id &optional force) - "Update `exwm--protocols' from WM_PROTOCOLS. -Argument ID contains the X window of the `exwm-mode' buffer. - -When FORCE is nil the update only takes place if `exwm--protocols' -is unset." - (exwm--log "#x%x" id) - (with-current-buffer (exwm--id->buffer id) - (unless (and exwm--protocols (not force)) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:icccm:get-WM_PROTOCOLS - :window id)))) - (when reply ;nil when destroyed - (setq exwm--protocols (append (slot-value reply 'value) nil))))))) - -(defun exwm--update-struts-legacy (id) - "Update struts of X window ID from _NET_WM_STRUT." - (exwm--log "#x%x" id) - (let ((pair (assq id exwm-workspace--id-struts-alist)) - reply struts) - (unless (and pair (< 4 (length (cdr pair)))) - (setq reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:ewmh:get-_NET_WM_STRUT - :window id))) - (when reply - (setq struts (slot-value reply 'value)) - (if pair - (setcdr pair struts) - (push (cons id struts) exwm-workspace--id-struts-alist)) - (exwm-workspace--update-struts)) - ;; Update workareas. - (exwm-workspace--update-workareas) - ;; Update workspaces. - (dolist (f exwm-workspace--list) - (exwm-workspace--set-fullscreen f))))) - -(defun exwm--update-struts-partial (id) - "Update struts of X window ID from _NET_WM_STRUT_PARTIAL." - (exwm--log "#x%x" id) - (let ((reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:ewmh:get-_NET_WM_STRUT_PARTIAL - :window id))) - struts pair) - (when reply - (setq struts (slot-value reply 'value) - pair (assq id exwm-workspace--id-struts-alist)) - (if pair - (setcdr pair struts) - (push (cons id struts) exwm-workspace--id-struts-alist)) - (exwm-workspace--update-struts)) - ;; Update workareas. - (exwm-workspace--update-workareas) - ;; Update workspaces. - (dolist (f exwm-workspace--list) - (exwm-workspace--set-fullscreen f)))) - -(defun exwm--update-struts (id) - "Update struts of X window ID from _NET_WM_STRUT_PARTIAL or _NET_WM_STRUT." - (exwm--log "#x%x" id) - (exwm--update-struts-partial id) - (exwm--update-struts-legacy id)) - -(defun exwm--on-PropertyNotify (data _synthetic) - "Handle PropertyNotify event. -DATA contains unmarshalled PropertyNotify event data." - (let ((obj (make-instance 'xcb:PropertyNotify)) - atom id buffer) - (xcb:unmarshal obj data) - (setq id (slot-value obj 'window) - atom (slot-value obj 'atom)) - (exwm--log "atom=%s(%s)" (x-get-atom-name atom exwm-workspace--current) atom) - (setq buffer (exwm--id->buffer id)) - (if (not (buffer-live-p buffer)) - ;; Properties of unmanaged X windows. - (cond ((= atom xcb:Atom:_NET_WM_STRUT) - (exwm--update-struts-legacy id)) - ((= atom xcb:Atom:_NET_WM_STRUT_PARTIAL) - (exwm--update-struts-partial id))) - (with-current-buffer buffer - (cond ((= atom xcb:Atom:_NET_WM_WINDOW_TYPE) - (exwm--update-window-type id t)) - ((= atom xcb:Atom:WM_CLASS) - (exwm--update-class id t)) - ((= atom xcb:Atom:_NET_WM_NAME) - (exwm--update-utf8-title id t)) - ((= atom xcb:Atom:WM_NAME) - (exwm--update-ctext-title id t)) - ((= atom xcb:Atom:WM_TRANSIENT_FOR) - (exwm--update-transient-for id t)) - ((= atom xcb:Atom:WM_NORMAL_HINTS) - (exwm--update-normal-hints id t)) - ((= atom xcb:Atom:WM_HINTS) - (exwm--update-hints id t)) - ((= atom xcb:Atom:WM_PROTOCOLS) - (exwm--update-protocols id t)) - ((= atom xcb:Atom:_NET_WM_USER_TIME)) ;ignored - (t - (exwm--log "Unhandled: %s(%d)" - (x-get-atom-name atom exwm-workspace--current) - atom))))))) - -(defun exwm--on-ClientMessage (raw-data _synthetic) - "Handle ClientMessage event. -RAW-DATA contains unmarshalled ClientMessage event data." - (let ((obj (make-instance 'xcb:ClientMessage)) - type id data) - (xcb:unmarshal obj raw-data) - (setq type (slot-value obj 'type) - id (slot-value obj 'window) - data (slot-value (slot-value obj 'data) 'data32)) - (exwm--log "atom=%s(%s) id=#x%x data=%s" (x-get-atom-name type exwm-workspace--current) - type (or id 0) data) - (cond - ;; _NET_NUMBER_OF_DESKTOPS. - ((= type xcb:Atom:_NET_NUMBER_OF_DESKTOPS) - (let ((current (exwm-workspace--count)) - (requested (elt data 0))) - ;; Only allow increasing/decreasing the workspace number by 1. - (cond - ((< current requested) - (make-frame)) - ((and (> current requested) - (> current 1)) - (let ((frame (car (last exwm-workspace--list)))) - (delete-frame frame)))))) - ;; _NET_CURRENT_DESKTOP. - ((= type xcb:Atom:_NET_CURRENT_DESKTOP) - (exwm-workspace-switch (elt data 0))) - ;; _NET_ACTIVE_WINDOW. - ((= type xcb:Atom:_NET_ACTIVE_WINDOW) - (let ((buffer (exwm--id->buffer id)) - window) - (if (buffer-live-p buffer) - ;; Either an `exwm-mode' buffer (an X window) or a floating frame. - (with-current-buffer buffer - (when (eq exwm--frame exwm-workspace--current) - (if exwm--floating-frame - (select-frame exwm--floating-frame) - (setq window (get-buffer-window nil t)) - (unless window - ;; State change: iconic => normal. - (setq window (frame-selected-window exwm--frame)) - (set-window-buffer window (current-buffer))) - ;; Focus transfer. - (select-window window)))) - ;; A workspace. - (dolist (f exwm-workspace--list) - (when (eq id (frame-parameter f 'exwm-outer-id)) - (x-focus-frame f t)))))) - ;; _NET_CLOSE_WINDOW. - ((= type xcb:Atom:_NET_CLOSE_WINDOW) - (let ((buffer (exwm--id->buffer id))) - (when (buffer-live-p buffer) - (exwm--defer 0 #'kill-buffer buffer)))) - ;; _NET_WM_MOVERESIZE - ((= type xcb:Atom:_NET_WM_MOVERESIZE) - (let ((direction (elt data 2)) - (buffer (exwm--id->buffer id))) - (unless (and buffer - (not (buffer-local-value 'exwm--floating-frame buffer))) - (cond ((= direction - xcb:ewmh:_NET_WM_MOVERESIZE_SIZE_KEYBOARD) - ;; FIXME - ) - ((= direction - xcb:ewmh:_NET_WM_MOVERESIZE_MOVE_KEYBOARD) - ;; FIXME - ) - ((= direction xcb:ewmh:_NET_WM_MOVERESIZE_CANCEL) - (exwm-floating--stop-moveresize)) - ;; In case it's a workspace frame. - ((and (not buffer) - (catch 'break - (dolist (f exwm-workspace--list) - (when (or (eq id (frame-parameter f 'exwm-outer-id)) - (eq id (frame-parameter f 'exwm-id))) - (throw 'break t))) - nil))) - (t - ;; In case it's a floating frame, - ;; move the corresponding X window instead. - (unless buffer - (catch 'break - (dolist (pair exwm--id-buffer-alist) - (with-current-buffer (cdr pair) - (when - (and exwm--floating-frame - (or (eq id - (frame-parameter exwm--floating-frame - 'exwm-outer-id)) - (eq id - (frame-parameter exwm--floating-frame - 'exwm-id)))) - (setq id exwm--id) - (throw 'break nil)))))) - ;; Start to move it. - (exwm-floating--start-moveresize id direction)))))) - ;; _NET_REQUEST_FRAME_EXTENTS - ((= type xcb:Atom:_NET_REQUEST_FRAME_EXTENTS) - (let ((buffer (exwm--id->buffer id)) - top btm) - (if (or (not buffer) - (not (buffer-local-value 'exwm--floating-frame buffer))) - (setq top 0 - btm 0) - (setq top (window-header-line-height) - btm (window-mode-line-height))) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_FRAME_EXTENTS - :window id - :left 0 - :right 0 - :top top - :bottom btm))) - (xcb:flush exwm--connection)) - ;; _NET_WM_DESKTOP. - ((= type xcb:Atom:_NET_WM_DESKTOP) - (let ((buffer (exwm--id->buffer id))) - (when (buffer-live-p buffer) - (exwm-workspace-move-window (elt data 0) id)))) - ;; _NET_WM_STATE - ((= type xcb:Atom:_NET_WM_STATE) - (let ((action (elt data 0)) - (props (list (elt data 1) (elt data 2))) - (buffer (exwm--id->buffer id)) - props-new) - ;; only support _NET_WM_STATE_FULLSCREEN / _NET_WM_STATE_ADD for frames - (when (and (not buffer) - (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN props) - (= action xcb:ewmh:_NET_WM_STATE_ADD)) - (xcb:+request - exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_STATE - :window id - :data (vector xcb:Atom:_NET_WM_STATE_FULLSCREEN))) - (xcb:flush exwm--connection)) - (when buffer ;ensure it's managed - (with-current-buffer buffer - ;; _NET_WM_STATE_FULLSCREEN - (when (or (memq xcb:Atom:_NET_WM_STATE_FULLSCREEN props) - (memq xcb:Atom:_NET_WM_STATE_ABOVE props)) - (cond ((= action xcb:ewmh:_NET_WM_STATE_ADD) - (unless (exwm-layout--fullscreen-p) - (exwm-layout-set-fullscreen id)) - (push xcb:Atom:_NET_WM_STATE_FULLSCREEN props-new)) - ((= action xcb:ewmh:_NET_WM_STATE_REMOVE) - (when (exwm-layout--fullscreen-p) - (exwm-layout-unset-fullscreen id))) - ((= action xcb:ewmh:_NET_WM_STATE_TOGGLE) - (if (exwm-layout--fullscreen-p) - (exwm-layout-unset-fullscreen id) - (exwm-layout-set-fullscreen id) - (push xcb:Atom:_NET_WM_STATE_FULLSCREEN props-new))))) - ;; _NET_WM_STATE_DEMANDS_ATTENTION - ;; FIXME: check (may require other properties set) - (when (memq xcb:Atom:_NET_WM_STATE_DEMANDS_ATTENTION props) - (when (= action xcb:ewmh:_NET_WM_STATE_ADD) - (unless (eq exwm--frame exwm-workspace--current) - (set-frame-parameter exwm--frame 'exwm-urgency t) - (setq exwm-workspace--switch-history-outdated t))) - ;; xcb:ewmh:_NET_WM_STATE_REMOVE? - ;; xcb:ewmh:_NET_WM_STATE_TOGGLE? - ) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_STATE - :window id :data (vconcat props-new))) - (xcb:flush exwm--connection))))) - ((= type xcb:Atom:WM_PROTOCOLS) - (let ((type (elt data 0))) - (cond ((= type xcb:Atom:_NET_WM_PING) - (setq exwm-manage--ping-lock nil)) - (t (exwm--log "Unhandled WM_PROTOCOLS of type: %d" type))))) - ((= type xcb:Atom:WM_CHANGE_STATE) - (let ((buffer (exwm--id->buffer id))) - (when (and (buffer-live-p buffer) - (= (elt data 0) xcb:icccm:WM_STATE:IconicState)) - (with-current-buffer buffer - (if exwm--floating-frame - (call-interactively #'exwm-floating-hide) - (bury-buffer)))))) - (t - (exwm--log "Unhandled: %s(%d)" - (x-get-atom-name type exwm-workspace--current) type))))) - -(defun exwm--on-SelectionClear (data _synthetic) - "Handle SelectionClear events. -DATA contains unmarshalled SelectionClear event data." - (exwm--log) - (let ((obj (make-instance 'xcb:SelectionClear)) - owner selection) - (xcb:unmarshal obj data) - (setq owner (slot-value obj 'owner) - selection (slot-value obj 'selection)) - (when (and (eq owner exwm--wmsn-window) - (eq selection xcb:Atom:WM_S0)) - (exwm-exit)))) - -(defun exwm--on-delete-terminal (terminal) - "Handle terminal being deleted without Emacs being killed. -This function is Hooked to `delete-terminal-functions'. - -TERMINAL is the terminal being (or that has been) deleted. - -This may happen when invoking `save-buffers-kill-terminal' within an emacsclient -session." - (when (eq terminal exwm--terminal) - (exwm-exit))) - -(defun exwm--init-icccm-ewmh () - "Initialize ICCCM/EWMH support." - (exwm--log) - ;; Handle PropertyNotify event - (xcb:+event exwm--connection 'xcb:PropertyNotify #'exwm--on-PropertyNotify) - ;; Handle relevant client messages - (xcb:+event exwm--connection 'xcb:ClientMessage #'exwm--on-ClientMessage) - ;; Handle SelectionClear - (xcb:+event exwm--connection 'xcb:SelectionClear #'exwm--on-SelectionClear) - ;; Set _NET_SUPPORTED - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_SUPPORTED - :window exwm--root - :data (vector - ;; Root windows properties. - xcb:Atom:_NET_SUPPORTED - xcb:Atom:_NET_CLIENT_LIST - xcb:Atom:_NET_CLIENT_LIST_STACKING - xcb:Atom:_NET_NUMBER_OF_DESKTOPS - xcb:Atom:_NET_DESKTOP_GEOMETRY - xcb:Atom:_NET_DESKTOP_VIEWPORT - xcb:Atom:_NET_CURRENT_DESKTOP - ;; xcb:Atom:_NET_DESKTOP_NAMES - xcb:Atom:_NET_ACTIVE_WINDOW - ;; xcb:Atom:_NET_WORKAREA - xcb:Atom:_NET_SUPPORTING_WM_CHECK - ;; xcb:Atom:_NET_VIRTUAL_ROOTS - ;; xcb:Atom:_NET_DESKTOP_LAYOUT - ;; xcb:Atom:_NET_SHOWING_DESKTOP - - ;; Other root window messages. - xcb:Atom:_NET_CLOSE_WINDOW - ;; xcb:Atom:_NET_MOVERESIZE_WINDOW - xcb:Atom:_NET_WM_MOVERESIZE - ;; xcb:Atom:_NET_RESTACK_WINDOW - xcb:Atom:_NET_REQUEST_FRAME_EXTENTS - - ;; Application window properties. - xcb:Atom:_NET_WM_NAME - ;; xcb:Atom:_NET_WM_VISIBLE_NAME - ;; xcb:Atom:_NET_WM_ICON_NAME - ;; xcb:Atom:_NET_WM_VISIBLE_ICON_NAME - xcb:Atom:_NET_WM_DESKTOP - ;; - xcb:Atom:_NET_WM_WINDOW_TYPE - ;; xcb:Atom:_NET_WM_WINDOW_TYPE_DESKTOP - xcb:Atom:_NET_WM_WINDOW_TYPE_DOCK - xcb:Atom:_NET_WM_WINDOW_TYPE_TOOLBAR - xcb:Atom:_NET_WM_WINDOW_TYPE_MENU - xcb:Atom:_NET_WM_WINDOW_TYPE_UTILITY - xcb:Atom:_NET_WM_WINDOW_TYPE_SPLASH - xcb:Atom:_NET_WM_WINDOW_TYPE_DIALOG - xcb:Atom:_NET_WM_WINDOW_TYPE_DROPDOWN_MENU - xcb:Atom:_NET_WM_WINDOW_TYPE_POPUP_MENU - xcb:Atom:_NET_WM_WINDOW_TYPE_TOOLTIP - xcb:Atom:_NET_WM_WINDOW_TYPE_NOTIFICATION - xcb:Atom:_NET_WM_WINDOW_TYPE_COMBO - xcb:Atom:_NET_WM_WINDOW_TYPE_DND - xcb:Atom:_NET_WM_WINDOW_TYPE_NORMAL - ;; - xcb:Atom:_NET_WM_STATE - ;; xcb:Atom:_NET_WM_STATE_MODAL - ;; xcb:Atom:_NET_WM_STATE_STICKY - ;; xcb:Atom:_NET_WM_STATE_MAXIMIZED_VERT - ;; xcb:Atom:_NET_WM_STATE_MAXIMIZED_HORZ - ;; xcb:Atom:_NET_WM_STATE_SHADED - ;; xcb:Atom:_NET_WM_STATE_SKIP_TASKBAR - ;; xcb:Atom:_NET_WM_STATE_SKIP_PAGER - xcb:Atom:_NET_WM_STATE_HIDDEN - xcb:Atom:_NET_WM_STATE_FULLSCREEN - ;; xcb:Atom:_NET_WM_STATE_ABOVE - ;; xcb:Atom:_NET_WM_STATE_BELOW - xcb:Atom:_NET_WM_STATE_DEMANDS_ATTENTION - ;; xcb:Atom:_NET_WM_STATE_FOCUSED - ;; - xcb:Atom:_NET_WM_ALLOWED_ACTIONS - xcb:Atom:_NET_WM_ACTION_MOVE - xcb:Atom:_NET_WM_ACTION_RESIZE - xcb:Atom:_NET_WM_ACTION_MINIMIZE - ;; xcb:Atom:_NET_WM_ACTION_SHADE - ;; xcb:Atom:_NET_WM_ACTION_STICK - ;; xcb:Atom:_NET_WM_ACTION_MAXIMIZE_HORZ - ;; xcb:Atom:_NET_WM_ACTION_MAXIMIZE_VERT - xcb:Atom:_NET_WM_ACTION_FULLSCREEN - xcb:Atom:_NET_WM_ACTION_CHANGE_DESKTOP - xcb:Atom:_NET_WM_ACTION_CLOSE - ;; xcb:Atom:_NET_WM_ACTION_ABOVE - ;; xcb:Atom:_NET_WM_ACTION_BELOW - ;; - xcb:Atom:_NET_WM_STRUT - xcb:Atom:_NET_WM_STRUT_PARTIAL - ;; xcb:Atom:_NET_WM_ICON_GEOMETRY - ;; xcb:Atom:_NET_WM_ICON - xcb:Atom:_NET_WM_PID - ;; xcb:Atom:_NET_WM_HANDLED_ICONS - ;; xcb:Atom:_NET_WM_USER_TIME - ;; xcb:Atom:_NET_WM_USER_TIME_WINDOW - xcb:Atom:_NET_FRAME_EXTENTS - ;; xcb:Atom:_NET_WM_OPAQUE_REGION - ;; xcb:Atom:_NET_WM_BYPASS_COMPOSITOR - - ;; Window manager protocols. - xcb:Atom:_NET_WM_PING - ;; xcb:Atom:_NET_WM_SYNC_REQUEST - ;; xcb:Atom:_NET_WM_FULLSCREEN_MONITORS - - ;; Other properties. - xcb:Atom:_NET_WM_FULL_PLACEMENT))) - ;; Create a child window for setting _NET_SUPPORTING_WM_CHECK - (let ((new-id (xcb:generate-id exwm--connection))) - (setq exwm--guide-window new-id) - (xcb:+request exwm--connection - (make-instance 'xcb:CreateWindow - :depth 0 - :wid new-id - :parent exwm--root - :x -1 - :y -1 - :width 1 - :height 1 - :border-width 0 - :class xcb:WindowClass:InputOnly - :visual 0 - :value-mask xcb:CW:OverrideRedirect - :override-redirect 1)) - ;; Set _NET_WM_NAME. Must be set to the name of the window manager, as - ;; required by wm-spec. - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window new-id :data "EXWM")) - (dolist (i (list exwm--root new-id)) - ;; Set _NET_SUPPORTING_WM_CHECK - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_SUPPORTING_WM_CHECK - :window i :data new-id)))) - ;; Set _NET_DESKTOP_VIEWPORT (we don't support large desktop). - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_DESKTOP_VIEWPORT - :window exwm--root - :data [0 0])) - (xcb:flush exwm--connection)) - -(defun exwm--wmsn-acquire (replace) - "Acquire the WM_Sn selection. - -REPLACE specifies what to do in case there already is a window -manager. If t, replace it, if nil, abort and ask the user if `ask'." - (exwm--log "%s" replace) - (with-slots (owner) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetSelectionOwner - :selection xcb:Atom:WM_S0)) - (when (/= owner xcb:Window:None) - (when (eq replace 'ask) - (setq replace (yes-or-no-p "Replace existing window manager? "))) - (when (not replace) - (user-error "Other window manager detected"))) - (let ((new-owner (xcb:generate-id exwm--connection))) - (xcb:+request exwm--connection - (make-instance 'xcb:CreateWindow - :depth 0 - :wid new-owner - :parent exwm--root - :x -1 - :y -1 - :width 1 - :height 1 - :border-width 0 - :class xcb:WindowClass:CopyFromParent - :visual 0 - :value-mask 0 - :override-redirect 0)) - (xcb:+request exwm--connection - (make-instance 'xcb:ewmh:set-_NET_WM_NAME - :window new-owner :data "EXWM: exwm--wmsn-window")) - (xcb:+request-checked+request-check exwm--connection - (make-instance 'xcb:SetSelectionOwner - :selection xcb:Atom:WM_S0 - :owner new-owner - :time xcb:Time:CurrentTime)) - (with-slots (owner) - (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetSelectionOwner - :selection xcb:Atom:WM_S0)) - (unless (eq owner new-owner) - (error "Could not acquire ownership of WM selection"))) - ;; Wait for the other window manager to terminate. - (when (/= owner xcb:Window:None) - (let (reply) - (cl-dotimes (i exwm--wmsn-acquire-timeout) - (setq reply (xcb:+request-unchecked+reply exwm--connection - (make-instance 'xcb:GetGeometry :drawable owner))) - (when (not reply) - (cl-return)) - (message "Waiting for other window manager to quit... %ds" i) - (sleep-for 1)) - (when reply - (error "Other window manager did not release selection in time")))) - ;; announce - (let* ((cmd (make-instance 'xcb:ClientMessageData - :data32 (vector xcb:Time:CurrentTime - xcb:Atom:WM_S0 - new-owner - 0 - 0))) - (cm (make-instance 'xcb:ClientMessage - :window exwm--root - :format 32 - :type xcb:Atom:MANAGER - :data cmd)) - (se (make-instance 'xcb:SendEvent - :propagate 0 - :destination exwm--root - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal cm exwm--connection)))) - (xcb:+request exwm--connection se)) - (setq exwm--wmsn-window new-owner)))) - -;;;###autoload -(cl-defun exwm-init (&optional frame) - "Initialize EXWM. -FRAME, if given, indicates the X display EXWM should manage." - (interactive) - (exwm--log "%s" frame) - (if frame - ;; The frame might not be selected if it's created by emacslicnet. - (select-frame-set-input-focus frame) - (setq frame (selected-frame))) - (when (not (eq 'x (framep frame))) - (message "[EXWM] Not running under X environment") - (cl-return-from exwm-init)) - (when exwm--connection - (exwm--log "EXWM already running") - (cl-return-from exwm-init)) - (condition-case err - (progn - (exwm-enable 'undo) ;never initialize again - (setq exwm--terminal (frame-terminal frame)) - (setq exwm--connection (xcb:connect)) - (set-process-query-on-exit-flag (slot-value exwm--connection 'process) - nil) ;prevent query message on exit - (setq exwm--root - (slot-value (car (slot-value - (xcb:get-setup exwm--connection) 'roots)) - 'root)) - ;; Initialize ICCCM/EWMH support - (xcb:icccm:init exwm--connection t) - (xcb:ewmh:init exwm--connection t) - ;; Try to register window manager selection. - (exwm--wmsn-acquire exwm-replace) - (when (xcb:+request-checked+request-check exwm--connection - (make-instance 'xcb:ChangeWindowAttributes - :window exwm--root - :value-mask xcb:CW:EventMask - :event-mask - xcb:EventMask:SubstructureRedirect)) - (error "Other window manager is running")) - ;; Disable some features not working well with EXWM - (setq use-dialog-box nil - confirm-kill-emacs #'exwm--confirm-kill-emacs) - (advice-add 'save-buffers-kill-terminal - :before-while #'exwm--confirm-kill-terminal) - ;; Clean up if the terminal is deleted. - (add-hook 'delete-terminal-functions 'exwm--on-delete-terminal) - (exwm--lock) - (exwm--init-icccm-ewmh) - (exwm-layout--init) - (exwm-floating--init) - (exwm-manage--init) - (exwm-workspace--init) - (exwm-input--init) - (exwm--unlock) - (exwm-workspace--post-init) - (exwm-input--post-init) - (run-hooks 'exwm-init-hook) - ;; Manage existing windows - (exwm-manage--scan)) - (user-error) - ((quit error) - (exwm-exit) - ;; Rethrow error - (warn "[EXWM] EXWM fails to start (%s: %s)" (car err) (cdr err))))) - - -;;;###autoload -(defun exwm-exit () - "Exit EXWM." - (interactive) - (exwm--log) - (run-hooks 'exwm-exit-hook) - (setq confirm-kill-emacs nil) - ;; Exit modules. - (when exwm--connection - (exwm-input--exit) - (exwm-manage--exit) - (exwm-workspace--exit) - (exwm-floating--exit) - (exwm-layout--exit) - (xcb:flush exwm--connection) - (xcb:disconnect exwm--connection)) - (setq exwm--connection nil) - (setq exwm--terminal nil) - (exwm--log "Exited")) - -;;;###autoload -(defun exwm-enable (&optional undo) - "Enable/Disable EXWM." - (exwm--log "%s" undo) - (pcase undo - (`undo ;prevent reinitialization - (remove-hook 'window-setup-hook #'exwm-init) - (remove-hook 'after-make-frame-functions #'exwm-init)) - (`undo-all ;attempt to revert everything - (remove-hook 'window-setup-hook #'exwm-init) - (remove-hook 'after-make-frame-functions #'exwm-init) - (remove-hook 'kill-emacs-hook #'exwm--server-stop) - (dolist (i exwm-blocking-subrs) - (advice-remove i #'exwm--server-eval-at))) - (_ ;enable EXWM - (setq frame-resize-pixelwise t ;mandatory; before init - window-resize-pixelwise t) - ;; Ignore unrecognized command line arguments. This can be helpful - ;; when EXWM is launched by some session manager. - (push #'vector command-line-functions) - ;; In case EXWM is to be started from a graphical Emacs instance. - (add-hook 'window-setup-hook #'exwm-init t) - ;; In case EXWM is to be started with emacsclient. - (add-hook 'after-make-frame-functions #'exwm-init t) - ;; Manage the subordinate Emacs server. - (add-hook 'kill-emacs-hook #'exwm--server-stop) - (dolist (i exwm-blocking-subrs) - (advice-add i :around #'exwm--server-eval-at))))) - -(defun exwm--server-stop () - "Stop the subordinate Emacs server." - (exwm--log) - (when exwm--server-process - (when (process-live-p exwm--server-process) - (cl-loop - initially (signal-process exwm--server-process 'TERM) - while (process-live-p exwm--server-process) - repeat (* 10 exwm--server-timeout) - do (sit-for 0.1))) - (delete-process exwm--server-process) - (setq exwm--server-process nil))) - -(defun exwm--server-eval-at (function &rest args) - "Wrapper of `server-eval-at' used to advice subrs. -FUNCTION is the function to be evaluated, ARGS are the arguments." - ;; Start the subordinate Emacs server if it's not alive - (exwm--log "%s %s" function args) - (unless (server-running-p exwm--server-name) - (when exwm--server-process (delete-process exwm--server-process)) - (setq exwm--server-process - (start-process exwm--server-name - nil - (car command-line-args) ;The executable file - "-d" (frame-parameter nil 'display) - "-Q" - (concat "--fg-daemon=" exwm--server-name) - "--eval" - ;; Create an invisible frame - "(make-frame '((window-system . x) (visibility)))")) - (while (not (server-running-p exwm--server-name)) - (sit-for 0.001))) - (server-eval-at - exwm--server-name - `(progn (select-frame (car (frame-list))) - (let ((result ,(nconc (list (make-symbol (subr-name function))) - args))) - (pcase (type-of result) - ;; Return the name of a buffer - (`buffer (buffer-name result)) - ;; We blindly convert all font objects to their XLFD names. This - ;; might cause problems of course, but it still has a chance to - ;; work (whereas directly passing font objects would merely - ;; raise errors). - ((or `font-entity `font-object `font-spec) - (font-xlfd-name result)) - ;; Passing following types makes little sense - ((or `compiled-function `finalizer `frame `hash-table `marker - `overlay `process `window `window-configuration)) - ;; Passing the name of a subr - (`subr (make-symbol (subr-name result))) - ;; For other types, return the value as-is. - (t result)))))) - -(defun exwm--confirm-kill-terminal (&optional _) - "Confirm before killing terminal." - ;; This is invoked instead of `save-buffers-kill-emacs' (C-x C-c) on client - ;; frames. - (if (exwm--terminal-p) - (exwm--confirm-kill-emacs "Kill terminal?") - t)) - -(defun exwm--confirm-kill-emacs (prompt &optional force) - "Confirm before exiting Emacs. -PROMPT a reason to present to the user. -If FORCE is nil, ask the user for confirmation. -If FORCE is the symbol `no-check', ask if there are unsaved buffers. -If FORCE is any other non-nil value, force killing of Emacs." - (exwm--log) - (when (cond - ((and force (not (eq force 'no-check))) - ;; Force killing Emacs. - t) - ((or (eq force 'no-check) (not exwm--id-buffer-alist)) - ;; Check if there's any unsaved file. - (pcase (catch 'break - (let ((kill-emacs-query-functions - (append kill-emacs-query-functions - (list (lambda () - (throw 'break 'break)))))) - (save-buffers-kill-emacs))) - (`break (y-or-n-p prompt)) - (x x))) - (t - (yes-or-no-p (format "[EXWM] %d X window(s) will be destroyed. %s" - (length exwm--id-buffer-alist) prompt)))) - ;; Run `kill-emacs-hook' (`server-force-stop' excluded) before Emacs - ;; frames are unmapped so that errors (if any) can be visible. - (if (memq #'server-force-stop kill-emacs-hook) - (progn - (setq kill-emacs-hook (delq #'server-force-stop kill-emacs-hook)) - (run-hooks 'kill-emacs-hook) - (setq kill-emacs-hook (list #'server-force-stop))) - (run-hooks 'kill-emacs-hook) - (setq kill-emacs-hook nil)) - ;; Exit each module, destroying all resources created by this connection. - (exwm-exit) - ;; Set the return value. - t)) - - - -(provide 'exwm) - -;;; exwm.el ends here diff --git a/third_party/exwm/xinitrc b/third_party/exwm/xinitrc deleted file mode 100644 index 591e41991..000000000 --- a/third_party/exwm/xinitrc +++ /dev/null @@ -1,20 +0,0 @@ -# Disable access control for the current user. -xhost +SI:localuser:$USER - -# Make Java applications aware this is a non-reparenting window manager. -export _JAVA_AWT_WM_NONREPARENTING=1 - -# Set default cursor. -xsetroot -cursor_name left_ptr - -# Set keyboard repeat rate. -xset r rate 200 60 - -# Uncomment the following block to use the exwm-xim module. -#export XMODIFIERS=@im=exwm-xim -#export GTK_IM_MODULE=xim -#export QT_IM_MODULE=xim -#export CLUTTER_IM_MODULE=xim - -# Finally start Emacs -exec emacs diff --git a/third_party/lisp/OWNERS b/third_party/lisp/OWNERS deleted file mode 100644 index 6536baf50..000000000 --- a/third_party/lisp/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -eta -aspen diff --git a/third_party/lisp/alexandria.nix b/third_party/lisp/alexandria.nix deleted file mode 100644 index 538c21d81..000000000 --- a/third_party/lisp/alexandria.nix +++ /dev/null @@ -1,28 +0,0 @@ -# Alexandria is one of the foundational Common Lisp libraries that -# pretty much everything depends on. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.alexandria; -in depot.nix.buildLisp.library { - name = "alexandria"; - - srcs = map (f: src + ("/alexandria-1/" + f)) [ - "package.lisp" - "definitions.lisp" - "binding.lisp" - "strings.lisp" - "conditions.lisp" - "symbols.lisp" - "macros.lisp" - "functions.lisp" - "io.lisp" - "hash-tables.lisp" - "control-flow.lisp" - "lists.lisp" - "types.lisp" - "arrays.lisp" - "sequences.lisp" - "numbers.lisp" - "features.lisp" - ]; -} diff --git a/third_party/lisp/anaphora.nix b/third_party/lisp/anaphora.nix deleted file mode 100644 index dfcb392c2..000000000 --- a/third_party/lisp/anaphora.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.anaphora; -in depot.nix.buildLisp.library { - name = "anaphora"; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - "early.lisp" - "symbolic.lisp" - "anaphora.lisp" - ]; -} diff --git a/third_party/lisp/asdf-flv/.gitattributes b/third_party/lisp/asdf-flv/.gitattributes deleted file mode 100644 index 2b45716e4..000000000 --- a/third_party/lisp/asdf-flv/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -.gitignore export-ignore -.gitattributes export-ignore diff --git a/third_party/lisp/asdf-flv/.gitignore b/third_party/lisp/asdf-flv/.gitignore deleted file mode 100644 index bdf4ad2ae..000000000 --- a/third_party/lisp/asdf-flv/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -sbcl-*/ -cmu-*/ -openmcl-*/ diff --git a/third_party/lisp/asdf-flv/Makefile b/third_party/lisp/asdf-flv/Makefile deleted file mode 100644 index b4c74feef..000000000 --- a/third_party/lisp/asdf-flv/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -### Makefile --- Toplevel directory - -## Copyright (C) 2011, 2015 Didier Verna - -## Author: Didier Verna - -## This file is part of ASDF-FLV. - -## Copying and distribution of this file, with or without modification, -## are permitted in any medium without royalty provided the copyright -## notice and this notice are preserved. This file is offered as-is, -## without any warranty. - - -### Commentary: - -## Contents management by FCM version 0.1. - - -### Code: - -PROJECT := asdf-flv -VERSION := 2.1 - -W3DIR := $(HOME)/www/software/lisp/$(PROJECT) - -DIST_NAME := $(PROJECT)-$(VERSION) -TARBALL := $(DIST_NAME).tar.gz -SIGNATURE := $(TARBALL).asc - - -all: - -clean: - -rm *~ - -distclean: clean - -rm *.tar.gz *.tar.gz.asc - -tag: - git tag -a -m 'Version $(VERSION)' 'version-$(VERSION)' - -tar: $(TARBALL) -gpg: $(SIGNATURE) -dist: tar gpg - -install-www: dist - -install -m 644 $(TARBALL) "$(W3DIR)/attic/" - -install -m 644 $(SIGNATURE) "$(W3DIR)/attic/" - echo "\ - \ -| \ -" \ - > "$(W3DIR)/latest.txt" - chmod 644 "$(W3DIR)/latest.txt" - cd "$(W3DIR)" \ - && ln -fs attic/$(TARBALL) latest.tar.gz \ - && ln -fs attic/$(SIGNATURE) latest.tar.gz.asc - -update-version: - perl -pi -e 's/:version ".*"/:version "$(VERSION)"/' \ - net.didierverna.$(PROJECT).asd - -$(TARBALL): - git archive --format=tar --prefix=$(DIST_NAME)/ \ - --worktree-attributes HEAD \ - | gzip -c > $@ - -$(SIGNATURE): $(TARBALL) - gpg -b -a $< - - -.PHONY: all clean distclean tag tar gpg dist install-www update-version - -### Makefile ends here diff --git a/third_party/lisp/asdf-flv/README.md b/third_party/lisp/asdf-flv/README.md deleted file mode 100644 index 7ccdd1888..000000000 --- a/third_party/lisp/asdf-flv/README.md +++ /dev/null @@ -1,7 +0,0 @@ -ASDF-FLV provides support for file-local variables through ASDF. A file-local -variable behaves like `*PACKAGE*` and `*READTABLE*` with respect to `LOAD` and -`COMPILE-FILE`: a new dynamic binding is created before processing the file, -so that any modification to the variable essentially becomes file-local. - -In order to make one or several variables file-local, use the macros -`SET-FILE-LOCAL-VARIABLE(S)`. diff --git a/third_party/lisp/asdf-flv/asdf-flv.lisp b/third_party/lisp/asdf-flv/asdf-flv.lisp deleted file mode 100644 index 76c6845b8..000000000 --- a/third_party/lisp/asdf-flv/asdf-flv.lisp +++ /dev/null @@ -1,64 +0,0 @@ -;;; asdf-flv.lisp --- Implementation - -;; Copyright (C) 2011, 2015 Didier Verna - -;; Author: Didier Verna - -;; This file is part of ASDF-FLV. - -;; Copying and distribution of this file, with or without modification, -;; are permitted in any medium without royalty provided the copyright -;; notice and this notice are preserved. This file is offered as-is, -;; without any warranty. - - -;;; Commentary: - -;; Contents management by FCM version 0.1. - - -;;; Code: - -(in-package :net.didierverna.asdf-flv) - - -(defvar *file-local-variables* () - "List of file-local special variables.") - - -(defun make-variable-file-local (symbol) - "Make special variable named by SYMBOL have a file-local value." - (pushnew symbol *file-local-variables*)) - -(defmacro set-file-local-variable (symbol) - "Set special variable named by SYMBOL as file-local. -SYMBOL need not be quoted." - `(make-variable-file-local ',symbol)) - -(defun make-variables-file-local (&rest symbols) - "Make special variables named by SYMBOLS have a file-local value." - (dolist (symbol symbols) - (pushnew symbol *file-local-variables*))) - -(defmacro set-file-local-variables (&rest symbols) - "Set special variables named by SYMBOLS as file-local. -SYMBOLS need not be quoted." - `(make-variables-file-local ,@(mapcar (lambda (symbol) (list 'quote symbol)) - symbols))) - - -(defmethod asdf:perform :around - ((operation asdf:load-op) (file asdf:cl-source-file)) - "Establish new dynamic bindings for file-local variables." - (progv *file-local-variables* - (mapcar #'symbol-value *file-local-variables*) - (call-next-method))) - -(defmethod asdf:perform :around - ((operation asdf:compile-op) (file asdf:cl-source-file)) - "Establish new dynamic bindings for file-local variables." - (progv *file-local-variables* - (mapcar #'symbol-value *file-local-variables*) - (call-next-method))) - -;;; asdf-flv.lisp ends here diff --git a/third_party/lisp/asdf-flv/default.nix b/third_party/lisp/asdf-flv/default.nix deleted file mode 100644 index e8ec4aa8f..000000000 --- a/third_party/lisp/asdf-flv/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -# Imported from https://github.com/didierverna/asdf-flv -{ depot, ... }: - -with depot.nix; -buildLisp.library { - name = "asdf-flv"; - deps = [ (buildLisp.bundled "asdf") ]; - - srcs = [ - ./package.lisp - ./asdf-flv.lisp - ]; -} diff --git a/third_party/lisp/asdf-flv/net.didierverna.asdf-flv.asd b/third_party/lisp/asdf-flv/net.didierverna.asdf-flv.asd deleted file mode 100644 index 41202746d..000000000 --- a/third_party/lisp/asdf-flv/net.didierverna.asdf-flv.asd +++ /dev/null @@ -1,43 +0,0 @@ -;;; net.didierverna.asdf-flv.asd --- ASDF system definition - -;; Copyright (C) 2011, 2015 Didier Verna - -;; Author: Didier Verna - -;; This file is part of ASDF-FLV. - -;; Copying and distribution of this file, with or without modification, -;; are permitted in any medium without royalty provided the copyright -;; notice and this notice are preserved. This file is offered as-is, -;; without any warranty. - - -;;; Commentary: - -;; Contents management by FCM version 0.1. - - -;;; Code: - -(asdf:defsystem :net.didierverna.asdf-flv - :long-name "ASDF File Local Variables" - :description "ASDF extension to provide support for file-local variables." - :long-description "\ -ASDF-FLV provides support for file-local variables through ASDF. A file-local -variable behaves like *PACKAGE* and *READTABLE* with respect to LOAD and -COMPILE-FILE: a new dynamic binding is created before processing the file, so -that any modification to the variable becomes essentially file-local. - -In order to make one or several variables file-local, use the macros -SET-FILE-LOCAL-VARIABLE(S)." - :author "Didier Verna" - :mailto "didier@didierverna.net" - :homepage "http://www.lrde.epita.fr/~didier/software/lisp/misc.php#asdf-flv" - :source-control "https://github.com/didierverna/asdf-flv" - :license "GNU All Permissive" - :version "2.1" - :serial t - :components ((:file "package") - (:file "asdf-flv"))) - -;;; net.didierverna.asdf-flv.asd ends here diff --git a/third_party/lisp/asdf-flv/package.lisp b/third_party/lisp/asdf-flv/package.lisp deleted file mode 100644 index 1d7fb2bab..000000000 --- a/third_party/lisp/asdf-flv/package.lisp +++ /dev/null @@ -1,28 +0,0 @@ -;;; package.lisp --- Package definition - -;; Copyright (C) 2011, 2015 Didier Verna - -;; Author: Didier Verna - -;; This file is part of ASDF-FLV. - -;; Copying and distribution of this file, with or without modification, -;; are permitted in any medium without royalty provided the copyright -;; notice and this notice are preserved. This file is offered as-is, -;; without any warranty. - - -;;; Commentary: - -;; Contents management by FCM version 0.1. - - -;;; Code: - -(in-package :cl-user) - -(defpackage :net.didierverna.asdf-flv - (:use :cl) - (:export :set-file-local-variable :set-file-local-variables)) - -;;; package.lisp ends here diff --git a/third_party/lisp/babel.nix b/third_party/lisp/babel.nix deleted file mode 100644 index 56de72738..000000000 --- a/third_party/lisp/babel.nix +++ /dev/null @@ -1,31 +0,0 @@ -# Babel is an encoding conversion library for Common Lisp. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.babel; -in depot.nix.buildLisp.library { - name = "babel"; - deps = [ - depot.third_party.lisp.alexandria - depot.third_party.lisp.trivial-features - ]; - - srcs = map (f: src + ("/src/" + f)) [ - "packages.lisp" - "encodings.lisp" - "enc-ascii.lisp" - "enc-ebcdic.lisp" - "enc-ebcdic-int.lisp" - "enc-iso-8859.lisp" - "enc-unicode.lisp" - "enc-cp1251.lisp" - "enc-cp1252.lisp" - "jpn-table.lisp" - "enc-jpn.lisp" - "enc-gbk.lisp" - "enc-koi8.lisp" - "external-format.lisp" - "strings.lisp" - "gbk-map.lisp" - "sharp-backslash.lisp" - ]; -} diff --git a/third_party/lisp/bordeaux-threads.nix b/third_party/lisp/bordeaux-threads.nix deleted file mode 100644 index 1edac4cd3..000000000 --- a/third_party/lisp/bordeaux-threads.nix +++ /dev/null @@ -1,47 +0,0 @@ -# This library is meant to make writing portable multi-threaded apps -# in Common Lisp simple. -{ depot, pkgs, ... }: - -let - src = with pkgs; srcOnly sbcl.pkgs.bordeaux-threads; - getSrc = f: "${src}/${f}"; -in -depot.nix.buildLisp.library { - name = "bordeaux-threads"; - deps = [ - depot.third_party.lisp.alexandria - depot.third_party.lisp.global-vars - depot.third_party.lisp.trivial-features - depot.third_party.lisp.trivial-garbage - ]; - - srcs = map getSrc [ - "apiv1/pkgdcl.lisp" - "apiv1/bordeaux-threads.lisp" - ] ++ [ - { - sbcl = getSrc "apiv1/impl-sbcl.lisp"; - ecl = getSrc "apiv1/impl-ecl.lisp"; - ccl = getSrc "apiv1/impl-clozure.lisp"; - } - ] ++ map getSrc [ - "apiv1/default-implementations.lisp" - - "apiv2/pkgdcl.lisp" - "apiv2/bordeaux-threads.lisp" - "apiv2/timeout-interrupt.lisp" - ] ++ [ - { - sbcl = getSrc "apiv2/impl-sbcl.lisp"; - ecl = getSrc "apiv2/impl-ecl.lisp"; - ccl = getSrc "apiv2/impl-clozure.lisp"; - } - (getSrc "apiv2/api-locks.lisp") - (getSrc "apiv2/api-threads.lisp") - (getSrc "apiv2/api-semaphores.lisp") - { - ccl = getSrc "apiv2/impl-condition-variables-semaphores.lisp"; - } - (getSrc "apiv2/api-condition-variables.lisp") - ]; -} diff --git a/third_party/lisp/cffi.nix b/third_party/lisp/cffi.nix deleted file mode 100644 index 63cc7932d..000000000 --- a/third_party/lisp/cffi.nix +++ /dev/null @@ -1,35 +0,0 @@ -# CFFI purports to be the Common Foreign Function Interface. -{ depot, pkgs, ... }: - -with depot.nix; -let src = with pkgs; srcOnly sbcl.pkgs.cffi; -in buildLisp.library { - name = "cffi"; - deps = with depot.third_party.lisp; [ - alexandria - babel - trivial-features - (buildLisp.bundled "asdf") - ]; - - srcs = [ - "${src}/src/package.lisp" - "${src}/src/sys-utils.lisp" - { - ecl = src + "/src/cffi-ecl.lisp"; - sbcl = src + "/src/cffi-sbcl.lisp"; - ccl = src + "/src/cffi-openmcl.lisp"; - } - ] ++ map (f: src + ("/src/" + f)) [ - "utils.lisp" - "libraries.lisp" - "early-types.lisp" - "types.lisp" - "enum.lisp" - "strings.lisp" - "structures.lisp" - "functions.lisp" - "foreign-vars.lisp" - "features.lisp" - ]; -} diff --git a/third_party/lisp/chipz.nix b/third_party/lisp/chipz.nix deleted file mode 100644 index ccde3cb42..000000000 --- a/third_party/lisp/chipz.nix +++ /dev/null @@ -1,26 +0,0 @@ -# Common Lisp library for decompressing deflate, zlib, gzip, and bzip2 data -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.chipz; -in depot.nix.buildLisp.library { - name = "chipz"; - deps = [ (depot.nix.buildLisp.bundled "asdf") ]; - - srcs = map (f: src + ("/" + f)) [ - "chipz.asd" - "package.lisp" - "constants.lisp" - "conditions.lisp" - "dstate.lisp" - "types-and-tables.lisp" - "crc32.lisp" - "adler32.lisp" - "inflate-state.lisp" - "gzip.lisp" - "zlib.lisp" - "inflate.lisp" - "bzip2.lisp" - "decompress.lisp" - "stream.lisp" - ]; -} diff --git a/third_party/lisp/chunga.nix b/third_party/lisp/chunga.nix deleted file mode 100644 index ea676af79..000000000 --- a/third_party/lisp/chunga.nix +++ /dev/null @@ -1,22 +0,0 @@ -# Portable chunked streams for Common Lisp -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.chunga; -in depot.nix.buildLisp.library { - name = "chunga"; - deps = with depot.third_party.lisp; [ - trivial-gray-streams - ]; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - "specials.lisp" - "util.lisp" - "known-words.lisp" - "conditions.lisp" - "read.lisp" - "streams.lisp" - "input.lisp" - "output.lisp" - ]; -} diff --git a/third_party/lisp/cl-ansi-text.nix b/third_party/lisp/cl-ansi-text.nix deleted file mode 100644 index e7b929032..000000000 --- a/third_party/lisp/cl-ansi-text.nix +++ /dev/null @@ -1,16 +0,0 @@ -# Enables ANSI colors for printing. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-ansi-text; -in depot.nix.buildLisp.library { - name = "cl-ansi-text"; - deps = with depot.third_party.lisp; [ - alexandria - cl-colors2 - ]; - - srcs = map (f: src + ("/src/" + f)) [ - "cl-ansi-text.lisp" - "define-colors.lisp" - ]; -} diff --git a/third_party/lisp/cl-base64.nix b/third_party/lisp/cl-base64.nix deleted file mode 100644 index 89e8090b9..000000000 --- a/third_party/lisp/cl-base64.nix +++ /dev/null @@ -1,14 +0,0 @@ -# Base64 encoding for Common Lisp -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-base64; -in depot.nix.buildLisp.library { - name = "cl-base64"; - srcs = [ - (src + "/package.lisp") - (src + "/encode.lisp") - (src + "/decode.lisp") - ]; -} - - diff --git a/third_party/lisp/cl-change-case.nix b/third_party/lisp/cl-change-case.nix deleted file mode 100644 index 8c20f9e66..000000000 --- a/third_party/lisp/cl-change-case.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-change-case; -in depot.nix.buildLisp.library { - name = "cl-change-case"; - - deps = with depot.third_party.lisp; [ cl-ppcre cl-ppcre.unicode ]; - - srcs = [ (src + "/src/cl-change-case.lisp") ]; - - tests = { - name = "cl-change-case-tests"; - srcs = [ (src + "/t/cl-change-case.lisp") ]; - deps = [ - depot.third_party.lisp.fiveam - ]; - - expression = '' - (5am:run! :cl-change-case) - ''; - }; -} diff --git a/third_party/lisp/cl-colors.nix b/third_party/lisp/cl-colors.nix deleted file mode 100644 index b206a55ea..000000000 --- a/third_party/lisp/cl-colors.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-colors; -in depot.nix.buildLisp.library { - name = "cl-colors"; - deps = [ - depot.third_party.lisp.alexandria - depot.third_party.lisp.let-plus - ]; - srcs = [ - "${src}/package.lisp" - "${src}/colors.lisp" - "${src}/colornames.lisp" - "${src}/hexcolors.lisp" - ]; -} diff --git a/third_party/lisp/cl-colors2.nix b/third_party/lisp/cl-colors2.nix deleted file mode 100644 index 6c3fe8d33..000000000 --- a/third_party/lisp/cl-colors2.nix +++ /dev/null @@ -1,26 +0,0 @@ -# TODO(sterni): package (switch to?) cl-colors-ng -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-colors2; -in depot.nix.buildLisp.library { - name = "cl-colors2"; - deps = with depot.third_party.lisp; [ - alexandria - cl-ppcre - parse-number - { - sbcl = depot.nix.buildLisp.bundled "uiop"; - default = depot.nix.buildLisp.bundled "asdf"; - } - ]; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "colors.lisp" - "colornames-x11.lisp" - "colornames-svg.lisp" - "colornames-gdk.lisp" - "hexcolors.lisp" - "print.lisp" - ]; -} diff --git a/third_party/lisp/cl-date-time-parser.nix b/third_party/lisp/cl-date-time-parser.nix deleted file mode 100644 index bc847531e..000000000 --- a/third_party/lisp/cl-date-time-parser.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ depot, pkgs, ... }: - -depot.nix.buildLisp.library { - name = "cl-date-time-parser"; - - srcs = [ - "${pkgs.srcOnly pkgs.sbcl.pkgs.cl-date-time-parser}/date-time-parser.lisp" - ]; - - deps = [ - depot.third_party.lisp.alexandria - depot.third_party.lisp.anaphora - depot.third_party.lisp.split-sequence - depot.third_party.lisp.cl-ppcre - depot.third_party.lisp.local-time - depot.third_party.lisp.parse-float - ]; -} diff --git a/third_party/lisp/cl-fad.nix b/third_party/lisp/cl-fad.nix deleted file mode 100644 index bffeb2e26..000000000 --- a/third_party/lisp/cl-fad.nix +++ /dev/null @@ -1,27 +0,0 @@ -# Portable pathname library -{ depot, pkgs, ... }: - -with depot.nix; - -let src = with pkgs; srcOnly sbcl.pkgs.cl-fad; -in buildLisp.library { - name = "cl-fad"; - - deps = with depot.third_party.lisp; [ - alexandria - bordeaux-threads - { - sbcl = buildLisp.bundled "sb-posix"; - } - ]; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - ] ++ [ - { ccl = "${src}/openmcl.lisp"; } - ] ++ map (f: src + ("/" + f)) [ - "fad.lisp" - "path.lisp" - "temporary-files.lisp" - ]; -} diff --git a/third_party/lisp/cl-json.nix b/third_party/lisp/cl-json.nix deleted file mode 100644 index 6b82fac77..000000000 --- a/third_party/lisp/cl-json.nix +++ /dev/null @@ -1,53 +0,0 @@ -# JSON encoder & decoder -{ depot, pkgs, ... }: - -let - inherit (depot.nix) buildLisp; - - # https://github.com/sharplispers/cl-json/pull/12/ - src = pkgs.fetchFromGitHub { - owner = "sternenseemann"; - repo = "cl-json"; - rev = "c059bec94e28a11102a994d6949e2e52764f21fd"; - sha256 = "0l07syw1b1x2zi8kj4iph3rf6vi6c16b7fk69iv7x27wrdsr1qwj"; - }; - - getSrcs = subdir: map (f: src + ("/" + subdir + "/" + f)); -in -buildLisp.library { - name = "cl-json"; - deps = [ (buildLisp.bundled "asdf") ]; - - srcs = [ "${src}/cl-json.asd" ] ++ - (getSrcs "src" [ - "package.lisp" - "common.lisp" - "objects.lisp" - "camel-case.lisp" - "decoder.lisp" - "encoder.lisp" - "utils.lisp" - "json-rpc.lisp" - ]); - - tests = { - deps = [ - depot.third_party.lisp.cl-unicode - depot.third_party.lisp.fiveam - ]; - srcs = [ - # CLOS tests are broken upstream as well - # https://github.com/sharplispers/cl-json/issues/11 - (pkgs.writeText "no-clos-tests.lisp" '' - (replace *features* (delete :cl-json-clos *features*)) - '') - ] ++ getSrcs "t" [ - "package.lisp" - "testencoder.lisp" - "testdecoder.lisp" - "testmisc.lisp" - ]; - - expression = "(fiveam:run! 'json-test::json)"; - }; -} diff --git a/third_party/lisp/cl-plus-ssl.nix b/third_party/lisp/cl-plus-ssl.nix deleted file mode 100644 index a302159ad..000000000 --- a/third_party/lisp/cl-plus-ssl.nix +++ /dev/null @@ -1,51 +0,0 @@ -# Common Lisp bindings to OpenSSL -{ depot, pkgs, ... }: - -with depot.nix; - -let - src = pkgs.srcOnly pkgs.sbcl.pkgs.cl_plus_ssl; -in - -buildLisp.library { - name = "cl-plus-ssl"; - deps = with depot.third_party.lisp; [ - alexandria - bordeaux-threads - cffi - flexi-streams - trivial-features - trivial-garbage - trivial-gray-streams - usocket - { - scbl = buildLisp.bundled "uiop"; - default = buildLisp.bundled "asdf"; - } - { sbcl = buildLisp.bundled "sb-posix"; } - ]; - - native = [ pkgs.openssl ]; - - srcs = map (f: src + ("/src/" + f)) [ - "config.lisp" - "package.lisp" - "reload.lisp" - "ffi.lisp" - "bio.lisp" - "conditions.lisp" - "ssl-funcall.lisp" - "init.lisp" - "ffi-buffer-all.lisp" - "ffi-buffer.lisp" - "streams.lisp" - "x509.lisp" - "random.lisp" - "context.lisp" - "verify-hostname.lisp" - ]; - - brokenOn = [ - "ecl" # dynamic cffi - ]; -} diff --git a/third_party/lisp/cl-ppcre.nix b/third_party/lisp/cl-ppcre.nix deleted file mode 100644 index 6861bef6a..000000000 --- a/third_party/lisp/cl-ppcre.nix +++ /dev/null @@ -1,39 +0,0 @@ -# cl-ppcre is a Common Lisp regular expression library. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-ppcre; -in depot.nix.buildLisp.library { - name = "cl-ppcre"; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - "specials.lisp" - "util.lisp" - "errors.lisp" - "charset.lisp" - "charmap.lisp" - "chartest.lisp" - "lexer.lisp" - "parser.lisp" - "regex-class.lisp" - "regex-class-util.lisp" - "convert.lisp" - "optimize.lisp" - "closures.lisp" - "repetition-closures.lisp" - "scanner.lisp" - "api.lisp" - ]; - - passthru = { - unicode = depot.nix.buildLisp.library { - name = "cl-ppcre-unicode"; - deps = with depot.third_party.lisp; [ cl-ppcre cl-unicode ]; - - srcs = map (f: src + ("/cl-ppcre-unicode/" + f)) [ - "packages.lisp" - "resolver.lisp" - ]; - }; - }; -} diff --git a/third_party/lisp/cl-prevalence.nix b/third_party/lisp/cl-prevalence.nix deleted file mode 100644 index 01476699f..000000000 --- a/third_party/lisp/cl-prevalence.nix +++ /dev/null @@ -1,29 +0,0 @@ -# cl-prevalence is an implementation of object prevalence for CL (i.e. -# an in-memory database) -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-prevalence; -in depot.nix.buildLisp.library { - name = "cl-prevalence"; - - deps = with depot.third_party.lisp; [ - moptilities - s-xml - s-sysdeps - ]; - - srcs = map (f: src + ("/src/" + f)) [ - "package.lisp" - "serialization/serialization.lisp" - "serialization/xml.lisp" - "serialization/sexp.lisp" - "prevalence.lisp" - "managed-prevalence.lisp" - "master-slave.lisp" - "blob.lisp" - ]; - - brokenOn = [ - "ecl" # see moptilities - ]; -} diff --git a/third_party/lisp/cl-smtp.nix b/third_party/lisp/cl-smtp.nix deleted file mode 100644 index a3b7c179d..000000000 --- a/third_party/lisp/cl-smtp.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-smtp; -in depot.nix.buildLisp.library { - name = "cl-smtp"; - deps = with depot.third_party.lisp; [ - alexandria - usocket - flexi-streams - frugal-uuid-non-frugal - cl-base64 - cl-plus-ssl - ]; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "attachments.lisp" - "cl-smtp.lisp" - "mime-types.lisp" - ]; - - brokenOn = [ - "ecl" # dynamic cffi - ]; -} diff --git a/third_party/lisp/cl-unicode.nix b/third_party/lisp/cl-unicode.nix deleted file mode 100644 index 2f91767b7..000000000 --- a/third_party/lisp/cl-unicode.nix +++ /dev/null @@ -1,75 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (pkgs) sbcl runCommand writeText; - inherit (depot.nix.buildLisp) bundled; - - src = pkgs.srcOnly pkgs.sbcl.pkgs.cl-unicode; - - cl-unicode-base = depot.nix.buildLisp.library { - name = "cl-unicode-base"; - deps = with depot.third_party.lisp; [ - cl-ppcre - ]; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - "specials.lisp" - "util.lisp" - ]; - }; - - cl-unicode-build = depot.nix.buildLisp.program { - name = "cl-unicode-build"; - deps = with depot.third_party.lisp; [ - cl-unicode-base - flexi-streams - { - ecl = bundled "asdf"; - default = bundled "uiop"; - } - ]; - - srcs = (map (f: src + ("/build/" + f)) [ - "util.lisp" - "char-info.lisp" - "read.lisp" - ]) ++ [ - (runCommand "dump.lisp" { } '' - substitute ${src}/build/dump.lisp $out \ - --replace ':defaults *this-file*' ":defaults (uiop:getcwd)" - '') - - (writeText "export-create-source-files.lisp" '' - (in-package :cl-unicode) - (export 'create-source-files) - '') - ]; - - main = "cl-unicode:create-source-files"; - }; - - - generated = runCommand "cl-unicode-generated" { } '' - mkdir -p $out/build - mkdir -p $out/test - cd $out/build - pwd - ${cl-unicode-build}/bin/cl-unicode-build - ''; - -in -depot.nix.buildLisp.library { - name = "cl-unicode"; - deps = [ cl-unicode-base ]; - srcs = [ - "${src}/conditions.lisp" - "${generated}/lists.lisp" - "${generated}/hash-tables.lisp" - "${src}/api.lisp" - "${generated}/methods.lisp" - "${src}/test-functions.lisp" - "${src}/derived.lisp" - "${src}/alias.lisp" - ]; -} diff --git a/third_party/lisp/cl-who.nix b/third_party/lisp/cl-who.nix deleted file mode 100644 index 3aebb0532..000000000 --- a/third_party/lisp/cl-who.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.cl-who; -in depot.nix.buildLisp.library { - name = "cl-who"; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - "specials.lisp" - "util.lisp" - "who.lisp" - ]; -} diff --git a/third_party/lisp/cl-yacc.nix b/third_party/lisp/cl-yacc.nix deleted file mode 100644 index 3542d1a05..000000000 --- a/third_party/lisp/cl-yacc.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ depot, pkgs, ... }: - -let - src = pkgs.fetchFromGitHub { - owner = "jech"; - repo = "cl-yacc"; - rev = "1812e05317dcab1e97905625c018c043d71f9187"; # 2023-01-08 - sha256 = "1f974ysi7mlrksnqg63iwwxgbypkng4n240q29imkrz6m5pwdig7"; - }; -in -depot.nix.buildLisp.library { - name = "cl-yacc"; - - srcs = map (f: src + ("/" + f)) [ - "yacc.lisp" - ]; -} diff --git a/third_party/lisp/closer-mop.nix b/third_party/lisp/closer-mop.nix deleted file mode 100644 index 5e946aa81..000000000 --- a/third_party/lisp/closer-mop.nix +++ /dev/null @@ -1,19 +0,0 @@ -# Closer to MOP is a compatibility layer that rectifies many of the -# absent or incorrect CLOS MOP features across a broad range of Common -# Lisp implementations -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.closer-mop; -in depot.nix.buildLisp.library { - name = "closer-mop"; - - srcs = [ - "${src}/closer-mop-packages.lisp" - "${src}/closer-mop-shared.lisp" - { - sbcl = "${src}/closer-sbcl.lisp"; - ecl = "${src}/closer-ecl.lisp"; - ccl = "${src}/closer-clozure.lisp"; - } - ]; -} diff --git a/third_party/lisp/closure-common.nix b/third_party/lisp/closure-common.nix deleted file mode 100644 index ed5726dbb..000000000 --- a/third_party/lisp/closure-common.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ depot, pkgs, ... }: - -let - src = with pkgs; srcOnly sbcl.pkgs.closure-common; - getSrcs = builtins.map (p: "${src}/${p}"); -in -depot.nix.buildLisp.library { - name = "closure-common"; - - # closure-common.asd surpresses some warnings otherwise breaking - # compilation. Feature macros across implementations: - # - # ECL #+rune-is-character #-rune-is-integer #-x&y-streams-are-stream - # CCL #+rune-is-character #-rune-is-integer #-x&y-streams-are-stream - # SBCL #+rune-is-character #-rune-is-integer #-x&y-streams-are-stream - # - # Since all implementations agree, the alternative files aren't encoded here. - srcs = getSrcs [ - "closure-common.asd" - "package.lisp" - "definline.lisp" - "characters.lisp" #+rune-is-character - "syntax.lisp" - "encodings.lisp" #-x&y-streams-are-stream - "encodings-data.lisp" #-x&y-streams-are-stream - "xstream.lisp" #-x&y-streams-are-stream - "ystream.lisp" #-x&y-streams-are-stream - "hax.lisp" - ]; - - deps = [ - (depot.nix.buildLisp.bundled "asdf") - depot.third_party.lisp.trivial-gray-streams - depot.third_party.lisp.babel #+rune-is-character - ]; - - brokenOn = [ - # TODO(sterni): fails when loading because it tries to access package.lisp at runtime - "ecl" - ]; -} diff --git a/third_party/lisp/closure-html/default.nix b/third_party/lisp/closure-html/default.nix deleted file mode 100644 index f0d73c760..000000000 --- a/third_party/lisp/closure-html/default.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ depot, pkgs, ... }: - -let - src = pkgs.applyPatches { - name = "closure-html-source"; - src = pkgs.sbcl.pkgs.closure-html.src; - - patches = [ - # delete unexported and unused double defun in sgml-dtd.lisp - # which reference undefined CL-USER:*HTML-DTD* (!) which - # unlike CLOSURE-HTML:*HTML-DTD* is not involved in the - # package's operation. - ./no-double-defun.patch - # Patches html-parser.lisp to look for the distributed - # dtd files and catalog in this source derivations out - # path in the nix store instead of the same directory - # relatively to the (built) system. - ./dtds-from-store.patch - ]; - - postPatch = '' - # Inject file which defines CLOSURE-HTML:*HTML-DTD* - # early in the package's build since SBCL otherwise - # fails due to the undefined variable. Need to inject - # this via postPatch since using a nix file results - # in failure to look up the file's true name which - # is done for … reasons, apparently. - cat > src/define-html-dtd.lisp << EOF - (in-package :closure-html) - (defvar *html-dtd*) - EOF - - # Substitute reference to @out@ of this source - # directory in this patched file. - substituteAllInPlace src/parse/html-parser.lisp - ''; - }; - - getSrcs = builtins.map (p: "${src}/${p}"); -in - -depot.nix.buildLisp.library { - name = "closure-html"; - - srcs = getSrcs [ - "src/defpack.lisp" - "src/define-html-dtd.lisp" - "src/glisp/util.lisp" - "src/util/clex.lisp" - "src/util/lalr.lisp" - "src/net/mime.lisp" - "src/parse/pt.lisp" - "src/parse/sgml-dtd.lisp" - "src/parse/sgml-parse.lisp" - "src/parse/html-parser.lisp" - "src/parse/lhtml.lisp" - "src/parse/unparse.lisp" - "src/parse/documentation.lisp" - ]; - - deps = [ - depot.third_party.lisp.flexi-streams - depot.third_party.lisp.closure-common - ]; - - brokenOn = [ - "ecl" # see closure-common - ]; -} diff --git a/third_party/lisp/closure-html/dtds-from-store.patch b/third_party/lisp/closure-html/dtds-from-store.patch deleted file mode 100644 index a9ffd8085..000000000 --- a/third_party/lisp/closure-html/dtds-from-store.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/src/parse/html-parser.lisp b/src/parse/html-parser.lisp -index 4e45b81..5025a26 100644 ---- a/src/parse/html-parser.lisp -+++ b/src/parse/html-parser.lisp -@@ -36,10 +36,7 @@ - (make-pathname - :name nil - :type nil -- :defaults (merge-pathnames -- "resources/" -- (asdf:component-relative-pathname -- (asdf:find-system :closure-html)))))) -+ :defaults "@out@/resources/"))) - (loop - :for (name . filename) - :in '(("-//W3O//DTD W3 HTML 3.0//EN" . "dtd/HTML-3.0") diff --git a/third_party/lisp/closure-html/no-double-defun.patch b/third_party/lisp/closure-html/no-double-defun.patch deleted file mode 100644 index ce7fb33ab..000000000 --- a/third_party/lisp/closure-html/no-double-defun.patch +++ /dev/null @@ -1,78 +0,0 @@ -diff --git a/src/parse/sgml-dtd.lisp b/src/parse/sgml-dtd.lisp -index de774c0..dbee852 100644 ---- a/src/parse/sgml-dtd.lisp -+++ b/src/parse/sgml-dtd.lisp -@@ -624,73 +624,6 @@ - (return)))) - classes)) - --;;;; ---------------------------------------------------------------------------------------------------- --;;;; Compiled DTDs --;;;; -- --;; Since parsing and 'compiling' DTDs is slow, I'll provide for a way --;; to (un)dump compiled DTD to stream. -- --(defun dump-dtd (dtd sink) -- (let ((*print-pretty* nil) -- (*print-readably* t) -- (*print-circle* t)) -- (princ "#." sink) -- (prin1 -- `(MAKE-DTD :NAME ',(dtd-name dtd) -- :ELEMENTS (LET ((R (MAKE-HASH-TABLE :TEST #'EQ))) -- (SETF ,@(let ((q nil)) -- (maphash (lambda (key value) -- (push `',value q) -- (push `(GETHASH ',key R) q)) -- (dtd-elements dtd)) -- q)) -- R) -- :ENTITIES ',(dtd-entities dtd) -- :RESOLVE-INFO (LET ((R (MAKE-HASH-TABLE :TEST #'EQUAL))) -- (SETF ,@(let ((q nil)) -- (maphash (lambda (key value) -- (push `',value q) -- (push `(GETHASH ',key R) q)) -- (dtd-resolve-info dtd)) -- q)) -- R) -- ;; XXX surclusion-cache fehlt -- ) -- sink))) -- --;;XXX --(defun save-html-dtd () -- (with-open-file (sink "html-dtd.lisp" :direction :output :if-exists :new-version) -- (print `(in-package :sgml) sink) -- (let ((*package* (find-package :sgml))) -- (princ "(SETQ " sink) -- (prin1 'cl-user::*html-dtd* sink) -- (princ " '" sink) -- (dump-dtd cl-user::*html-dtd* sink) -- (princ ")" sink)))) -- --;;; -------------------------------------------------------------------------------- --;;; dumping DTDs -- -- --(defun dump-dtd (dtd filename) -- (let ((*foo* dtd)) -- (declare (special *foo*)) -- (with-open-file (sink (merge-pathnames filename "*.lisp") -- :direction :output -- :if-exists :new-version) -- (format sink "(in-package :sgml)(locally (declare (special *foo*))(setq *foo* '#.*foo*))")) -- (compile-file (merge-pathnames filename "*.lisp")))) -- --(defun undump-dtd (filename) -- (let (*foo*) -- (declare (special *foo*)) -- (load (compile-file-pathname (merge-pathnames filename "*.lisp")) -- :verbose nil -- :print nil) -- *foo*)) -- - (defmethod make-load-form ((self dtd) &optional env) - (declare (ignore env)) - `(make-dtd :name ',(dtd-name self) diff --git a/third_party/lisp/defclass-std.nix b/third_party/lisp/defclass-std.nix deleted file mode 100644 index ba22ed5e6..000000000 --- a/third_party/lisp/defclass-std.nix +++ /dev/null @@ -1,16 +0,0 @@ -# A shortcut macro to write DEFCLASS forms quickly -# Seems to be unmaintained (since early 2021) -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.defclass-std; -in depot.nix.buildLisp.library { - name = "defclass-std"; - deps = with depot.third_party.lisp; [ - alexandria - anaphora - ]; - - srcs = map (f: src + ("/src/" + f)) [ - "defclass-std.lisp" - ]; -} diff --git a/third_party/lisp/drakma.nix b/third_party/lisp/drakma.nix deleted file mode 100644 index 699d442c5..000000000 --- a/third_party/lisp/drakma.nix +++ /dev/null @@ -1,34 +0,0 @@ -# Drakma is an HTTP client for Common Lisp. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.drakma; -in depot.nix.buildLisp.library { - name = "drakma"; - deps = with depot.third_party.lisp; [ - chipz - chunga - cl-base64 - cl-plus-ssl - cl-ppcre - flexi-streams - puri - usocket - (depot.nix.buildLisp.bundled "asdf") - ]; - - srcs = map (f: src + ("/" + f)) [ - "drakma.asd" # Required because the system definition is used - "packages.lisp" - "specials.lisp" - "conditions.lisp" - "util.lisp" - "read.lisp" - "cookies.lisp" - "encoding.lisp" - "request.lisp" - ]; - - brokenOn = [ - "ecl" # dynamic cffi - ]; -} diff --git a/third_party/lisp/easy-routes.nix b/third_party/lisp/easy-routes.nix deleted file mode 100644 index f2c4e663b..000000000 --- a/third_party/lisp/easy-routes.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ depot, pkgs, ... }: - -let - - src = pkgs.srcOnly pkgs.sbcl.pkgs.easy-routes; -in - -depot.nix.buildLisp.library { - name = "easy-routes"; - deps = with depot.third_party.lisp; [ - hunchentoot - routes - ]; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "util.lisp" - "easy-routes.lisp" - "routes-map-printer.lisp" - ]; - - brokenOn = [ - "ecl" # dynamic cffi - ]; -} diff --git a/third_party/lisp/fiveam.nix b/third_party/lisp/fiveam.nix deleted file mode 100644 index b27cf9c70..000000000 --- a/third_party/lisp/fiveam.nix +++ /dev/null @@ -1,29 +0,0 @@ -# FiveAM is a Common Lisp testing framework. -# -# Imported from https://github.com/sionescu/fiveam.git - -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.fiveam; -in depot.nix.buildLisp.library { - name = "fiveam"; - - deps = with depot.third_party.lisp; [ - alexandria - asdf-flv - trivial-backtrace - ]; - - srcs = map (f: src + ("/src/" + f)) [ - "package.lisp" - "utils.lisp" - "check.lisp" - "fixture.lisp" - "classes.lisp" - "random.lisp" - "test.lisp" - "explain.lisp" - "suite.lisp" - "run.lisp" - ]; -} diff --git a/third_party/lisp/flexi-streams.nix b/third_party/lisp/flexi-streams.nix deleted file mode 100644 index 492d4c460..000000000 --- a/third_party/lisp/flexi-streams.nix +++ /dev/null @@ -1,33 +0,0 @@ -# Flexible bivalent streams for Common Lisp -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.flexi-streams; -in depot.nix.buildLisp.library { - name = "flexi-streams"; - deps = [ depot.third_party.lisp.trivial-gray-streams ]; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - "mapping.lisp" - "ascii.lisp" - "koi8-r.lisp" - "mac.lisp" - "iso-8859.lisp" - "enc-cn-tbl.lisp" - "code-pages.lisp" - "specials.lisp" - "util.lisp" - "conditions.lisp" - "external-format.lisp" - "length.lisp" - "encode.lisp" - "decode.lisp" - "in-memory.lisp" - "stream.lisp" - "output.lisp" - "input.lisp" - "io.lisp" - "strings.lisp" - ]; -} - diff --git a/third_party/lisp/frugal-uuid-non-frugal.nix b/third_party/lisp/frugal-uuid-non-frugal.nix deleted file mode 100644 index 875f7b9d8..000000000 --- a/third_party/lisp/frugal-uuid-non-frugal.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.nix) buildLisp; - inherit (pkgs.sbcl.pkgs.frugal-uuid) src; -in - -buildLisp.library { - # TODO(sterni): can't use / since name influences paths - name = "frugal-uuid-non-frugal"; - - deps = [ - depot.third_party.lisp.frugal-uuid - depot.third_party.lisp.babel - depot.third_party.lisp.bordeaux-threads - depot.third_party.lisp.ironclad - depot.third_party.lisp.trivial-clock - ]; - - # Note that these can be built individually, but we don't bother (yet) - srcs = builtins.map (f: "${src}/non-frugal/${f}") [ - "strong-random" - "thread-safe" - "name-based" - "accurate-clock" - "minara" - ]; - - brokenOn = [ - "ecl" # trivial-clock - ]; -} diff --git a/third_party/lisp/frugal-uuid.nix b/third_party/lisp/frugal-uuid.nix deleted file mode 100644 index c22cc7ba8..000000000 --- a/third_party/lisp/frugal-uuid.nix +++ /dev/null @@ -1,40 +0,0 @@ -{ pkgs, depot, ... }: - -let - inherit (depot.nix) buildLisp; - inherit (pkgs.sbcl.pkgs.frugal-uuid) src; - -in - -buildLisp.library { - name = "frugal-uuid"; - srcs = builtins.map (f: "${src}/${f}.lisp") [ - "package" - "frugal-uuid" - "frugal-uuid-node" - "frugal-uuid-clock" - "frugal-uuid-random" - "frugal-uuid-namespace" - "frugal-uuid-v1" - "frugal-uuid-v2" - "frugal-uuid-v3" - "frugal-uuid-v4" - "frugal-uuid-v5" - "frugal-uuid-v6" - "frugal-uuid-v7" - "frugal-uuid-v8" - ]; - - tests = { - name = "frugal-uuid-test"; - srcs = [ - "${src}/frugal-uuid-test.lisp" - ]; - deps = [ - depot.third_party.lisp.fiveam - ]; - expression = '' - (fiveam:run! :frugal-uuid) - ''; - }; -} diff --git a/third_party/lisp/global-vars.nix b/third_party/lisp/global-vars.nix deleted file mode 100644 index 529816b00..000000000 --- a/third_party/lisp/global-vars.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.global-vars; -in depot.nix.buildLisp.library { - name = "global-vars"; - srcs = [ "${src}/global-vars.lisp" ]; -} diff --git a/third_party/lisp/hunchentoot.nix b/third_party/lisp/hunchentoot.nix deleted file mode 100644 index 8b351fa9a..000000000 --- a/third_party/lisp/hunchentoot.nix +++ /dev/null @@ -1,68 +0,0 @@ -# Hunchentoot is a web framework for Common Lisp. -{ depot, pkgs, lib, ... }: - -let - src = with pkgs; srcOnly sbcl.pkgs.hunchentoot; - - url-rewrite = depot.nix.buildLisp.library { - name = "url-rewrite"; - - srcs = map (f: src + ("/url-rewrite/" + f)) [ - "packages.lisp" - "specials.lisp" - "primitives.lisp" - "util.lisp" - "url-rewrite.lisp" - ]; - }; -in -depot.nix.buildLisp.library { - name = "hunchentoot"; - - deps = with depot.third_party.lisp; [ - alexandria - bordeaux-threads - chunga - cl-base64 - cl-fad - rfc2388 - cl-plus-ssl - cl-ppcre - flexi-streams - md5 - trivial-backtrace - usocket - url-rewrite - ]; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - "compat.lisp" - ] ++ [ - (pkgs.runCommand "specials.lisp" { } '' - substitute "${src}/specials.lisp" "$out" --replace-fail \ - ${lib.escapeShellArg "#.(asdf:component-version (asdf:find-system :hunchentoot))"} \ - '"${lib.removePrefix "v" src.version}"' - '') - ] ++ map (f: src + ("/" + f)) [ - "conditions.lisp" - "mime-types.lisp" - "util.lisp" - "log.lisp" - "cookie.lisp" - "reply.lisp" - "request.lisp" - "session.lisp" - "misc.lisp" - "headers.lisp" - "set-timeouts.lisp" - "taskmaster.lisp" - "ssl.lisp" - "acceptor.lisp" - "easy-handlers.lisp" - ]; - - brokenOn = [ - "ecl" # dynamic cffi - ]; -} diff --git a/third_party/lisp/ironclad.nix b/third_party/lisp/ironclad.nix deleted file mode 100644 index 0148dc1f9..000000000 --- a/third_party/lisp/ironclad.nix +++ /dev/null @@ -1,173 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (pkgs) runCommand; - inherit (depot.nix.buildLisp) bundled; - src = with pkgs; srcOnly sbcl.pkgs.ironclad; - getSrc = f: "${src}/src/${f}"; - -in -depot.nix.buildLisp.library { - name = "ironclad"; - - deps = with depot.third_party.lisp; [ - (bundled "asdf") - { sbcl = bundled "sb-rotate-byte"; } - { sbcl = bundled "sb-posix"; } - alexandria - bordeaux-threads - nibbles - ]; - - srcs = map getSrc [ - # { - # # TODO(grfn): Figure out how to get this compiling with the assembly - # # optimization eventually - see https://cl.tvl.fyi/c/depot/+/1333 - # sbcl = runCommand "package.lisp" {} '' - # substitute ${src}/src/package.lisp $out \ - # --replace \#-ecl-bytecmp "" \ - # --replace '(pushnew :ironclad-assembly *features*)' "" - # ''; - # default = getSrc "package.lisp"; - # } - "package.lisp" - "conditions.lisp" - "generic.lisp" - "macro-utils.lisp" - "util.lisp" - ] ++ [ - { sbcl = getSrc "opt/sbcl/fndb.lisp"; } - { sbcl = getSrc "opt/sbcl/x86oid-vm.lisp"; } - { sbcl = getSrc "opt/sbcl/cpu-features.lisp"; } - - { ecl = getSrc "opt/ecl/c-functions.lisp"; } - - { ccl = getSrc "opt/ccl/x86oid-vm.lisp"; } - ] ++ map getSrc [ - "common.lisp" - - "ciphers/cipher.lisp" - "ciphers/padding.lisp" - "ciphers/make-cipher.lisp" - "ciphers/modes.lisp" - - "digests/digest.lisp" - "macs/mac.lisp" - "prng/prng.lisp" - "prng/os-prng.lisp" - "math.lisp" - "octet-stream.lisp" - "aead/aead.lisp" - "kdf/kdf.lisp" - "public-key/public-key.lisp" - "public-key/pkcs1.lisp" - "public-key/elliptic-curve.lisp" - - # subsystem def ironclad/ciphers - "ciphers/aes.lisp" - "ciphers/arcfour.lisp" - "ciphers/aria.lisp" - "ciphers/blowfish.lisp" - "ciphers/camellia.lisp" - "ciphers/cast5.lisp" - "ciphers/chacha.lisp" - "ciphers/des.lisp" - "ciphers/idea.lisp" - "ciphers/kalyna.lisp" - "ciphers/kuznyechik.lisp" - "ciphers/misty1.lisp" - "ciphers/rc2.lisp" - "ciphers/rc5.lisp" - "ciphers/rc6.lisp" - "ciphers/salsa20.lisp" - "ciphers/keystream.lisp" - "ciphers/seed.lisp" - "ciphers/serpent.lisp" - "ciphers/sm4.lisp" - "ciphers/sosemanuk.lisp" - "ciphers/square.lisp" - "ciphers/tea.lisp" - "ciphers/threefish.lisp" - "ciphers/twofish.lisp" - "ciphers/xchacha.lisp" - "ciphers/xor.lisp" - "ciphers/xsalsa20.lisp" - "ciphers/xtea.lisp" - - # subsystem def ironclad/digests - "digests/adler32.lisp" - "digests/blake2.lisp" - "digests/blake2s.lisp" - "digests/crc24.lisp" - "digests/crc32.lisp" - "digests/groestl.lisp" - ] ++ [ - { - # Work around compiler warning for CCL: - # https://github.com/sharplispers/ironclad/commit/ebc994b06409829c463b099fe460276cba564d43#commitcomment-153059140 - ccl = pkgs.runCommand "jh.lisp" { } '' - substitute "${src}/src/digests/jh.lisp" "$out" \ - --replace-fail "(declare (notinline jh-buffer jh-state))" "" - ''; - default = "${src}/src/digests/jh.lisp"; - } - ] ++ map getSrc [ - "digests/kupyna.lisp" - "digests/md2.lisp" - "digests/md4.lisp" - "digests/md5.lisp" - "digests/md5-lispworks-int32.lisp" - "digests/ripemd-128.lisp" - "digests/ripemd-160.lisp" - "digests/sha1.lisp" - "digests/sha256.lisp" - "digests/sha3.lisp" - "digests/sha512.lisp" - "digests/skein.lisp" - "digests/sm3.lisp" - "digests/streebog.lisp" - "digests/tiger.lisp" - "digests/tree-hash.lisp" - "digests/whirlpool.lisp" - - # subsystem def ironclad/macs - "macs/blake2-mac.lisp" - "macs/blake2s-mac.lisp" - "macs/cmac.lisp" - "macs/hmac.lisp" - "macs/gmac.lisp" - "macs/poly1305.lisp" - "macs/siphash.lisp" - "macs/skein-mac.lisp" - - # subsystem def ironclad/prngs - "prng/generator.lisp" - "prng/fortuna.lisp" - - # subsystem def ironclad/aeads - "aead/eax.lisp" - "aead/etm.lisp" - "aead/gcm.lisp" - - # subsystem def ironclad/kdfs - "kdf/argon2.lisp" - "kdf/bcrypt.lisp" - "kdf/hmac.lisp" - "kdf/pkcs5.lisp" - "kdf/password-hash.lisp" - "kdf/scrypt.lisp" - - # subsystem def ironclad/public-keys - "public-key/dsa.lisp" - "public-key/rsa.lisp" - "public-key/elgamal.lisp" - "public-key/curve25519.lisp" - "public-key/curve448.lisp" - "public-key/ed25519.lisp" - "public-key/ed448.lisp" - "public-key/secp256k1.lisp" - "public-key/secp256r1.lisp" - "public-key/secp384r1.lisp" - "public-key/secp521r1.lisp" - ]; -} diff --git a/third_party/lisp/iterate.nix b/third_party/lisp/iterate.nix deleted file mode 100644 index eef708c2c..000000000 --- a/third_party/lisp/iterate.nix +++ /dev/null @@ -1,12 +0,0 @@ -# iterate is an iteration construct for Common Lisp, similar to the -# LOOP macro. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.iterate; -in depot.nix.buildLisp.library { - name = "iterate"; - srcs = [ - "${src}/package.lisp" - "${src}/iterate.lisp" - ]; -} diff --git a/third_party/lisp/lass.nix b/third_party/lisp/lass.nix deleted file mode 100644 index a4356dc7d..000000000 --- a/third_party/lisp/lass.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ depot, pkgs, ... }: - -let - src = pkgs.applyPatches { - src = pkgs.srcOnly pkgs.sbcl.pkgs.lass; - patches = [ - # https://github.com/Shinmera/LASS/pull/22 - (pkgs.fetchpatch { - name = "lass-fix-ccl-build.patch"; - url = "https://github.com/Shinmera/LASS/commit/957afc830f0517f1053cdd8605af1dc5e457527f.patch"; - sha256 = "06fp0rnqqvai08lr6aldzga2xc9dxdfffrpgs3rha9gp0xmvlz43"; - }) - ]; - }; -in -depot.nix.buildLisp.library { - name = "lass"; - - deps = with depot.third_party.lisp; [ - trivial-indent - trivial-mimes - cl-base64 - (depot.nix.buildLisp.bundled "asdf") - ]; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "readable-list.lisp" - "compiler.lisp" - "property-funcs.lisp" - "writer.lisp" - "lass.lisp" - "special.lisp" - "asdf.lisp" - ]; -} diff --git a/third_party/lisp/let-plus.nix b/third_party/lisp/let-plus.nix deleted file mode 100644 index f9be858a2..000000000 --- a/third_party/lisp/let-plus.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.let-plus; -in depot.nix.buildLisp.library { - name = "let-plus"; - deps = [ - depot.third_party.lisp.alexandria - depot.third_party.lisp.anaphora - ]; - srcs = [ - "${src}/package.lisp" - "${src}/let-plus.lisp" - "${src}/extensions.lisp" - ]; -} diff --git a/third_party/lisp/lisp-binary.nix b/third_party/lisp/lisp-binary.nix deleted file mode 100644 index cc4dcbfa4..000000000 --- a/third_party/lisp/lisp-binary.nix +++ /dev/null @@ -1,33 +0,0 @@ -# A library to easily read and write complex binary formats. -{ depot, pkgs, ... }: - -let - src = pkgs.srcOnly pkgs.sbcl.pkgs.lisp-binary; -in -depot.nix.buildLisp.library { - name = "lisp-binary"; - - deps = with depot.third_party.lisp; [ - alexandria - cffi - closer-mop - flexi-streams - moptilities - quasiquote_2 - ]; - - srcs = map (f: src + ("/" + f)) [ - "utils.lisp" - "integer.lisp" - "float.lisp" - "simple-bit-stream.lisp" - "reverse-stream.lisp" - "binary-1.lisp" - "binary-2.lisp" - "types.lisp" - ]; - - brokenOn = [ - "ecl" # TODO(sterni): disable conditionally cffi for ECL - ]; -} diff --git a/third_party/lisp/local-time.nix b/third_party/lisp/local-time.nix deleted file mode 100644 index 0d5d3a465..000000000 --- a/third_party/lisp/local-time.nix +++ /dev/null @@ -1,22 +0,0 @@ -# Library for manipulating dates & times -{ depot, pkgs, ... }: - -let - inherit (depot.nix) buildLisp; - src = with pkgs; srcOnly sbcl.pkgs.local-time; -in -buildLisp.library { - name = "local-time"; - deps = [ - depot.third_party.lisp.cl-fad - { - scbl = buildLisp.bundled "uiop"; - default = buildLisp.bundled "asdf"; - } - ]; - - srcs = [ - "${src}/src/package.lisp" - "${src}/src/local-time.lisp" - ]; -} diff --git a/third_party/lisp/marshal.nix b/third_party/lisp/marshal.nix deleted file mode 100644 index b7232aff7..000000000 --- a/third_party/lisp/marshal.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.marshal; -in depot.nix.buildLisp.library { - name = "marshal"; - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "serialization-format.lisp" - "coding-idiom.lisp" - "marshal.lisp" - "unmarshal.lisp" - ]; -} diff --git a/third_party/lisp/md5.nix b/third_party/lisp/md5.nix deleted file mode 100644 index 218fffeb4..000000000 --- a/third_party/lisp/md5.nix +++ /dev/null @@ -1,16 +0,0 @@ -# MD5 hash implementation -{ depot, pkgs, ... }: - -with depot.nix; - -let src = with pkgs; srcOnly sbcl.pkgs.md5; -in buildLisp.library { - name = "md5"; - deps = [ - { - sbcl = buildLisp.bundled "sb-rotate-byte"; - default = depot.third_party.lisp.flexi-streams; - } - ]; - srcs = [ (src + "/md5.lisp") ]; -} diff --git a/third_party/lisp/metabang-bind.nix b/third_party/lisp/metabang-bind.nix deleted file mode 100644 index b06acdad4..000000000 --- a/third_party/lisp/metabang-bind.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ depot, pkgs, ... }: - -let - getSrcs = builtins.map (p: "${pkgs.srcOnly pkgs.sbcl.pkgs.metabang-bind}/${p}"); -in - -depot.nix.buildLisp.library { - name = "metabang-bind"; - - srcs = getSrcs [ - "dev/packages.lisp" - "dev/macros.lisp" - "dev/bind.lisp" - "dev/binding-forms.lisp" - ]; -} diff --git a/third_party/lisp/mime4cl/OWNERS b/third_party/lisp/mime4cl/OWNERS deleted file mode 100644 index 2e9580706..000000000 --- a/third_party/lisp/mime4cl/OWNERS +++ /dev/null @@ -1 +0,0 @@ -sterni diff --git a/third_party/lisp/mime4cl/README.md b/third_party/lisp/mime4cl/README.md deleted file mode 100644 index c7af881c1..000000000 --- a/third_party/lisp/mime4cl/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# mime4cl - -`MIME4CL` is a Common Lisp library for dealing with MIME messages. It was -originally been written by Walter C. Pelissero and vendored into depot -([mime4cl-20150207T211851.tbz](http://wcp.sdf-eu.org/software/mime4cl-20150207T211851.tbz) -to be exact) as upstream has become inactive. Its [original -website](http://wcp.sdf-eu.org/software/#mime4cl) can still be accessed. - -The depot version has since diverged from upstream. Main aims were to improve -performance and reduce code size by relying on third party libraries like -flexi-streams. It is planned to improve encoding handling in the long term. -Work towards this happens intermittently. - -WARNING: -mime4cl currently doesn't have a _comprehensive_ test suite -and decidedly lacks performance. - -## Differences from the original version - -* `//nix/buildLisp` is used as the build system. ASDF has been removed - since it was untested (it should be reintroduced once mime4cl is - “ready”). - -* The dependency on [sclf](http://wcp.sdf-eu.org/software/#sclf) has been - eliminated by inlining the relevant parts. - -* `MY-STRING-INPUT-STREAM`, `DELIMITED-INPUT-STREAM`, - `CHARACTER-INPUT-ADAPTER-STREAM`, `BINARY-INPUT-ADAPTER-STREAM` etc. have been - replaced by (thin wrappers around) flexi-streams. In addition to improved - handling of encodings, this allows using `READ-SEQUENCE` via the gray stream - interface. diff --git a/third_party/lisp/mime4cl/address.lisp b/third_party/lisp/mime4cl/address.lisp deleted file mode 100644 index 42688a595..000000000 --- a/third_party/lisp/mime4cl/address.lisp +++ /dev/null @@ -1,300 +0,0 @@ -;;; address.lisp --- e-mail address parser - -;;; Copyright (C) 2007, 2008, 2009 by Walter C. Pelissero -;;; Copyright (C) 2022-2023 The TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -;;; Although not MIME specific, this parser is often useful together -;;; with the MIME primitives. It should be able to parse the address -;;; syntax described in RFC2822 excluding the obsolete syntax (see -;;; RFC822). Have a look at the test suite to get an idea of what -;;; kind of addresses it can parse. - -(in-package :mime4cl) - -(defstruct (mailbox (:conc-name mbx-)) - description - user - host - domain) - -(defstruct (mailbox-group (:conc-name mbxg-)) - name - mailboxes) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun write-mailbox-domain-name (addr &optional (stream *standard-output*)) - (when (eq :internet (mbx-domain addr)) - (write-char #\[ stream)) - (write-string (mbx-host addr) stream) - (when (eq :internet (mbx-domain addr)) - (write-char #\] stream)) - (when (stringp (mbx-domain addr)) - (write-char #\. stream) - (write-string (mbx-domain addr) stream))) - -(defun write-mailbox-address (addr &optional (stream *standard-output*)) - (write-string (mbx-user addr) stream) - (when (mbx-host addr) - (write-char #\@ stream) - (write-mailbox-domain-name addr stream))) - -(defmethod mbx-domain-name ((MBX mailbox)) - "Return the complete domain name string of MBX, in the form -\"host.domain\"." - (with-output-to-string (out) - (write-mailbox-domain-name mbx out))) - -(defmethod mbx-address ((mbx mailbox)) - "Return the e-mail address string of MBX, in the form -\"user@host.domain\"." - (with-output-to-string (out) - (write-mailbox-address mbx out))) - -(defun write-mailbox (addr &optional (stream *standard-output*)) - (awhen (mbx-description addr) - (write it :stream stream :readably t) - (write-string " <" stream)) - (write-mailbox-address addr stream) - (awhen (mbx-description addr) - (write-char #\> stream))) - -(defun write-mailbox-group (grp &optional (stream *standard-output*)) - (write-string (mbxg-name grp) stream) - (write-string ": " stream) - (loop - for mailboxes on (mbxg-mailboxes grp) - for mailbox = (car mailboxes) - do (write-mailbox mailbox stream) - unless (endp (cdr mailboxes)) - do (write-string ", " stream)) - (write-char #\; stream)) - -(defmethod print-object ((mbx mailbox) stream) - (if (or *print-readably* *print-escape*) - (call-next-method) - (write-mailbox mbx stream))) - -(defmethod print-object ((grp mailbox-group) stream) - (if (or *print-readably* *print-escape*) - (call-next-method) - (write-mailbox-group grp stream))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun parser-make-mailbox (description address-list) - (make-mailbox :description description - :user (car address-list) - :host (cadr address-list) - :domain (when (cddr address-list) - (string-concat (cddr address-list) ".")))) - - -(defun populate-grammar () - (defrule address-list - := (+ address ",")) - - (defrule address - := mailbox - := group) - - (defrule mailbox - := display-name? angle-addr comment? - :reduce (parser-make-mailbox (or display-name comment) angle-addr) - := addr-spec comment? - :reduce (parser-make-mailbox comment addr-spec)) - - (defrule angle-addr - := "<" addr-spec ">") - - (defrule group - := display-name ":" mailbox-list ";" - :reduce (make-mailbox-group :name display-name :mailboxes mailbox-list)) - - (defrule display-name - := phrase - :reduce (string-concat phrase " ")) - - (defrule phrase - := word+) - - (defrule word - := atext - := string) - - (defrule mailbox-list - := (+ mailbox ",")) - - (defrule addr-spec - := local-part "@" domain :reduce (cons local-part domain)) - - (defrule local-part - := dot-atom :reduce (string-concat dot-atom ".") - := string) - - (defrule domain - := dot-atom - := domain-literal :reduce (list domain-literal :internet)) - - ;; actually, according to the RFC, dot-atoms don't allow spaces in - ;; between but these rules do - (defrule dot-atom - := (+ atom ".")) - - (defrule atom - := atext+ - :reduce (apply #'concatenate 'string atext))) - -(deflazy define-grammar - (let ((*package* #.*package*) - (*compile-print* (when npg::*debug* t))) - (reset-grammar) - (format t "~&creating e-mail address grammar...~%") - (populate-grammar) - (let ((grammar (npg:generate-grammar #'string=))) - (reset-grammar) - (npg:print-grammar-figures grammar) - grammar))) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; The lexical analyser - -(defstruct cursor - stream - (position 0)) - -(defun read-delimited-string (stream end-char &key nesting-start-char (escape-char #\\)) - (labels ((collect () - (with-output-to-string (out) - (loop - for c = (read-char stream nil) - while (and c (not (char= c end-char))) - do (cond ((char= c escape-char) - (awhen (read-char stream nil) - (write-char it out))) - ((and nesting-start-char - (char= c nesting-start-char)) - (write-char nesting-start-char out) - (write-string (collect) out) - (write-char end-char out)) - (t (write-char c out))))))) - (collect))) - - -(defun read-string (cursor) - (make-token :type 'string - :value (read-delimited-string (cursor-stream cursor) #\") - :position (incf (cursor-position cursor)))) - -(defun read-domain-literal (cursor) - (make-token :type 'domain-literal - :value (read-delimited-string (cursor-stream cursor) #\]) - :position (incf (cursor-position cursor)))) - -(defun read-comment (cursor) - (make-token :type 'comment - :value (read-delimited-string (cursor-stream cursor) #\) :nesting-start-char #\() - :position (incf (cursor-position cursor)))) - -(declaim (inline atom-component-p)) -(defun atom-component-p (c) - (declare (type character c)) - (not (find c " ()\"[]@.<>:;,"))) - -(defun read-atext (first-character cursor) - (let ((string (with-output-to-string (out) - (write-char first-character out) - (loop - for c = (read-char (cursor-stream cursor) nil) - while (and c (atom-component-p c)) - do (write-char c out) - finally (when c - (unread-char c (cursor-stream cursor))))))) - (make-token :type 'atext - :value string - :position (incf (cursor-position cursor))))) - -(defmethod read-next-tokens ((cursor cursor)) - (flet ((make-keyword (c) - (make-token :type 'keyword - :value (string c) - :position (incf (cursor-position cursor))))) - (let ((in (cursor-stream cursor))) - (loop - for c = (read-char in nil) - while c - unless (whitespace-p c) - return (list - (cond ((char= #\( c) - (read-comment cursor)) - ((char= #\" c) - (read-string cursor)) - ((char= #\[ c) - (read-domain-literal cursor)) - ((find c "@.<>:;,") - (make-keyword c)) - (t - ;; anything else is considered a text atom even - ;; though it's just a single character - (read-atext c cursor)))))))) - -(defun analyse-string (string) - "Return the list of tokens produced by a lexical analysis of -STRING. These are the tokens that would be seen by the parser." - (with-input-from-string (stream string) - (let ((cursor (make-cursor :stream stream))) - (loop - for tokens = (read-next-tokens cursor) - until (endp tokens) - append tokens)))) - -(defun mailboxes-only (list-of-mailboxes-and-groups) - "Return a flat list of MAILBOX-ADDRESSes from -LIST-OF-MAILBOXES-AND-GROUPS, which is the kind of list returned -by PARSE-ADDRESSES. This turns out to be useful when your -program is not interested in mailbox groups and expects the user -addresses only." - (mapcan #'(lambda (mbx) - (if (typep mbx 'mailbox-group) - (mbxg-mailboxes mbx) - (list mbx))) - list-of-mailboxes-and-groups)) - -(defun parse-addresses (string &key no-groups) - "Parse STRING and return a list of MAILBOX-ADDRESSes or -MAILBOX-GROUPs. If STRING is unparsable return NIL. If -NO-GROUPS is true, return a flat list of mailboxes throwing away -the group containers, if any." - (let ((grammar (force define-grammar))) - (with-input-from-string (stream string) - (let* ((cursor (make-cursor :stream stream)) - (mailboxes (ignore-errors ; ignore parsing errors - (parse grammar 'address-list cursor)))) - (if no-groups - (mailboxes-only mailboxes) - mailboxes))))) - -(defun debug-addresses (string) - "More or less like PARSE-ADDRESSES, but don't ignore parsing errors." - (let ((grammar (force define-grammar))) - (with-input-from-string (stream string) - (let ((cursor (make-cursor :stream stream))) - (parse grammar 'address-list cursor))))) - diff --git a/third_party/lisp/mime4cl/benchmark/bench.lisp b/third_party/lisp/mime4cl/benchmark/bench.lisp deleted file mode 100644 index 1a25f2010..000000000 --- a/third_party/lisp/mime4cl/benchmark/bench.lisp +++ /dev/null @@ -1,30 +0,0 @@ -(defpackage :mime4cl-bench - (:use :common-lisp :mime4cl) - (:export :main)) - -(in-package :mime4cl-bench) - -;; Write to /dev/null so that I/O is less (?) of a factor -(defparameter *output-path* (pathname "/dev/null")) - -(defun parse-message (path) - (let ((msg (mime-message path))) - ;; to prove we are doing something, print the subject - (format t "Subject: ~A~%" (car (mime-message-header-values "Subject" msg :decode t))) - msg)) - -(defun main () - (destructuring-bind (bench-name message-path) (uiop:command-line-arguments) - (let ((action (intern (string-upcase bench-name) :mime4cl-bench)) - (message-path (pathname message-path))) - (ccase action - ((parse) (parse-message message-path)) - ((extract) (do-parts (part (parse-message message-path)) - (format t "Content-Type: ~A~%" (mime-type-string part)) - (let ((in (mime-body-stream part))) - (with-open-file (output-stream (pathname *output-path*) - :direction :output - :if-does-not-exist :create - :element-type (stream-element-type in) - :if-exists :overwrite) - (redirect-stream in output-stream))))))))) diff --git a/third_party/lisp/mime4cl/benchmark/default.nix b/third_party/lisp/mime4cl/benchmark/default.nix deleted file mode 100644 index 847515de8..000000000 --- a/third_party/lisp/mime4cl/benchmark/default.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - # Example email that's going to push the parser due to its big attachment - # of almost 200MB. We are using a GHC bindist since it's quite big and a - # fixed output derivation that's already part of nixpkgs, so whitby only - # needs to download it once (and it won't change). - message = pkgs.runCommand "huge.mime" - { - nativeBuildInputs = [ pkgs.buildPackages.mblaze ]; - } - '' - mmime > $out < -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - - -(in-package :mime4cl) - -(defun redirect-stream (in out &key (buffer-size 4096)) - "Consume input stream IN and write all its content to output stream OUT. -The streams' element types need to match." - (let ((buf (make-array buffer-size :element-type (stream-element-type in)))) - (loop for pos = (read-sequence buf in) - while (> pos 0) - do (write-sequence buf out :end pos)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Thank you SBCL for rendering constants totally useless! -(defparameter +base64-encode-table+ - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") - -(declaim (type simple-string +base64-encode-table+)) - -(defvar *base64-line-length* 76 - "Maximum length of the encoded base64 line. NIL means it can -be of unlimited length \(no line breaks will be done by the -encoding function).") - -(defvar *quoted-printable-line-length* 72 - "Maximum length of the encoded quoted printable line. NIL -means it can be of unlimited length \(no line breaks will be done -by the encoding function).") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defclass decoder () - ((input-function :initarg :input-function - :reader decoder-input-function - :type function - :documentation - "Function is called repeatedly by the decoder methods to get the next character. -It should return a character os NIL (indicating EOF).")) - (:documentation - "Abstract base class for decoders.")) - -(defclass parsing-decoder (decoder) - ((parser-errors :initform nil - :initarg :parser-errors - :reader decoder-parser-errors - :type boolean)) - (:documentation - "Abstract base class for decoders that do parsing.")) - -(defclass encoder () - ((output-function :initarg :output-function - :reader encoder-output-function - :type function - :documentation - "Function is called repeatedly by the encoder methods to output a character. -It should expect a character as its only argument.")) - (:documentation - "Abstract base class for encoders.")) - -(defclass line-encoder (encoder) - ((column :initform 0 - :type fixnum) - (line-length :initarg :line-length - :initform nil - :reader encoder-line-length - :type (or fixnum null))) - (:documentation - "Abstract base class for line encoders.")) - -(defclass 8bit-decoder (decoder) - () - (:documentation - "Class for decoders that do nothing.")) - -(defclass 8bit-encoder (encoder) - () - (:documentation - "Class for encoders that do nothing.")) - -(defclass 7bit-decoder (decoder) - () - (:documentation - "Class for decoders that do nothing.")) - -(defclass 7bit-encoder (encoder) - () - (:documentation - "Class for encoders that do nothing.")) - -(defclass byte-decoder (decoder) - () - (:documentation - "Class for decoders that turns chars to bytes.")) - -(defclass byte-encoder (encoder) - () - (:documentation - "Class for encoders that turns bytes to chars.")) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric encoder-write-byte (encoder byte)) -(defgeneric encoder-finish-output (encoder)) -(defgeneric decoder-read-byte (decoder)) - -(defmethod encoder-finish-output ((encoder encoder)) - (values)) - -(defmethod encoder-write-byte ((encoder 8bit-encoder) byte) - (funcall (slot-value encoder 'output-function) - (code-char byte)) - (values)) - -(defmethod decoder-read-byte ((decoder 8bit-decoder)) - (awhen (funcall (slot-value decoder 'input-function)) - (char-code it))) - -(defmethod encoder-write-byte ((encoder 7bit-encoder) byte) - (funcall (slot-value encoder 'output-function) - (code-char (logand #x7F byte))) - (values)) - -(defmethod decoder-read-byte ((decoder 7bit-decoder)) - (awhen (funcall (slot-value decoder 'input-function)) - (logand #x7F (char-code it)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun decoder-read-sequence (sequence decoder &key (start 0) (end (length sequence))) - (declare (optimize (speed 3) (safety 0) (debug 0)) - (type fixnum start end) - (type vector sequence)) - (loop - for i fixnum from start below end - for byte = (decoder-read-byte decoder) - while byte - do (setf (aref sequence i) byte) - finally (return i))) - -(defun decoder-read-line (decoder) - (with-output-to-string (str) - (loop - for byte = (decoder-read-byte decoder) - unless byte - do (return-from decoder-read-line nil) - do (let ((c (code-char byte))) - (cond ((char= c #\return) - ;; skip the newline - (decoder-read-byte decoder) - (return nil)) - ((char= c #\newline) - ;; the #\return was missing - (return nil)) - (t (write-char c str))))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(declaim (inline parse-hex)) -(defun parse-hex (c1 c2) - "Parse two characters as hexadecimal and return their combined -value." - (declare (optimize (speed 3) (safety 0) (debug 0)) - (type character c1 c2)) - (flet ((digit-value (char) - (or (position char "0123456789ABCDEF") - (return-from parse-hex nil)))) - (+ (* 16 (digit-value c1)) - (digit-value c2)))) - -(defclass quoted-printable-decoder (parsing-decoder) - ((saved-bytes :initform (make-queue)))) - -(defmethod decoder-read-byte ((decoder quoted-printable-decoder)) - (declare (optimize (speed 3) (safety 0) (debug 0))) - (with-slots (input-function saved-bytes parser-errors) decoder - (declare (type function input-function)) - (labels ((saveb (b) - (queue-append saved-bytes b) - (values)) - (save (c) - (saveb (char-code c))) - (push-next () - (let ((c (funcall input-function))) - (declare (type (or null character) c)) - (cond ((not c)) - ((or (char= c #\space) - (char= c #\tab)) - (save c) - (push-next)) - ((char= c #\=) - (let ((c1 (funcall input-function))) - (cond ((not c1) - (save #\=)) - ((char= c1 #\return) - ;; soft line break: skip the next - ;; character which we assume to be a - ;; newline (pity if it isn't) - (funcall input-function) - (push-next)) - ((char= c1 #\newline) - ;; soft line break: the #\return is - ;; missing, but we are tolerant - (push-next)) - (t - ;; hexadecimal sequence: get the 2nd digit - (let ((c2 (funcall input-function))) - (if c2 - (aif (parse-hex c1 c2) - (saveb it) - (if parser-errors - (error "invalid hex sequence ~A~A" c1 c2) - (progn - (save #\=) - (save c1) - (save c2)))) - (progn - (save c) - (save c1)))))))) - (t - (save c)))))) - (or (queue-pop saved-bytes) - (progn - (push-next) - (queue-pop saved-bytes)))))) - -(defmacro make-encoder-loop (encoder-class input-form output-form) - (with-gensyms (encoder byte) - `(loop - with ,encoder = (make-instance ',encoder-class - :output-function #'(lambda (char) ,output-form)) - for ,byte = ,input-form - while ,byte - do (encoder-write-byte ,encoder ,byte) - finally (encoder-finish-output ,encoder)))) - -(defmacro make-decoder-loop (decoder-class input-form output-form &key parser-errors) - (with-gensyms (decoder) - `(loop - with ,decoder = (make-instance ',decoder-class - :input-function #'(lambda () ,input-form) - :parser-errors ,parser-errors) - for byte = (decoder-read-byte ,decoder) - while byte - do ,output-form))) - -(defun decode-quoted-printable-stream (in out &key parser-errors) - "Read from stream IN a quoted printable text and write to -binary output OUT the decoded stream of bytes." - (make-decoder-loop quoted-printable-decoder - (read-byte in nil) (write-byte byte out) - :parser-errors parser-errors)) - -(defmacro make-stream-to-sequence-decoder (decoder-class input-form &key parser-errors) - "Decode the character stream STREAM and return a sequence of bytes." - (with-gensyms (output-sequence) - `(let ((,output-sequence (make-array 0 - :element-type '(unsigned-byte 8) - :fill-pointer 0 - :adjustable t))) - (make-decoder-loop ,decoder-class ,input-form - (vector-push-extend byte ,output-sequence) - :parser-errors ,parser-errors) - ,output-sequence))) - -(defun decode-quoted-printable-stream-to-sequence (stream &key parser-errors) - "Read from STREAM a quoted printable text and return a vector of -bytes." - (make-stream-to-sequence-decoder quoted-printable-decoder - (read-char stream nil) - :parser-errors parser-errors)) - -(defun decode-quoted-printable-string (string &key (start 0) (end (length string)) parser-errors) - "Decode STRING as quoted printable sequence of characters and -return a decoded sequence of bytes." - (with-input-from-string (in string :start start :end end) - (decode-quoted-printable-stream-to-sequence in :parser-errors parser-errors))) - -(defclass quoted-printable-encoder (line-encoder) - ((line-length :initform *quoted-printable-line-length* - :type (or fixnum null)) - (pending-space :initform nil - :type boolean))) - -(defmethod encoder-write-byte ((encoder quoted-printable-encoder) byte) - (declare (optimize (speed 3) (safety 0) (debug 0)) - (type (unsigned-byte 8) byte)) - (with-slots (output-function column pending-space line-length) encoder - (declare (type function output-function) - (type fixnum column) - (type (or fixnum null) line-length) - (type boolean pending-space)) - (labels ((out (c) - (funcall output-function c) - (values)) - (outs (str) - (declare (type simple-string str)) - (loop - for c across str - do (out c)) - (values)) - (out2hex (x) - (declare (type fixnum x)) - (multiple-value-bind (a b) (truncate x 16) - (out (digit-char a 16)) - (out (digit-char b 16))))) - (cond ((= byte #.(char-code #\newline)) - (when pending-space - (outs "=20") - (setf pending-space nil)) - (out #\newline) - (setf column 0)) - ((= byte #.(char-code #\space)) - (if pending-space - (progn - (out #\space) - (f++ column)) - (setf pending-space t))) - (t - (when pending-space - (out #\space) - (f++ column) - (setf pending-space nil)) - (cond ((or (< byte 32) - (= byte #.(char-code #\=)) - (> byte 126)) - (out #\=) - (out2hex byte) - (f++ column 3)) - (t - (out (code-char byte)) - (f++ column))))) - (when (and line-length - (>= column line-length)) - ;; soft line break - (outs #.(coerce '(#\= #\newline) 'string)) - (setf column 0))))) - -(defmethod encoder-finish-output ((encoder quoted-printable-encoder)) - (declare (optimize (speed 3) (safety 0) (debug 0))) - (with-slots (pending-space output-function) encoder - (declare (type boolean pending-space) - (type function output-function)) - (when pending-space - (flet ((outs (s) - (declare (type simple-string s)) - (loop - for c across s - do (funcall output-function c)))) - (setf pending-space nil) - (outs "=20"))))) - -(defun encode-quoted-printable-stream (in out) - "Read from IN a stream of bytes and write to OUT a stream of -characters quoted printables encoded." - (make-encoder-loop quoted-printable-encoder - (read-byte in nil) - (write-char char out))) - -(defun encode-quoted-printable-sequence-to-stream (sequence stream &key (start 0) (end (length sequence))) - "Encode the sequence of bytes SEQUENCE and write to STREAM a -quoted printable sequence of characters." - (let ((i start)) - (make-encoder-loop quoted-printable-encoder - (when (< i end) - (prog1 (elt sequence i) - (f++ i))) - (write-char char stream)))) - -(defun encode-quoted-printable-sequence (sequence &key (start 0) (end (length sequence))) - "Encode the sequence of bytes SEQUENCE into a quoted printable -string and return it." - (with-output-to-string (out) - (encode-quoted-printable-sequence-to-stream sequence out :start start :end end))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defclass base64-encoder (line-encoder) - ((line-length :initform *base64-line-length*) - (bitstore :initform 0 - :type fixnum) - (bytecount :initform 0 - :type fixnum)) - (:documentation - "Class for Base64 encoder output streams.")) - - -(eval-when (:load-toplevel :compile-toplevel) - (unless (> most-positive-fixnum (expt 2 (* 8 3))))) - -(macrolet ((with-encoder (encoder &body forms) - `(with-slots (bitstore line-length column bytecount output-function) ,encoder - (declare (type fixnum column) - (type fixnum bitstore bytecount) - (type (or fixnum null) line-length) - (type function output-function)) - (labels ((emitr (i b) - (declare (type fixnum i b)) - (unless (zerop i) - (emitr (1- i) (ash b -6))) - (emitc - (char +base64-encode-table+ (logand b #x3F))) - (values)) - (out (c) - (funcall output-function c)) - (eol () - (progn - (out #\return) - (out #\newline))) - (emitc (char) - (out char) - (f++ column) - (when (and line-length - (>= column line-length)) - (setf column 0) - (eol)))) - (declare (inline out eol emitc) - (ignorable (function emitr) (function out) (function eol) (function emitc))) - ,@forms)))) - ;; For this function to work correctly, the FIXNUM must be at least - ;; 24 bits. - (defmethod encoder-write-byte ((encoder base64-encoder) byte) - (declare (optimize (speed 3) (safety 0) (debug 0)) - (type (unsigned-byte 8) byte)) - (with-encoder encoder - (setf bitstore (logior byte (the fixnum (ash bitstore 8)))) - (f++ bytecount) - (when (= 3 bytecount) - (emitr 3 bitstore) - (setf bitstore 0 - bytecount 0))) - (values)) - - (defmethod encoder-finish-output ((encoder base64-encoder)) - (with-encoder encoder - (unless (zerop bytecount) - (multiple-value-bind (saved6 rest) (truncate (* bytecount 8) 6) - (setf bitstore (ash bitstore (- 6 rest))) - (emitr saved6 bitstore) - (dotimes (x (- 3 saved6)) - (emitc #\=)))) - (when (and line-length - (not (zerop column))) - (eol))) - (values))) - -(defun encode-base64-stream (in out) - "Read a byte stream from IN and write to OUT the encoded Base64 -character stream." - (make-encoder-loop base64-encoder (read-byte in nil) - (write-char char out))) - -(defun encode-base64-sequence-to-stream (sequence stream &key (start 0) (end (length sequence))) - "Encode the sequence of bytes SEQUENCE and write to STREAM the -Base64 character sequence." - (let ((i start)) - (make-encoder-loop base64-encoder - (when (< i end) - (prog1 (elt sequence i) - (incf i))) - (write-char char stream)))) - -(defun encode-base64-sequence (sequence &key (start 0) (end (length sequence))) - "Encode the sequence of bytes SEQUENCE into a Base64 string and -return it." - (with-output-to-string (out) - (encode-base64-sequence-to-stream sequence out :start start :end end))) - -(defun decode-base64-stream (in out &key parser-errors) - "Read from IN a stream of characters Base64 encoded and write -to OUT a stream of decoded bytes." - ;; parser-errors are ignored for base64 - (declare (ignore parser-errors)) - (redirect-stream (make-instance 'qbase64:decode-stream - :underlying-stream in) - out)) - -(defun decode-base64-stream-to-sequence (stream &key parser-errors) - "Read Base64 characters from STREAM and return result of decoding them as a -binary sequence." - ;; parser-errors are ignored for base64 - (declare (ignore parser-errors)) - (let* ((buffered-size 4096) - (dstream (make-instance 'qbase64:decode-stream - :underlying-stream stream)) - (output-seq (make-array buffered-size - :element-type '(unsigned-byte 8) - :adjustable t))) - (loop for cap = (array-dimension output-seq 0) - for pos = (read-sequence output-seq dstream :start (or pos 0)) - if (>= pos cap) - do (adjust-array output-seq (+ cap buffered-size)) - else - do (progn - (adjust-array output-seq pos) - (return output-seq))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun dump-stream-binary (in out) - "Write content of IN character stream to OUT binary stream." - (loop - for c = (read-char in nil) - while c - do (write-byte (char-code c) out))) - -(defun decode-string (string encoding &key parser-errors-p) - (gcase (encoding string-equal) - (:quoted-printable - (decode-quoted-printable-string string - :parser-errors parser-errors-p)) - (:base64 - ;; parser-errors-p is unused in base64 - (qbase64:decode-string string)) - (otherwise - (map '(vector (unsigned-byte 8)) #'char-code string)))) - -(defun decode-stream-to-sequence (stream encoding &key parser-errors-p) - (gcase (encoding string-equal) - (:quoted-printable - (decode-quoted-printable-stream-to-sequence stream - :parser-errors parser-errors-p)) - (:base64 - (decode-base64-stream-to-sequence stream - :parser-errors parser-errors-p)) - (otherwise - (loop - with output-sequence = (make-array 0 :fill-pointer 0 - :element-type '(unsigned-byte 8) - :adjustable t) - for c = (read-char stream nil) - while c - do (vector-push-extend (char-code c) output-sequence) - finally (return output-sequence))))) - -(defun encode-stream (in out encoding) - (gcase (encoding string-equal) - (:quoted-printable - (encode-quoted-printable-stream in out)) - (:base64 - (encode-base64-stream in out)) - (otherwise - (loop - for byte = (read-byte in nil) - while byte - do (write-char (code-char byte) out))))) - -(defun encode-sequence-to-stream (sequence out encoding) - (gcase (encoding string-equal) - (:quoted-printable - (encode-quoted-printable-sequence-to-stream sequence out)) - (:base64 - (encode-base64-sequence-to-stream sequence out)) - (otherwise - (loop - for byte across sequence - do (write-char (code-char byte) out))))) - -(defun encode-sequence (sequence encoding) - (gcase (encoding string-equal) - (:quoted-printable - (encode-quoted-printable-sequence sequence)) - (:base64 - (encode-base64-sequence sequence)) - (otherwise - (map 'string #'code-char sequence)))) - -;; This is similar to decode-quoted-printable-string but #\_ is used -;; instead of space -(defun decode-quoted-printable-RFC2047-string (string &key (start 0) (end (length string))) - "Decode a string encoded according to the quoted printable -method of RFC2047 and return a sequence of bytes." - (declare (optimize (speed 3) (debug 0) (safety 0)) - (type simple-string string)) - (loop - with output-sequence = (make-array (length string) - :element-type '(unsigned-byte 8) - :fill-pointer 0) - for i fixnum from start by 1 below end - for c = (char string i) - do (case c - (#\= - (vector-push-extend (or (parse-hex (char string (1+ i)) (char string (+ 2 i))) - ;; the char code was malformed - #.(char-code #\?)) - output-sequence) - (f++ i 2)) - (#\_ (vector-push-extend #.(char-code #\space) output-sequence)) - (otherwise - (vector-push-extend (char-code c) output-sequence))) - finally (return output-sequence))) - -(defun decode-RFC2047-part (encoding string &key (start 0) (end (length string))) - "Decode STRING according to RFC2047 and return a sequence of -bytes." - (gcase (encoding string-equal) - ("Q" (decode-quoted-printable-RFC2047-string string :start start :end end)) - ("B" (qbase64:decode-string (subseq string start end))) - (t string))) - -(defun parse-RFC2047-text (text) - "Parse the string TEXT according to RFC2047 rules and return a list -of pairs and strings. The strings are the bits interposed between the -actually encoded text. The pairs are composed of: a decoded byte -sequence, a charset string indicating the original coding." - (loop - with result = '() - with previous-end = 0 - for start = (search "=?" text :start2 previous-end) - while start - for first-? = (position #\? text :start (+ 2 start)) - while first-? - for second-? = (position #\? text :start (1+ first-?)) - while second-? - for end = (search "?=" text :start2 (1+ second-?)) - while end - do (let ((charset (string-upcase (subseq text (+ 2 start) first-?))) - (encoding (subseq text (1+ first-?) second-?))) - (unless (= previous-end start) - (push (subseq text previous-end start) - result)) - (setf previous-end (+ end 2)) - (push (cons (decode-RFC2047-part encoding text :start (1+ second-?) :end end) - charset) - result)) - finally (unless (= previous-end (length text)) - (push (subseq text previous-end (length text)) - result)) - (return (nreverse result)))) - -(defun decode-RFC2047 (text) - "Decode TEXT into a fully decoded string. Whenever a non ASCII part is - encountered, try to decode it using flexi-streams, otherwise signal an error." - (flet ((decode-part (part) - (etypecase part - (cons (flexi-streams:octets-to-string - (car part) - :external-format (flexi-streams:make-external-format - ;; TODO(sterni): sanitize charset before interning - (intern (string-upcase (cdr part)) 'keyword)))) - (string part)))) - (apply #'concatenate - (cons 'string - (mapcar #'decode-part (mime:parse-RFC2047-text text)))))) diff --git a/third_party/lisp/mime4cl/ex-sclf.lisp b/third_party/lisp/mime4cl/ex-sclf.lisp deleted file mode 100644 index e6246c149..000000000 --- a/third_party/lisp/mime4cl/ex-sclf.lisp +++ /dev/null @@ -1,312 +0,0 @@ -;;; ex-sclf.lisp --- subset of sclf used by mime4cl - -;;; Copyright (C) 2005-2010 by Walter C. Pelissero -;;; Copyright (C) 2022-2023 The TVL Authors - -;;; Author: sternenseemann -;;; Project: mime4cl -;;; -;;; mime4cl uses sclf for miscellaneous utility functions. sclf's portability -;;; is quite limited. Since mime4cl is the only thing in TVL's depot depending -;;; on sclf, it made more sense to strip down sclf to the extent mime4cl needed -;;; in order to lessen the burden of porting it to other CL implementations -;;; later. -;;; -;;; Eventually it probably makes sense to drop the utilities we don't like and -;;; merge the ones we do like into depot's own utility package, klatre. - -#+cmu (ext:file-comment "$Module: ex-sclf.lisp $") - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(defpackage :mime4cl-ex-sclf - (:use :common-lisp) - - (:export - #:aif - #:awhen - #:aand - #:it - - #:gcase - - #:with-gensyms - - #:split-at - #:split-string-at-char - #:+whitespace+ - #:whitespace-p - #:string-concat - #:s+ - #:string-starts-with - #:string-trim-whitespace - #:string-left-trim-whitespace - #:string-right-trim-whitespace - - #:queue - #:make-queue - #:queue-append - #:queue-pop - #:queue-empty-p - - #:save-file-excursion - #:read-file - - #:promise - #:make-promise - #:lazy - #:force - #:forced-p - #:deflazy - - #:f++ - - #:week-day->string - #:month->string)) - -(in-package :mime4cl-ex-sclf) - -;; MACRO UTILS - -(defmacro with-gensyms ((&rest symbols) &body body) - "Gensym all SYMBOLS and make them available in BODY. -See also LET-GENSYMS." - `(let ,(mapcar #'(lambda (s) - (list s '(gensym))) symbols) - ,@body)) - -;; CONTROL FLOW - -(defmacro aif (test then &optional else) - `(let ((it ,test)) - (if it - ,then - ,else))) - -(defmacro awhen (test &body then) - `(let ((it ,test)) - (when it - ,@then))) - -(defmacro aand (&rest args) - (cond ((null args) t) - ((null (cdr args)) (car args)) - (t `(aif ,(car args) (aand ,@(cdr args)))))) - -(defmacro gcase ((value &optional (test 'equalp)) &rest cases) - "Generic CASE macro. Match VALUE to CASES as if by the normal CASE -but use TEST as the comparison function, which defaults to EQUALP." - (with-gensyms (val) - `(let ((,val ,value)) - ,(cons 'cond - (mapcar #'(lambda (case-desc) - (destructuring-bind (vals &rest forms) case-desc - `(,(cond ((consp vals) - (cons 'or (mapcar #'(lambda (v) - (list test val v)) - vals))) - ((or (eq vals 'otherwise) - (eq vals t)) - t) - (t (list test val vals))) - ,@forms))) - cases))))) - -;; SEQUENCES - -(defun position-any (bag sequence &rest position-args) - "Find any element of bag in sequence and return its position. -Accept any argument accepted by the POSITION function." - (apply #'position-if #'(lambda (element) - (find element bag)) sequence position-args)) - -(defun split-at (bag sequence &key (start 0) key) - "Split SEQUENCE at occurence of any element from BAG. -Contiguous occurences of elements from BAG are considered atomic; -so no empty sequence is returned." - (let ((len (length sequence))) - (labels ((split-from (start) - (unless (>= start len) - (let ((sep (position-any bag sequence :start start :key key))) - (cond ((not sep) - (list (subseq sequence start))) - ((> sep start) - (cons (subseq sequence start sep) - (split-from (1+ sep)))) - (t - (split-from (1+ start)))))))) - (split-from start)))) - -;; STRINGS - -(defvar +whitespace+ '(#\return #\newline #\tab #\space #\page)) - -(defun whitespace-p (char) - (member char +whitespace+)) - -(defun string-trim-whitespace (string) - (string-trim +whitespace+ string)) - -(defun string-right-trim-whitespace (string) - (string-right-trim +whitespace+ string)) - -(defun string-left-trim-whitespace (string) - (string-left-trim +whitespace+ string)) - -(defun split-string-at-char (string separator &key escape skip-empty) - "Split STRING at SEPARATORs and return a list of the substrings. If -SKIP-EMPTY is true then filter out the empty substrings. If ESCAPE is -not nil then split at SEPARATOR only if it's not preceded by ESCAPE." - (declare (type string string) (type character separator)) - (labels ((next-separator (beg) - (let ((pos (position separator string :start beg))) - (if (and escape - pos - (plusp pos) - (char= escape (char string (1- pos)))) - (next-separator (1+ pos)) - pos))) - (parse (beg) - (cond ((< beg (length string)) - (let* ((end (next-separator beg)) - (substring (subseq string beg end))) - (cond ((and skip-empty (string= "" substring)) - (parse (1+ end))) - ((not end) - (list substring)) - (t - (cons substring (parse (1+ end))))))) - (skip-empty - '()) - (t - (list ""))))) - (parse 0))) - -(defun s+ (&rest strings) - "Return a string which is made of the concatenation of STRINGS." - (apply #'concatenate 'string strings)) - -(defun string-concat (list &optional (separator "")) - "Concatenate the strings in LIST interposing SEPARATOR (default -nothing) between them." - (reduce #'(lambda (&rest args) - (if args - (s+ (car args) separator (cadr args)) - "")) - list)) - -(defun string-starts-with (prefix string &optional (compare #'string=)) - (let ((prefix-length (length prefix))) - (and (>= (length string) prefix-length) - (funcall compare prefix string :end2 prefix-length)))) - -;; QUEUE - -(defstruct queue - first - last) - -(defgeneric queue-append (queue objects)) -(defgeneric queue-pop (queue)) -(defgeneric queue-empty-p (queue)) - -(defmethod queue-append ((queue queue) (objects list)) - (cond ((null (queue-first queue)) - (setf (queue-first queue) objects - (queue-last queue) (last objects))) - (t - (setf (cdr (queue-last queue)) objects - (queue-last queue) (last objects)))) - queue) - -(defmethod queue-append ((queue queue) object) - (queue-append queue (list object))) - -(defmethod queue-pop ((queue queue)) - (prog1 (car (queue-first queue)) - (setf (queue-first queue) (cdr (queue-first queue))))) - -(defmethod queue-empty-p ((queue queue)) - (null (queue-first queue))) - -;; STREAMS - -(defmacro save-file-excursion ((stream &optional position) &body forms) - "Execute FORMS returning, on exit, STREAM to the position it was -before FORMS. Optionally POSITION can be set to the starting offset." - (unless position - (setf position (gensym))) - `(let ((,position (file-position ,stream))) - (unwind-protect (progn ,@forms) - (file-position ,stream ,position)))) - -(defun read-file (pathname &key (element-type 'character) (if-does-not-exist :error) default) - "Read the whole content of file and return it as a sequence which -can be a string, a vector of bytes, or whatever you specify as -ELEMENT-TYPE." - (with-open-file (in pathname - :element-type element-type - :if-does-not-exist (unless (eq :value if-does-not-exist) - :error)) - (if in - (let ((seq (make-array (file-length in) :element-type element-type))) - (read-sequence seq in) - seq) - default))) - -;; LAZY - -(defstruct promise - procedure - value) - -(defmacro lazy (form) - `(make-promise :procedure #'(lambda () ,form))) - -(defun forced-p (promise) - (null (promise-procedure promise))) - -(defun force (promise) - (if (forced-p promise) - (promise-value promise) - (prog1 (setf (promise-value promise) - (funcall (promise-procedure promise))) - (setf (promise-procedure promise) nil)))) - -(defmacro deflazy (name value &optional documentation) - `(defparameter ,name (lazy ,value) - ,@(when documentation - (list documentation)))) - -;; FIXNUMS - -(defmacro f++ (x &optional (delta 1)) - "Same as INCF but hopefully optimised for fixnums." - `(setf ,x (+ (the fixnum ,x) (the fixnum ,delta)))) - -;; TIME - -(defun week-day->string (day &optional sunday-first) - "Return the weekday string corresponding to DAY number." - (elt (if sunday-first - #("Sunday" "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday") - #("Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday")) - day)) - -(defvar +month-names+ #("January" "February" "March" "April" "May" "June" "July" - "August" "September" "October" "November" "December")) - -(defun month->string (month) - "Return the month string corresponding to MONTH number." - (elt +month-names+ (1- month))) diff --git a/third_party/lisp/mime4cl/mime.lisp b/third_party/lisp/mime4cl/mime.lisp deleted file mode 100644 index da13a1126..000000000 --- a/third_party/lisp/mime4cl/mime.lisp +++ /dev/null @@ -1,1035 +0,0 @@ -;;; mime4cl.lisp --- MIME primitives for Common Lisp - -;;; Copyright (C) 2005-2008, 2010 by Walter C. Pelissero -;;; Copyright (C) 2021-2023 by the TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :mime4cl) - -(defclass mime-part () - ((subtype - :type (or string null) - :initarg :subtype - :accessor mime-subtype - ;; some mime types don't require a subtype - :initform nil) - (type-parameters - :type list - :initarg :type-parameters - :initform '() - :accessor mime-type-parameters) - (version - :type (or string null) - :initarg :mime-version - :initform "1.0" - :accessor mime-version) - (id - :initform nil - :initarg :id - :reader mime-id) - (description - :initform nil - :initarg :description - :accessor mime-description) - (encoding - :initform :7bit - :initarg :encoding - :reader mime-encoding - :documentation - "It's supposed to be either: - :7BIT, :8BIT, :BINARY, :QUOTED-PRINTABLE, :BASE64, a - X-token or an ietf-token (whatever that means).") - (disposition - :type (or string null) - :initarg :disposition - :initform nil - :accessor mime-disposition) - (disposition-parameters - :type list - :initarg :disposition-parameters - :initform '() - :accessor mime-disposition-parameters)) - (:documentation - "Abstract base class for all types of MIME parts.")) - -(defparameter +redundant-headers+ '(:mime-version - :content-type - :content-id - :content-description - :content-disposition - :content-transfer-encoding) - "Headers that don't need to be preserved in the HEADERS slot of MIME-MESSAGE -because they are stored in dedicated slots in MIME-PART.") - -(defclass mime-bodily-part (mime-part) - ((body - :initarg :body - :accessor mime-body)) - (:documentation - "Abstract base class for MIME parts with a body.")) - -(defclass mime-unknown-part (mime-bodily-part) - ((type - :initarg :type - :reader mime-type - :documentation - "The original type string from the MIME header.")) - (:documentation - "MIME part unknown to this library. Accepted but not handled.")) - -(defclass mime-text (mime-bodily-part) ()) - -;; This turns out to be handy when making methods specialised -;; non-textual attachments. -(defclass mime-binary (mime-bodily-part) ()) - -(defclass mime-image (mime-binary) ()) - -(defclass mime-audio (mime-binary) ()) - -(defclass mime-video (mime-binary) ()) - -(defclass mime-application (mime-binary) ()) - -(defclass mime-multipart (mime-part) - ((parts :initarg :parts - :accessor mime-parts))) - -(defclass mime-message (mime-part) - ((headers :initarg :headers - :initform '() - :type list - :accessor mime-message-headers) - (real-message :initarg :body - :accessor mime-body))) - -(defun mime-part-p (object) - (typep object 'mime-part)) - -(defmethod initialize-instance ((part mime-multipart) &key &allow-other-keys) - (call-next-method) - ;; The initialization argument of the PARTS slot of a mime-multipart - ;; is expected to be a list of mime-parts. Thus, we implicitly - ;; create the mime parts using the arguments found in this list. - (with-slots (parts) part - (when (slot-boundp part 'parts) - (setf parts - (mapcar #'(lambda (subpart) - (if (mime-part-p subpart) - subpart - (apply #'make-instance subpart))) - parts))))) - -(defmethod initialize-instance ((part mime-message) &key &allow-other-keys) - (call-next-method) - ;; Allow a list of mime parts to be specified as body of a - ;; mime-message. In that case we implicitly create a mime-multipart - ;; and assign to the body slot. - (with-slots (real-message headers) part - (when (and (slot-boundp part 'real-message) - (consp real-message)) - (setf real-message - (make-instance 'mime-multipart :parts real-message))) - ;; Remove headers that are parsed and stored in MIME-PART (i.e. - ;; REAL-MESSAGE). This prevents redundant storage and rendering of these - ;; headers as well as MIME= depending on the specific rendering of these - ;; headers which may diverge between mime4cl and other software. We do this - ;; here since construction of REAL-MESSAGE may access the HEADERS slot. - (setf headers - (delete-if (lambda (h) - (member (car h) +redundant-headers+ :test #'string-equal)) - headers)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun alist= (alist1 alist2 &key (test #'eql)) - (null - (set-difference alist1 alist2 - :test #'(lambda (x y) - (and (funcall test (car x) (car y)) - (funcall test (cdr x) (cdr y))))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric mime= (mime1 mime2) - (:documentation - "Return true if MIME1 and MIME2 have equivalent structure and identical bodies (as for EQ).")) - -(defmethod mime= ((part1 mime-part) (part2 mime-part)) - (macrolet ((null-or (compare x y) - `(or (and (not ,x) - (not ,y)) - (and ,x ,y - (,compare ,x ,y)))) - (cmp-slot (compare reader) - `(null-or ,compare (,reader part1) (,reader part2)))) - (and (eq (class-of part1) (class-of part2)) - (cmp-slot string-equal mime-subtype) - (alist= (mime-type-parameters part1) - (mime-type-parameters part2) - :test #'string-equal) - (cmp-slot string= mime-id) - (cmp-slot string= mime-description) - (cmp-slot eq mime-encoding) - (cmp-slot equal mime-disposition) - (alist= (mime-disposition-parameters part1) - (mime-disposition-parameters part2) - :test #'string-equal)))) - -(defmethod mime= ((part1 mime-multipart) (part2 mime-multipart)) - (and (call-next-method) - (every #'mime= (mime-parts part1) (mime-parts part2)))) - -(defmethod mime= ((part1 mime-message) (part2 mime-message)) - (and (call-next-method) - (alist= (mime-message-headers part1) (mime-message-headers part2) - :test #'string=) - (mime= (mime-body part1) (mime-body part2)))) - -(defgeneric mime-body-stream (mime-part) - (:documentation - "Returns stream that allows reading the decoded body of the given part. -STREAM-ELEMENT-TYPE depends on part type.")) - -;; TODO(sterni): Allow accessing underlying binary stream? -;; Would need matching behavior with :7bit -(defmethod mime-body-stream ((part mime-text)) - (let ((underlying-stream (call-next-method))) - (if (eq (stream-element-type underlying-stream) 'character) - underlying-stream - (make-flexi-stream underlying-stream - :external-format - ;; TODO(sterni): sanitize charset before interning - (intern (string-upcase (mime-text-charset part)) - 'keyword))))) - -(defmethod mime-body-stream ((part mime-part)) - (make-input-adapter (mime-body part))) - -(defmacro with-input-from-mime-body-stream ((stream part) &body forms) - `(with-open-stream (,stream (mime-body-stream ,part)) - ,@forms)) - -(defmethod mime= ((part1 mime-bodily-part) (part2 mime-bodily-part)) - (and (call-next-method) - (with-input-from-mime-body-stream (in1 part1) - (with-input-from-mime-body-stream (in2 part2) - (loop - for b1 = (read-byte in1 nil) - for b2 = (read-byte in2 nil) - always (eq b1 b2) - while (and b1 b2)))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric get-mime-type-parameter (part name) - (:documentation - "Return the MIME type parameter associated to NAME of PART.")) - -(defgeneric (setf get-mime-type-parameter) (value part name) - (:documentation - "Set the MIME type parameter associated to NAME of PART.")) - -(defmethod get-mime-type-parameter ((part mime-part) name) - (cdr (assoc name (mime-type-parameters part) :test #'string-equal))) - -(defmethod (setf get-mime-type-parameter) (value part name) - (aif (assoc name (mime-type-parameters part) :test #'string-equal) - (setf (cdr it) value) - (push (cons name value) - (mime-type-parameters part))) - value) - -(defgeneric get-mime-disposition-parameter (part name) - (:documentation - "Return the MIME disposition parameter associated to NAME of PART.")) - -(defmethod get-mime-disposition-parameter ((part mime-part) name) - (cdr (assoc name (mime-disposition-parameters part) :test #'string-equal))) - -(defmethod (setf get-mime-disposition-parameter) (value part name) - (aif (assoc name (mime-disposition-parameters part) :test #'string-equal) - (setf (cdr it) value) - (push (cons name value) - (mime-disposition-parameters part)))) - -(defmethod mime-part-file-name ((part mime-part)) - "Return the filename associated to mime PART or NIL if the mime -part doesn't have a file name." - (or (get-mime-disposition-parameter part :filename) - (get-mime-type-parameter part :name))) - -(defmethod (setf mime-part-file-name) (value (part mime-part)) - "Set the filename associated to mime PART." - (setf (get-mime-disposition-parameter part :filename) value - (get-mime-type-parameter part :name) value)) - -(defun mime-text-charset (part) - (get-mime-type-parameter part :charset)) - -(defun split-header-parts (string) - "Split parts of a MIME headers. These are divided by -semi-colons not within strings or comments." - (labels ((skip-comment (pos) - (loop - while (< pos (length string)) - do (case (elt string pos) - (#\( (setf pos (skip-comment (1+ pos)))) - (#\\ (incf pos 2)) - (#\) (return (1+ pos))) - (otherwise (incf pos))) - finally (return pos))) - (skip-string (pos) - (loop - while (< pos (length string)) - do (case (elt string pos) - (#\\ (incf pos 2)) - (#\" (return (1+ pos))) - (otherwise (incf pos))) - finally (return pos)))) - (loop - with start = 0 and i = 0 and parts = '() - while (< i (length string)) - do (case (elt string i) - (#\; (push (subseq string start i) parts) - (setf start (incf i))) - (#\" (setf i (skip-string i))) - (#\( (setf i (skip-comment (1+ i)))) - (otherwise (incf i))) - finally (return (mapcar #'string-trim-whitespace (nreverse (cons (subseq string start) parts))))))) - -(defun parse-parameter (string) - "Given a string like \"foo=bar\" return a pair (\"foo\" . -\"bar\"). Return NIL if string is not parsable." - ;; TODO(sterni): when-let - (let ((equal-position (position #\= string))) - (when equal-position - (let ((key (subseq string 0 equal-position))) - (if (= equal-position (1- (length string))) - (cons key "") - (let ((value (string-trim-whitespace (subseq string (1+ equal-position))))) - (cons key - (if (and (> (length value) 1) - (char= #\" (elt value 0))) - ;; the syntax of a RFC822 string is more or - ;; less the same as the Lisp one: use the Lisp - ;; reader - (or (ignore-errors (read-from-string value)) - (subseq value 1)) - (let ((end (or (position-if #'whitespace-p value) - (length value)))) - (subseq value 0 end)))))))))) - -(defun parse-content-type (string) - "Parse string as a Content-Type MIME header and return a list -of three elements. The first is the type, the second is the -subtype and the third is an alist of parameters and their values. -Example: (\"text\" \"plain\" ((\"charset\" . \"us-ascii\")...))." - (let* ((parts (split-header-parts string)) - (content-type-string (car parts)) - (slash (position #\/ content-type-string))) - ;; You'd be amazed to know how many MUA can't produce an RFC - ;; compliant message. - (when slash - (let ((type (subseq content-type-string 0 slash)) - (subtype (subseq content-type-string (1+ slash)))) - (list type subtype (remove nil (mapcar #'parse-parameter (cdr parts)))))))) - -(defun parse-content-disposition (string) - "Parse string as a Content-Disposition MIME header and return a -list. The first element is the layout, the other elements are -the optional parameters alist. -Example: (\"inline\" (\"filename\" . \"doggy.jpg\"))." - (let ((parts (split-header-parts string))) - (cons (car parts) (mapcan #'(lambda (parameter-string) - (awhen (parse-parameter parameter-string) - (list it))) - (cdr parts))))) - -(defun parse-RFC822-header (string) - "Parse STRING which should be a valid RFC822 message header and -return two values: a string of the header name and a string of -the header value." - (let ((colon (position #\: string))) - (when colon - (values (string-trim-whitespace (subseq string 0 colon)) - (string-trim-whitespace (subseq string (1+ colon))))))) - - -(defvar *default-type* '("text" "plain" (("charset" . "us-ascii"))) - "Internal special variable that contains the default MIME type at -any given time of the parsing phase. There are MIME container parts -that may change this.") - -(defvar *mime-types* - '((:text mime-text) - (:image mime-image) - (:audio mime-audio) - (:video mime-video) - (:application mime-application) - (:multipart mime-multipart) - (:message mime-message))) - -(defgeneric print-mime-part (part stream) - (:documentation - "Output to STREAM one of the possible human-readable representation -of mime PART. Binary parts are omitted. This function can be used to -quote messages, for instance.")) - -(defun do-multipart-parts (body-stream part-boundary contents-function end-part-function) - "Read through BODY-STREAM. Call CONTENTS-FUNCTION at -each (non-boundary) line or END-PART-FUNCTION at each PART-BOUNDARY." - (let* ((boundary (s+ "--" part-boundary)) - (boundary-length (length boundary))) - (labels ((output-line (line) - (funcall contents-function line)) - (end-part () - (funcall end-part-function)) - (last-part () - (end-part) - (return-from do-multipart-parts)) - (process-line (line) - (cond ((not (string-starts-with boundary line)) - ;; normal line - (output-line line)) - ((and (= (length (string-trim-whitespace line)) - (+ 2 boundary-length)) - (string= "--" line :start2 boundary-length)) - ;; end of the last part - (last-part)) - ;; according to RFC2046 "the boundary may be followed - ;; by zero or more characters of linear whitespace" - ((= (length (string-trim-whitespace line)) boundary-length) - ;; beginning of the next part - (end-part)) - (t - ;; the line boundary is followed by some - ;; garbage; we treat it as a normal line - (output-line line))))) - (loop - for line = (read-line body-stream nil) - ;; we should never reach the end of a proper multipart MIME - ;; stream, but we don't want to be fooled by corrupted ones, - ;; so we check for EOF - unless line - do (last-part) - do (process-line line))))) - -(defun index-multipart-parts (body-stream part-boundary) - "Read from BODY-STREAM and return the file offset of the MIME parts -separated by PART-BOUNDARY." - (let ((parts '()) - (start 0) - (len 0) - (beginning-of-part-p t)) - (flet ((sum-chars (line) - (incf len (length line)) - ;; account for the #\newline - (if beginning-of-part-p - (setf beginning-of-part-p nil) - (incf len))) - (end-part () - (setf beginning-of-part-p t) - (push (cons start (+ start len)) parts) - (setf start (file-position body-stream) - len 0))) - (do-multipart-parts body-stream part-boundary #'sum-chars #'end-part) - ;; the first part is all the stuff up to the first boundary; - ;; just junk - (cdr (nreverse parts))))) - -(defgeneric encode-mime-part (part stream)) -(defgeneric encode-mime-body (part stream)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun write-mime-header (part stream) - (when (mime-version part) - (format stream "~&MIME-Version: ~A~%" (mime-version part))) - (format stream "~&Content-Type: ~A~:{; ~A=~S~}~%" (mime-type-string part) - (mapcar #'(lambda (pair) - (list (car pair) (cdr pair))) - (mime-type-parameters part))) - (awhen (mime-encoding part) - (format stream "Content-Transfer-Encoding: ~A~%" it)) - (awhen (mime-description part) - (format stream "Content-Description: ~A~%" it)) - (when (mime-disposition part) - (format stream "Content-Disposition: ~A~:{; ~A=~S~}~%" - (mime-disposition part) - (mapcar #'(lambda (pair) - (list (car pair) (cdr pair))) - (mime-disposition-parameters part)))) - (awhen (mime-id part) - (format stream "Content-ID: ~A~%" it)) - (terpri stream)) - -(defmethod encode-mime-part ((part mime-part) stream) - (write-mime-header part stream) - (encode-mime-body part stream)) - -(defmethod encode-mime-part ((part mime-message) stream) - ;; tricky: we have to mix the MIME headers with the message headers, i.e. - ;; ENCODE-MIME-PART will output additional headers - (dolist (h (mime-message-headers part)) - (unless (stringp (car h)) - (setf (car h) - (string-capitalize (car h)))) - (format stream "~A: ~A~%" - (car h) (cdr h))) - (encode-mime-part (mime-body part) stream)) - -(defmethod encode-mime-part ((part mime-multipart) stream) - (declare (ignore stream)) ; call-next-method - ;; choose a boundary if not already set - (let* ((original-boundary (get-mime-type-parameter part :boundary)) - (boundary (choose-boundary (mime-parts part) original-boundary))) - (unless (and original-boundary - (string= boundary original-boundary)) - (setf (get-mime-type-parameter part :boundary) boundary)) - (call-next-method))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defmethod encode-mime-body ((part mime-part) stream) - (with-input-from-mime-body-stream (in part) - (encode-stream in stream (mime-encoding part)))) - -(defmethod encode-mime-body ((part mime-message) stream) - (encode-mime-body (mime-body part) stream)) - -(defmethod encode-mime-body ((part mime-multipart) stream) - (let ((boundary (or (get-mime-type-parameter part :boundary) - (setf (get-mime-type-parameter part :boundary) - (choose-boundary (mime-parts part)))))) - (dolist (p (mime-parts part)) - (format stream "~%--~A~%" boundary) - (encode-mime-part p stream)) - (format stream "~%--~A--~%" boundary))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun time-RFC822-string (&optional (epoch (get-universal-time))) - "Return a string describing the current time according to -the RFC822." - (multiple-value-bind (ss mm hh day month year week-day dst tz) (decode-universal-time epoch) - (declare (ignore dst)) - (format nil "~A, ~A ~A ~2,'0D ~2,'0D:~2,'0D:~2,'0D ~:[-~;+~]~2,'0D~2,'0D" - (subseq (week-day->string week-day) 0 3) - day (subseq (month->string month) 0 3) (mod year 100) hh mm ss - (plusp tz) (abs (truncate tz)) (mod (* 60 tz) 60)))) - -(defun parse-RFC822-date (date-string) - "Parse a RFC822 compliant date string and return an universal -time." - ;; if we can't parse it, just return NIL - (ignore-errors - ;; skip the optional DoW - (awhen (position #\, date-string) - (setf date-string (subseq date-string (1+ it)))) - (destructuring-bind (day month year time &optional tz &rest rubbish) - (split-at '(#\space #\tab) date-string) - (declare (ignore rubbish)) - (destructuring-bind (hh mm &optional ss) (split-string-at-char time #\:) - (encode-universal-time - (if ss - (read-from-string ss) - 0) - (read-from-string mm) - (read-from-string hh) - (read-from-string day) - (1+ (position month - '("Jan" "Feb" "Mar" "Apr" "May" "Jun" - "Jul" "Aug" "Sep" "Oct" "Nov" "Dec") - :test #'string-equal)) - (read-from-string year) - (when (and tz (or (char= #\+ (elt tz 0)) - (char= #\- (elt tz 0)))) - (/ (read-from-string tz) 100))))))) - -(defun read-RFC822-headers (stream &optional required-headers) - "Read RFC822 compliant headers from STREAM and return them in a -alist of keyword and string pairs. REQUIRED-HEADERS is a list of -header names we are interested in; if NIL return all headers -found in STREAM." - ;; the skip-header variable is to avoid the mistake of appending a - ;; continuation line of a header we don't want to a header we want - (loop - with headers = '() and skip-header = nil - for line = (let ((line (read-line stream nil))) - ;; skip the Unix "From " header if present - (if (string-starts-with "From " line) - (read-line stream nil) - line)) - then (read-line stream nil) - while (and line - (not (zerop (length line)))) - do (if (whitespace-p (elt line 0)) - (unless (or skip-header - (null headers)) - (setf (cdar headers) (s+ (cdar headers) '(#\newline) line))) - (multiple-value-bind (name value) (parse-RFC822-header line) - ;; the line contained rubbish instead of an header: we - ;; play nice and return as we were at the end of the - ;; headers - (unless name - (return (nreverse headers))) - (if (or (null required-headers) - (member name required-headers :test #'string-equal)) - (progn - (push (cons name value) headers) - (setf skip-header nil)) - (setf skip-header t)))) - finally (return (nreverse headers)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric mime-message (thing) - (:documentation - "Convert THING to a MIME-MESSAGE object.")) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun mime-message-header-values (name message &key decode) - "Return all values of the header with NAME in MESSAGE, optionally decoding - it according to RFC2047 if :DECODE is T." - (loop ;; A header may occur multiple times - for header in (mime-message-headers message) - ;; MIME Headers should be case insensitive - ;; https://stackoverflow.com/a/6143644 - when (string-equal (car header) name) - collect (if decode - (decode-RFC2047 (cdr header)) - (cdr header)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defvar *lazy-mime-decode* t - "If true don't decode mime bodies in memory.") - -(defgeneric decode-mime-body (part input-stream)) - -(defmethod decode-mime-body ((part mime-part) (stream flexi-stream)) - (let ((base (flexi-stream-root-stream stream))) - (if *lazy-mime-decode* - (setf (mime-body part) - (make-file-portion :data (etypecase base - (vector-stream - (flexi-streams::vector-stream-vector base)) - (file-stream - (pathname base))) - :encoding (mime-encoding part) - :start (flexi-stream-position stream) - :end (flexi-stream-bound stream))) - (call-next-method)))) - -(defmethod decode-mime-body ((part mime-part) (stream file-stream)) - (if *lazy-mime-decode* - (setf (mime-body part) - (make-file-portion :data (pathname stream) - :encoding (mime-encoding part) - :start (file-position stream))) - (call-next-method))) - -(defmethod decode-mime-body ((part mime-part) (stream vector-stream)) - (if *lazy-mime-decode* - (setf (mime-body part) - (make-file-portion :data (flexi-streams::vector-stream-vector stream) - :encoding (mime-encoding part) - :start (flexi-streams::vector-stream-index stream))) - (call-next-method))) - -(defmethod decode-mime-body ((part mime-part) stream) - (setf (mime-body part) - (decode-stream-to-sequence stream (mime-encoding part)))) - -(defmethod decode-mime-body ((part mime-multipart) stream) - "Decode STREAM according to PART characteristics and return a -list of MIME parts." - (save-file-excursion (stream) - (let ((offsets (index-multipart-parts stream (get-mime-type-parameter part :boundary)))) - (setf (mime-parts part) - (mapcar #'(lambda (p) - (destructuring-bind (start . end) p - (let ((*default-type* (if (eq :digest (mime-subtype part)) - '("message" "rfc822" ()) - '("text" "plain" (("charset" . "us-ascii"))))) - (in (make-positioned-flexi-input-stream stream - :position start - :bound end - :ignore-close t))) - (read-mime-part in)))) - offsets))))) - -(defmethod decode-mime-body ((part mime-message) stream) - "Read from STREAM the body of PART. Return the decoded MIME -body." - (setf (mime-body part) - (read-mime-message stream))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defvar +known-encodings+ '(:7BIT :8BIT :BINARY :QUOTED-PRINTABLE :BASE64) - "List of known content encodings.") - -(defun keywordify-encoding (string) - "Return a keyword for a content transfer encoding string. -Return STRING itself if STRING is an unkown encoding." - (when string - (aif (member string +known-encodings+ :test #'string-equal) - (car it) - string))) - -(defun header (name headers) - (let ((elt (assoc name headers :test #'string-equal))) - (values (cdr elt) (car elt)))) - -(defun (setf header) (value name headers) - (let ((entry (assoc name headers :test #'string-equal))) - (unless entry - (error "missing header ~A can't be set" name)) - (setf (cdr entry) value))) - -(defun make-mime-part (headers stream) - "Create a MIME-PART object based on HEADERS and a body which -has to be read from STREAM. If the mime part type can't be -guessed from the headers, use the *DEFAULT-TYPE*." - (flet ((hdr (what) - (header what headers))) - (destructuring-bind (type subtype parms) - (or - (aand (hdr :content-type) - (parse-content-type it)) - *default-type*) - (let* ((class (or (cadr (assoc type *mime-types* :test #'string-equal)) - 'mime-unknown-part)) - (disp (aif (hdr :content-disposition) - (parse-content-disposition it) - (values nil nil))) - (part (make-instance class - :type (hdr :content-type) - :subtype subtype - :type-parameters parms - :disposition (car disp) - :disposition-parameters (cdr disp) - :mime-version (hdr :mime-version) - :encoding (or (keywordify-encoding - (hdr :content-transfer-encoding)) - :7bit) ; default per RFC2045 - :description (hdr :content-description) - :id (hdr :content-id) - :allow-other-keys t))) - (decode-mime-body part stream) - part)))) - -(defun read-mime-part (stream) - "Read mime part from STREAM. Return a MIME-PART object." - (let ((headers (read-rfc822-headers stream - '(:mime-version :content-transfer-encoding :content-type - :content-disposition :content-description :content-id)))) - (make-mime-part headers stream))) - -(defun read-mime-message (stream) - "Main function to read a MIME message from a stream. It -returns a MIME-MESSAGE object." - (let ((headers (read-rfc822-headers stream)) - (*default-type* '("text" "plain" (("charset" . "us-ascii"))))) - (flet ((hdr (what) - (header what headers))) - (destructuring-bind (type subtype parms) - (or (aand (hdr :content-type) - (parse-content-type it)) - *default-type*) - (declare (ignore type subtype)) - (make-instance 'mime-message - :headers headers - ;; this is just for easy access - :type-parameters parms - :body (make-mime-part headers stream)))))) - -(defmethod mime-message ((msg mime-message)) - msg) - -(defmethod mime-message ((msg string)) - (mime-message (flexi-streams:string-to-octets msg))) - -(defmethod mime-message ((msg vector)) - (with-input-from-sequence (in msg) - (mime-message in))) - -(defmethod mime-message ((msg pathname)) - (with-open-file (in msg :element-type '(unsigned-byte 8)) - (mime-message in))) - -(defmethod mime-message ((msg stream)) - (mime-message (make-flexi-stream msg))) - -(defmethod mime-message ((msg flexi-stream)) - (read-mime-message msg)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric mime-part (object) - (:documentation - "Promote object, if necessary, to MIME-PART.")) - -(defmethod mime-part ((object string)) - (make-instance 'mime-text :subtype "plain" :body object)) - -(defmethod mime-part ((object pathname)) - (make-instance 'mime-application - :subtype "octect-stream" - :content-transfer-encoding :base64 - :body (read-file object :element-type '(unsigned-byte 8)))) - -(defmethod mime-part ((object mime-part)) - object) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defmethod make-encoded-body-stream ((part mime-bodily-part)) - (let ((body (mime-body part))) - (make-instance (case (mime-encoding part) - (:base64 - 'base64-encoder-input-stream) - (:quoted-printable - 'quoted-printable-encoder-input-stream) - (otherwise - '8bit-encoder-input-stream)) - :underlying-stream - (make-input-adapter body)))) - -(defun choose-boundary (parts &optional default) - (labels ((match-in-parts (boundary parts) - (loop - for p in parts - thereis (typecase p - (mime-multipart - (match-in-parts boundary (mime-parts p))) - (mime-bodily-part - (match-in-body p boundary))))) - (match-in-body (part boundary) - (with-open-stream (in (make-encoded-body-stream part)) - (loop - for line = (read-line in nil) - while line - when (string= line boundary) - return t - finally (return nil))))) - (do ((boundary (if default - (format nil "--~A" default) - #1=(format nil "--~{~36R~}" - (loop - for i from 0 below 20 - collect (random 36)))) - #1#)) - ((not (match-in-parts boundary parts)) (subseq boundary 2))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defmethod print-mime-part ((part mime-multipart) (out stream)) - (case (mime-subtype part) - (:alternative - ;; try to choose something simple to print or the first thing - (let ((parts (mime-parts part))) - (print-mime-part (or (find-if #'(lambda (part) - (and (eq (class-of part) (find-class 'mime-text)) - (eq (mime-subtype part) :plain))) - parts) - (car parts)) out))) - (otherwise - (dolist (subpart (mime-parts part)) - (print-mime-part subpart out))))) - -;; This is WRONG. Here we don't use any special character encoding -;; because we don't know which one we should use. Messages written in -;; anything but ASCII will likely be unreadable -wcp11/10/07. -(defmethod print-mime-part ((part mime-text) (out stream)) - (let ((body (mime-body part))) - (etypecase body - (string - (write-string body out)) - (vector - (loop - for byte across body - do (write-char (code-char byte) out))) - (file-portion - (redirect-stream (open-decoded-file-portion body) out)) - (pathname - (with-open-file (in body) - (redirect-stream in out)))))) - -(defmethod print-mime-part ((part mime-message) (out stream)) - (flet ((hdr (name) - (multiple-value-bind (value tag) - (header name (mime-message-headers part)) - (cons tag value)))) - (dolist (h (mapcar #'hdr '("from" "subject" "to" "date" "x-march-archive-id"))) - (when h - (format out "~&~A: ~A" (car h) (cdr h)))) - (format out "~2%") - (print-mime-part (mime-body part) out))) - -(defmethod print-mime-part ((part mime-part) (out stream)) - (format out "~&[ ~A subtype=~A ~@[description=~S ~]]~%" - (type-of part) (mime-subtype part) (mime-description part))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric find-mime-part-by-path (mime path) - (:documentation - "Return a subpart of MIME identified by PATH, which is a list of -integers. For example '(2 3 1) is the first part of the third of the -second in MIME.")) - -(defmethod find-mime-part-by-path ((part mime-part) path) - (if (null path) - part - (error "~S doesn't have subparts" part))) - -(defmethod find-mime-part-by-path ((part mime-message) path) - (if (null path) - part - (if (= 1 (car path)) - (find-mime-part-by-path (mime-body part) (cdr path)) - (error "~S may have just one subpart, but part ~D was requested (parts are enumerated base 1)." - part (car path))))) - -(defmethod find-mime-part-by-path ((part mime-multipart) path) - (if (null path) - part - (let ((parts (mime-parts part)) - (part-number (car path))) - (if (<= 1 part-number (length parts)) - (find-mime-part-by-path (nth (1- (car path)) (mime-parts part)) (cdr path)) - (error "~S has just ~D subparts, but part ~D was requested (parts are enumerated base 1)." - part (length parts) part-number))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric find-mime-part-by-id (part id) - (:documentation - "Return a subpart of PAR, whose Content-ID is the same as ID, which -is a string.")) - -(defmethod find-mime-part-by-id ((part mime-part) id) - (when (string= id (mime-id part)) - part)) - -(defmethod find-mime-part-by-id ((part mime-message) id) - (find-mime-part-by-id (mime-body part) id)) - -(defmethod find-mime-part-by-id ((part mime-multipart) id) - (or (call-next-method) - (some #'(lambda (p) - (find-mime-part-by-id p id)) - (mime-parts part)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric find-mime-text-part (msg) - (:documentation - "Return message if it is a text message or first text part. - If no suitable text part is found, return NIL.")) - -(defmethod find-mime-text-part ((part mime-text)) - part) ; found our target - -(defmethod find-mime-text-part ((msg mime-message)) - ;; mime-body is either a mime-part or mime-multipart - (find-mime-text-part (mime-body msg))) - -(defmethod find-mime-text-part ((parts mime-multipart)) - ;; multipart messages may have a body, otherwise we - ;; search for the first text part - (or (call-next-method) - (find-if #'find-mime-text-part (mime-parts parts)))) - -(defmethod find-mime-text-part ((part mime-part)) - nil) ; default case - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric mime-type-string (mime-part) - (:documentation - "Return the string describing the MIME part.")) - -(defmethod mime-type-string ((part mime-text)) - (format nil "text/~A" (mime-subtype part))) - -(defmethod mime-type-string ((part mime-image)) - (format nil "image/~A" (mime-subtype part))) - -(defmethod mime-type-string ((part mime-audio)) - (format nil "audio/~A" (mime-subtype part))) - -(defmethod mime-type-string ((part mime-video)) - (format nil "video/~A" (mime-subtype part))) - -(defmethod mime-type-string ((part mime-application)) - (format nil "application/~A" (mime-subtype part))) - -(defmethod mime-type-string ((part mime-multipart)) - (format nil "multipart/~A" (mime-subtype part))) - -(defmethod mime-type-string ((part mime-message)) - (format nil "message/~A" (mime-subtype part))) - -(defmethod mime-type-string ((part mime-unknown-part)) - (mime-type part)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgeneric map-parts (function mime-part) - (:documentation - "Recursively map FUNCTION to MIME-PART or its components.")) - -;; Here we wrongly assume that we'll never want to replace messages -;; and multiparts altogether. If you need to do so you have to write -;; your own mapping functions. - -(defmethod map-parts ((function function) (part mime-part)) - (funcall function part)) - -(defmethod map-parts ((function function) (part mime-message)) - (setf (mime-body part) (map-parts function (mime-body part))) - part) - -(defmethod map-parts ((function function) (part mime-multipart)) - (setf (mime-parts part) (mapcar #'(lambda (p) - (map-parts function p)) - (mime-parts part))) - part) - -;; apply-on-parts is like map-parts but doesn't modify the parts (at least -;; not implicitly) - -(defgeneric apply-on-parts (function part)) - -(defmethod apply-on-parts ((function function) (part mime-part)) - (funcall function part)) - -(defmethod apply-on-parts ((function function) (part mime-multipart)) - (dolist (p (mime-parts part)) - (apply-on-parts function p))) - -(defmethod apply-on-parts ((function function) (part mime-message)) - (apply-on-parts function (mime-body part))) - -(defmacro do-parts ((var mime-part) &body body) - `(apply-on-parts #'(lambda (,var) ,@body) ,mime-part)) diff --git a/third_party/lisp/mime4cl/package.lisp b/third_party/lisp/mime4cl/package.lisp deleted file mode 100644 index 8af53fabf..000000000 --- a/third_party/lisp/mime4cl/package.lisp +++ /dev/null @@ -1,101 +0,0 @@ -;;; package.lisp --- package declaration - -;;; Copyright (C) 2005-2007, 2010 by Walter C. Pelissero -;;; Copyright (C) 2022 The TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :cl-user) - -(defpackage :mime4cl - (:nicknames :mime) - (:use :common-lisp :npg :mime4cl-ex-sclf :trivial-gray-streams :flexi-streams) - (:export #:*lazy-mime-decode* - #:print-mime-part - #:read-mime-message - #:mime-part - #:mime-text - #:mime-binary - #:mime-id - #:mime-image - #:mime-message - #:mime-multipart - #:mime-audio - #:mime-unknown-part - #:get-mime-disposition-parameter - #:get-mime-type-parameter - #:mime-disposition - #:mime-disposition-parameters - #:mime-encoding - #:mime-application - #:mime-video - #:mime-description - #:mime-subtype - #:mime-body - #:mime-body-stream - #:mime-parts - #:mime-part-p - #:mime-type - #:mime-type-string - #:mime-type-parameters - #:mime-message-headers - #:mime-message-header-values - #:mime= - #:find-mime-part-by-path - #:find-mime-part-by-id - #:find-mime-text-part - #:encode-mime-part - #:encode-mime-body - #:decode-quoted-printable-stream - #:decode-quoted-printable-string - #:encode-quoted-printable-stream - #:encode-quoted-printable-sequence - #:encode-base64-stream - #:encode-base64-sequence - #:parse-RFC2047-text - #:decode-RFC2047 - #:parse-RFC822-header - #:read-RFC822-headers - #:time-RFC822-string - #:parse-RFC822-date - #:map-parts - #:do-parts - #:apply-on-parts - #:mime-part-file-name - #:mime-text-charset - #:with-input-from-mime-body-stream - ;; endec.lisp - #:base64-encoder - #:null-encoder - #:null-decoder - #:byte-encoder - #:byte-decoder - #:quoted-printable-encoder - #:quoted-printable-decoder - #:encoder-write-byte - #:encoder-finish-output - #:decoder-read-byte - #:decoder-read-sequence - #:*base64-line-length* - #:*quoted-printable-line-length* - ;; address.lisp - #:parse-addresses #:mailboxes-only - #:mailbox #:mbx-description #:mbx-user #:mbx-host #:mbx-domain #:mbx-domain-name #:mbx-address - #:mailbox-group #:mbxg-name #:mbxg-mailboxes - ;; streams.lisp - #:redirect-stream - )) diff --git a/third_party/lisp/mime4cl/streams.lisp b/third_party/lisp/mime4cl/streams.lisp deleted file mode 100644 index 71a32d84e..000000000 --- a/third_party/lisp/mime4cl/streams.lisp +++ /dev/null @@ -1,274 +0,0 @@ -;;; streams.lisp --- En/De-coding Streams - -;;; Copyright (C) 2012 by Walter C. Pelissero -;;; Copyright (C) 2021-2023 by the TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :mime4cl) - -(defun flexi-stream-root-stream (stream) - "Return the non FLEXI-STREAM stream a given chain of FLEXI-STREAMs is based on." - (if (typep stream 'flexi-stream) - (flexi-stream-root-stream (flexi-stream-stream stream)) - stream)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defclass coder-stream-mixin () - ((real-stream :type stream - :initarg :underlying-stream - :reader real-stream) - (dont-close :initform nil - :initarg :dont-close))) - -(defmethod stream-file-position ((stream coder-stream-mixin)) - (file-position (slot-value stream 'real-stream))) - -(defmethod (setf stream-file-position) (newval (stream coder-stream-mixin)) - (file-position (slot-value stream 'real-stream) newval)) - -(defclass coder-input-stream-mixin (fundamental-binary-input-stream coder-stream-mixin) - ()) -(defclass coder-output-stream-mixin (fundamental-binary-output-stream coder-stream-mixin) - ()) - -;; TODO(sterni): temporary, ugly measure to make flexi-streams happy -(defmethod stream-element-type ((stream coder-input-stream-mixin)) - (declare (ignore stream)) - '(unsigned-byte 8)) - -(defclass quoted-printable-decoder-stream (coder-input-stream-mixin quoted-printable-decoder) ()) -(defclass 8bit-decoder-stream (coder-input-stream-mixin 8bit-decoder) ()) - -(defclass quoted-printable-encoder-stream (coder-output-stream-mixin quoted-printable-encoder) ()) -(defclass base64-encoder-stream (coder-output-stream-mixin base64-encoder) ()) -(defclass 8bit-encoder-stream (coder-output-stream-mixin 8bit-encoder) ()) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defmethod initialize-instance :after ((stream coder-stream-mixin) &key &allow-other-keys) - (unless (slot-boundp stream 'real-stream) - (error "REAL-STREAM is unbound. Must provide a :UNDERLYING-STREAM argument."))) - -(defmethod initialize-instance ((stream coder-output-stream-mixin) &key &allow-other-keys) - (call-next-method) - (unless (slot-boundp stream 'output-function) - (setf (slot-value stream 'output-function) - #'(lambda (char) - (write-char char (slot-value stream 'real-stream)))))) - -(defmethod initialize-instance ((stream coder-input-stream-mixin) &key &allow-other-keys) - (call-next-method) - (unless (slot-boundp stream 'input-function) - (setf (slot-value stream 'input-function) - #'(lambda () - (read-char (slot-value stream 'real-stream) nil))))) - -(defmethod stream-read-byte ((stream coder-input-stream-mixin)) - (or (decoder-read-byte stream) - :eof)) - -(defmethod stream-write-byte ((stream coder-output-stream-mixin) byte) - (encoder-write-byte stream byte)) - -(defmethod close ((stream coder-stream-mixin) &key abort) - (with-slots (real-stream dont-close) stream - (unless dont-close - (close real-stream :abort abort)))) - -(defmethod close ((stream coder-output-stream-mixin) &key abort) - (unless abort - (encoder-finish-output stream)) - (call-next-method)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defclass encoder-input-stream (fundamental-character-input-stream coder-stream-mixin) - ((encoder) - (buffer-queue :initform (make-queue))) - (:documentation - "This is the base class for encoders with the direction swapped. It -reads from REAL-STREAM a stream of bytes, encodes it and returnes it -in a stream of character.")) - -(defclass quoted-printable-encoder-input-stream (encoder-input-stream) ()) -(defclass base64-encoder-input-stream (encoder-input-stream) ()) -(defclass 8bit-encoder-input-stream (fundamental-character-input-stream coder-stream-mixin) ()) - -(defmethod initialize-instance ((stream quoted-printable-encoder-input-stream) &key &allow-other-keys) - (call-next-method) - (with-slots (encoder buffer-queue) stream - (setf encoder - (make-instance 'quoted-printable-encoder - :output-function #'(lambda (char) - (queue-append buffer-queue char)))))) - -(defmethod initialize-instance ((stream base64-encoder-input-stream) &key &allow-other-keys) - (call-next-method) - (with-slots (encoder buffer-queue) stream - (setf encoder - (make-instance 'base64-encoder - :output-function #'(lambda (char) - (queue-append buffer-queue char)))))) - -(defmethod stream-read-char ((stream encoder-input-stream)) - (with-slots (encoder buffer-queue real-stream) stream - (loop - while (queue-empty-p buffer-queue) - do (let ((byte (read-byte real-stream nil))) - (if byte - (encoder-write-byte encoder byte) - (progn - (encoder-finish-output encoder) - (queue-append buffer-queue :eof))))) - (queue-pop buffer-queue))) - - -(defmethod stream-read-char ((stream 8bit-encoder-input-stream)) - (with-slots (real-stream) stream - (aif (read-byte real-stream nil) - (code-char it) - :eof))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun make-custom-flexi-stream (class stream other-args) - (apply #'make-instance - class - :stream stream - (mapcar (lambda (x) - ;; make-flexi-stream has a discrepancy between :initarg of - ;; make-instance and its &key which we mirror here. - (if (eq x :external-format) :flexi-stream-external-format x)) - other-args))) - -(defclass adapter-flexi-input-stream (flexi-input-stream) - ((ignore-close - :initform nil - :initarg :ignore-close - :documentation - "If T, calling CLOSE on the stream does nothing. -If NIL, the underlying stream is closed.")) - (:documentation "FLEXI-STREAM that does not close the underlying stream on -CLOSE if :IGNORE-CLOSE is T.")) - -(defmethod close ((stream adapter-flexi-input-stream) &key abort) - (declare (ignore abort)) - (with-slots (ignore-close) stream - (unless ignore-close - (call-next-method)))) - -(defun make-input-adapter (source) - (etypecase source - ;; If it's already a stream, we need to make sure it's not closed by the adapter - (stream - (assert (input-stream-p source)) - (if (and (typep source 'adapter-flexi-input-stream) - (slot-value source 'ignore-close)) - source ; already ignores CLOSE - (make-adapter-flexi-input-stream source :ignore-close t))) - ;; TODO(sterni): is this necessary? (maybe with (not *lazy-mime-decode*)?) - (string - (make-input-adapter (string-to-octets source))) - ((vector (unsigned-byte 8)) - (make-in-memory-input-stream source)) - (pathname - (make-flexi-stream (open source :element-type '(unsigned-byte 8)))) - (file-portion - (open-decoded-file-portion source)))) - -(defun make-adapter-flexi-input-stream (stream &rest args) - "Create a ADAPTER-FLEXI-INPUT-STREAM. Accepts the same keyword arguments as -MAKE-FLEXI-STREAM as well as :IGNORE-CLOSE. If T, the underlying stream is not -closed." - (make-custom-flexi-stream 'adapter-flexi-input-stream stream args)) - -(defclass positioned-flexi-input-stream (adapter-flexi-input-stream) - () - (:documentation - "FLEXI-INPUT-STREAM that automatically advances the underlying :STREAM to -the location given by :POSITION. This uses FILE-POSITION internally, so it'll -only works if the underlying stream position is tracked in bytes. Note that -the underlying stream is still advanced, so having multiple instances of -POSITIONED-FLEXI-INPUT-STREAM based with the same underlying stream won't work -reliably. -Also supports :IGNORE-CLOSE of ADAPTER-FLEXI-INPUT-STREAM.")) - -(defmethod initialize-instance ((stream positioned-flexi-input-stream) - &key &allow-other-keys) - (call-next-method) - ;; The :POSITION initarg is only informational for flexi-streams: It assumes - ;; it is were the stream it got is already at and continuously updates it - ;; for querying (via FLEXI-STREAM-POSITION) and bound checking. - ;; Since we have streams that are not positioned correctly, we need to do this - ;; here using FILE-POSITION. Note that assumes the underlying implementation - ;; uses bytes for FILE-POSITION which is not guaranteed (probably some streams - ;; even in SBCL don't). - (file-position (flexi-stream-stream stream) (flexi-stream-position stream))) - -(defun make-positioned-flexi-input-stream (stream &rest args) - "Create a POSITIONED-FLEXI-INPUT-STREAM. Accepts the same keyword arguments as -MAKE-FLEXI-STREAM as well as :IGNORE-CLOSE. Causes the FILE-POSITION of STREAM to -be modified to match the :POSITION argument." - (make-custom-flexi-stream 'positioned-flexi-input-stream stream args)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO(sterni): test correct behavior with END NIL -(defstruct file-portion - data ; string or a pathname - encoding - start - end) - -(defun open-decoded-file-portion (file-portion) - (with-slots (data encoding start end) - file-portion - (let* ((binary-stream - (etypecase data - (pathname - (open data :element-type '(unsigned-byte 8))) - ((vector (unsigned-byte 8)) - (flexi-streams:make-in-memory-input-stream data)) - (stream - ;; TODO(sterni): assert that bytes/flexi-stream - data))) - (params (ccase encoding - ((:quoted-printable :base64) '(:external-format :us-ascii)) - (:8bit '(:element-type (unsigned-byte 8))) - (:7bit '(:external-format :us-ascii)))) - (portion-stream (apply #'make-positioned-flexi-input-stream - binary-stream - :position start - :bound end - ;; if data is a stream we can't have a - ;; FILE-PORTION without modifying it when - ;; reading etc. The least we can do, though, - ;; is forgo destroying it. - :ignore-close (typep data 'stream) - params)) - (needs-decoder-stream (member encoding '(:quoted-printable - :base64)))) - - (if needs-decoder-stream - (make-instance - (ccase encoding - (:quoted-printable 'quoted-printable-decoder-stream) - (:base64 'qbase64:decode-stream)) - :underlying-stream portion-stream) - portion-stream)))) diff --git a/third_party/lisp/mime4cl/test/.skip-tree b/third_party/lisp/mime4cl/test/.skip-tree deleted file mode 100644 index 28023cca5..000000000 --- a/third_party/lisp/mime4cl/test/.skip-tree +++ /dev/null @@ -1 +0,0 @@ -parent exposes tests diff --git a/third_party/lisp/mime4cl/test/address.lisp b/third_party/lisp/mime4cl/test/address.lisp deleted file mode 100644 index a3653985c..000000000 --- a/third_party/lisp/mime4cl/test/address.lisp +++ /dev/null @@ -1,123 +0,0 @@ -;;; address.lisp --- tests for the e-mail address parser - -;;; Copyright (C) 2007, 2009 by Walter C. Pelissero -;;; Copyright (C) 2022 by The TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :mime4cl-tests) - -(defun test-parsing (string) - (format nil "~{~A~^, ~}" (parse-addresses string))) - -(deftest address-parse-simple.1 - (test-parsing "foo@bar") - "foo@bar") - -(deftest address-parse-simple.2 - (test-parsing "foo@bar.com") - "foo@bar.com") - -(deftest address-parse-simple.3 - (test-parsing "foo@bar.baz.com") - "foo@bar.baz.com") - -(deftest address-parse-simple.4 - (test-parsing "foo.ooo@bar.baz.com") - "foo.ooo@bar.baz.com") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(deftest address-parse-simple-commented.1 - (test-parsing "foo@bar (Some Comment)") - "\"Some Comment\" ") - -(deftest address-parse-simple-commented.2 - (test-parsing "foo@bar (Some, Comment)") - "\"Some, Comment\" ") - -(deftest address-parse-simple-commented.3 - (test-parsing "foo@bar (Some Comment (yes, indeed))") - "\"Some Comment (yes, indeed)\" ") - -(deftest address-parse-simple-commented.4 - (test-parsing "foo.bar@host.complicated.domain.net (Some Comment (yes, indeed))") - "\"Some Comment (yes, indeed)\" ") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(deftest address-parse-angle.1 - (test-parsing "") - "foo@bar.baz.net") - -(deftest address-parse-angle.2 - (test-parsing "My far far friend ") - "\"My far far friend\" ") - -(deftest address-parse-angle.3 - (test-parsing "\"someone, I don't like\" ") - "\"someone, I don't like\" ") - -(deftest address-parse-angle.4 - (test-parsing "\"this could (be a comment)\" ") - "\"this could (be a comment)\" ") - -(deftest address-parse-angle.5 - (test-parsing "don't be fooled ") - "\"don't be fooled\" ") - -(deftest address-parse-angle.6 - (test-parsing "") - "foo@bar") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(deftest address-parse-domain-literal.1 - (test-parsing "") - "foo@[bar]") - -(deftest address-parse-domain-literal.2 - (test-parsing "") - "foo@[bar.net]") - -(deftest address-parse-domain-literal.3 - (test-parsing "") - "foo@[10.0.0.2]") - -(deftest address-parse-domain-literal.4 - (test-parsing "") - "foo.bar@[10.0.0.2]") - -(deftest address-parse-domain-literal.5 - (test-parsing "somewhere unkown ") - "\"somewhere unkown\" ") - -(deftest address-parse-domain-literal.6 - (test-parsing "\"Some--One\" ") - "\"Some--One\" ") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(deftest address-parse-group.1 - (test-parsing "friends:john@bar.in.soho, jack@pub.round.the.corner, jim@[10.0.1.2];") - "friends: john@bar.in.soho, jack@pub.round.the.corner, jim@[10.0.1.2];") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(deftest address-parse-mixed.1 - (test-parsing "Foo BAR , \"John, Smith (that one!)\" , friends:john@bar,jack@pub;, foo.bar.baz@wow.mail.mine, dont.bark@me (Fierce Dog)") - "\"Foo BAR\" , \"John, Smith (that one!)\" , friends: john@bar, jack@pub;, foo.bar.baz@wow.mail.mine, \"Fierce Dog\" ") diff --git a/third_party/lisp/mime4cl/test/endec.lisp b/third_party/lisp/mime4cl/test/endec.lisp deleted file mode 100644 index 6b22b3f6a..000000000 --- a/third_party/lisp/mime4cl/test/endec.lisp +++ /dev/null @@ -1,184 +0,0 @@ -;;; endec.lisp --- test suite for the MIME encoder/decoder functions - -;;; Copyright (C) 2006, 2007, 2009, 2010 by Walter C. Pelissero -;;; Copyright (C) 2022 by The TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :mime4cl-tests) - -(deftest quoted-printable.1 - (encode-quoted-printable-sequence (map '(vector (unsigned-byte 8)) #'char-code - "Français, Español, böse, skøl")) - "Fran=E7ais, Espa=F1ol, b=F6se, sk=F8l") - -(deftest quoted-printable.2 - (encode-quoted-printable-sequence (map '(vector (unsigned-byte 8)) #'char-code - "Français, Español, böse, skøl") - :start 10 :end 17) - "Espa=F1ol") - -(deftest quoted-printable.3 - (map 'string #'code-char - (decode-quoted-printable-string "Fran=E7ais, Espa=F1ol, b=F6se, sk=F8l")) - "Français, Español, böse, skøl") - -(deftest quoted-printable.4 - (map 'string #'code-char - (decode-quoted-printable-string "Fran=E7ais, Espa=F1ol, b=F6se, sk=F8l" - :start 12 :end 21)) - "Español") - -(deftest quoted-printable.5 - (map 'string #'code-char - (decode-quoted-printable-string "this = wrong")) - "this = wrong") - -(deftest quoted-printable.6 - (map 'string #'code-char - (decode-quoted-printable-string "this is wrong=")) - "this is wrong=") - -(deftest quoted-printable.7 - (map 'string #'code-char - (decode-quoted-printable-string "this is wrong=1")) - "this is wrong=1") - -(deftest quoted-printable.8 - (encode-quoted-printable-sequence (map '(vector (unsigned-byte 8)) #'char-code - "x = x + 1")) - "x =3D x + 1") - -(deftest quoted-printable.9 - (encode-quoted-printable-sequence (map '(vector (unsigned-byte 8)) #'char-code - "x = x + 1 ")) - "x =3D x + 1 =20") - -(deftest quoted-printable.10 - (encode-quoted-printable-sequence (map '(vector (unsigned-byte 8)) #'char-code - "this string is very very very very very very very very very very very very very very very very very very very very long")) - "this string is very very very very very very very very very very very ve= -ry very very very very very very very very long") - -(deftest quoted-printable.11 - (encode-quoted-printable-sequence (map '(vector (unsigned-byte 8)) #'char-code - "this string is very very very very long")) - "this string is very very = - very very long") - -(deftest quoted-printable.12 - (encode-quoted-printable-sequence (map '(vector (unsigned-byte 8)) #'char-code - "please read the next -line")) - "please read the next =20 -line") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(deftest base64.1 - (let ((*base64-line-length* nil)) - (encode-base64-sequence (map '(vector (unsigned-byte 8)) #'char-code - "Some random string."))) - "U29tZSByYW5kb20gc3RyaW5nLg==") - -(deftest base64.2 - (let ((*base64-line-length* nil)) - (encode-base64-sequence (map '(vector (unsigned-byte 8)) #'char-code - "Some random string.") :start 5 :end 11)) - "cmFuZG9t") - -(deftest base64.3 - (map 'string #'code-char - (qbase64:decode-string "U29tZSByYW5kb20gc3RyaW5nLg==")) - "Some random string.") - -(deftest base64.4 - (map 'string #'code-char - (qbase64:decode-string "U29tZSByYW5kb20gc3RyaW5nLg==")) - "Some random string.") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(deftest RFC2047.1 - (parse-RFC2047-text "foo bar") - ("foo bar")) - -;; from RFC2047 section 8 -(deftest RFC2047.2 - (decode-RFC2047 "=?US-ASCII?Q?Keith_Moore?= ") - "Keith Moore ") - -;; from RFC2047 section 8 -(deftest RFC2047.3 - (decode-RFC2047 "=?ISO-8859-1?Q?Olle_J=E4rnefors?=") - "Olle Järnefors") - -;; from RFC2047 section 8 -(deftest RFC2047.4 - (decode-RFC2047 "Nathaniel Borenstein (=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?=)") - "Nathaniel Borenstein (םולש ןב ילטפנ)") - -;; from RFC2047 section 8 -(deftest RFC2047.5 - (decode-RFC2047 "=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= ") - "Keld Jørn Simonsen ") - -(defun perftest-encoder (encoder-class &optional (megs 100)) - (declare (optimize (speed 3) (debug 0) (safety 0)) - (type fixnum megs)) - (with-open-file (in #P"/dev/random" :element-type '(unsigned-byte 8)) - (let* ((meg (* 1024 1024)) - (buffer (make-sequence '(vector (unsigned-byte 8)) meg)) - (encoder (make-instance encoder-class - :output-function #'(lambda (c) (declare (ignore c)))))) - (declare (type fixnum meg)) - (time - (progn - (dotimes (x megs) - (read-sequence buffer in) - (dotimes (i meg) - (mime4cl:encoder-write-byte encoder (aref buffer i)))) - (mime4cl:encoder-finish-output encoder)))))) - -(defun perftest-decoder (decoder-class &optional (megs 100)) - (declare (optimize (speed 3) (debug 0) (safety 0)) - (type fixnum megs)) - (with-open-file (in #P"/dev/random" :element-type '(unsigned-byte 8)) - (let ((*tmp-file-defaults* (make-pathname :defaults #.(or *load-pathname* *compile-file-pathname*) - :type "encoded-data"))) - (with-temp-file (tmp nil :direction :io) - (let* ((meg (* 1024 1024)) - (buffer (make-sequence '(vector (unsigned-byte 8)) meg)) - (encoder-class (ecase decoder-class - (mime4cl:quoted-printable-decoder 'mime4cl:quoted-printable-encoder))) - (encoder (make-instance encoder-class - :output-function #'(lambda (c) - (write-char c tmp)))) - (decoder (make-instance decoder-class - :input-function #'(lambda () - (read-char tmp nil))))) - (declare (type fixnum meg)) - (dotimes (x megs) - (read-sequence buffer in) - (dotimes (i meg) - (mime4cl:encoder-write-byte encoder (aref buffer i)))) - (mime4cl:encoder-finish-output encoder) - (file-position tmp 0) - (time - (loop - for b = (mime4cl:decoder-read-byte decoder) - while b))))))) diff --git a/third_party/lisp/mime4cl/test/mime.lisp b/third_party/lisp/mime4cl/test/mime.lisp deleted file mode 100644 index dbd1dd996..000000000 --- a/third_party/lisp/mime4cl/test/mime.lisp +++ /dev/null @@ -1,41 +0,0 @@ -;;; mime.lisp --- MIME regression tests - -;;; Copyright (C) 2012 by Walter C. Pelissero -;;; Copyright (C) 2021-2023 by the TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :mime4cl-tests) - -(defvar *samples-directory* - (merge-pathnames (make-pathname :directory '(:relative "samples")) - #.(or *compile-file-pathname* - *load-pathname* - #P""))) - -(loop - for f in (directory (make-pathname :defaults *samples-directory* - :name :wild - :type "msg")) - for i from 1 - do - (add-test (intern (format nil "MIME.~A" i)) - `(let* ((orig (mime-message ,f)) - (dup (mime-message - (with-output-to-string (out) (encode-mime-part orig out))))) - (mime= orig dup)) - t)) diff --git a/third_party/lisp/mime4cl/test/package.lisp b/third_party/lisp/mime4cl/test/package.lisp deleted file mode 100644 index 965680448..000000000 --- a/third_party/lisp/mime4cl/test/package.lisp +++ /dev/null @@ -1,27 +0,0 @@ -;;; package.lisp --- package description for the regression tests - -;;; Copyright (C) 2006, 2009 by Walter C. Pelissero -;;; Copyright (C) 2022 by The TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(cl:in-package :common-lisp) - -(defpackage :mime4cl-tests - (:use :common-lisp - :rtest :mime4cl :mime4cl-ex-sclf) - (:export)) diff --git a/third_party/lisp/mime4cl/test/rt.lisp b/third_party/lisp/mime4cl/test/rt.lisp deleted file mode 100644 index 3f3aa5c56..000000000 --- a/third_party/lisp/mime4cl/test/rt.lisp +++ /dev/null @@ -1,258 +0,0 @@ -#|----------------------------------------------------------------------------| - | Copyright 1990 by the Massachusetts Institute of Technology, Cambridge MA. | - | Copyright 2023 by the TVL Authors | - | | - | Permission to use, copy, modify, and distribute this software and its | - | documentation for any purpose and without fee is hereby granted, provided | - | that this copyright and permission notice appear in all copies and | - | supporting documentation, and that the name of M.I.T. not be used in | - | advertising or publicity pertaining to distribution of the software | - | without specific, written prior permission. M.I.T. makes no | - | representations about the suitability of this software for any purpose. | - | It is provided "as is" without express or implied warranty. | - | | - | M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | - | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | - | M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | - | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | - | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | - | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | - | SOFTWARE. | - |----------------------------------------------------------------------------|# - -(defpackage #:regression-test - (:nicknames #:rtest #-lispworks #:rt) - (:use #:cl) - (:export #:*do-tests-when-defined* #:*test* #:continue-testing - #:deftest #:add-test #:do-test #:do-tests #:get-test #:pending-tests - #:rem-all-tests #:rem-test) - (:documentation "The MIT regression tester with pfdietz's modifications")) - -(in-package :regression-test) - -(defvar *test* nil "Current test name") -(defvar *do-tests-when-defined* nil) -(defvar *entries* '(nil) "Test database") -(defvar *in-test* nil "Used by TEST") -(defvar *debug* nil "For debugging") -(defvar *catch-errors* t - "When true, causes errors in a test to be caught.") -(defvar *print-circle-on-failure* nil - "Failure reports are printed with *PRINT-CIRCLE* bound to this value.") -(defvar *compile-tests* nil - "When true, compile the tests before running them.") -(defvar *optimization-settings* '((safety 3))) -(defvar *expected-failures* nil - "A list of test names that are expected to fail.") - -(defstruct (entry (:conc-name nil) - (:type list)) - pend name form) - -(defmacro vals (entry) `(cdddr ,entry)) - -(defmacro defn (entry) `(cdr ,entry)) - -(defun pending-tests () - (do ((l (cdr *entries*) (cdr l)) - (r nil)) - ((null l) (nreverse r)) - (when (pend (car l)) - (push (name (car l)) r)))) - -(defun rem-all-tests () - (setq *entries* (list nil)) - nil) - -(defun rem-test (&optional (name *test*)) - (do ((l *entries* (cdr l))) - ((null (cdr l)) nil) - (when (equal (name (cadr l)) name) - (setf (cdr l) (cddr l)) - (return name)))) - -(defun get-test (&optional (name *test*)) - (defn (get-entry name))) - -(defun get-entry (name) - (let ((entry (find name (cdr *entries*) - :key #'name - :test #'equal))) - (when (null entry) - (report-error t - "~%No test with name ~:@(~S~)." - name)) - entry)) - -(defmacro deftest (name form &rest values) - `(add-entry '(t ,name ,form .,values))) - -(defun add-test (name form &rest values) - (funcall #'add-entry (append (list 't name form) values))) - -(defun add-entry (entry) - (setq entry (copy-list entry)) - (do ((l *entries* (cdr l))) (nil) - (when (null (cdr l)) - (setf (cdr l) (list entry)) - (return nil)) - (when (equal (name (cadr l)) - (name entry)) - (setf (cadr l) entry) - (report-error nil - "Redefining test ~:@(~S~)" - (name entry)) - (return nil))) - (when *do-tests-when-defined* - (do-entry entry)) - (setq *test* (name entry))) - -(defun report-error (error? &rest args) - (cond (*debug* - (apply #'format t args) - (if error? (throw '*debug* nil))) - (error? (apply #'error args)) - (t (apply #'warn args)))) - -(defun do-test (&optional (name *test*)) - (do-entry (get-entry name))) - -(defun equalp-with-case (x y) - "Like EQUALP, but doesn't do case conversion of characters." - (cond - ((eq x y) t) - ((consp x) - (and (consp y) - (equalp-with-case (car x) (car y)) - (equalp-with-case (cdr x) (cdr y)))) - ((and (typep x 'array) - (= (array-rank x) 0)) - (equalp-with-case (aref x) (aref y))) - ((typep x 'vector) - (and (typep y 'vector) - (let ((x-len (length x)) - (y-len (length y))) - (and (eql x-len y-len) - (loop - for e1 across x - for e2 across y - always (equalp-with-case e1 e2)))))) - ((and (typep x 'array) - (typep y 'array) - (not (equal (array-dimensions x) - (array-dimensions y)))) - nil) - ((typep x 'array) - (and (typep y 'array) - (let ((size (array-total-size x))) - (loop for i from 0 below size - always (equalp-with-case (row-major-aref x i) - (row-major-aref y i)))))) - (t (eql x y)))) - -(defun do-entry (entry &optional - (s *standard-output*)) - (catch '*in-test* - (setq *test* (name entry)) - (setf (pend entry) t) - (let* ((*in-test* t) - ;; (*break-on-warnings* t) - (aborted nil) - r) - ;; (declare (special *break-on-warnings*)) - - (block aborted - (setf r - (flet ((%do - () - (if *compile-tests* - (multiple-value-list - (funcall (compile - nil - `(lambda () - (declare - (optimize ,@*optimization-settings*)) - ,(form entry))))) - (multiple-value-list - (eval (form entry)))))) - (if *catch-errors* - (handler-bind - ((style-warning #'muffle-warning) - (error #'(lambda (c) - (setf aborted t) - (setf r (list c)) - (return-from aborted nil)))) - (%do)) - (%do))))) - - (setf (pend entry) - (or aborted - (not (equalp-with-case r (vals entry))))) - - (when (pend entry) - (let ((*print-circle* *print-circle-on-failure*)) - (format s "~&Test ~:@(~S~) failed~ - ~%Form: ~S~ - ~%Expected value~P: ~ - ~{~S~^~%~17t~}~%" - *test* (form entry) - (length (vals entry)) - (vals entry)) - (format s "Actual value~P: ~ - ~{~S~^~%~15t~}.~%" - (length r) r))))) - (when (not (pend entry)) *test*)) - -(defun continue-testing () - (if *in-test* - (throw '*in-test* nil) - (do-entries *standard-output*))) - -(defun do-tests (&optional - (out *standard-output*)) - (dolist (entry (cdr *entries*)) - (setf (pend entry) t)) - (if (streamp out) - (do-entries out) - (with-open-file - (stream out :direction :output) - (do-entries stream)))) - -(defun do-entries (s) - (format s "~&Doing ~A pending test~:P ~ - of ~A tests total.~%" - (count t (cdr *entries*) - :key #'pend) - (length (cdr *entries*))) - (dolist (entry (cdr *entries*)) - (when (pend entry) - (format s "~@[~<~%~:; ~:@(~S~)~>~]" - (do-entry entry s)))) - (let ((pending (pending-tests)) - (expected-table (make-hash-table :test #'equal))) - (dolist (ex *expected-failures*) - (setf (gethash ex expected-table) t)) - (let ((new-failures - (loop for pend in pending - unless (gethash pend expected-table) - collect pend))) - (if (null pending) - (format s "~&No tests failed.") - (progn - (format s "~&~A out of ~A ~ - total tests failed: ~ - ~:@(~{~<~% ~1:;~S~>~ - ~^, ~}~)." - (length pending) - (length (cdr *entries*)) - pending) - (if (null new-failures) - (format s "~&No unexpected failures.") - (when *expected-failures* - (format s "~&~A unexpected failures: ~ - ~:@(~{~<~% ~1:;~S~>~ - ~^, ~}~)." - (length new-failures) - new-failures))) - )) - (null pending)))) diff --git a/third_party/lisp/mime4cl/test/samples/google-groups-msg-with-patch.msg b/third_party/lisp/mime4cl/test/samples/google-groups-msg-with-patch.msg deleted file mode 100644 index 71fbdc22b..000000000 --- a/third_party/lisp/mime4cl/test/samples/google-groups-msg-with-patch.msg +++ /dev/null @@ -1,206 +0,0 @@ -Received: by 2002:a05:6838:9619:0:0:0:0 with SMTP id y25csp3021959nkj; - Sun, 27 Sep 2020 16:35:15 -0700 (PDT) -X-Received: by 2002:a05:6402:396:: with SMTP id o22mr12644027edv.316.1601249714826; - Sun, 27 Sep 2020 16:35:14 -0700 (PDT) -ARC-Seal: i=3; a=rsa-sha256; t=1601249714; cv=pass; - d=google.com; s=arc-20160816; - b=JZF8xwEI+NfpPypYuVsDwKKN4In4Gxk3qcvm260gDbKPo04eS7Dn3CcoeQkbB3Ryck - FUtB8PfISQOsDboMeEXqGbhbCSbH2HoXWySM6XucTVzfeL2hXF9sPjFUCx6LLuvSDSxL - 7E146B7H3dNvB1ndqkWyefiVeSgeES7KzVvYbkoMJJlKozR6FUsKMCVMdrRq0ja6iGbf - 7TlLWvlci49+8LZQKtDQ2ovU/DSQmu2f7eWcbozsIP3ArBxQ+814bQprLWQYsI5Z4fZz - 0kPEC6dbZpajPDNpTx5ark/+EV/ICGVE6kODmNjFTi18eMjMU1PXULE8FImkw+duFdzP - DF4g== -ARC-Message-Signature: i=3; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; - h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post - :list-id:mailing-list:precedence:subject:to:from:date:message-id - :mime-version:user-agent:sender:dkim-signature; - bh=2VC221ICpWr3atnjvjQBr2VGuwcTNaQLBA5EJvQxzNE=; - b=oI1vj3HEqVB2vRTlg44B8ik+G5jSMm7YHiPOdg+oWwiZSeK1DlKf3S0C9brs8iLBDU - paovJkxdJu++lY1zzBorw34bMDPHsfnBf6ztDZfAhpDSQM3VZEW+jAvAc9vFh6eL5ilE - qdZR9blzrqoi5GoPmVx7j/Z30zFidppWNbZLzuC7pAcS86WzKd8Ta56EDxxHE48RFRyO - TYhIonS2QEBp+Yn2Pm5SGez/5HHI2s3vu1kXTZ0JKETvWSkZUtBsX7u7KTfcy3EAjvc8 - 3s2dxQpMCYXZvyvJ0g2k0dsecEDRBWa2gv9Wr3iip7v5NaRcKuz1nuN/AiazKZPTDION - f/tg== -ARC-Authentication-Results: i=3; mx.google.com; - dkim=pass header.i=@tazj.in header.s=google header.b=dVeQt6cm; - arc=pass (i=2 dkim=pass dkdomain=firefly.nu dkim=pass dkdomain=messagingengine.com); - spf=pass (google.com: domain of depot+bncbdhlpx4g2ierbmwdyt5qkgqexgc7sqy@tazj.in designates 209.85.220.69 as permitted sender) smtp.mailfrom=depot+bncBDHLPX4G2IERBMWDYT5QKGQEXGC7SQY@tazj.in -Return-Path: -Received: from mail-sor-f69.google.com (mail-sor-f69.google.com. [209.85.220.69]) - by mx.google.com with SMTPS id li22sor4242657ejb.49.2020.09.27.16.35.14 - for - (Google Transport Security); - Sun, 27 Sep 2020 16:35:14 -0700 (PDT) -Received-SPF: pass (google.com: domain of depot+bncbdhlpx4g2ierbmwdyt5qkgqexgc7sqy@tazj.in designates 209.85.220.69 as permitted sender) client-ip=209.85.220.69; -Authentication-Results: mx.google.com; - dkim=pass header.i=@tazj.in header.s=google header.b=dVeQt6cm; - arc=pass (i=2 dkim=pass dkdomain=firefly.nu dkim=pass dkdomain=messagingengine.com); - spf=pass (google.com: domain of depot+bncbdhlpx4g2ierbmwdyt5qkgqexgc7sqy@tazj.in designates 209.85.220.69 as permitted sender) smtp.mailfrom=depot+bncBDHLPX4G2IERBMWDYT5QKGQEXGC7SQY@tazj.in -ARC-Seal: i=2; a=rsa-sha256; t=1601249714; cv=pass; - d=google.com; s=arc-20160816; - b=e/oahP75xCAPQvP5D7B1dG2SDAEC5XNRI40cafqhXEI32hdW9TQNSs1krZ7tQHOht2 - /ZGbOLY/BNxS3VoDM+Mcif7BCx7bjeOpmVkVzEhM0KZoBHorf91SOBM05PvewA9nQtLb - 1pXB8bdivzOkYUuSX56rX1sOjNjMrWWUPF8Ven5zy3r2MIqJ561O8pPN/6Uz0tajiK7Y - klavaIk/Pxo91kuVbOKDJTH2mmggFTthqYkkCQuelgeKx4zBdDjS32vx3kPLRhMnfuGu - +CHC9L2Gv0ww0PyfRhkYeNLRrAqVHWDyCrw26f2QxFBEoTv/OnzH380uqO9n+SdmILBI - fNzw== -ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; - h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post - :list-id:mailing-list:precedence:subject:to:from:date:message-id - :mime-version:user-agent:sender:dkim-signature; - bh=2VC221ICpWr3atnjvjQBr2VGuwcTNaQLBA5EJvQxzNE=; - b=BONPbsQkjSVRgH8pu89B9aXx6IAuchsgfp2pedA7kEz7Gw3/M9nQoPxTbjcAXKFWoi - SDqYH/Ch6TrYFy6WmgKyw5NB0WuB6WIC9jhRbeiGsXlxbnm1cP1thD7uRFJTaAhcaRBO - cbRA5Ue7pTphAtNVWkHeC37swSOrLtl9WFj+vXwo2l8ndO+5uP6jBi3ApaZDXyx7NODT - i3Jo1kehj7rnA+PINKR8tjlZ1COJYmxWz7upypJY4rZxLdJYzXPS19Rdhq4zmumyqRxt - NsnIIPsPRnYopcLd15rwgSOaHYi4CWwalkpfsBL1IaKXuk0K/XwmLsWdGrNRAN4aUEoR - 7KEw== -ARC-Authentication-Results: i=2; mx.google.com; - dkim=pass header.i=@firefly.nu header.s=fm2 header.b=P5Ezbo3T; - dkim=pass header.i=@messagingengine.com header.s=fm3 header.b=pHVhf6X0; - spf=neutral (google.com: 64.147.123.21 is neither permitted nor denied by best guess record for domain of firefly@firefly.nu) smtp.mailfrom=firefly@firefly.nu -DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; - d=tazj.in; s=google; - h=sender:user-agent:mime-version:message-id:date:from:to:subject - :x-original-sender:x-original-authentication-results:precedence - :mailing-list:list-id:list-post:list-help:list-archive - :list-subscribe:list-unsubscribe; - bh=2VC221ICpWr3atnjvjQBr2VGuwcTNaQLBA5EJvQxzNE=; - b=dVeQt6cmfZBkKqjl826gk0BnxKVtl6OsjaldzCuNQxqxhrecw9GbSofGqS3WxrxWWP - S8cg2AoRtIFC8nuTiRCAEgREb+4paYH5BtDbLtL/Y56jOA0djb6APwYx8MYOVwQxflrx - yyGWSXI04MYjkX/+0gFyvzi0VfZM4UK4pjfPN6WhHBe4xy6bF8VBds11PPAaKZdSdAvR - z8j+CpWBNzKNfbM3bUdLbEuPmt3+Qeem/4HAnRhY6jIYyBJb2a2vXT/edBasnTE/gNSd - Cf4SppE7H3EpRwveBAF367MeeX3stQrXN//t2aXljnuxymM90yPkIq2Xn0zBfp1O47WR - aOBg== -X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; - d=1e100.net; s=20161025; - h=sender:x-gm-message-state:user-agent:mime-version:message-id:date - :from:to:subject:x-original-sender:x-original-authentication-results - :precedence:mailing-list:list-id:x-spam-checked-in-group:list-post - :list-help:list-archive:list-subscribe:list-unsubscribe; - bh=2VC221ICpWr3atnjvjQBr2VGuwcTNaQLBA5EJvQxzNE=; - b=qScRnwtHSE4Boeu7UpmdBjsVhesvMMFHVmdPjW3sNCgR1SxUIOLjFpJNPXy/l+dlOh - sApL/oDMQ25yHodkQF8G2mRCV+SBDVAsrIo0w+LILPP3h+Y0y2yTLiLwKE4WLqoaPi1l - jugZUthJC3KEHq8fhtQHRTtBc5V7UQJIecH2kIU43DUNKpzkzOdf7km6Q0cY9CdXs23x - PSuSg4PzbHOo6cGdBVKvbsjh+sOn6WFuxoXOTtNmFJfE9fTfUlz7LJumTZU3J7DKc5Ho - aYzHFmRwdZUyoX/FQwT//Tf2RQbnVGD3o5a+6lhzt8MFecmLHvRImbKCL/L8K+WTYYFY - ou0g== -Sender: depot@tazj.in -X-Gm-Message-State: AOAM530ZJ8ZcOIvD5lsuI9DM+tccfbSnX8Qgkk03neyoDAKpidBSMC/W - yt/uGXfgEMSbcEOWEu/zxLqwyI0F -X-Google-Smtp-Source: ABdhPJySQZLzFZhvk2VQDhHrXOWbCQqFMNYvDodhQIOIvOgRkT6bOuvTGVrWIiY58v2NVvIzUZCfKw== -X-Received: by 2002:a17:906:d78c:: with SMTP id pj12mr12868809ejb.36.1601249714531; - Sun, 27 Sep 2020 16:35:14 -0700 (PDT) -X-BeenThere: depot@tazj.in -Received: by 2002:a17:906:547:: with SMTP id k7ls3670922eja.7.gmail; Sun, 27 - Sep 2020 16:35:13 -0700 (PDT) -X-Received: by 2002:a17:906:2cd2:: with SMTP id r18mr13573990ejr.371.1601249713549; - Sun, 27 Sep 2020 16:35:13 -0700 (PDT) -ARC-Seal: i=1; a=rsa-sha256; t=1601249713; cv=none; - d=google.com; s=arc-20160816; - b=oi0sYnQxS35/hNyKRgiTTgLNV0zvOtiE8Irv6bfmQCOADDql9vaDvs430N+tsEzON3 - wd8frXphZvgkZjVvPer5CgLyr84ixyrrHhEDwqs89AYR9wHibQ6QtinQfr5xoDkQW9Tb - MMlgl55c2AHzXXqe+eY4gEHww/y8ys1aCDAWEhGxe1M09FiUVBn3+F2ZOV5IW4q+p9TW - EMPNZyByXAZnqkYZCX+KHJ+3nyuQ0PsRVuIVbQA/a0GvVwl+yEhyJno7l2AUR8cfl8at - MeevKmvuYTCuc03cLceleXov097xsF0WvO8H68OPkZj1Kf9wrE3qg6avyZF285ixaXrS - Kc6A== -ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; - h=subject:to:from:date:message-id:mime-version:user-agent - :dkim-signature:dkim-signature; - bh=RahJwSWaN3jErVsNLXnMXbf7yUdzKHDGCF4swc44ayM=; - b=qzsApa+4gOUyfT8CcBmrz26QKrvOy54oZgzrHdDe7oNkLANtUyxqKD3KhDAKGUMLYQ - jbXSNrQnhNR4GUNAYmpT/TM0RnbEgdO9rr9LcA3pGA9/LuJo3jBkV87a9H7cC5mp8Zwc - sL4WScovJaK7m0m83VBDqq9Zhp0hexHCKCnH/LrNtpTrWiQvYz6BuDM04BuOEXN4mq1c - tXXcDsrcoj4hTLtGplWU5qGhYnem00cKPXsQ09ivGKFib1TbNgiVGsnHrICktmmionRw - SioEgIoc0ZUlHQOvoV0UlbkCAEEPS9GBR3NeTbm+Dth08zejgs+Il9QiFV2kLnJ0QMpn - oB8A== -ARC-Authentication-Results: i=1; mx.google.com; - dkim=pass header.i=@firefly.nu header.s=fm2 header.b=P5Ezbo3T; - dkim=pass header.i=@messagingengine.com header.s=fm3 header.b=pHVhf6X0; - spf=neutral (google.com: 64.147.123.21 is neither permitted nor denied by best guess record for domain of firefly@firefly.nu) smtp.mailfrom=firefly@firefly.nu -Received: from wout5-smtp.messagingengine.com (wout5-smtp.messagingengine.com. [64.147.123.21]) - by mx.google.com with ESMTPS id m23si6276235ejo.333.2020.09.27.16.35.13 - for - (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); - Sun, 27 Sep 2020 16:35:13 -0700 (PDT) -Received-SPF: neutral (google.com: 64.147.123.21 is neither permitted nor denied by best guess record for domain of firefly@firefly.nu) client-ip=64.147.123.21; -Received: from compute1.internal (compute1.nyi.internal [10.202.2.41]) - by mailout.west.internal (Postfix) with ESMTP id AF9D4858 - for ; Sun, 27 Sep 2020 19:35:11 -0400 (EDT) -Received: from imap6 ([10.202.2.56]) - by compute1.internal (MEProxy); Sun, 27 Sep 2020 19:35:11 -0400 -X-ME-Sender: - -X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedujedrvdehgddvfecutefuodetggdotefrodftvf - curfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdpuffrtefokffrpgfnqfghnecu - uegrihhlohhuthemuceftddtnecunecujfgurhepofgfggfkfffhvffutgesmhdtreerre - ertdenucfhrhhomhephfhirhgvhfhlhicuoehfihhrvghflhihsehfihhrvghflhihrdhn - uheqnecuggftrfgrthhtvghrnhepgfejjeeivdduheehhffgiedvvdeivefhfeekhfejvd - fgleekffdtvefgtdeuheefnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehm - rghilhhfrhhomhepfhhirhgvfhhlhiesfhhirhgvfhhlhidrnhhu -X-ME-Proxy: - - - -Received: by mailuser.nyi.internal (Postfix, from userid 501) - id AEA2C1400D7; Sun, 27 Sep 2020 19:35:10 -0400 (EDT) -X-Mailer: MessagingEngine.com Webmail Interface -User-Agent: Cyrus-JMAP/3.3.0-355-g3ece53b-fm-20200922.004-g3ece53b9 -Mime-Version: 1.0 -Message-Id: <4f4614f5-23dc-4263-b506-c557588232b2@www.fastmail.com> -Date: Mon, 28 Sep 2020 01:34:48 +0200 -From: FireFly -To: depot@tazj.in -Subject: [PATCH] feat(tvl-slapd): add firefly -Content-Type: multipart/mixed; - boundary=07c9605219da4b40b95ea5a855089bfa -X-Original-Sender: firefly@firefly.nu -X-Original-Authentication-Results: mx.google.com; dkim=pass - header.i=@firefly.nu header.s=fm2 header.b=P5Ezbo3T; dkim=pass - header.i=@messagingengine.com header.s=fm3 header.b=pHVhf6X0; - spf=neutral (google.com: 64.147.123.21 is neither permitted nor denied - by best guess record for domain of firefly@firefly.nu) smtp.mailfrom=firefly@firefly.nu -Precedence: list -Mailing-list: list depot@tazj.in; contact depot+owners@tazj.in -List-ID: -X-Spam-Checked-In-Group: depot@tazj.in -X-Google-Group-Id: 728837484537 -List-Post: , -List-Help: , -List-Archive: -List-Subscribe: , -List-Unsubscribe: , - - ---07c9605219da4b40b95ea5a855089bfa -Content-Type: text/plain; charset="UTF-8" - -Adding an account for myself - - ---07c9605219da4b40b95ea5a855089bfa -Content-Disposition: attachment;filename="0001-feat-tvl-slapd-add-firefly.patch" -Content-Type: application/octet-stream; name="0001-feat-tvl-slapd-add-firefly.patch" -Content-Transfer-Encoding: BASE64 - -RnJvbSA4ZDNiNmI5NWQ0Y2RlMDNmM2I2MjQzZmYyYWJhYmQ0YTEzNDhjZmUzIE1vbiBTZXAg -MTcgMDA6MDA6MDAgMjAwMQpGcm9tOiA9P1VURi04P3E/Sm9uYXM9MjBIPUMzPUI2Z2x1bmQ/ -PSA8ZmlyZWZseUBmaXJlZmx5Lm51PgpEYXRlOiBNb24sIDI4IFNlcCAyMDIwIDAxOjI4OjI5 -ICswMjAwClN1YmplY3Q6IFtQQVRDSF0gZmVhdCh0dmwtc2xhcGQpOiBhZGQgZmlyZWZseQoK -LS0tCiBvcHMvbml4b3MvdHZsLXNsYXBkL2RlZmF1bHQubml4IHwgNSArKysrKwogMSBmaWxl -IGNoYW5nZWQsIDUgaW5zZXJ0aW9ucygrKQoKZGlmZiAtLWdpdCBhL29wcy9uaXhvcy90dmwt -c2xhcGQvZGVmYXVsdC5uaXggYi9vcHMvbml4b3MvdHZsLXNsYXBkL2RlZmF1bHQubml4Cmlu -ZGV4IDQyMGU4ZTE5Ni4uMzk3N2ZjNzkyIDEwMDY0NAotLS0gYS9vcHMvbml4b3MvdHZsLXNs -YXBkL2RlZmF1bHQubml4CisrKyBiL29wcy9uaXhvcy90dmwtc2xhcGQvZGVmYXVsdC5uaXgK -QEAgLTYwLDYgKzYwLDExIEBAIGxldAogICAgICAgZW1haWwgPSAiZXRhQHRoZXRhLmV1Lm9y -ZyI7CiAgICAgICBwYXNzd29yZCA9ICJ7U1NIQX1zT1I1eHppN0xmdjM3NlhHUUE4SGY2anlo -VHZvMFhZYyI7CiAgICAgfQorICAgIHsKKyAgICAgIHVzZXJuYW1lID0gImZpcmVmbHkiOwor -ICAgICAgZW1haWwgPSAiZmlyZWZseUBmaXJlZmx5Lm51IjsKKyAgICAgIHBhc3N3b3JkID0g -IntBUkdPTjJ9JGFyZ29uMmlkJHY9MTkkbT02NTUzNix0PTIscD0xJFJZVlZrRm9pM0ExeVlr -SThKMnpVd2ckR1VFUnZnSHZVOFNHalFtaWxESkdadTUwaFlSQUh3K2VqdHVMK1NreWdzOCI7 -CisgICAgfQogICAgIHsKICAgICAgIHVzZXJuYW1lID0gImdsaXR0ZXJzaGFyayI7CiAgICAg -ICBlbWFpbCA9ICJncmZuQGd3cy5meWkiOwotLSAKMi4yNS4xCgo= - ---07c9605219da4b40b95ea5a855089bfa-- - diff --git a/third_party/lisp/mime4cl/test/samples/mail-note-from-notemap.msg b/third_party/lisp/mime4cl/test/samples/mail-note-from-notemap.msg deleted file mode 100644 index 2f74313b1..000000000 --- a/third_party/lisp/mime4cl/test/samples/mail-note-from-notemap.msg +++ /dev/null @@ -1,13 +0,0 @@ -From: -Date: Wed, 25 Dec 2024 23:54:39 +0100 -X-Universally-Unique-Identifier: d2ccdc74-830c-41ee-9d64-2221f1c35449 -X-Uniform-Type-Identifier: com.apple.mail-note -X-Mailer: notemap -MIME-Version: 1.0 -Content-Type: text/plain; charset="utf-8" -Content-Transfer-Encoding: quoted-printable -Subject: =?utf-8?Q?test.txt?= -X-TUID: clxSN23/djqG - -gr=C3=BC=C3=9Fe from notemap - diff --git a/third_party/lisp/mime4cl/test/samples/mail-note-from-notes-app.msg b/third_party/lisp/mime4cl/test/samples/mail-note-from-notes-app.msg deleted file mode 100644 index 577fceb21..000000000 --- a/third_party/lisp/mime4cl/test/samples/mail-note-from-notes-app.msg +++ /dev/null @@ -1,338 +0,0 @@ -Content-Type: multipart/related; - type="text/html"; - boundary=Apple-Mail-89556518-7D3B-49E6-BE3B-A3267CB0D688 -Content-Transfer-Encoding: 7bit -From: sternenseemann -X-Uniform-Type-Identifier: com.apple.mail-note -Mime-Version: 1.0 (iOS/17.6.1 \(21G93\) dataaccessd/1.0) -Date: Fri, 22 Nov 2024 12:49:56 +0100 -X-Mail-Created-Date: Fri, 22 Nov 2024 12:49:52 +0100 -Subject: example note -X-Universally-Unique-Identifier: D81CB91D-C210-46B1-835A-6A7C34DB666B -Message-Id: <2CF676DC-A86B-433A-8DB5-53D547D415F3@systemli.org> -X-TUID: GhgIofLgzNSd - - ---Apple-Mail-89556518-7D3B-49E6-BE3B-A3267CB0D688 -Content-Type: text/html; - charset=utf-8 -Content-Transfer-Encoding: quoted-printable - -
    example note

    bold italic bold & italic= - strikethrough

    = -

    It is technically possible= - to create arbitrary (?) HTML markup via copy & paste from e.g. a browse= -r. Let=E2=80=99s not test that for now.
    = - ---Apple-Mail-89556518-7D3B-49E6-BE3B-A3267CB0D688 -Content-Type: image/jpeg; - name=IMG_1637.JPG; - x-apple-part-url="C457B697-405B-4A9D-9419-AC33C4A20638@mobilenotes.apple.com" -Content-Disposition: inline; - filename=IMG_1637.JPG -Content-Transfer-Encoding: base64 -Content-Id: - -/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU -FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgo -KCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAEsASwDAREA -AhEBAxEB/8QAHAAAAgMBAQEBAAAAAAAAAAAABAUCAwYBBwAI/8QAOhAAAQQBBAEDAwIFAgQGAwAA -AQACAxEEBRIhMUEGE1EiYXEUMgcjQoGRUqEIFSSxFiUzYtHxNEPB/8QAGwEAAgMBAQEAAAAAAAAA -AAAAAgMAAQQFBgf/xAApEQADAAICAgEEAwEBAAMAAAAAAQIDERIhBDFBBRMiUTJhcRRCgZGh/9oA -DAMBAAIRAxEAPwDGNbws7g6U0TaCOktyHyLWlUQkHfKohIFUWju5VoIk0q9bITFqkV7O2pohwlWW -USKmQEl5tRIv0DSDgqwWBTMsFWAATRd8KFMBlj7UKBXs7V7LKxG53QVpFNnxx3V0UaQpg0uOR4TZ -E0AzR0eESFsHPaIA4oQ+UIdChC+F9FU0WhljPS6RohjbEelND0xxhn6gqSLH2EeQpxK2abTSAAr4 -g7NDidBVxAbGcDkaQDYzxqTEgGwwCwjSF7KMigCiSIK8gXavgTYueCHFTgFyPMI+UNSapZYAlNDE -zh7SKWmEjrShLOgqMJdE2AuNAWVNF70H4uBJJ2FakB2M4dIJHLUXADmdfpJAP0qcSuYBkae9gNBC -5DmhZM1zCQ4FB/oxPYI/m1EwisstWAyiRnasFgcsffChQK7Fc88BWkC3omzS9w5CJSDyLm6a1g5C -YpAbKZsVrRYCPQOxZkwDyFaAYpyoaJ4VoVQrmjq0QJQoQ+pQh8FCE2GioQNxn9JbGwxxhuSx6eh5 -huoAolJNjzBk5CviTZosCYAK1IDZocOfjtXxAbGmPKFakF0M8fIaPIRqQGwj9a35CJIrZTLlNffK -YpB2AzSjnlGpA5AbpBZso+BaZ5jGeVnpG2WXD8pNINUccs9DURBSgyUbS91DyoVsfaXgg0aTJkCq -NTp+nih9KYpFuhxDgtA6RJC+RKTAaR0r0TkxVnaaNp4QOQ1Rl9VwKBG1LcjZozE8RjcQUr0PT2Vg -cKFEHNUBD9A9Nal6gy/Y0vGdKR+554Yz8lHEOhN5FHs9N0f+DIEbXanqdPrlmOzgf3KcolGd5aYf -k/wf08s/6fUslj/l7WuCL8f0V9yjFepv4daxo8T5omszcZvJdD+4D7t/+FalP0yfd/aPP8iO7pQL -YNj6Rm6g8swsSaY3/S00P7obuY/k9C6yTPtjI/ww9QTvIMUMY22C5/Z+Fkf1DBPuhLy/pGI9Temd -T0SV7M/FewN7e0Et/wArXizRlW4eypyJiXTNMzdVzW4mmYk+Xkv/AGxQsLnH/Cckw20vZ6fov/D9 -601CJsuW3A00OF7cia3j8hoNKdL2yt0/SDs//hz9VwQl+NnaTlOAvYJHMJ/uRSicfv8A/Cbv9Hmv -qf0jrvpXIEWv6ZPh7jTXuFxv/DhwVfHra7RFab18iqA8pTGwN8R3IQpD9jvFdwERNjnCdRCtIEd4 -stBGkC3obYuXXlGoFNjCPUNvlGoA5Ejqp8OTZxguiQ1UjyjWMDmWR6oD5RKAeRGTUb8olIOyk5bi -btFxJsxDHBYmjoSy0PSKGI+L1mv2Ol9HA4JWhiYy0uMOdaKUBTNfpcA44TUhTZp8KKgKCMBsaRx0 -FYJ1zOFCAOVGC08KFpmZ1eAbTwgpDJZidUion8pLQ+WKWuo0UrQex36U0KX1Dq8eHEdkf7pZK/Yw -efyiieT0KyXwWz9F6BpuJo+nxYmBE2OFgrgcuPyfkrXrrSMLbfbM5/En+JGk+hceE57ZcnLnsxY0 -NbiB2STwApp/AJidA/4hdAzppGaxg5emNAtkn/rNd9jt5BVPkvgs1Wg/xV9JeodSi07TtSJy5uI2 -SxOj3n4BPn7IW9e0WCepPR2kSZztSONTruRjOGk/NLJ5mbJjxuoFXtLr0SxhHBDsx2NiYOg0Va8n -l8m7e2xKZ97hAdudaz8yciP6VmpPjw3MjmjmO17JBYr5WvxKusimHpkS59G09K+ltH9NQSN0jBgx -nym5ZGNAc8/c/H2XtI2pSfY+ImfRXjetvTWVqMuDja7pz8uNxY6L3gCD5HPam9ew/wDBs7Lh90R+ -9F7juQzeNx/AtXtfsvsB1rAw9VwZsLUcaLJxpBtfFK2wUSbntAtKlpn5M/i9/Dp3ozU25Wnb5NEy -XVGXcuhd3scfj4KJ6rtEjcvizF4h6Qo0f0O8PwrZSHOM7gIpIMoZaCZKF0wls5HSdKFs6cogclNS -FHG5V9nlMQLRIZZ+USB0TZlG+CiRWtBbMmgi1oE7+q+6ohl3S7fKwX0b5Z0T/dZaY6ToltZ6HyTZ -JZ/ugCHukO5HKOQKNrpNEBMQs1OEOEaFjBo4VlHxHChAPJH0lUQzOrftchY2TD6s4AuSmOkzj5Kk -ItKYaez2b+DeGyDRZc1wHu5MlA/+1vFf5tPxLox5629HpjJQGWSAmiD8ffxw1/G9S/xCyZdKkfkw -QxsxWOAsOc2920fFo0Dv5M76L9MZ3qb1Fi6biwShr5B70mwgRsv6iT44VNa9lcl8H6X0b+EfpTRN -Sxs7Fx8l+TjPEkbpZy4Bw6NIKra1onH5bNTrOWPbdED9Tu/sFw/qflLHDxr2wboQOmt5Deh4XmG9 -mfZCV4aAOfsAh0Rsnp+Q2HLZILa5pHadht47VfovHWmehY+SzJxgQQWvFEL3HjZVkhWjX7R+df4s -/wAGcDRdH1DXtAy5mwY7fdkxJhv43c7Xd+fK2LVfHYDVT89HhrczIbK2Vs8wkb+1/uHcPwb4QaQx -H6r/AIDeqc/1F6Kf/wA1ldPk4U5x/ef+6RtAi/kjq0tTxbSLNF610qD1B6ez9NyWhzZ4yGk/0vHL -T/Y0il8WRraPyBEx0Mr4pRUjHFjh8EGio1roanvsb4b+KVljfGeikgfG5MkWyTpaCdIplLp/umbB -SKnZP3Rpk0cbl+LVpk4l0M5BslNlg0gsZnHaJsWpIjLKXyL0xQ6W1lyI1QViQhYbNEssbLwkMamW -Mm5HKrQWx7o8/wBQ5RJAM3ejztAaLTJYt9Gu0+UEBGLY2ZRaoUmcJ4UILs6UBpULRk9YyBRQsZKM -HrM1udt5PwlManoWaVpuZquRtxonbb5fX0hZ8mSca3TBvNML+z3L0axmnaPjYbHbhEKv5Np3i5Vl -x8kZOfPsd61E/VNBz8GGcwS5MD4myjthIq1pQL7Wked/wg/hnH6SfNn6ycfJ1Q2yMs5bGz7X5Ktv -9Arv2eoh0MG58bI2buXFrQL/ACgu9LbZOkKs/VxtLYDf/uXn/M+qruMX/wBi6yfoTSTlznE9/c9r -z13VvdCeX7KhKCdoFuJ/whK2n0V+40kgP68eQrSK2ilz4y0ubIS4/wBqRaYL0/ka6HrL8GcQykuh -d5+F1fp/mPA9V/Ediya/FmqzRj6jgT42Q0S42RGY3tPTmkUQvV47T1SND7Wj88+tf4Js0rSdQ1HR -dSlyP07DK3GljG4tHYDh2QE5NV6B25Wxp/w1a8x2i6ppDmgSQSjIa7/W1/Bv8Ef7pT6ocesZOWKP -Kplo/J3qXa31Tq4jrb+qkqvyrYUetHMVyiYY2xZOBaJFMZRP4TpYpn0nIKYmVoElNAokUlsEdIfl -GmQgJVNloujyKVqimgmOYu8q3ZXEJYbag5l8RVuV0iI+32slyNmtHN6zVOhyo6JEAexvpmRtrlWg -Wa7Ss+q5Vp6BZsNL1IULKLYDNDj6g3b2ESYBKbUG7ewFeyIQanqQFi0Ow0Y/V9RsOooRiF2i6Lka -1P7+/wBrFYeXkcu+wWPyfKnCu/YrLmULSN3FBDhYrcXDbsjaKvyfuV53N5FZa2zm3kdE9Lyjib2z -uobraV0/p/lzjnhQeHJpaY9j1rGY36pmhdGvPwyvY15pXyVzeoWCxBG57h5PAWHL9YldY0IryUvS -FztQycskzS7WXw1poLjeR5uXN/JiHmqyLZAGENIFFYtEVaIiZt7SdtjvpTROR8x5a3+Q0Ob5JNWq -0n7IuvQLM/3JAXEscf8ASOSmSin2+yl7wxr9pa5zubIpGlsr16Iske8tIkcQD2R2r6RW2xpp2vS4 -ThHKXPivmx1+F0fC8ysL0/4j8efXVD4ahFmY7tjg9jgQR9vgr0eDyZyrcs1qlS6Md6a9K6R6Syc6 -fS/c9zKPJkde1t3tH2Tm9vYcrQwzM80QCNx4AKVdqVyYW9LZ+cfUOBnafreWNRicySSVz9xHDrN2 -EUWrXKQcV8kRxTwi+R6Y1xjwAiRTYxhdwmoWwjwmIoEyW8GkxEF0qsoHLqJUYSOsfZq0OwmHY1ml -TZXQ2jjJYg2TQmcwrQ2AUuBFlKrstFe/tZ6Q2WfNebWdocmHYcm0hCUx3hZZbXKhTY/wdRI/qKmw -GOYtXcB+5RMrRN2rkj9yLkCJ9S1IuaTuVbDnor9OaadWndkZdjDjPN/1n4WTyvJWFf2Bly8Fo2jp -I2MbDjMEUbRQaPC87kyVkrlRzqp0z7c2vqI5+6zsW9FbwCCQTt65VJimVMaxpFtHavbBSQQ0tcSH -gCuqS3ssmDQduPFfhCQkXtcG7mk3zY5V6D6CCQ4bHNFn57IQjHp9AzxI2N7WycAbWgcIl/YtppaB -H5BbbX1vApvZNpin9Fb/AGCTyujFtYZPG74TJlP5Kb0QGQfbaWij1+EXAm/lE/r2bi4WVSa9FNP2 -Rimkx3gta9pPJIPB/KbFue5YUZKk67UJn2Ht/BXSxedU/wAuzTHkNewGWeWSYEHgKZ/L+7LQbzcu -j71HokfqfSPYkLW5kYuGQ/Pwfsl+H5f2K4v0yppy9o8gztOytIzn4mfH7crf8H7heiila3L2jXGT -kgjHcCmJBbGML0aBCg7hNSKbK3t3ApiRWwKZh5V6K2BSMPwpovZ9HHRVaL2NcGOyhaL2PIoxsCWQ -VPxDXSJ2HxBZcavCB0TiATQ7SaQt7LU6BzYNpFIbIRjuSvQTGWPIbUFtjTHlKoHYwglJHJVEZa6Q -gdqESAX75pWxsBLnGgFG9LbI+ls2DZo9Mx4cODtgt3PnyuB5Dea2zn5L5UT/AFW8h18/YrLw0JYV -FJfAIpx7PaTSAZfvbYDrLbrlBoAvYQTwe/HhBpk9Em8VRAvzSFlI+c2QHl1x+QfKpaL0ywObGeAA -P6la7DWl6Ivl5LqkIPYvhTRXJFT5OC4t2A8NDueUSRNlLngt3e5Z/FfmkSTIDSvdW2mgfYdo5SKI -OPA2ta9hHZ7tEiejhkLaNEg8UOVetlM7IJC3a2vlRaXZegZwJcA4cDx8FMTIV0eTXB+EWwkwzEPQ -B2mkuhssjruj4fqDFDMljP1MYIjlqjf3+y2+H5lYHxfoNbXaPIM3BydLzZMbMiMcjDXI4P4Xqoqb -XKX0aYtUi2BxTUgw6I2EyRbLgLCaimyiZnBRJA7Anx2VNE5HzIubVaJyGOEKKCkEmOI3DalBpnZI -e1l57NjkClg74U5A6F2TBVqkyaFczKtU2EuipjtpSmgtbGWIdygprQyhdtVAhTJgPKomz52RfCss -L0c/+YwO22d3+EvKvwYF/wASrXNQEepSOcSPqpcyI2ujl77Gunz+5GxwP0u8/Kz5I0E0OceUActv -nwelluRbQbHkhrQGinXXKQ5B6QTE8BzQ1u49kpbRX9IvaWhp22B2a8oGiyRedtteOj32VWiI+BLx -9Rpo4JU9E/0+c1pLm0b7+ocKIrWwR7zG3a4AlxNkE8//AAmrsm9AxkhY/bJY3dDv/wCkaTa6Iml0 -QdJ9UrKIo2Cf9lanXZN/BzGssDHEcknnwpXT2ipLNmx4G4WR0q3tF6Kw0R9vJB5B+EXstLRW973N -HuOb+2wa7RJL4LKwQG7h31SItE2S7b3NAcOaVcQ5JsnaAXA/5U47DQn9b4h1XSTLCwHIxvqLvJbX -K7H0rO4r7den6Cl6ezzrF/a2/K9KjSMYekaBZeOkaKK5OQiTB0U+3yrTA0dDKKvZWiyO2lKYyVoO -jf8ASlMah66H7Ll8zpuQaWDg8K+QHAWZUPB4VqiuIkyoKtXyC4gQj5U2RSXxOMbvpQbLqU0HxTAh -GZqnRbvU0Douh5U0WMcAluTEQaN+Eu10y6X4sF9T47pMkjbxdrnw+LZxsm1RToudJC8xOugKaSel -WWE1sKL30zT4eTe0AgOI55WO4JSGmPlNPEgBrgWO1lqP0Kf9hUZY0jcCAejaW0CGQOaWUx4sc7fs -k0v6CSRZK8jaTd+eOEGgafyXQutp9oEj7+EL/stPforkLre4j7Hbzf4RInfsGmDASCC93FfY/BTJ -2RorO4MeZY4w1F/jKS/ZV9JprWbneSeKRafyXolTC4GSi7+lo4v8qv8AC1/ZH3IX9h7QB3Xn7K+L -RfRVJI0NDGua4E3yfCOZftlr0BTPp7gBuZd0T4TUiaKZpXDcWOAaK7RqQkgd+QN+4Sso8do1CDS0 -UZOosjbZkIoc2Uc49hqT7TdQOR7wa+2e27dzwOE7Hj45J/0v+jz6Ke5jyCAaFfFr08s0L0M8Z9gI -09EaDG9I0wWfbUW9lHA2iiK0d2qFaKyKVFosY4gIOIWzdug+y82sh3KkHlxvkJisU0K8rGNnhGqK -0JcrHqxSNMJC2SCiVNhaB3NIKLZWjjX7UcibktZLyjEPoNgk4CmgQ+CbY5rvgoGhjW1oL1Efqomy -ji+CuZmnhbOR5EcbYDFjBjXHsn7IHWxEy12XtndjuHuC2/KrXL0NVL5GmJnNfzdivHJSKx6KqBpB -mAxhocTRJqlnrE0xfEMx8gNstFkf5CTUMoMxstgc4Bu/nk/n7JNY2Ugg5LSQGAg1y7oBB9t/Jf8A -hKTbtG6QNbX7uLKilr4LckZ3MazayncXfyimWMc6QHPIJGcOPH+yZMtfAGil8zYmkFzrNHjhEpbZ -XoqnytzQ179wN0apHON/BF37B3ZTm7trw55+fKZ9sLQDNl1I5zYg0n/BTJjrsiSBcieQgAnaf9Xf -PwmzCGKRZlZzY4ntmmAI4vpOnHv0MmRDna+WB7MYOe8/t44WiMG/YWkhbB+vz5WjIJ23yE58Ma6E -1kRrMdn6DRc2TadohI/ykYd3mRMfezB4klVS7qZuHOJL0EeyDaCSwiTB0FMFokyHxaiTB0QIpEmV -ordShCNqEPVX4/a8eqPRMGlhFJs0JaF+TjjaUxMHQizMerTEyaE2TFtJTU9hCydtEogdgjjRKZPo -CiG8hMSM9BWPPQ5KvQpsKblgeeFXEJUPNJlZlYMo9wFzT+3yFg8yfTMfkrfoldErCZCEga4Dd0VF -0XrYLNA4cwuc0/ZGq/ZW2vRT/wA1nwzUjHFtdjlGsSr0Emmdb6txg4bpQx279pscKv8Akp+kGsLp -dBsPqnEe4e3O3f2Wl3aW/FrXoH7DXwHf+JGua57ZWhod9Vm9o+Er/k09aB+1X6Kf/EjXEf8AUtG4 -V+6wCj/5f6DWKkEO9SODuQXfTQFjlV/zIvi2QOulzpS4At45a6j/AHU/59egXDPhrLHWBKCQKBq1 -Psa+AeAKNTbKeZbA7aQQD+Ef2tEUnBqNsftDG0eyVPthKQaTWGgbHPaXM+D2iWJlqV8lHvZU73GO -MtaSCC4dotSvZfJJFb9DdNKH5LySea8BWs3FaRSotj0OBpaQ2/hV95sXVDGDBYwhwH+PCU8jFeyj -1G4x6DLC1p3SuDLHwt30/HyyOhvP7aRgm4roz5Xa4GiM6YXjlzDyqa0PTQ1xpuO0SLGUMnHaJPRW -i4mwrRWit5pFsrRQ9yvZTK9yvZR7PK3ul4zZ6PQLIzgo5YDQuyR2nSU0J8uMm6CdIIkzYSAVoiQK -ehJltIuwmaA2KZ30eEaBbBny8dpqRnplDspwNAo0hFMujyD5KporYx0jPGJmxyOd9F078JWXHzlo -ldo1cz2k72kFjuRXlcSpcvRiudAz5TXflTREThmaGhrnclU0FrZJ8cUo5I5UVNCnAp1D0/BkB1sF -1xY5T4ztewoyVD2mZjO9NSxEuic6vC1z5G/Zvx+ZNdWhRNp+TFYIcQe6J5TZzSzoRhnKt42mCuhl -joHeK656Rq5foqvGufaLn5mY6ryZTQoEu5UUz+hX2f6OMy8xj9zJ5AartRzD+Cvsh2HNrGQ8CB0r -yPJbwl0sKXYjIscfyY/xtH1ueTfkZpjujTT0s9ZsU9JGOs0/CHGP6dfJ/wDmZWRK6/ngrPXkL/yh -Ltv0N8bTMPGmDWMAdXZHaRWS32VthrGNja4NcK6BQb2WkR3t2tHBJ8qF6PmlocR2ALtQW/0XBvgd -HpAuySu9AetxNkjijLHb2/4Xo/p2Hhj2/ky+Rk29IRSYIPQXTSAx5GgKXE2+FHBvxZSijGfslOdG -2b2G48v3QphhzJLCJEPnlWCDPKtAspLjaso9zI7XjkejBph4CJEF8zOzS0QgWLclva1xIlibNaOV -plCaZndQaBaapFcjPZgomlfEp2LXuKiQqmUOKYhRwSEdKtFEvfI6KrRaZsfRmQ/OxZsdxv2uW2ud -5mNL8hWRJjBzSNzSKr4WAztaAHOd7liiUxLopMIjyXMA5BQuRnsJjzRe6uevsgcAuQzHfHMGFw4P -j/uhe16FVGgj/lunvbUgp5HIrhAstr0AnU9yCSeldOkc6nOHkUUX/RSOjh+r+ViWt7X9g0nozTmk -OLnObXN0Fa8nIzavrtOXvFO//kux/TmkQkPbjscfIcbVvNkfyc/J9Rz5et6/xBQigha4RBjABwCO -v7IVTfsyNOvZX+shjHNUDV15V8GWp2Rfnje4RyFz+DzxQU4P5DWPRVNmM9wEEX5P3VqGEoKxkts7 -SSK/q8ouJetF8EoIOw9V4QNC2whrw5xFEPPKFoUw7TYTk5LGbi5t2QEzDHK0g59DPP09rrNcr1OL -paOfkjvYiy8EtsgLTKE6aFU8IN8co+JpxUK8mCr4QXBvx2BNcY314WVzo1qtoOgk47UCCN1jhGii -lysAhtV6Ie+PhscBeMTPSAj4O76TYWwGCT44ANcLXEi+Qlzoi0Fa4QFMQZpItaZkz2zO6i4fUmzJ -nqjO5ZslHxF72K5TylNEKHIkQrtUCcLlCGs/h3kbc6eLbe5nYWLzF+Gxdro004BLz07qlyzPvYtl -Yfb4RJgaAJHOZIK6TUtlqi6GTaa7+FTQxUXCaWOyCaHFBA0g1pk4NSDD/OsDsE9Knj36BcJhjdZj -dC+pi13G0tP/APEP2nsH7RWNQMxFSMvvdVWr4a+CfbKHai5p5kY7k2R2UXANYwZ2oF0290tkDkA+ -PhFw6C4Akmqhzy4sAaOA0+UaxvRfFFEmoGV30g8HhWo17J6CMaWWQMaBx5+yppIF1oYYjXAGMuN+ -DXKXXXYl0HxGSMiiLri0p6YDYSA94ElHcOwPKH+ika/0phtGPJkOFF3Db+F0vBx6XJodroaZMQIK -7uOTBkFGXAKPC0zIjRmc+La8kBNUhT0xPkssFDUmvG+hRPGSeFlqTZFaLsVhKBQM5jGOGwmKAXRx -8BHSjknNFPtkE2FWtBbP0CW8LxEnpWUPAWnGKaA52ggrZApibPioFaIFszOoxDnhaoYizIaq1wc6 -ulplGRiHJvm1bKTFs3ZSWWCPdZVbIVkqEIkqEH/oXIMWuMY3+tpBWbylvGwLRtMyxOfgeFxkYt6B -JSyRjgByPujXRafJAToW1ub2UaYIO54jJ+qyjXZEy1koIv8A2vtC0MmiD2NI6sflWnoYmCTx001y -PhEmEC7i3px/CPRaZB0r9wJI6VpIJMiS6+CQT9lEVsvxsZ8hd2fNqnWgHQdBhUQGndQ5HlBVCnQf -jYoaRZ4+6W6AbYdHGwuq+W+R8pbbKCQ0u4NO8UhBC8OJ80zI2h1P47UiOdKRsTtm3ilbBBHE2gGi -qC9Hix8UkbLjjOj79Ru7XQxz0crKuwXMeNhWmZEaMxqJBJpM4kSEkw7CFofPQI6MG0pyPVEoItpQ -8S1QxhaKRqSci0x8dIXJaoodHyeAg4oYqPc3tXgUeqKXMtaIAYPJDa2Y2JoWZ2O7YeFqQpmV1OMg -O4WiGJoyuoRfuJWmWZqRlNQG0lR0AJZ39pWy9AhdyoURJVohEuUIMvTEhZruIW9l9JOZbxsGvR6P -qLT7rvkrhmGxY+oJAeymrtAS9H0rfdi+kgEmyqXTD9+hbkN2vof2CciFVkv8UERC5ryyM8DlC0gk -zjnN+kE/lVoYmUzRgm2hWi9gbo7cWj8o0w0yyMfVT2nlQB9h0DhE2w6m/A5QMBhEcgsuYCHeeO0L -QDWvYRDK8hv0h18WULQIY1xsU3mr78pZC2KR7ydp4Hj7oS0h1olRSGaXgjrlb/p+LlfLXo1YZ72O -35LH8hwteijGFkopfltaDytcTo59rYHNmh4q0+ZM7TFeS7dZRNFpC6XspbGJlACriFstYxTgXsLg -bZU4kTCa4VNBIpc3k8JLQxNnuhYF8/UnrGRMQKfCFtlMkJAWmRbYuy4/pPCdN6BaRltVhH1cLROQ -FwYvWBt30mzexFwYzVfPyidCHJn5zZKmyaBSe0WwGRtWURJUIMPTji3W8Rw7EgS8v8WDXo9S1GxM -4CurXDMVoUzAAB/38o5FaIMeA4Du1ei09FeVFfIAoK5YYvc2nG6u0wjRAiSyXAj4CsmyuQuoOdyQ -aV6LTO+4f2nk0poNMp9wBx45+VehiPhJZtx4CmiaL2TDr7qtAtFzcza4bqJB8eUPEFyEiUknZdH6 -hfhVxB4hmNKH0S8uHlLa/QOguHbI4NcXNI6LfKDvY2JL5ssMcImO+lvkFej8DAseNfs1ytI+ZmvH -TiupOkLqdk3ZbnduR8hTxEWym7JTJsTWIk6S2lM5GdzoDlPJQllbDyrRTCYuQj0CFwhVoJMucQAl -UGigvFrO32PXo94FUvByesZNgCfIqjkjRSdLEtCvNaKKtMtIzGqtBDkSoNIw2tx/uTJoC56MJqwr -cnzWzLU6M5M7kpyFMFJRIW0RtECcUIF6M/ZqmM4nqQf90Frcsp+j1nUQDI0j+oDlcJrsxX7FeTQZ -RsopFMFLgwA+T8I12DoIY73mEWAfFodaGJgORFsPQryUyXssDeXOcTuJATEQrfTSdoJJ8qIsjQ3H -ca48KyFT2m6A/JV+g5og9p4DTZ/CtBqtkbkbY5FfCvoLaLI+Tuuz3+FTBYZjSe5vbuO4f4S30DxD -YOa+rk90UtlqWOMeIsx5Z7BAFA2mePHO+/g0Y429CppdZJ7K7qypG5eOyxshCtZxi8YuY8pk5Ni6 -w6L2PvorVNmS8ZMvsJ80Ybgoe4I9iGirfSnIriWRz15V8yuIU3L+6p2WoOuyrHKTdjpkoOQL5KzO -zRM9H6BikuqK8RJ6mkXgkeU9CWde/hNTFsWZrrBVbIkZjU3cFWmXrRitad+5Nkp+jz7W38uWmDNk -RmpXclaEZmDkqwDiJME6OVNlBmlQ+5qGM0juQIKfTZT9Hrme0AMFVTQuFT7Ziv2xNkGw5o5+6ORT -A3GuRVhNSIfNlILSOVHJCc1TRkV/hCuhksBfFtFcWPCYnsogWFw+lpAHZVkIytY26suPRtEmQi76 -iABQd2qLJuit1A2PFKi0z6OKHa7cSZK5CjbJtkPZIb7kTA1vwi3v2EmSbF7YZID33SHew0HYUW+T -mtvikqhi6NFPGI9E+BdI8GTTZu+nR9zKIiFqWZnoVgR8Aji2yVjSRawLbjZgyxouZwCtuNnOyyfF -y0yzn5EUSP7R8jK0DOk7QOy1BD3kHMNQSbMULsJQd98pVZBkyfCbjtZ3Y9T0fo2B4XlJ6PRUE7uO -E1CGVyPoco0ytC7KlFFWRIzeqPH1K5I/RhNfm2h6dIps881aXc5y04xGRiSTklaEZmUnsqwDrBah -EO/T/p/M1icMx4ztvlxCVkyzjW2D/h7H6W/h/g6TC2bNAlnq+Vyc/nOupLUa9i71DTct7WimjoJM -Pa2YMi/JmfnNMO0dlPkS0CPFkAA/dGiEXbnOAoAD4V6KTLW00gDm0Oi09HHR7pBYVp6QSZXIw39A -oeVaZNlBgJLRQAHm0XImybIS76Rt58nwpshBsZ2ubwNvG5TZZGMGFpkaQ49UrCRxzi4/S7h3d9KB -JbJwNFENu/hC2NlB+GNkgaG8nylv9kutdD/UmE4MEf8AcpuCNps7X0hcU6Fjcb7LTOI7P3DnsV4T -pxgVkObNtrVjnRjyUmQc6rWuDm5WUPkWiTn2CSydqqoQltgxkSKsdMkQ+7S3kDUnfcoIeYSkiZe0 -urDmdkw/jspDseoP0fG++ivPo7lBAkNJiQhlM05oqwUKsuegVaL2Z3VJ/pKNAUzCeoJtzXcrRCMt -0YPPNkrTC0JqtixwTUKZCrKIE0npT0xl6zkMLY3CC+XHyFlz+TOJf2T36PdND0rG0jFayFgDgOSA -vP5vIrJQaWgnLyHOa6ncpRGYvWyXPs/uW3F6Odk9iKQPeK4HynJ6ElUjKFWCTwjT2CVthdvF1Svl -0V0WRwnfVgUhddFIvfH1Zs/ZCmTZVKz6CG8FEmEmCuDP3ucCR2Aj7LKXbHPLmAj7WiSaL0UvlkHD -Q0t8q9BLRVujBcX7m/ZFoNI5CAHXdg+FTDSC2fQ3cfPhL9hb0htpcBmlb5c4igl29IT/ACZotRxJ -YfbEjTt2iiuh4jmo6PSeEljx6QE5gAW6ZNLsHkAopikU7Ap3gBMlGe66AZZeCnyjBkvYHJOm70Y2 -9gks1pF0XKKt3Payuhy0TYCg2Xs64EdIWEtFBeQaS2xspEg/4S9j0j9HMkLVxZR2aeyx2RQTpM9I -GmyO0XsS2KMzIHPKJTsW7M5qeUKKYpFuzFavKXFy0RJlyWZTLaS4p6QlPYA9p5RohpvQ3peTWsxs -szSMZh8jtY/L8lYp0vZaXI9x07BgwMdsWOwNAFceV528jt7Y3pFkjuDygRNgD5af9kxLoFmb12N7 -Hl7eWlacTWtGPND3tCM8jnsrQjIREdAniz0r2U0S27aLip/gOiTSwHolUWkdqgdrqtQmgeWwHtsV -8o0WAy7Q0tFE/KZJaBSANxLg6/nwjD0UtyHCIsaRSvQalIgS6QHcASVPRYRixiiHgtrzSGmGi+Bn -6iQBh+lqFviuxV1v0bL03jtdlNLm/s5WLNekOwTtm0mijzcZzHgXVBL8fyHhraOlNuTDarA/Cncx -/wC3wV6jDlnJPJG6L5oVyy9p6ZHIDPJ2mSzLk9C6eTtNVIw3Iull5KF2K4lQeXEpLeym9BcEe6lS -kU8qDGxcdKOQVkISRGktyOnIATNolJpGrHRBo4SGal6P0U6SvK5ak6DyEHTAikxSJrICSyd8pikz -1kFGdKADymKDO8hmNSmu6KbMi3ZmdQddp8oz3YjnZZKPQKoP9Menn6znBlEQtP1H5WfPn+1O/kZP -5HtekaZBpmIyDHaAAKJC87mzPJW2PS0FzTRxNJfI0AfJSVLr0WLjqmJNKYYpWuf8Apn2qS20DtP0 -VPHJKJFFMsTJmFrhYPyiTaBa2ZrUtLfC9z47LP8AstOPLvpmPJia7QAxwIIPYTNGf+jkkoFANHCt -LZCPutoloN1/ur4kQO+SR/JcWtHaNJL0WCOnLfca362lFxLSA5JyGbSAAjSGJA5lAtpH90Wg0iIe -KIoflTReibHChzRCpomgqFxmcGMuj2UOtdg1WhzpuM4PDYxZ+UjJX7BmHTNlpEf6dv1VuPaw5Hs3 -4p4odRTBpuwElodvYF6lwxmYBkYPraLXT+neRxrgxmO3FHneQ8sJabBHBXeWQ6bjktoXyzXaJZDP -eMCmfdolZjudAcnKvlsx00i/EgLz0U2I2c3Pn09DvFw+BwnKDJ94NbiGukLgucxCbF4NhLcDpyif -KgolZsknQw5NgoYsr6OpHo9zlmryuepG1kApMrbfKdMGesgLNn8dpqgQ8gnzcuweUagS8iEGXMCT -ymqRNZBPlO3GgjU6EO9nNM0qfVMoQwMJs8muAl5Mk41tjMe6fR61oOkY3p/TQJS1rq+olee8jNWa -ujfKUIznqT1u2FzoNNb7j+rCZh8NvuxN50vRk5H6rqj9+RkPDCf2g0ti+3j9IyVnb+TXekNGbhNf -O63SP8uWLycvN6NHjp62zRSCisqNGyqkRDpjEjSCAVChRmaC2V5fC7Yfik2czXsReFP0L5/T2du/ -lNDgOyCmLyY+RLwUL8rR85l3A8H5ATZzQ/kB4qXwLptOyWE+7vr4Caskv0Dp/oCODO3cAx1fhHzk -LYLJiy7iCDSYqRarRB+BJX0tNKLIvkJWcZpuQ8GmOKjyyguWxhhen8qY2WOr8JdeRKL41Xo0ulen -BHt97iu1lyeQ36CnD+x62GOBpbGxo+9LPtv2aZlLpFsDSTyUNBoF9RxZJwvdw5C2WPmh5RYHPLVA -ZG0to76V9R/qGDHz2bXdG+im5fHcPnBMOXmS9TekzlRnK043fNDytOHzNrjR1PG8nh+NHnWbiz4s -ro8iNzHD5C6GO+Xo0ZLmltAbwVpk5mWtEY4dzrK1Y42zj+RmSQ60+AUKC2xOkcTJe2PsaEbbpGkI -d6CxHx0qckWQpmiaWmkFSOjIxDnx04rHkk6/i2KyzkrC12d3G/xPVZ8jvlZpgz1lF2RkjnlNmTNW -UWT5NXymKDPWUV5OV90yYEPKLpJDIabyT8ItJA8mxro/pbO1FzXbCyP5Ky5vKjGntjIjZ6Bpult0 -TG2Y8QdLXJXEzeT917bNquca1Ih9Q4uoZocHyuDD2ArxZMciMmZsR43p9kBsgOPyU2vI5ejI72Mc -bFG8MDezSS7JG6ejUwRiKANA6Cyt7ezryuK0RfZ5KgZFoDvsrIWtYWi+wq2UWxt44QtlFwNISEXf -Ua/p+FaRCBZE0csYT9wrK0DyRYz/AN0TP7BEtomkUHCwSDcLCPwi5V+ycUc/RYV22Bn9gpyr9k0i -Yx8dgpkTB/ZVtv5LRFwaCQ0AK0WUE90iLREgk2BwoWWRtpC3sIte0OaWnkEKl0VraM27BazMc39t -mwVvx5euzAreKx/puXqOnt+giWL/AElDeHHb2no2/wDRNLaBdYy8DVmujy8cRSnyRx/lNxK8Xp7C -nOYfVtElxXOfD/Mh/wB12MGab9+zNnyUlsBxYHPdVLrY4OFlybNDgYtAcLTMGSmOYYeOkxSZqZN0 -dBC5KQHlP2NKTZrxoQ5bg4m1iyHW8ZaYtdwT0sVLs72N/iaybPdygmTkVlF0+eeeU1SId7Fk+aSe -Cj6QvtkcSOfOnbFAwvc4+EF5FK2y+J6J6c9IMxmNmzgC+rAK4nl/Ul6gep0ts1MbxCzZGNrfFLhX -ldvsB2VSSu2kHlLQt2xblvLrACdAp2xXI0tLiVplgp6OadBvyy/sNRU9LRt8Sd1scutL2dQjW4G1 -N6IZ71PrLdNxi2P6sh3DWhavHwvI9v0BdqUOdAMkmk47pj/Mc2ys+bStpBJ7Qwazm7SiI64hvRUR -CJN8hEiA0pvgIkiFFHxavZDrWdk3ShCVEDgKFnSCOyoQHeOT5RIhACnWTwr2Whfrept0xkMjwPac -/afsmYsbybROWhpjyRzwtfGba4WCkNNPTDRZtofKogu1GKnNeO7TYrRg8uGvyCcBziKJ4QXejEno -KdpEWawiSrPlDHmPGxs1/YsyfT+djteIT7sFdHwux4vm4LpcumXeW+LQhh018UrhKza6+qXscDm1 -+LOPextj4wHgLUpE6YbHEAFegKgryAACUFIqIEOou5KyZDbikzuVLTisORnWwQCGSzyVjfZ2Ynoe -zyE2q5HH+0wGZpPYV8i1hGmg+mMnVJA5zSyG/wBxCy5/LnCuwWkukelaTpGDpMDWQxtdIO3UvP8A -kebeX5BbSDnyFwsu4XPdNi2ykmxyQQq2CyqQNrgqIFpAMgbzuKfO/gVoSZ+UGWByteKN+yhtosQG -L7hFOcl5X+Wjr+LHGNhxZXfSBM1CP1FrMWmxFjCHZDuGtHytODC7e36F3ahGKix5snKE2Yd8j3D+ -3Phb6tTOpMLyOq7PT8Rojx42tFU0Bciu2dBeiTjd8qIsqJvtWQB1nVIdLw3TzuFDigm4sTyPSKb0 -WYr/ANRDHLZ2uFoX09Fl+37ISH1dqyHA0VyoQW4eqY+a+dsDwXRO2kX5TaxOPZE9lt8qizlW7lTe -izP+toRPpOzv6lp8StWJzVqTNelPUUulZH6PNJdATTXE9LT5PjrJ+U+yYsnwekxTCaIPicHNIsEL -lNaemaF6KspnuQOB7Vy+xWaeUNC/FyS223RHCOoOJW0x3gZLy7kmljyQkXLY8je/bx58LOnpjlTI -5GBDkMJexokPkLqeD9Vy+NXvoq8c2vQlnwnQOIIsDyvoPhfUMflQmn2YKwuegZ5DV0CvtbF+dMKK -XRFi0ZnUp/3UsWWjZixmdyHFziudko6eCCobq6WRs6kLo1BhLjQFkpfIxcNGk9P+nRI4T5rajHIB -XP8AK81QtT7MuTIvSNhE9kEftQtDYxwKXBy5Kt7Zkdg8kwbZBtAk2JdFIzWBp3nyi+036B5i/P12 -DGaaIJ+LT8fiui+2JZvVrN1AgBap8EZONsHPqNryfIRrxdEeJopjyG5mZExlkucjc8JbJjxcno3s -TRHE1oFUFzTrpaWhN6m12LS8Vw/dM7hrQtODA8jBu1CMPhQTZmX+qy3EudyL8LoVSieKOfkybe2O -Y46zMdgAP1DlZ2/xYGPukbcGmjmlz9HWIn8hEWVyOa1hLuAObVrso839WZTtVyXMjJMEXA57K6vj -ysS79mPLl3Wl8Gy9I5H6jQ4N5+to2lYfInjbNOOuUpji/wD7SAzhPdKEAtVyP02nzyn+lppMxzyp -IqnpNnk/prUn6Z6jJkcRFkO+q/krs+Rj+5i69oTis9V4LQWmweVxvRpPrIBUKE/qUj9C3dyNyfg/ -kI8j+JhNWxGvi3NFFdLFfejJFaGHo31C/FkGFluJYTTSfCR5Pjqvzk34r+Gegbw9oc08FcxLTHMz -edktxs9wcVrmHcnHzxxtjPH1mCCLc8274CS/GqnpCONA03ryOF5ZGAa45KJfTd+xix2H4PrRuRtD -uCSk5Pp/HegW6Xs0+NqMORF9VOB/2QYM2XxK3AfJUtMXalCGMMjf2L3/ANM+oz5WPt9irniZPPls -mjwuhkrQURsR5R3WuZls348YCYd3hc7JRuxwd/ThI2bZXR6Vo+jtiqfIaPsCuV5Pl6/GTk+Rm+EN -3ycbQKHgBcht17OXeQFkmc0OFq5lCHQHNkOo0e01QRdiTUc/aCC4CvhaseMOZ2ZfPynva5262/JW -+J0a8eLZl8jIeZDRNLVM6RsmUkX4mW9oIoqqhAXKZuP4fwmfJfO+yGcC1zvMelpFYI72bDW9Zi07 -Ec95G+vpb5JWHDheSjRdKVs89YMjVc85GTZs8D4XUfHHPFHPyZHTNFjwNjZ+FlqmzM3sswxv1SED -ocob/iP8ZbtGsDiO+lkOoSAUIZn1dqLoYhh47v50nf2C1+Nj2+TEZ8nGdGexcb24vqaCVoqts5vL -scej5yybKxncc7gEjyJ6VG7xa2mjUEnwO1k0ayVgd8KEM36zyQ3FZC3neefwtXiz3sz+RWlo801q -Hb/MjsEG11sT+GZ8dHoHozVP+YaSzcQZo/pcuZ5GPhZ0Je0PLAvlZwhXr4DsQA/Kbi9mfyP4mXmh -3MIrpbJrswJiDUMYwyb28G/C0y99D8dG09J6wcrHEErh7jB58rn+Ri4vaNuOt9AnqoXlRObwTxaZ -43poVmxqnsd6No0R0wucfcle27Pheo8DxcdY967OdkrjWkeb6vpz8fVpYzfdhYfJj7VtGiL3I50n -De1rXONLmZKM11s2OlZD4WFpcK+VzssJik9GgiyW5EPtO5BHCDxs1+Nk5yx8vktMxuvxuxMgtP7X -dL2uDy/+jGrG450JC7cUjJRvxosijtYqZrgIECWap9HpkmQXNr/ZeVa2zyl2DTzBgNdopkzt7FuT -mijQsj4T4x7K9iPM1C7BO1a8eLQyZbFbcabLkLgXe35JWj+KNePEKdckbG32mdBNxLfZplGdDC5x -K0jNh2LENvIQNme6PRfS2zTdFMrqBdyuV5G8mTSHY2pjbEGoTS6tnOfISGA/SFqiVjkyZMvNjbT4 -DAwUAfukXWzOw8UeyAfhK9Ak9Ibeq2OgOlWR/ia/FX57NLd9rMdEE1HMGFiyTSOAAHAR445vSKqu -K2YWD3c3LflZJLi43fwF0XqFxRy8t8ntjF+wMSUIYLhZH6bX4HNsNf8AQ5Hc8sbNXj1q0bsScfuW -A6RBz/v/ALKIhh/UOSJdSe1xsMFBdDBOpMGet1oQ5sTXQuB89LTD0xMvsH9HZx07VzC41HLwfyi8 -mPuRtfBvxUemUD+KXJNAq13nGbz/AFJuLpmfyP4iSVtNAsrSjAwDMxjK00mTQUsV6a9+DqLXA1zR -TMiVSaovRpNd/wCoiikabpZsPT0Ot+jVekpDJhNDjyBS9Z9JvcaOb5K7EXrbT2x5DMqMDvkpf1TB -+PNC8ddaBMJjXhpJFUvL2wbGUIAJDUlihniOI5BWekNlkdfxBm4Bc0fzWLd9P8l464P0zXjezFQt -O6j8rt09m+BlBF0k0jTDCvbCXo0p9GuklPzS8wpPH0wHInIs9gJ0yCI8/LLdxaaH2WuIGxOwjQ/T -2RqUwnmBbjjnnytkR0dTxvEb7foN172sKExQgAAeAlX2w8vT0jzbUT707j91ojpArpFEcNGyi5C6 -rYdixX0gpiKZo4pZZcJkR4a3wsrSVbBrK3PEIwsahuIBJQ1XwJb6GUQEbK7H2SH32CjhaOfKi2UE -+n4j+ulcTwAhyvo3eIu2x8baCSEjZvMP6mzn5+eMbH5ij/d9yuh48cJ5P5MWfJt6RLDxNsVk8kdK -qowtlvtiNv1H+1IE9gifVC6N7JRwGOBC0Y+00Nh6ezeYUwnxopG9OaCufS02jry9rZ9ky+3E9x4o -EqStsj6WzAyn3JZJHckuvldGelo5Vvb2VPAew8AfCJPRS6M5nxOiyQ9vBBu1qh7WjTio9I9PZpz9 -MikHYFELk5Y4UzdD2tkta4xhQ5vlTF7E+R/ERg9g8laGYSDhfZ7VplinPxgJN7R5TprfTDljSA7s -WNp5I+Un0xjvaSH+hymC2g1YXb+kZdVoXnnaI628ZMD438jwu35LWSHJmiGmZ/DJhtpP4tePzY+N -NBXIzgfYHKytGahljkkAMNfKRa0WmMcdxb9LuWnu0pPi9o0Y70zOapp3sZ7jELY7leh8bL92NnTx -1svgxXBt0U1o0yy4Y5rpVoemMMma+zyvNRJ5L2JszJO0gOK1RA2ZND6N9IO1YNzMwObDf0tPn7rZ -jx7Ov4nidc6PR5NNiw8BzY201rfhaX+MnS9I8Y9XZFZEovorF7o5dvdMxLuXF33T0A2TjYXXSoVT -HGm49ssj+6TdCWx3A1obRq1ne2KCIGg3XCBlF4BaLVbKK3A87OLUSIhj6ZaaneTZukvM/R0fEXTZ -D1XqpwsX2oXXPJxXx90Xj4ub2/Q3Nk4T/ZltMjN+5IefP3Wy38HNb2NwygNjiFnFlcgeQC91noBW -tFC/U2Okgc3bynY32FLHvo3KMule242+I7Vm8idXs6uCtwE69MYtOk+TwEOKd0XmeoZjXB3YC3Jn -NIuaavhWQXapjl0e6kzHQzG9BnorUf02YcaQ/wAuTr8pflY+U8kbcV96NjrB/wCkJA6Paw4/ZfkL -8GZ9wBcT5WnZgZ13R45UTLBpGbm06kaZaJwtAZx2qZa7GeETubzytngXxs0ceSJZjHkldqsxJwi/ -IxXPYXtB3N7pczyp5dg5cW10cwp4waef8rl1L+DnVPY5xXMLKj8rPU/sXrQyx2ktJJ58JFP4Dhls -2O2WME8uC6P0/L+XA6WCt9EoMfjpdribJZd+l+Ah4jlRmc/LouDSAvP48ejzczsbeiPTk2tZ7MjJ -Yf0jeeR+4rbjxnV8TxdvlXo9rw8eHFgbFE0Na0UKC1zKXSOqugL1BIItNlcPhDk/iDT6Pzr6lyd+ -VKSLslY4W3s5be2zOcGyOE4FhOG0l6FiaZocUFraCzUIbC42Hg8pe/gEMjLeAO0DKJbuav8AyhZR -HIIDLBIVyWhnpU7cPR3TP82fyl3PO9HSwvhj2zIZ8rs3MdLMTuJ4+wW6EoWkYsl83sYYjWMjaCLp -Jp9imFOd9QIoWgKINO5zr6CsoHmHuRu5o14RyFIH6QyXY+ryQONNl8fcJnkRuNm7xq70PfVEn8mK -Nvk2s2BdtheU+kjNln3WvZiIloaOwSrXZGU5I3xm666RSFIjaHQZQcy2uDrBT3+S0aZro9Fxcgal -o5b/APsDeVyql47NHJZIYmohpAHXZWhGD+iHHkm1ZZFwscqFHGCjQPCsYhxpMe+ZoR+PWrNWLs07 -tKDhe3/ZdTma+BEaMCCNvB4PCqnyBcbMJ6hwHabqRYLDDyLWO50cvPHGjun5hY4V/hZLgyD7Dzfc -cst49ArpjSB1ygHypgr7dpmzDWmaXF03fE1wHa9PFcpTOin0EjTCB0r0Fs8p0LBk1jUo4GD6LtxP -wuNEGLxvH5s9w0lsGn4jIIAGtaPHlaZ6O0p0tIPGWPkI9k0KPVea1uky2fBSsj2tC8nUn531qbfk -PI6JtKhHN0LQN32TPQDGWl/+oPIS79CLY7YdjgQVnYhhrHFzBd/2S2CydjgF3KHRC6wKDjarRQPk -PcGkA8IpLR82Z08DI3WGtHA8FTWnsZWRuUgVsLTK4nx4Rp9C9hjWgADgD7oCjrQGE/SXHxXSomis -tBcd1i1ZCiZxdwPpA8hEi0xK9xx9Shlju2uu1p1uGmOx1xezQ6rksnmY9rtwDfCyxLnoZntU+hdL -GDRb5TU9CCgsDSSRaPeyaIlm51NHfSm/2EhlgekHZjvey3GNh6A7SL8xT1I1VpGlxtFx8JhELzdU -bKyPPVMKL4iTUNLkjJfAS9nJP2WmMqfTBqd+hZuAtrhz8pz79AMg6+AOlaIjjGkE0oGmaD039ebG -0+fKmL+RrxHqcWG32m8A8Lqz6NpIYbPgIgTGfxI0hsune+1o3M5SssbWzJ5M7nZ5njsJPHCw0+jk -se6fG5tHtZbYDGkchD73chZ9DsbPS/Sjm5OnN5shei8K+eM62N7kdiAD4WsM8e9PZcOk49NoyO5L -lzpjo045WNaQ7b6kH+oK9DORa31IP9Q/yponIC1/XG5GmSNBv+6Va0JzV+OjyTUX7shyGF0YQRt7 -u0z4F0OtMaGiys99mW2NoGOk4a0uPgBIfXsDTY4w9LzHgEQuAPzxSTWSV8k4MPj9PS3/ADZGtPYA -SX5C+Avt/wBkm6E+3B+QyvHCr/oXwTgv2QydCc2OxNZ+CKB/urnyE2TgvhioN2nY4AVxwnv9iq9k -enUwX8lRA7OhhogkXfwpss+O5v7Tu4+FCaZTZ5LuQjIQB3XyQFCwaXDdM9vstL3XzQ6RK1PsJJsL -OFkhl/p31+O0H3J/YfFlLsSfr23hx6G1F9yf2TiwR0bmEhzXE/BFJiaZSTND6d0xrYxk5LRyfpB8 -LHny/wDlFt6Q7zMyPFge8uYWgdALNjxu3pIGW2+jH5/qPIcXbI2tYBwasro4/GlIekl0DYPqOV5L -JHNeOqraUdeOl2g5aJZlCUllbXcilJ9AWuyi+KJ5VgpbJROINFRho0Ppgj/mEZdwFMX8jVi9nq8W -QzYKI6XWn0bCfvt+QiKFfqZjMnR529/SVVLaFZFylnjWPEGyuFcArk5OmcW1obQWAs7Eey9pLRdf -3QNDY6Nx6C1ABskLuD2LXS+nZNNydTBW1o2H6kfK7BoPzt70n+orl7Zr0SbPJ/qKmyE/1En+oqbI -dfO92M8E2gp9Cc3oyuW4+8eVcoyEGcyBEKo0GmNDnMaeiaWbJ0Zmts9GwMeKBjPajaCR3S5WS2wt -69B24+2TfKRrZWyl08hDbI6vpWpQOwbLyZYot7HckdeEeOFXsFmYn1TKnyJInSFrAapvC2zimO0g -5lewmJodKGno0qb0L12MMLAhe87t3B45SLyNLoascjaDTcUOFxA/k2s7zW/kvigbVMeIwyD22jae -KFJmGnsLimuzJOH8zbZpb/gxjB+FE3Hjd9RLquykq22xvBa2OdIYyDEjEbQNxsmuTykZHyrsbrSW -gt0jvb76IS+KIqeip0jtzhxxSJIpNnzmtc2nsa78i1Spr5LVMmGCto4FeFf9l8VXsS6vgRSjc90h -5qt3C0YsjRfFJdCmTT8ccFpIHglP+4ykhLqGFBj5LHQt2l3YvhOx26XYSDsriGOvgBBPsqwYuI6R -oFF0YBQthobaQ4ty4qNchXi/kacXs3gyZA0U5deV0aj4Zct/uR6BZJ2RI+JzXGwRRULZ5fnPdHnz -NZwA5czNK2zkeQkmwrHe54ouNLHS0ZGMWcUElsuWN/T0z485uw1af4jayI6HjvTNX+pl/wBS9CvR -uP/Z ---Apple-Mail-89556518-7D3B-49E6-BE3B-A3267CB0D688-- diff --git a/third_party/lisp/mime4cl/test/samples/sample1.msg b/third_party/lisp/mime4cl/test/samples/sample1.msg deleted file mode 100644 index 662a9fab3..000000000 --- a/third_party/lisp/mime4cl/test/samples/sample1.msg +++ /dev/null @@ -1,86 +0,0 @@ -From wcp@scylla.home.lan Fri Feb 17 11:02:28 2012 -Status: RO -X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil] - ["1133" "Friday" "17" "February" "2012" "11:02:27" "+0100" "Walter C. Pelissero" "walter@pelissero.de" nil "56" "test" "^From:" nil nil "2" nil nil nil nil nil nil nil nil nil nil] - nil) -X-Clpmr-Processed: 2012-02-17T11:02:31 -X-Clpmr-Version: 2011-10-23T12:55:20, SBCL 1.0.49 -Received: from scylla.home.lan (localhost [127.0.0.1]) - by scylla.home.lan (8.14.5/8.14.5) with ESMTP id q1HA2Sik004513 - for ; Fri, 17 Feb 2012 11:02:28 +0100 (CET) - (envelope-from wcp@scylla.home.lan) -Received: (from wcp@localhost) - by scylla.home.lan (8.14.5/8.14.5/Submit) id q1HA2SqU004512; - Fri, 17 Feb 2012 11:02:28 +0100 (CET) - (envelope-from wcp) -Message-ID: <20286.9651.890757.323027@scylla.home.lan> -X-Mailer: VM 8.1.1 under 23.3.1 (amd64-portbld-freebsd8.2) -Reply-To: walter@pelissero.de -X-Attribution: WP -X-For-Spammers: blacklistme@pelissero.de -X-MArch-Processing-Time: 0.552s -MIME-Version: 1.0 -Content-Type: multipart/mixed; boundary="615CiWUaGO" -Content-Transfer-Encoding: 7BIT -From: walter@pelissero.de (Walter C. Pelissero) -To: wcp@scylla.home.lan -Subject: test -Date: Fri, 17 Feb 2012 11:02:27 +0100 - - ---615CiWUaGO -Content-Type: text/plain; charset="us-ascii" -Content-Transfer-Encoding: 7BIT -Content-Description: message body text - -Hereafter three attachments. - -The first: - ---615CiWUaGO -Content-Type: application/octet-stream; name="attach1" -Content-Transfer-Encoding: BASE64 -Content-Disposition: attachment; filename="attach1" - -YXR0YWNoMQo= - ---615CiWUaGO -Content-Type: text/plain; charset="us-ascii" -Content-Transfer-Encoding: 7BIT -Content-Description: message body text - - -The second: - ---615CiWUaGO -Content-Type: application/octet-stream; name="attach2" -Content-Transfer-Encoding: BASE64 -Content-Disposition: attachment; filename="attach2" - -YXR0YWNoMgo= - ---615CiWUaGO -Content-Type: text/plain; charset="us-ascii" -Content-Transfer-Encoding: 7BIT -Content-Description: message body text - - -The third: - ---615CiWUaGO -Content-Type: application/octet-stream; name="attach3" -Content-Transfer-Encoding: BASE64 -Content-Disposition: attachment; filename="attach3" - -YXR0YWNoMwo= - ---615CiWUaGO -Content-Type: text/plain; charset="us-ascii" -Content-Transfer-Encoding: 7BIT -Content-Description: .signature - - --- -http://pelissero.de ---615CiWUaGO-- - diff --git a/third_party/lisp/mime4cl/test/temp-file.lisp b/third_party/lisp/mime4cl/test/temp-file.lisp deleted file mode 100644 index 554f35844..000000000 --- a/third_party/lisp/mime4cl/test/temp-file.lisp +++ /dev/null @@ -1,72 +0,0 @@ -;;; temp-file.lisp --- temporary file creation - -;;; Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 by Walter C. Pelissero -;;; Copyright (C) 2022 The TVL Authors - -;;; Author: Walter C. Pelissero -;;; Project: mime4cl -;;; -;;; Code taken from SCLF - -#+cmu (ext:file-comment "$Module: temp-file.lisp $") - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :mime4cl-tests) - -(defvar *tmp-file-defaults* #P"/tmp/") - -(defun temp-file-name (&optional (default *tmp-file-defaults*)) - "Create a random pathname based on DEFAULT. No effort is made -to make sure that the returned pathname doesn't identify an -already existing file. If missing DEFAULT defaults to -*TMP-FILE-DEFAULTS*." - (make-pathname :defaults default - :name (format nil "~36R" (random #.(expt 36 10))))) - -(defun open-temp-file (&optional default-pathname &rest open-args) - "Open a new temporary file and return a stream to it. This function -makes sure the pathname of the temporary file is unique. OPEN-ARGS -are arguments passed verbatim to OPEN. If OPEN-ARGS specify -the :DIRECTION it should be either :OUTPUT (default) or :IO; -any other value causes an error. If DEFAULT-PATHNAME is specified and -not NIL it's used as defaults to produce the pathname of the temporary -file, otherwise *TMP-FILE-DEFAULTS* is used." - (unless default-pathname - (setf default-pathname *tmp-file-defaults*)) - ;; if :DIRECTION is specified check that it's compatible with the - ;; purpose of this function, otherwise make it default to :OUTPUT - (aif (getf open-args :direction) - (unless (member it '(:output :io)) - (error "Can't create temporary file with open direction ~A." it)) - (setf open-args (append '(:direction :output) - open-args))) - (do* ((name #1=(temp-file-name default-pathname) #1#) - (stream #2=(apply #'open name - :if-exists nil - :if-does-not-exist :create - open-args) #2#)) - (stream stream))) - -(defmacro with-temp-file ((stream &rest open-temp-args) &body body) - "Execute BODY within a dynamic extent where STREAM is bound to -a STREAM open on a unique temporary file name. OPEN-TEMP-ARGS are -passed verbatim to OPEN-TEMP-FILE." - `(let ((,stream (open-temp-file ,@open-temp-args))) - (unwind-protect - (progn ,@body) - (close ,stream) - ;; body may decide to rename the file so we must ignore the errors - (ignore-errors - (delete-file (pathname ,stream)))))) diff --git a/third_party/lisp/moptilities.nix b/third_party/lisp/moptilities.nix deleted file mode 100644 index 89766e0a8..000000000 --- a/third_party/lisp/moptilities.nix +++ /dev/null @@ -1,13 +0,0 @@ -# Compatibility layer for minor MOP implementation differences -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.moptilities; -in depot.nix.buildLisp.library { - name = "moptilities"; - deps = [ depot.third_party.lisp.closer-mop ]; - srcs = [ "${src}/dev/moptilities.lisp" ]; - - brokenOn = [ - "ecl" # TODO(sterni): https://gitlab.com/embeddable-common-lisp/ecl/-/issues/651 - ]; -} diff --git a/third_party/lisp/nibbles.nix b/third_party/lisp/nibbles.nix deleted file mode 100644 index 3136e9330..000000000 --- a/third_party/lisp/nibbles.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.nix.buildLisp) bundled; - src = with pkgs; srcOnly (sbcl.pkgs.nibbles.overrideAttrs (oldAttrs: { - patches = oldAttrs.patches or [ ] ++ [ - # Restoring the weird progn apparently fixes unbound MAKE-EA and EAX-OFFSET - # which we were seeing during macroexpansion. Curiously, building niblbes - # with ASDF is not affected by this problem. - (pkgs.fetchpatch { - name = "nibbles-sbcl-x86-restore-weird-progn.patch"; - url = "https://github.com/sharplispers/nibbles/commit/f37322b864ea12018bc0acbd70cb1e24bf0426eb.patch"; - revert = true; - sha256 = "0h601g145qscmvykrzrf9bnlakfh5qawwmdd1z8f2cslfxrkj9jc"; - }) - ]; - })); -in -depot.nix.buildLisp.library { - name = "nibbles"; - - deps = with depot.third_party.lisp; [ - (bundled "asdf") - ]; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "types.lisp" - "macro-utils.lisp" - "vectors.lisp" - "streams.lisp" - ] ++ [ - { sbcl = "${src}/sbcl-opt/fndb.lisp"; } - { sbcl = "${src}/sbcl-opt/nib-tran.lisp"; } - { sbcl = "${src}/sbcl-opt/x86-vm.lisp"; } - { sbcl = "${src}/sbcl-opt/x86-64-vm.lisp"; } - ]; -} diff --git a/third_party/lisp/npg/.project b/third_party/lisp/npg/.project deleted file mode 100644 index 82a8fe48b..000000000 --- a/third_party/lisp/npg/.project +++ /dev/null @@ -1 +0,0 @@ -NPG a Naive Parser Generator diff --git a/third_party/lisp/npg/.skip-subtree b/third_party/lisp/npg/.skip-subtree deleted file mode 100644 index 5051f60d6..000000000 --- a/third_party/lisp/npg/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -prevent readTree from creating entries for subdirs that don't contain an .nix files diff --git a/third_party/lisp/npg/COPYING b/third_party/lisp/npg/COPYING deleted file mode 100644 index 223ede7de..000000000 --- a/third_party/lisp/npg/COPYING +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/third_party/lisp/npg/OWNERS b/third_party/lisp/npg/OWNERS deleted file mode 100644 index 2e9580706..000000000 --- a/third_party/lisp/npg/OWNERS +++ /dev/null @@ -1 +0,0 @@ -sterni diff --git a/third_party/lisp/npg/README b/third_party/lisp/npg/README deleted file mode 100644 index a1661e744..000000000 --- a/third_party/lisp/npg/README +++ /dev/null @@ -1,48 +0,0 @@ - - NPG a Naive Parser Generator - for Common Lisp - - Copyright (C) 2003-2006, 2010 by Walter C. Pelissero - Copyright (C) 2021 by the TVL Authors - -Vendored into depot as it is a dependency of mime4cl and upstream has -become inactive. Upstream and depot version may diverge. - -Upstream Website: http://wcp.sdf-eu.org/software/#npg -Vendored Tarball: http://wcp.sdf-eu.org/software/npg-20150517T144652.tbz - -This library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation; either version 2.1 of the -License, or (at your option) any later version. This library is -distributed in the hope that it will be useful, but WITHOUT ANY -WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. You should have received a copy of the GNU -Lesser General Public License along with this library; if not, write -to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, -Boston, MA 02111-1307 USA - - -This library generates on the fly (no external representation of the -parser is produced) a recursive descent parser based on the grammar -rules you have fed it with. The parser object can then be used to -scan tokenised input. Although a facility to produce a lexical -analiser is not provided, to write such a library is fairly easy for -most languages. NPG parsers require your lexer to adhere to a certain -protocol to be able to communicate with them. Examples are provided -that explain these requirements. - -While quite possibly not producing the fastest parsers in town, it's -fairly simple and hopefully easy to debug. It accepts a lispy EBNF -grammar description of arbitrary complexity with the exception of -mutually left recursive rules (watch out, they produce undetected -infinite recursion) and produces a backtracking recursive descent -parser. Immediate left recursive rules are properly simplified, -though. - -Multiple concurrent parsers are supported. - -To compile, an ASDF and nix file are provided. - -See the examples directory for clues on how to use it. diff --git a/third_party/lisp/npg/default.nix b/third_party/lisp/npg/default.nix deleted file mode 100644 index af7ec53ea..000000000 --- a/third_party/lisp/npg/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (C) 2021 by the TVL Authors -# SPDX-License-Identifier: LGPL-2.1-or-later -{ depot, pkgs, ... }: - -depot.nix.buildLisp.library { - name = "npg"; - - srcs = [ - ./src/package.lisp - ./src/common.lisp - ./src/define.lisp - ./src/parser.lisp - ]; -} diff --git a/third_party/lisp/npg/examples/python.lisp b/third_party/lisp/npg/examples/python.lisp deleted file mode 100644 index a45ac614f..000000000 --- a/third_party/lisp/npg/examples/python.lisp +++ /dev/null @@ -1,336 +0,0 @@ -;;; python.lisp --- sample grammar definition for the Python language - -;;; Copyright (C) 2003 by Walter C. Pelissero - -;;; Author: Walter C. Pelissero -;;; Project: NPG a Naive Parser Generator -;;; $Id: F-C1A8CD5961889C584B22F05E8B956006.lisp,v 1.3 2004/03/09 10:33:06 wcp Exp $ - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -;;; Commentary: -;;; -;;; This is far from being a complete Python grammar. Actually I -;;; haven't even read a Python book before starting to write this -;;; stuff, so the code below comes mostly from wild guessing while -;;; reading a Python source file. -;;; -;;; It's a design decision to avoid writing any transformation in this -;;; module; only tagging is done at this level. This improves the -;;; separation between parsing and transformation, making the grammar -;;; reusable for other purposes. - - -#+cmu (ext:file-comment "$Id: F-C1A8CD5961889C584B22F05E8B956006.lisp,v 1.3 2004/03/09 10:33:06 wcp Exp $") - -(in-package :grammar) - -(deflazy define-grammar - (let ((*package* #.*package*) - (*compile-print* (and parser::*debug* t))) - (reset-grammar) - (format t "~&creating Python grammar...~%") - (populate-grammar) - (let ((grammar (parser:generate-grammar))) - (reset-grammar) - (parser:print-grammar-figures grammar) - grammar))) - -(defun populate-grammar () - -(defrule program - := comment-string? statement+) - -(defrule comment-string - := string eol - :reduce string) - -;;; BOB = Beginning Of Block, EOB = End Of Block. It's lexical -;;; analyzer's task to find out where a statement or block starts/ends. - -(defrule suite - := statement-list eol - :reduce statement-list - := statement-block) - -(defrule commentable-suite - := statement-list eol - :reduce statement-list - := commented-statement-block) - -(defrule statement-block - := bob statement+ eob - :reduce $2) - -(defrule commented-statement-block - := bob comment-string? statement* eob - :reduce (cons comment-string statement)) - -(defrule statement-list - := (+ simple-statement ";") - :reduce (if (cdr $1) - (cons :statement-list $1) - (car $1))) - -(defrule statement - := statement-list eol - :reduce statement-list - := compound-statement) - -(defrule simple-statement - := import-statement - := raise-statement - := assignment - := function-call - := return-statement - := assert-statement - := pass-statement - := break-statement - := continue-statement) - -(defrule compound-statement - := class-definition - := method-definition - := try-statement - := if-statement - := while-statement - := for-statement) - -(defrule import-statement - := "import" (+ package-name ",") - :tag :import - := "from" package-name "import" (+ symbol-name ",") - :tag :import-from) - -(defrule package-name := identifier) - -(defrule symbol-name - := identifier - := "*") - -(defrule try-statement - := "try" ":" suite try-except-part* try-finally-part? - :tag :try) - -(defrule try-except-part - := "except" exception-subject? ":" suite) - -(defrule try-finally-part - := "finally" ":" suite) - -(defrule exception-subject - := exception-name exception-variable?) - -(defrule exception-variable - := "," identifier) - -(defrule exception-name := class-name) - -(defrule class-name := identifier) - -(defrule raise-statement - := "raise" - :tag :raise-same - := "raise" exception-name - :tag :raise - := "raise" exception-name "," expression - :tag :raise - := "raise" exception-name "(" expression ")" - :tag :raise) - -(defrule assignment - := (+ variable-with-optional-subscript ",") "=" more-assignment - :tag :set) - -(defrule more-assignment - := expression - := assignment) - -(defrule variable-with-optional-subscript - := variable-name subscript - :tag :subscript - := variable-name) - -(defrule variable-name - := (+ identifier ".") - :tag :varef) - -(defrule expression - := expression "or" expression1 - :tag :or - := expression1) - -(defrule expression1 - := expression1 "and" expression2 - :tag :and - := expression2) - -(defrule expression2 - := expression2 "==" expression3 - :tag :equal - := expression2 ">=" expression3 - :tag :more-equal - := expression2 "<=" expression3 - :tag :less-equal - := expression2 "!=" expression3 - :tag :not-equal - := expression2 ">" expression3 - :tag :more - := expression2 "<" expression3 - :tag :less - := expression2 "is" expression3 - :tag :equal - := expression2 "is" "not" expression3 - :tag :not-equal - := expression3) - -(defrule expression3 - := expression3 "+" expression4 - :tag :plus - := expression3 "-" expression4 - :tag :minus - := expression3 "|" expression4 - :tag :bit-or - := expression4) - -;; high priority expression -(defrule expression4 - := expression4 "*" expression5 - :tag :mult - := expression4 "/" expression5 - :tag :div - := expression4 "%" expression5 - :tag :modulo - := expression4 "&" expression5 - :tag :bit-and - := expression4 "in" expression5 - :tag :in - := expression5) - -(defrule expression5 - := "~" expression5 - :tag :bit-not - := "not" expression5 - :tag :not - := "(" expression ")" - := expression6) - -(defrule expression6 - := simple-expression subscript - :tag :subscript - := simple-expression) - -(defrule simple-expression - := function-call - := variable-name - := constant - := string-conversion - := list-constructor) - -(defrule subscript - := "[" expression "]" - := "[" expression ":" expression "]" - := "[" expression ":" "]" - :reduce (list expression nil) - := "[" ":" expression "]" - :reduce (list nil expression)) - -(defrule string-conversion - := "`" expression "`" - :tag :to-string) - -(defrule constant - := number - := string - := lambda-expression) - -(defrule number - := float - := integer) - -(defrule list-constructor - := "[" (* expression ",") "]" - :tag :make-list) - -(defrule class-definition - := "class" class-name superclasses? ":" commentable-suite - :tag :defclass) - -(defrule superclasses - := "(" class-name+ ")") - -(defrule method-definition - := "def" method-name "(" method-arguments ")" ":" commentable-suite - :tag :defmethod) - -(defrule method-arguments - := (* method-argument ",")) - -(defrule method-argument - := identifier argument-default?) - -(defrule argument-default - := "=" expression) - -(defrule method-name := identifier) - -(defrule if-statement - := "if" expression ":" suite elif-part* else-part? - :tag :if) - -(defrule else-part - := "else" ":" suite) - -(defrule elif-part - := "elif" expression ":" suite) - -(defrule lambda-expression - := "lambda" method-arguments ":" expression - :tag :lambda) - -(defrule function-call - := (+ identifier ".") "(" (* expression ",") ")" - :tag :funcall) - -(defrule for-statement - := "for" identifier "in" expression ":" suite - :tag :do-list - := "for" identifier "in" "range" "(" expression "," expression ")" ":" suite - :tag :do-range) - -(defrule while-statement - := "while" expression ":" suite - :tag :while) - -(defrule return-statement - := "return" expression? - :tag :return) - -(defrule assert-statement - := "assert" expression "," string - :tag :assert) - -(defrule pass-statement - := "pass" - :tag :pass) - -(defrule break-statement - := "break" - :tag :break) - -(defrule continue-statement - := "continue" - :tag :continue) - -) ; end of POPULATE-GRAMMAR diff --git a/third_party/lisp/npg/examples/vs-cobol-ii.lisp b/third_party/lisp/npg/examples/vs-cobol-ii.lisp deleted file mode 100644 index 9ebd45a16..000000000 --- a/third_party/lisp/npg/examples/vs-cobol-ii.lisp +++ /dev/null @@ -1,1901 +0,0 @@ -;;; vs-cobol-ii.lisp --- sample grammar for VS-Cobol II - -;;; Copyright (C) 2003 by Walter C. Pelissero - -;;; Author: Walter C. Pelissero -;;; Project: NPG a Naive Parser Generator -;;; $Id: F-1D03709AEB30BA7644C1CFA2DF60FE8C.lisp,v 1.2 2004/03/09 10:33:07 wcp Exp $ - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -;;; Commentary: -;;; -;;; A fairly incomplete VS-Cobol II grammar fro NPG. It's probably -;;; not very accurate either. - -#+cmu (ext:file-comment "$Id: F-1D03709AEB30BA7644C1CFA2DF60FE8C.lisp,v 1.2 2004/03/09 10:33:07 wcp Exp $") - -(in-package :grammar) - -(defun make-keyword (string) - "Create a keyword from STRING." - (intern (string-upcase string) :keyword)) - -(defun flatten-list (list) - "Remove one depth level in LIST." - (mapcan #'identity list)) - -(deflazy define-grammar - (let ((*package* #.*package*) - (*compile-print* (and parser::*debug* t))) - (reset-grammar) - (format t "creating Cobol grammar...~%") - (populate-grammar) - (let ((grammar (parser:generate-grammar))) - (reset-grammar) - (parser:print-grammar-figures grammar) - grammar))) - -(defun populate-grammar () -;;; -;;; Hereafter PP means Partial Program -;;; - -#+nil -(defrule pp--declarations - := identification-division environment-division? data-division? "PROCEDURE" "DIVISION" using-phrase? "." :rest) - -;;; We need to split the parsing of the declarations from the rest -;;; because the declarations may change the lexical rules (ie decimal -;;; point) - -(defrule pp--declarations - := identification-division environment-division? data-division-head-or-procedure-division-head :rest) - -(defrule data-division-head-or-procedure-division-head - := data-division-head - :reduce :data-division - := procedure-division-head - :reduce (list :procedure-division $1)) - -(defrule pp--data-division - := data-division-content procedure-division-head :rest) - -(defrule pp--sentence - := sentence :rest - := :eof) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; The real grammar -;;; - -(defrule cobol-source-program - := identification-division environment-division? data-division procedure-division end-program?) - -(defrule identification-division - := identification "DIVISION" "." program-id-cobol-source-program identification-division-content - :reduce program-id-cobol-source-program) - -(defrule priority-number - := integer) - -(defrule level-number - := integer) - -(defrule to-id-or-lit - := "TO" id-or-lit) - -(defrule inspect-by-argument - := variable-identifier - := string - := figurative-constant-simple) - -(defrule figurative-constant-simple - := "ZERO" - :reduce :zero - := "ZEROS" - :reduce :zero - := "ZEROES" - :reduce :zero - := "SPACE" - :reduce :space - := "SPACES" - :reduce :space - := "HIGH-VALUE" - :reduce :high - := "HIGH-VALUES" - :reduce :high - := "LOW-VALUE" - :reduce :low - := "LOW-VALUES" - :reduce :low - := "QUOTE" - :reduce :quote - := "QUOTES" - :reduce :quote - := "NULL" - :reduce :null - := "NULLS" - :reduce :null) - -(defrule write-exceptions - := at-end-of-page-statement-list? not-at-end-of-page-statement-list? invalid-key-statement-list? not-invalid-key-statement-list?) - -(defrule set-statement-phrase - := variable-identifier+ set-oper set-src) - -(defrule set-src - := variable-identifier - := literal - := "TRUE" - := "ON" - := "OFF") - -(defrule set-oper - := "TO" - :reduce :to - := "UP" "BY" - :reduce :up - := "DOWN" "BY" - :reduce :down) - -(defrule fce-phrase - := reserve-clause - := fce-organization - := fce-access-mode - := record-key-clause - := password-clause - := alternate-record-key-clause - := file-status-clause - := padding-character-clause - := record-delimiter-clause) - -(defrule fce-organization - := organization-is? alt-indexed-relative-sequential - :reduce (list :organization (make-keyword alt-indexed-relative-sequential))) - -(defrule fce-access-mode - := "ACCESS" "MODE"? "IS"? alt-sequential-random-dynamic relative-key-clause? - :reduce (list :access-mode (make-keyword alt-sequential-random-dynamic))) - -(defrule alt-indexed-relative-sequential - := "INDEXED" - := "RELATIVE" - := "SEQUENTIAL") - -(defrule is-not - := "IS"? "NOT"?) - -(defrule all-procedures - := "ALL" "PROCEDURES") - -(defrule next-sentence - := "NEXT" "SENTENCE") - -(defrule no-rewind - := "NO" "REWIND") - -(defrule for-removal - := "FOR"? "REMOVAL") - -(defrule values - := "VALUE" - := "VALUES") - -(defrule records - := "RECORD" - := "RECORDS") - -(defrule end-program - := "END" "PROGRAM" program-name ".") - -(defrule environment-division - := "ENVIRONMENT" "DIVISION" "." environment-division-content) - -(defrule data-division-head - := "DATA" "DIVISION" ".") - -(defrule data-division - := data-division-head data-division-content - :reduce data-division-content) - -(defrule identification - := "IDENTIFICATION" - := "ID") - -(defrule identification-division-content - := identification-division-phrase*) - -(defrule author - := "AUTHOR" ".") - -(defrule installation - := "INSTALLATION" ".") - -(defrule date-written - := "DATE-WRITTEN" ".") - -(defrule date-compiled - := "DATE-COMPILED" ".") - -(defrule security - := "SECURITY" ".") - -(defrule remarks - := "REMARKS" ".") - -(defrule identification-division-phrase - := author - := installation - := date-written - := date-compiled - := security - := remarks) - -(defrule program-id-cobol-source-program - := "PROGRAM-ID" "."? program-name initial-program? "." - :reduce program-name) - -(defrule initial-program - := "IS"? "INITIAL" "PROGRAM"?) - -(defrule environment-division-content - := configuration-section? input-output-section?) - -(defrule input-output-section - := "INPUT-OUTPUT" "SECTION" "." file-control-paragraph? i-o-control-paragraph? - :reduce file-control-paragraph) - -(defrule file-control-paragraph - := "FILE-CONTROL" "." file-control-entry*) - -(defrule file-control-entry - := select-clause assign-clause fce-phrase* "." - :reduce (append select-clause - assign-clause - (flatten-list fce-phrase))) - -(defrule organization-is - := "ORGANIZATION" "IS"?) - -(defrule alt-sequential-random-dynamic - := "SEQUENTIAL" - := "RANDOM" - := "DYNAMIC") - -(defrule select-clause - := "SELECT" "OPTIONAL"? file-name - :reduce (list file-name :optional (and $2 t))) - -(defrule assign-clause - := "ASSIGN" "TO"? alt-assignment-name-literal+ - :reduce (list :assign alt-assignment-name-literal)) - -(defrule alt-assignment-name-literal - := assignment-name - := literal) - -(defrule reserve-clause - := "RESERVE" integer areas?) - -(defrule areas - := "AREA" - := "AREAS") - -(defrule padding-character-clause - := "PADDING" "CHARACTER"? "IS"? alt-qualified-data-name-literal) - -(defrule record-delimiter-clause - := "RECORD" "DELIMITER" "IS"? record-delimiter-name) - -(defrule record-delimiter-name - := "STANDARD-1" - := assignment-name) - -(defrule password-clause - := "PASSWORD" "IS"? data-name) - -(defrule file-status-clause - := "FILE"? "STATUS" "IS"? qualified-data-name qualified-data-name? - :reduce (list :file-status qualified-data-name)) - -(defrule relative-key-clause - := "RELATIVE" "KEY"? "IS"? qualified-data-name - :reduce (list :relative-key qualified-data-name)) - -(defrule record-key-clause - := "RECORD" "KEY"? "IS"? qualified-data-name - :reduce (list :key qualified-data-name)) - -(defrule alternate-record-key-clause - := "ALTERNATE" "RECORD"? "KEY"? "IS"? qualified-data-name password-clause? with-duplicates? - :reduce (list :alternate-key qualified-data-name with-duplicates)) - -(defrule with-duplicates - := "WITH"? "DUPLICATES") - -(defrule i-o-control-paragraph - := "I-O-CONTROL" "." i-o-sam? i-o-sort-merge?) - -(defrule i-o-sam - := qsam-or-sam-or-vsam-i-o-control-entries+ ".") - -(defrule i-o-sort-merge - := sort-merge-i-o-control-entries ".") - -(defrule qsam-or-sam-or-vsam-i-o-control-entries - := qsam-or-sam-or-vsam-i-o-control-entries-1 - := qsam-or-sam-or-vsam-i-o-control-entries-2 - := qsam-or-sam-or-vsam-i-o-control-entries-3 - := qsam-or-sam-or-vsam-i-o-control-entries-4) - -(defrule qsam-or-sam-or-vsam-i-o-control-entries-1 - := "RERUN" "ON" alt-assignment-name-file-name "EVERY"? every-phrase "OF"? file-name) - -(defrule every-phrase-1 - := integer "RECORDS") - -(defrule every-phrase-2 - := "END" "OF"? alt-reel-unit) - -(defrule every-phrase - := every-phrase-1 - := every-phrase-2) - -(defrule alt-assignment-name-file-name - := assignment-name - := file-name) - -(defrule qsam-or-sam-or-vsam-i-o-control-entries-2 - := "SAME" "RECORD"? "AREA"? "FOR"? file-name file-name+) - -(defrule qsam-or-sam-or-vsam-i-o-control-entries-3 - := "MULTIPLE" "FILE" "TAPE"? "CONTAINS"? file-name-position+) - -(defrule position - := "POSITION" integer) - -(defrule file-name-position - := file-name position?) - -(defrule qsam-or-sam-or-vsam-i-o-control-entries-4 - := "APPLY" "WRITE-ONLY" "ON"? file-name+) - -(defrule sort-merge-i-o-control-entries - := rerun-on? same-area+) - -(defrule rerun-on - := "RERUN" "ON" assignment-name) - -(defrule record-sort - := "RECORD" - := "SORT" - := "SORT-MERGE") - -(defrule same-area - := "SAME" record-sort "AREA"? "FOR"? file-name file-name+) - -(defrule configuration-section - := "CONFIGURATION" "SECTION" "." configuration-section-paragraph* - :reduce (flatten-list configuration-section-paragraph)) - -(defrule configuration-section-paragraph - := source-computer-paragraph - := object-computer-paragraph - := special-names-paragraph) - -(defrule source-computer-paragraph - := "SOURCE-COMPUTER" "." source-computer-name - :reduce (list :source-computer source-computer-name)) - -(defrule with-debugging-mode - := "WITH"? "DEBUGGING" "MODE") - -(defrule source-computer-name - := computer-name with-debugging-mode? "." - :reduce computer-name) - -(defrule object-computer-paragraph - := "OBJECT-COMPUTER" "." object-computer-name - :reduce (list :object-computer object-computer-name)) - -(defrule memory-size-type - := "WORDS" - := "CHARACTERS" - := "MODULES") - -(defrule memory-size - := "MEMORY" "SIZE"? integer memory-size-type) - -(defrule object-computer-name - := computer-name memory-size? object-computer-paragraph-sequence-phrase "." - :reduce computer-name) - -(defrule object-computer-paragraph-sequence-phrase - := program-collating-sequence? segment-limit?) - -(defrule program-collating-sequence - := "PROGRAM"? "COLLATING"? "SEQUENCE" "IS"? alphabet-name) - -(defrule segment-limit - := "SEGMENT-LIMIT" "IS"? priority-number) - -(defrule special-names-paragraph - := "SPECIAL-NAMES" "." special-names-paragraph-phrase* special-names-paragraph-clause* "." - :reduce (flatten-list special-names-paragraph-clause)) - -(defrule is-mnemonic-name - := "IS"? mnemonic-name special-names-paragraph-status-phrase?) - -(defrule special-names-paragraph-phrase-tail - := is-mnemonic-name - := special-names-paragraph-status-phrase) - -(defrule special-names-paragraph-phrase - := environment-name special-names-paragraph-phrase-tail) - -(defrule special-names-paragraph-status-phrase - := special-names-paragraph-status-phrase-1 - := special-names-paragraph-status-phrase-2) - -(defrule special-names-paragraph-status-phrase-1 - := "ON" "STATUS"? "IS"? condition off-status?) - -(defrule off-status - := "OFF" "STATUS"? "IS"? condition) - -(defrule special-names-paragraph-status-phrase-2 - := "OFF" "STATUS"? "IS"? condition on-status?) - -(defrule on-status - := "ON" "STATUS"? "IS"? condition) - -(defrule special-names-paragraph-clause - ;; := alphabet-clause - ;; := symbolic-characters-clause - := currency-sign-clause - := decimal-point-clause) - -(defrule alphabet-clause - := "ALPHABET" alphabet-name "IS"? alphabet-type) - -(defrule alphabet-type-also - := "ALSO" literal) - -(defrule alphabet-type-alsos - := alphabet-type-also+) - -(defrule alphabet-type-also-through - := through-literal - := alphabet-type-alsos) - -(defrule alphabet-type-other - := literal alphabet-type-also-through?) - -(defrule alphabet-type-others - := alphabet-type-other+) - -(defrule alphabet-type - := "STANDARD-1" - := "STANDARD-2" - := "NATIVE" - := "EBCDIC" - := alphabet-type-others) - -(defrule symbolic-characters-clause - := "SYMBOLIC" "CHARACTERS"? symbolic-character-mapping+ in-alphabet-name?) - -(defrule are - := "ARE" - := "IS") - -(defrule symbolic-character-mapping - := symbolic-character+ are? integer+) - -(defrule in-alphabet-name - := "IN" alphabet-name) - -(defrule currency-sign-clause - := "CURRENCY" "SIGN"? "IS"? literal - :reduce (list :currency-sign literal)) - -(defrule decimal-point-clause - := "DECIMAL-POINT" "IS"? "COMMA" - :reduce (list :decimal-point #\,)) - -(defrule data-division-content - := file-section? working-storage-section? linkage-section?) - -(defrule file-section-entry - := file-and-sort-description-entry data-description-entry+ - :reduce (cons file-and-sort-description-entry data-description-entry)) - -(defrule file-section-head - := "FILE" "SECTION" ".") - -(defrule file-section - := file-section-head file-section-entry* - :reduce $2) - -(defrule working-storage-section-head - := "WORKING-STORAGE" "SECTION" ".") - -(defrule working-storage-section - := working-storage-section-head data-description-entry* - :reduce $2) - -(defrule linkage-section-head - := "LINKAGE" "SECTION" ".") - -(defrule linkage-section - := linkage-section-head data-description-entry* - :reduce $2) - -(defrule file-and-sort-description-entry - := alt-fd-sd file-name file-and-sort-description-entry-clause* "." - :reduce (list (make-keyword alt-fd-sd) file-name file-and-sort-description-entry-clause)) - -(defrule alt-fd-sd - := "FD" - := "SD") - -(defrule file-and-sort-description-entry-clause - := external-clause - := global-clause - := block-contains-clause - := record-clause - := label-records-clause - := value-of-clause - := data-records-clause - := linage-clause - := recording-mode-clause - := code-set-clause) - -(defrule integer-to - := integer "TO") - -(defrule block-contains-clause - := "BLOCK" "CONTAINS"? integer-to? integer alt-characters-records?) - -(defrule alt-characters-records - := "CHARACTERS" - := "RECORDS" - := "RECORD") - -(defrule record-clause - := "RECORD" record-clause-tail) - -(defrule depending-on - := "DEPENDING" "ON"? data-name) - -(defrule record-clause-tail-1 - := "CONTAINS"? integer "CHARACTERS"?) - -(defrule record-clause-tail-2 - := "CONTAINS"? integer "TO" integer "CHARACTERS"?) - -(defrule record-clause-tail-3 - := record-varying-phrase depending-on?) - -(defrule record-clause-tail - := record-clause-tail-2 - := record-clause-tail-1 - := record-clause-tail-3) - -(defrule record-varying-phrase - := "IS"? "VARYING" "IN"? "SIZE"? from-integer? to-integer? "CHARACTERS"?) - -(defrule from-integer - := "FROM"? integer) - -(defrule to-integer - := "TO" integer) - -(defrule label-records-clause - := "LABEL" records-are label-records-clause-tail - :reduce (list :label-record label-records-clause-tail)) - -(defrule data-names - := data-name+) - -(defrule label-records-clause-tail - := "STANDARD" :reduce :standard - := "OMITTED" :reduce :omitted - := data-names) - -(defrule value-of-clause - := "VALUE" "OF" value-of-clause-tail+) - -(defrule alt-qualified-data-name-literal - := qualified-data-name - := literal) - -(defrule value-of-clause-tail - := variable-identifier "IS"? alt-qualified-data-name-literal) - -(defrule data-records-clause - := "DATA" records-are data-name+) - -(defrule records-are - := records are?) - -(defrule linage-clause - := "LINAGE" "IS"? alt-data-name-integer "LINES"? linage-footing-phrase) - -(defrule linage-footing-phrase - := footing? lines-top? lines-bottom?) - -(defrule alt-data-name-integer - := data-name - := integer) - -(defrule footing - := "WITH"? "FOOTING" "AT"? alt-data-name-integer) - -(defrule lines-top - := "LINES"? "AT"? "TOP" alt-data-name-integer) - -(defrule lines-bottom - := "LINES"? "AT"? "BOTTOM" alt-data-name-integer) - -(defrule recording-mode-clause - := "RECORDING" "MODE"? "IS"? variable-identifier) - -(defrule code-set-clause - := "CODE-SET" "IS"? alphabet-name) - -(defrule data-description-entry - := level-number alt-data-name-filler? data-description-entry-clause* "." - :reduce (append (list level-number alt-data-name-filler) - (flatten-list data-description-entry-clause))) - -(defrule alt-data-name-filler - := data-name - := "FILLER" - :reduce (list)) - -(defrule data-description-entry-clause - := picture-clause - := redefines-clause - := blank-when-zero-clause - := external-clause - := global-clause - := justified-clause - := occurs-clause - := sign-clause - := synchronized-clause - := usage-clause - := renames-clause - := value-clause) - -(defrule value-clause - := "VALUE" "IS"? literal - :reduce (list :value literal)) - -(defrule redefines-clause - := "REDEFINES" data-name - :reduce `(:redefines ,data-name)) - -(defrule blank-when-zero-clause - := "BLANK" "WHEN"? zeroes - :reduce '(:blank-when-zero t)) - -(defrule zeroes - := "ZERO" - := "ZEROS" - := "ZEROES") - -(defrule external-clause - := "IS"? "EXTERNAL" - :reduce '(:external t)) - -(defrule global-clause - := "IS"? "GLOBAL" - :reduce '(:global t)) - -(defrule justified-clause - := justified "RIGHT"? - :reduce `(:justified ,(if $2 :right :left))) - -(defrule justified - := "JUSTIFIED" - := "JUST") - -(defrule occurs-clause - := "OCCURS" integer "TIMES"? occurs-clause-key* indexed-by? - ;; to be completed -wcp16/7/03. - :reduce `(:times ,integer) - := "OCCURS" integer "TO" integer "TIMES"? "DEPENDING" "ON"? qualified-data-name occurs-clause-key* indexed-by? - ;; to be completed -wcp16/7/03. - :reduce `(:times (,integer ,integer2 ,qualified-data-name))) - -(defrule occurs-clause-key - := alt-ascending-descending "KEY"? "IS"? qualified-data-name+) - -(defrule indexed-by - := "INDEXED" "BY"? index-name+) - -(defrule picture-clause - := picture "IS"? picture-string - :reduce `(:picture ,picture-string)) - -(defrule picture - := "PICTURE" - := "PIC") - -(defrule sign-clause - := sign-is? alt-leading-trailing separate-character? - :reduce `(:separate-sign ,separate-character :sign-position ,alt-leading-trailing)) - -(defrule sign-is - := "SIGN" "IS"?) - -(defrule separate-character - := "SEPARATE" "CHARACTER"? - :reduce t) - -(defrule alt-leading-trailing - := "LEADING" - :reduce :leading - := "TRAILING" - :reduce :trailing) - -(defrule synchronized-clause - := synchronized alt-left-right? - :reduce `(:synchronized ,(if alt-left-right - alt-left-right - t))) - -(defrule alt-left-right - := "LEFT" - :reduce :left - := "RIGHT" - :reduce :right) - -(defrule synchronized - := "SYNCHRONIZED" - := "SYNC") - -(defrule usage-clause - := usage-is? usage - :reduce (list :encoding usage)) - -(defrule usage-is - := "USAGE" "IS"?) - -(defrule usage - := "BINARY" - :reduce :binary - := "COMP" - :reduce :comp - := "COMP-1" - :reduce :comp1 - := "COMP-2" - :reduce :comp2 - := "COMP-3" - :reduce :comp3 - := "COMP-4" - :reduce :comp4 - := "COMPUTATIONAL" - :reduce :comp - := "COMPUTATIONAL-1" - :reduce :comp1 - := "COMPUTATIONAL-2" - :reduce :comp2 - := "COMPUTATIONAL-3" - :reduce :comp3 - := "COMPUTATIONAL-4" - :reduce :comp4 - := "DISPLAY" - :reduce :display - := "DISPLAY-1" - :reduce :display1 - := "INDEX" - :reduce :index - := "PACKED-DECIMAL" - :reduce :packed-decimal - := "POINTER" - :reduce :pointer) - -(defrule renames-clause - := "RENAMES" qualified-data-name through-qualified-data-name? - :reduce `(:renames ,qualified-data-name ,through-qualified-data-name)) - -(defrule through-qualified-data-name - := through qualified-data-name - :reduce qualified-data-name) - -(defrule condition-value-clause - := values-are literal-through-literal+) - -(defrule through-literal - := through literal) - -(defrule literal-through-literal - := literal through-literal?) - -(defrule values-are - := values are?) - -(defrule procedure-division-head - := "PROCEDURE" "DIVISION" using-phrase? ".") - -(defrule procedure-division - := procedure-division-head sentence+) - -(defrule using-phrase - := "USING" data-name+) - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -(defrule declaratives - := "DECLARATIVES" "." declaratives-content+ "END" "DECLARATIVES" ".") - -(defrule declaratives-content - := cobol-identifier "SECTION" "." use-statement "." sentence*) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - - -(defrule paragraph-header - := cobol-identifier "SECTION"? - :reduce (list (if $2 :section :label) $1)) - -(defrule sentence - := declaratives - := statement* "." - :reduce $1 - := paragraph-header "." - :reduce $1) - -(defrule statement - := move-statement - := if-statement - := perform-statement - := go-to-statement - := accept-statement - := add-statement - := alter-statement - := call-statement - := cancel-statement - := close-statement - := compute-statement - := continue-statement - := delete-statement - := display-statement - := divide-statement - := entry-statement - := evaluate-statement - := exit-program-statement - := exit-statement - := goback-statement - := initialize-statement - := inspect-statement - := merge-statement - := multiply-statement - := open-statement - := read-statement - := release-statement - := return-statement - := rewrite-statement - := search-statement - := set-statement - := sort-statement - := start-statement - := stop-statement - := string-statement - := subtract-statement - := unstring-statement - := write-statement - := paragraph-header) - -(defrule accept-statement - := "ACCEPT" variable-identifier "FROM" date - := "ACCEPT" variable-identifier "AT" screen-coordinates - :reduce (apply #'list 'accept-at variable-identifier screen-coordinates) - := "ACCEPT" variable-identifier from-environment-name?) - -(defrule from-environment-name - := "FROM" cobol-identifier) - - -(defrule date - := "DATE" - := "DAY" - := "DAY-OF-WEEK" - := "TIME") - -(defrule add-statement - := "ADD" id-or-lit+ to-id-or-lit? "GIVING" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-ADD"? - := "ADD" id-or-lit+ "TO" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-ADD"? - := "ADD" corresponding variable-identifier "TO" variable-identifier "ROUNDED"? on-size-error-statement-list? not-on-size-error-statement-list? "END-ADD"?) - -(defrule statement-list - := statement+) - -(defrule alter-statement - := "ALTER" procedure-to-procedure+) - -(defrule proceed-to - := "PROCEED" "TO") - -(defrule procedure-to-procedure - := procedure-name "TO" proceed-to? procedure-name) - -(defrule call-statement - := "CALL" id-or-lit using-parameters? call-rest-phrase "END-CALL"? - :reduce (list 'call id-or-lit (cons 'list using-parameters))) - -(defrule by-reference - := "BY"? "REFERENCE") - -(defrule content-parameter-value - := cobol-identifier - := literal) - -(defrule reference-parameter - := by-reference? variable-identifier) - -(defrule content-parameter - := "BY"? "CONTENT" content-parameter-value+) - -(defrule parameter - := reference-parameter - := content-parameter - := literal) - -(defrule using-parameters - := "USING" parameter+) - -(defrule call-rest-phrase - := on-exception-statement-list? not-on-exception-statement-list? on-overflow-statement-list?) - -(defrule on-exception-statement-list - := "ON"? "EXCEPTION" statement-list) - -(defrule not-on-exception-statement-list - := "NOT" "ON"? "EXCEPTION" statement-list) - -(defrule cancel-statement - := "CANCEL" id-or-lit+) - -(defrule close-statement - := "CLOSE" close-statement-file-name+ - :reduce (list 'close close-statement-file-name)) - -(defrule alt-removal-no-rewind - := for-removal - := with-no-rewind) - -(defrule alt-reel-unit - := "REEL" - := "UNIT") - -(defrule alt-no-rewind-lock - := no-rewind - := "LOCK") - -(defrule close-statement-options-1 - := alt-reel-unit alt-removal-no-rewind?) - -(defrule close-statement-options-2 - := "WITH"? alt-no-rewind-lock) - -(defrule close-statement-options - := close-statement-options-1 - := close-statement-options-2) - -(defrule close-statement-file-name - := file-name close-statement-options?) - -(defrule compute-statement - := "COMPUTE" cobword-rounded+ equal arithmetic-expression on-size-error-statement-list? not-on-size-error-statement-list? "END-COMPUTE"? - :reduce (list 'compute cobword-rounded arithmetic-expression :on-size-error on-size-error-statement-list - :not-on-size-error not-on-size-error-statement-list)) - -(defrule equal - := "=" - := "EQUAL") - -(defrule continue-statement - := "CONTINUE") - -(defrule delete-statement - := "DELETE" file-name "RECORD"? invalid-key-statement-list? not-invalid-key-statement-list? "END-DELETE"? - :reduce (list 'delete file-name :invalid invalid-key-statement-list :not-invalid not-invalid-key-statement-list)) - -(defrule display-statement - := "DISPLAY" id-or-lit+ upon-environment-name? with-no-advancing? - :reduce (list 'display (cons 'list id-or-lit) :upon upon-environment-name :advance (not with-no-advancing)) - := "DISPLAY" id-or-lit "AT" screen-coordinates - :reduce (apply #'list 'display-at id-or-lit screen-coordinates)) - -(defrule screen-coordinates - := integer - :reduce (multiple-value-list (truncate integer 100))) - -(defrule upon-environment-name - := "UPON" cobol-identifier) - -(defrule with-no-advancing - := "WITH"? "NO" "ADVANCING") - -(defrule divide-statement - := "DIVIDE" id-or-lit "INTO" id-or-lit "GIVING" variable-identifier "ROUNDED"? "REMAINDER" variable-identifier on-size-error-statement-list? not-on-size-error-statement-list? "END-DIVIDE"? - := "DIVIDE" id-or-lit "BY" id-or-lit "GIVING" variable-identifier "ROUNDED"? "REMAINDER" variable-identifier on-size-error-statement-list? not-on-size-error-statement-list? "END-DIVIDE"? - := "DIVIDE" id-or-lit "INTO" id-or-lit "GIVING" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-DIVIDE"? - := "DIVIDE" id-or-lit "BY" id-or-lit "GIVING" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-DIVIDE"? - := "DIVIDE" id-or-lit "INTO" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-DIVIDE"?) - -(defrule entry-statement - := "ENTRY" literal using-phrase?) - -(defrule evaluate-statement - := "EVALUATE" evaluate-condition also-phrase* when-phrases+ when-other-phrase? "END-EVALUATE"?) - -(defrule evaluate-condition - := condition - := "TRUE" - := "FALSE") - -(defrule also-phrase - := "ALSO" evaluate-condition) - -(defrule when-phrase-also-phrase - := "ALSO" evaluate-phrase) - -(defrule when-phrase - := "WHEN" evaluate-phrase when-phrase-also-phrase*) - -(defrule when-phrases - := when-phrase+ statement-list) - -(defrule when-other-phrase - := "WHEN" "OTHER" statement-list) - -(defrule evaluate-phrase - := "ANY" - := condition - := "TRUE" - := "FALSE" - := evaluate-phrase-1) - -(defrule evaluate-phrase-1 - := "NOT"? arithmetic-expression through-arithmetic-expression?) - -(defrule through-arithmetic-expression - := through arithmetic-expression) - -(defrule exit-statement - := "EXIT" - :reduce '(exit-paragraph)) - -(defrule exit-program-statement - := "EXIT" "PROGRAM" - :reduce '(exit-program)) - -(defrule goback-statement - := "GOBACK" - :reduce '(go-back)) - -(defrule go-to-statement - := "GO" "TO"? procedure-name+ "DEPENDING" "ON"? variable-identifier - :reduce (list 'goto-depending variable-identifier procedure-name) - := "GO" "TO"? procedure-name - :reduce (list 'goto procedure-name)) - -(defrule if-phrase - := "IF" condition "THEN"? alt-statement-list-next-sentence "ELSE" alt-statement-list-next-sentence - :reduce (list 'if condition - (if (cdr alt-statement-list-next-sentence) - (cons 'progn alt-statement-list-next-sentence) - (car alt-statement-list-next-sentence)) - (if (cdr alt-statement-list-next-sentence2) - (cons 'progn alt-statement-list-next-sentence2) - (car alt-statement-list-next-sentence2))) - := "IF" condition "THEN"? alt-statement-list-next-sentence - :reduce (append (list 'when condition) alt-statement-list-next-sentence)) - -(defrule if-statement - := if-phrase "END-IF"? - :reduce $1) - -(defrule initialize-statement - := "INITIALIZE" variable-identifier+ initialize-replacing-phrase?) - -(defrule initialize-replacing-type - := "ALPHABETIC" - := "ALPHANUMERIC" - := "NUMERIC" - := "ALPHANUMERIC-EDITED" - := "NUMERIC-EDITED" - := "DBCS" - := "EGCS") - -(defrule initialize-replacing-argument - := initialize-replacing-type "DATA"? "BY" id-or-lit) - -(defrule initialize-replacing-phrase - := "REPLACING" initialize-replacing-argument+) - -(defrule inspect-statement - := inspect-statement-1 - := inspect-statement-2 - := inspect-statement-3 - := inspect-statement-4) - -(defrule inspect-statement-1 - := "INSPECT" variable-identifier "TALLYING" tallying-argument+) - -(defrule inspect-statement-2 - := "INSPECT" variable-identifier "CONVERTING" id-or-lit "TO" id-or-lit before-after-phrase*) - -(defrule inspect-statement-3 - := "INSPECT" variable-identifier "TALLYING" tallying-argument+ "REPLACING" inspect-replacing-phrase+) - -(defrule tallying-for-id-or-lit - := id-or-lit before-after-phrase*) - -(defrule alt-all-leading - := "ALL" - := "LEADING") - -(defrule tallying-for-argument-1 - := "CHARACTERS" before-after-phrase*) - -(defrule tallying-for-argument-2 - := alt-all-leading tallying-for-id-or-lit+) - -(defrule tallying-for-argument - := tallying-for-argument-1 - := tallying-for-argument-2) - -(defrule tallying-argument - := variable-identifier "FOR" tallying-for-argument+) - -(defrule inspect-statement-4 - := "INSPECT" variable-identifier "REPLACING" inspect-replacing-phrase+) - -(defrule inspect-replacing-argument - := inspect-by-argument "BY" inspect-by-argument before-after-phrase*) - -(defrule alt-all-leading-first - := "ALL" - := "LEADING" - := "FIRST") - -(defrule inspect-replacing-phrase-1 - := "CHARACTERS" "BY" id-or-lit before-after-phrase*) - -(defrule inspect-replacing-phrase-2 - := alt-all-leading-first inspect-replacing-argument+) - -(defrule inspect-replacing-phrase - := inspect-replacing-phrase-1 - := inspect-replacing-phrase-2) - -(defrule before-after-phrase - := alt-before-after "INITIAL"? id-or-lit) - -(defrule merge-statement - := "MERGE" file-name on-key-phrase+ collating-sequence? "USING" file-name file-name+ merge-statement-tail) - -(defrule on-key-phrase - := "ON"? alt-ascending-descending "KEY"? qualified-data-name+) - -(defrule merge-statement-tail - := output-procedure - := giving-file-names) - -(defrule move-statement - := "MOVE" id-or-lit "TO" variable-identifier+ - :reduce (apply #'list 'move id-or-lit variable-identifier) - := "MOVE" corresponding variable-identifier "TO" variable-identifier+ - :reduce (apply #'list 'move-corresponding variable-identifier variable-identifier2)) - -(defrule multiply-statement - := "MULTIPLY" id-or-lit "BY" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-MULTIPLY"? - :reduce (list 'multiply id-or-lit cobword-rounded :on-size-error on-size-error-statement-list - :not-on-size-error not-on-size-error-statement-list) - := "MULTIPLY" id-or-lit "BY" id-or-lit "GIVING" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-MULTIPLY"? - :reduce (list 'multiply id-or-lit id-or-lit2 :giving cobword-rounded - :on-size-error on-size-error-statement-list - :not-on-size-error not-on-size-error-statement-list)) - -(defrule open-statement - := "OPEN" open-statement-phrase+ - :reduce (list 'open open-statement-phrase)) - -(defrule alt-reversed-with-no-rewind - := "REVERSED" - := with-no-rewind) - -(defrule open-statement-input-file-name - := file-name alt-reversed-with-no-rewind?) - -(defrule with-no-rewind - := "WITH"? "NO" "REWIND") - -(defrule open-statement-output-file-name - := file-name with-no-rewind?) - -(defrule open-statement-input - := "INPUT" open-statement-input-file-name+) - -(defrule open-statement-output - := "OUTPUT" open-statement-output-file-name+) - -(defrule open-statement-i-o - := "I-O" file-name+) - -(defrule open-statement-extend - := "EXTEND" file-name+) - -(defrule open-statement-phrase - := open-statement-input - := open-statement-output - := open-statement-i-o - := open-statement-extend) - -(defrule perform-statement - := "PERFORM" procedure-name through-procedure-name? perform-until-phrase - :reduce `(perform-until ,procedure-name ,through-procedure-name ,perform-until-phrase) - := "PERFORM" procedure-name through-procedure-name? perform-varying-phrase perform-after-phrase* - :reduce `(perform-varying ,perform-varying-phrase ,procedure-name ,through-procedure-name ,perform-after-phrase) - := "PERFORM" procedure-name through-procedure-name? cobword-int "TIMES" - :reduce `(perform-times ,cobword-int ,procedure-name ,through-procedure-name) - := "PERFORM" procedure-name through-procedure-name? - :reduce (append (list 'perform procedure-name) through-procedure-name)) - -(defrule perform-varying-phrase - := with-test? "VARYING" variable-identifier "FROM" id-or-lit "BY" id-or-lit "UNTIL" condition) - -(defrule perform-after-phrase - := "AFTER" variable-identifier "FROM" id-or-lit "BY" id-or-lit "UNTIL" condition) - -(defrule perform-until-phrase - := with-test? "UNTIL" condition) - -(defrule with-test - := "WITH"? "TEST" alt-before-after - :reduce alt-before-after) - -(defrule read-statement - := "READ" file-name "NEXT"? "RECORD"? into-identifier? key-is-qualified-data-name? invalid-key-statement-list? not-invalid-key-statement-list? at-end-statement-list? not-at-end-statement-list? "END-READ"?) - -(defrule key-is-qualified-data-name - := "KEY" "IS"? qualified-data-name) - -(defrule release-statement - := "RELEASE" record-name from-identifier?) - -(defrule return-statement - := "RETURN" file-name "RECORD"? into-identifier? "AT"? "END" statement-list not-at-end-statement-list? "END-RETURN"?) - -(defrule into-identifier - := "INTO" variable-identifier) - -(defrule not-at-end-statement-list - := "NOT" "AT"? "END" statement-list) - -(defrule rewrite-statement - := "REWRITE" record-name from-identifier? invalid-key-statement-list? not-invalid-key-statement-list? "END-REWRITE"?) - -(defrule search-statement - := search-statement-1 - := search-statement-2) - -(defrule search-statement-1 - := "SEARCH" cobol-identifier varying-identifier? at-end-statement-list? when-condition-stats+ "END-SEARCH"?) - -(defrule varying-identifier - := "VARYING" variable-identifier) - -(defrule when-condition-stats - := "WHEN" condition alt-statement-list-next-sentence) - -(defrule search-statement-2 - := "SEARCH" "ALL" variable-identifier at-end-statement-list? "WHEN" search-statement-condition search-statement-condition-tail* alt-statement-list-next-sentence "END-SEARCH"?) - -(defrule at-end-statement-list - := "AT"? "END" statement-list) - -(defrule search-statement-equal-expression - := variable-identifier "IS"? equal-to arithmetic-expression - :reduce (list '= variable-identifier arithmetic-expression)) - -(defrule search-statement-condition - := search-statement-equal-expression - := condition-name-reference) - -(defrule search-statement-condition-tail - := "AND" search-statement-condition) - -(defrule alt-statement-list-next-sentence - := statement+ - := next-sentence - :reduce :next-sentence) - -(defrule set-statement - := "SET" set-statement-phrase+) - -(defrule sort-statement - := "SORT" file-name on-key-is-phrase+ with-duplicates-in-order? collating-sequence? sort-statement-in sort-statement-out) - -(defrule key-is - := "KEY" "IS"?) - -(defrule alt-ascending-descending - := "ASCENDING" - := "DESCENDING") - -(defrule on-key-is-phrase - := "ON"? alt-ascending-descending key-is? qualified-data-name+) - -(defrule with-duplicates-in-order - := "WITH"? "DUPLICATES" "IN"? "ORDER"?) - -(defrule collating-sequence - := "COLLATING"? "SEQUENCE" "IS"? alphabet-name) - -(defrule through - := "THROUGH" - := "THRU") - -(defrule through-procedure-name - := through procedure-name - :reduce procedure-name) - -(defrule using-file-names - := "USING" file-name+) - -(defrule input-procedure - := "INPUT" "PROCEDURE" "IS"? procedure-name through-procedure-name?) - -(defrule giving-file-names - := "GIVING" file-name+) - -(defrule output-procedure - := "OUTPUT" "PROCEDURE" "IS"? procedure-name through-procedure-name?) - -(defrule sort-statement-in - := using-file-names - := input-procedure) - -(defrule sort-statement-out - := giving-file-names - := output-procedure) - -(defrule start-statement - := "START" file-name key-is-rel-op-qualified-data-name? invalid-key-statement-list? not-invalid-key-statement-list? "END-START"?) - -(defrule rel-op - := equal-to - :reduce '= - := greater-than - :reduce '> - := greater-equal - :reduce '>=) - -(defrule key-is-rel-op-qualified-data-name - := "KEY" "IS"? rel-op qualified-data-name - :reduce (list rel-op qualified-data-name)) - -(defrule stop-statement - := "STOP" alt-run-literal - :reduce '(stop)) - -(defrule alt-run-literal - := "RUN" - := literal) - -(defrule string-statement - := "STRING" delimited-by-phrase+ "INTO" variable-identifier with-pointer-identifier? on-overflow-statement-list? not-on-overflow-statement-list? "END-STRING"? - :reduce (list 'string-concat delimited-by-phrase variable-identifier :with-pointer with-pointer-identifier :on-overflow on-overflow-statement-list :not-on-overflow not-on-overflow-statement-list)) - -(defrule id-or-lit-size - := literal - := variable-identifier - := "SIZE") - -(defrule delimited-by-phrase - := id-or-lit+ "DELIMITED" "BY"? id-or-lit-size - :reduce (list id-or-lit id-or-lit-size)) - -(defrule subtract-statement - := "SUBTRACT" id-or-lit+ "FROM" id-or-lit "GIVING" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-SUBTRACT"? - :reduce (list 'subtract-giving id-or-lit id-or-lit2 cobword-rounded - :on-size-error on-size-error-statement-list - :not-on-size-error not-on-size-error-statement-list) - := "SUBTRACT" id-or-lit+ "FROM" cobword-rounded+ on-size-error-statement-list? not-on-size-error-statement-list? "END-SUBTRACT"? - :reduce (list 'subtract id-or-lit cobword-rounded - :on-size-error on-size-error-statement-list - :not-on-size-error not-on-size-error-statement-list) - := "SUBTRACT" corresponding variable-identifier "FROM" variable-identifier "ROUNDED"? on-size-error-statement-list? not-on-size-error-statement-list? "END-SUBTRACT"? - :reduce (list 'subtract-corr variable-identifier variable-identifier - :rounded (and $5 t) - :on-size-error on-size-error-statement-list - :not-on-size-error not-on-size-error-statement-list)) - -(defrule cobword-rounded - := variable-identifier "ROUNDED"? - :reduce (list variable-identifier (and $2 t))) - -(defrule on-size-error-statement-list - := "ON"? "SIZE" "ERROR" statement-list - :reduce statement-list) - -(defrule not-on-size-error-statement-list - := "NOT" "ON"? "SIZE" "ERROR" statement-list - :reduce statement-list) - -(defrule corresponding - := "CORRESPONDING" - := "CORR") - -(defrule unstring-statement - := "UNSTRING" variable-identifier delimited-by-all-phrase? "INTO" unstring-statement-dst+ with-pointer-identifier? tallying-in-identifier? on-overflow-statement-list? not-on-overflow-statement-list? "END-UNSTRING"? - :reduce (list 'unstring variable-identifier unstring-statement-dst - :delimited-by-all delimited-by-all-phrase - :with-pointer with-pointer-identifier - :tallying tallying-in-identifier - :on-overflow on-overflow-statement-list - :not-on-overflow not-on-overflow-statement-list)) - -(defrule id-or-lit - := literal - := variable-identifier) - -(defrule or-all-id-or-lit - := "OR" "ALL"? id-or-lit) - -(defrule delimited-by-all-phrase - := "DELIMITED" "BY"? "ALL"? id-or-lit or-all-id-or-lit*) - -(defrule delimiter-in-identifier - := "DELIMITER" "IN"? variable-identifier) - -(defrule count-in-identifier - := "COUNT" "IN"? variable-identifier) - -(defrule unstring-statement-dst - := variable-identifier delimiter-in-identifier? count-in-identifier?) - -(defrule with-pointer-identifier - := "WITH"? "POINTER" variable-identifier) - -(defrule tallying-in-identifier - := "TALLYING" "IN"? variable-identifier) - -(defrule on-overflow-statement-list - := "ON"? "OVERFLOW" statement-list) - -(defrule not-on-overflow-statement-list - := "NOT" "ON"? "OVERFLOW" statement-list) - -(defrule write-statement - := "WRITE" record-name from-identifier? advancing-phrase? write-exceptions "END-WRITE"?) - -(defrule lines - := "LINE" - := "LINES") - -(defrule cobword-int - := cobol-identifier - := integer) - -(defrule nr-lines-phrase - := cobword-int lines?) - -(defrule page-phrase - := nr-lines-phrase - := "PAGE") - -(defrule alt-before-after - := "BEFORE" - := "AFTER") - -(defrule advancing-phrase - := alt-before-after "ADVANCING"? page-phrase) - -(defrule from-identifier - := "FROM" variable-identifier) - -(defrule invalid-key-statement-list - := "INVALID" "KEY"? statement-list - :reduce statement-list) - -(defrule not-invalid-key-statement-list - := "NOT" "INVALID" "KEY"? statement-list - :reduce statement-list) - -(defrule end-of-page - := "END-OF-PAGE" - := "EOP") - -(defrule at-end-of-page-statement-list - := "AT"? end-of-page statement-list - :reduce statement-list) - -(defrule not-at-end-of-page-statement-list - := "NOT" "AT"? end-of-page statement-list - :reduce statement-list) - -;; This is left in the grammar but is not used. COPYs are handled by -;; the lexical scanner. -(defrule copy-statement - := "COPY" alt-text-name-literal in-library? "SUPPRESS"? copy-statement-replacing-phrase?) - -(defrule in - := "OF" - := "IN") - -(defrule alt-library-name-literal - := library-name - := literal) - -(defrule in-library - := in alt-library-name-literal) - -(defrule copy-statement-by-phrase - := copy-operand "BY" copy-operand) - -(defrule copy-statement-replacing-phrase - := "REPLACING" copy-statement-by-phrase+) - -(defrule alt-text-name-literal - := text-name - := literal) - -(defrule copy-operand - := cobol-identifier - := literal) - -(defrule use-statement - := use-statement-1 - := use-statement-2 - := use-statement-3) - -(defrule use-statement-1 - := "USE" "GLOBAL"? "AFTER" "STANDARD"? alt-exception-error "PROCEDURE" "ON"? alt-file-names-i-o) - -(defrule alt-exception-error - := "EXCEPTION" - := "ERROR") - -(defrule use-statement-2 - := "USE" "GLOBAL"? "AFTER" "STANDARD"? alt-beginning-ending? alt-file-reel-unit? "LABEL" "PROCEDURE" "ON"? alt-file-names-i-o) - -(defrule alt-beginning-ending - := "BEGINNING" - := "ENDING") - -(defrule alt-file-reel-unit - := "FILE" - := "REEL" - := "UNIT") - -(defrule file-names - := file-name+) - -(defrule alt-file-names-i-o - := file-names - := "INPUT" - := "OUTPUT" - := "I-O" - := "EXTEND") - -(defrule use-statement-3 - := "USE" "FOR"? "DEBUGGING" "ON"? alt-procedures-all-procedures) - -(defrule procedure-names - := procedure-name+) - -(defrule alt-procedures-all-procedures - := procedure-names - := all-procedures) - -(defrule condition - := combinable-condition - := combinable-condition "AND" condition - :reduce `(and ,combinable-condition ,condition) - := combinable-condition "OR" condition - :reduce `(or ,combinable-condition ,condition) - := combinable-condition "AND" id-or-lit - :reduce `(and ,combinable-condition (,(car combinable-condition) ,(cadr combinable-condition) ,id-or-lit)) - := combinable-condition "OR" id-or-lit - :reduce `(or ,combinable-condition (,(car combinable-condition) ,(cadr combinable-condition) ,id-or-lit))) - -(defrule combinable-condition - := "NOT"? simple-condition - :reduce (if $1 - (list 'not simple-condition) - simple-condition)) - -(defrule simple-condition - := class-condition - := relation-condition - := sign-condition - := "(" condition ")" - ;; not sure if it's necessary -wcp15/7/03. - ;; := arithmetic-expression - ) - -(defrule class-condition - := variable-identifier "IS"? "NOT"? class-type - :reduce (if $3 - (list 'not (list 'type-of variable-identifier (make-keyword class-type))) - (list 'type-of variable-identifier (make-keyword class-type)))) - -(defrule class-type - := "NUMERIC" - := "ALPHABETIC" - := "ALPHABETIC-LOWER" - := "ALPHABETIC-UPPER" - := "DBCS") - -(defun unfold-subrelations (main-relation subs) - (destructuring-bind (main-operator main-variable other-variable) main-relation - (declare (ignore other-variable)) - (labels ((unfold (subs) - (if (null subs) - main-relation - (destructuring-bind (connection operator variable) (car subs) - (list connection - (list (or operator main-operator) main-variable variable) - (unfold (cdr subs))))))) - (unfold subs)))) - -(defrule relation-condition - ;; This is too complex - ;; := arithmetic-expression relational-operator simple-condition - := id-or-lit relational-operator id-or-lit subordinate-relation* - :reduce (unfold-subrelations (list relational-operator id-or-lit id-or-lit2) subordinate-relation)) - -(defrule or-and - := "OR" :reduce 'or - := "AND" :reduce 'and) - -(defrule subordinate-relation - := or-and relational-operator? id-or-lit - :reduce (list or-and relational-operator id-or-lit)) - -(defrule relational-operator - := "IS"? relational-operator-type - :reduce relational-operator-type) - -(defrule less-than - := "LESS" "THAN"? - := "<") - -(defrule greater-equal - := "GREATER" "THAN"? "OR" "EQUAL" "TO"? - := ">=" - := ">" "=" - := "NOT" "<" - := "NOT" "LESS" "THAN"?) - -(defrule less-equal - := "LESS" "THAN"? "OR" "EQUAL" "TO"? - := "<=" - := "<" "=" - := "NOT" ">" - := "NOT" "GREATER" "THAN"?) - -(defrule greater-than - := "GREATER" "THAN"? - := ">") - -(defrule equal-to - := "EQUAL" "TO"? - := "=") - -(defrule relational-operator-type - := greater-equal - :reduce 'cob>= - := less-equal - :reduce 'cob<= - := greater-than - :reduce 'cob> - := less-than - :reduce 'cob< - := equal-to - :reduce 'cob= - := "NOT" equal-to - :reduce 'cob-not=) - -(defrule sign-condition - := arithmetic-expression "IS"? "NOT"? sign-type - :reduce (if $3 - `(not (,sign-type ,arithmetic-expression)) - `(,sign-type ,arithmetic-expression))) - -(defrule sign-type - := "POSITIVE" :reduce '> - := "NEGATIVE" :reduce '< - := "ZERO" :reduce '= - := "ZEROES" :reduce '= - := "ZEROS" :reduce '=) - -(defrule procedure-name - := paragraph-or-section-name in-section-name - :reduce (list paragraph-or-section-name in-section-name) - := paragraph-or-section-name - :reduce paragraph-or-section-name) - -(defrule in-section-name - := in cobol-identifier - :reduce cobol-identifier) - -(defrule variable-identifier - := qualified-data-name subscript-parentheses* ;; reference-modification? - :reduce (if subscript-parentheses - (list :aref qualified-data-name subscript-parentheses) - qualified-data-name)) - -(defrule reference-modification - := "(" leftmost-character-position ":" length? ")" - :reduce (if length - (list :range leftmost-character-position length) - leftmost-character-position)) - -(defrule condition-name-reference - := condition-name in-data-or-file-or-mnemonic-name* subscript-parentheses*) - -(defrule in-data-or-file-or-mnemonic-name - := in data-or-file-or-mnemonic-name) - -(defrule subscript-parentheses - := "(" subscript ")") - -(defrule subscript - := subscript-expression+) - -(defrule plus-minus-integer - := plus-or-minus integer) - -(defrule subscript-expression-ambiguous - := qualified-data-name plus-minus-integer?) - -(defrule subscript-expression - := literal - := subscript-expression-ambiguous) - -(defrule qualified-data-name - := data-name in-data-or-file-name* - :reduce (if in-data-or-file-name - (list data-name in-data-or-file-name) ; incomplete -wcp15/7/03. - data-name) - := "ADDRESS" "OF" data-name - :reduce (list 'address-of data-name) - := "LENGTH" "OF" cobol-identifier - :reduce (list 'length-of cobol-identifier)) - -(defrule in-data-or-file-name - := in data-or-file-name) - -(defrule leftmost-character-position - := arithmetic-expression) - -(defrule length - := arithmetic-expression) - -(defrule arithmetic-expression - := times-div - := times-div "+" arithmetic-expression - :reduce `(+ ,times-div ,arithmetic-expression) - := times-div "-" arithmetic-expression - :reduce `(- ,times-div ,arithmetic-expression)) - -(defrule times-div - := power - := power "*" times-div - :reduce `(* ,power ,times-div) - := power "/" times-div - :reduce `(/ ,power ,times-div)) - -(defrule power - := plus-or-minus? basis - := plus-or-minus? basis "**" power - :reduce (if plus-or-minus - `(plus-or-minus (expt basis basis2)) - `(expt basis basis2))) - -(defrule plus-or-minus - := "+" - :reduce '+ - := "-" - :reduce '-) - -;; (defrule power-tail -;; := "**" basis) - -(defrule basis - := literal - := variable-identifier - := "(" arithmetic-expression ")") - -(defrule alphabet-name - := cobol-identifier) - -(defrule condition-name - := cobol-identifier) - -(defrule data-name - := cobol-identifier) - -(defrule cobol-identifier - := identifier - :reduce (intern (string-upcase identifier))) - -(defrule file-name - := cobol-identifier) - -(defrule data-or-file-name - := cobol-identifier) - -(defrule index-name - := cobol-identifier) - -(defrule mnemonic-name - := cobol-identifier) - -(defrule data-or-file-or-mnemonic-name - := cobol-identifier) - -(defrule record-name - := qualified-data-name) - -(defrule symbolic-character - := cobol-identifier) - -(defrule library-name - := cobol-identifier) - -(defrule program-name - := cobol-identifier - := string) - -(defrule text-name - := cobol-identifier) - -(defrule paragraph-or-section-name - := cobol-identifier - := integer) - -(defrule computer-name - := identifier) - -(defrule environment-name - := cobol-identifier) - -(defrule assignment-name - := cobol-identifier) - -(defrule figurative-constant - := figurative-constant-simple - := figurative-constant-all) - -(defrule figurative-constant-all - := "ALL" literal) - -(defrule literal - := string - := float - := integer - := figurative-constant) - -) ; defun populate-grammar diff --git a/third_party/lisp/npg/npg.asd b/third_party/lisp/npg/npg.asd deleted file mode 100644 index 1e35186d6..000000000 --- a/third_party/lisp/npg/npg.asd +++ /dev/null @@ -1,55 +0,0 @@ -;;; npg.asd --- declaration of this system - -;;; Copyright (C) 2003, 2006 by Walter C. Pelissero - -;;; Author: Walter C. Pelissero -;;; Project: NPG a Naive Parser Generator - -#+cmu (ext:file-comment "$Module: npg.asd, Time-stamp: <2006-01-03 17:20:21 wcp> $") - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(defpackage :npg-system - (:use :common-lisp :asdf)) - -(in-package :npg-system) - -(defclass sample-file (doc-file) ()) -(defmethod source-file-type ((c sample-file) (s module)) - "lisp") - -(defsystem npg - :name "NPG" - :author "Walter C. Pelissero " - :maintainer "Walter C. Pelissero " - :licence "Lesser General Public License" - :description "NPG a Naive Parser Generator" - :long-description - "NPG is a backtracking recursive descent parser generator for -Common Lisp. It accepts rules in a Lispy EBNF syntax without indirect -left recursive rules." - :components - ((:doc-file "README") - (:doc-file "COPYING") - (:doc-file ".project") - (:module :examples - :components - ((:sample-file "python") - (:sample-file "vs-cobol-ii"))) - (:module :src - :components - ((:file "package") - (:file "common" :depends-on ("package")) - (:file "define" :depends-on ("package" "common")) - (:file "parser" :depends-on ("package" "common")))))) diff --git a/third_party/lisp/npg/src/common.lisp b/third_party/lisp/npg/src/common.lisp deleted file mode 100644 index 8b64f5cc0..000000000 --- a/third_party/lisp/npg/src/common.lisp +++ /dev/null @@ -1,79 +0,0 @@ -;;; common.lisp --- common stuff - -;;; Copyright (C) 2003-2006, 2009 by Walter C. Pelissero - -;;; Author: Walter C. Pelissero -;;; Project: NPG a Naive Parser Generator - -#+cmu (ext:file-comment "$Module: common.lisp $") - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :naive-parser-generator) - -(eval-when (:compile-toplevel :load-toplevel) - (defstruct grammar - rules - keywords - equal-p) - - (defstruct rule - name - productions) - - (defstruct (production (:conc-name prod-)) - tokens - (tokens-length 0 :type fixnum) - action) - - (defstruct token - type ; type of token (identifier, number, ...) - value ; its actual value - position) ; line/column in the input stream - ) ; eval-when - -(defmethod print-object ((obj rule) stream) - (format stream "#R(~A)" (rule-name obj))) - -(defmethod print-object ((obj production) stream) - (format stream "#P(action: ~S)" (prod-action obj))) - -(defmethod print-object ((obj token) stream) - (format stream "#T:~A=~S" (token-type obj) (token-value obj))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(declaim (inline make-rules-table find-rule add-rule)) - -(defun make-rules-table () - (make-hash-table)) - -(defun find-rule (rule-name rules) - (gethash rule-name rules)) - -(defun add-rule (rule-name rule rules) - (setf (gethash rule-name rules) rule)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(declaim (inline make-keywords-table find-keyword add-keyword)) - -(defun make-keywords-table () - (make-hash-table :test 'equal)) - -(defun find-keyword (keyword-name keywords) - (gethash keyword-name keywords)) - -(defun add-keyword (keyword keywords) - (setf (gethash keyword keywords) t)) diff --git a/third_party/lisp/npg/src/define.lisp b/third_party/lisp/npg/src/define.lisp deleted file mode 100644 index 783f071fc..000000000 --- a/third_party/lisp/npg/src/define.lisp +++ /dev/null @@ -1,408 +0,0 @@ -;;; define.lisp --- grammar rules definition - -;;; Copyright (C) 2003-2006, 2009 by Walter C. Pelissero - -;;; Author: Walter C. Pelissero -;;; Project: NPG a Naive Parser Generator - -#+cmu (ext:file-comment "$Module: define.lisp $") - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :naive-parser-generator) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defvar *smart-default-reduction* t - "If true the default reductions take only the non-static tokens - -those that are not declared as strings in the grammar.") - -;; These two are filled with DEFRULE. -(defvar *rules* (make-rules-table)) -(defvar *keywords* (make-keywords-table)) - -(defun make-action-arguments (tokens) - "Given a list of tokens making up a production, return three values: -the list of variables for the function reducing this production, those -that are non static and their unambiguous user-friendly names." - (flet ((unique (sym list) - (if (not (assoc sym list)) - sym - (loop - for i of-type fixnum from 2 - for x = (intern (format nil "~:@(~A~)~A" sym i)) - while (assoc x list) - finally (return x))))) - (loop - for tok in tokens - for i of-type fixnum from 1 - for arg = (intern (format nil "$~A" i) (find-package #.*package*)) - collect arg into args - unless (const-terminal-p tok) - collect arg into vars - and when (symbolp tok) - collect (list (unique tok named-vars) arg) into named-vars - when (and (listp tok) - (symbolp (cadr tok))) - collect (list (unique (cadr tok) named-vars) arg) into named-vars - finally - (return (values args vars named-vars))))) - -(defun make-action-function (name tokens action) - "Create a function with name NAME, arguments derived from TOKENS and -body ACTION. Return it's definition." - (let ((function - (multiple-value-bind (args vars named-vars) - (make-action-arguments tokens) - `(lambda ,args - (declare (ignorable ,@args)) - (let (($vars (list ,@vars)) - ($all (list ,@args)) - ,@named-vars - ($alist (list ,@(mapcar #'(lambda (v) - `(cons ',(intern (symbol-name (car v))) - ,(cadr v))) - named-vars)))) - (declare (ignorable $vars $all $alist ,@(mapcar #'car named-vars))) - (flet ((make-object (&optional type args) - (apply #'make-instance (or type ',name) - (append args $alist)))) - ,action)))))) - (when *compile-print* - (if *compile-verbose* - (format t "; Compiling ~S:~% ~S~%" name function) - (format t "; Compiling ~S~%" name))) - (compile name function))) - -(defun define-rule (name productions) - "Accept a rule in EBNF-like syntax, translate it into a sexp and a -call to INSERT-RULE-IN-CURRENT-GRAMMAR." - (flet ((transform (productions) - (loop - for tok in productions - with prod = nil - with action = nil - with phase = nil - with new-prods = nil - while tok - do (cond ((eq tok :=) - (push (list (nreverse prod) action) new-prods) - (setf prod nil - action nil - phase :prod)) - ((eq tok :reduce) - (setf phase :action)) - ((eq tok :tag) - (setf phase :tag)) - ((eq phase :tag) - (setf action `(cons ,tok $vars))) - ((eq phase :action) - (setf action tok)) - ((eq phase :prod) - (push tok prod))) - finally - (return (cdr (nreverse (cons (list (nreverse prod) action) new-prods))))))) - (insert-rule-in-current-grammar name (transform productions)))) - -(defmacro defrule (name &rest productions) - "Wrapper macro for DEFINE-RULE." - `(define-rule ',name ',productions)) - -(defun make-optional-rule (token) - "Make a rule for a possibly missing (non)terminal (? syntax) and -return it." - (insert-rule-in-current-grammar - (gensym (concatenate 'string "OPT-" - (if (rule-p token) - (symbol-name (rule-name token)) - (string-upcase token)))) - `(((,token)) (())))) - -(defun make-alternative-rule (tokens) - "Make a rule for a list of alternatives (\"or\" syntax) and return it." - (insert-rule-in-current-grammar - (gensym "ALT") - (mapcar #'(lambda (alternative) - `((,alternative))) - tokens))) - -(defun make-nonempty-list-rule (token &optional separator) - "Make a rule for a non-empty list (+ syntax) and return it." - (let ((rule-name (gensym (concatenate 'string "NELST-" - (if (rule-p token) - (symbol-name (rule-name token)) - (string-upcase token)))))) - (insert-rule-in-current-grammar - rule-name - (if separator - `(((,token ,separator ,rule-name) - (cons $1 $3)) - ((,token) ,#'list)) - `(((,token ,rule-name) - (cons $1 $2)) - ((,token) ,#'list)))))) - -(defun make-list-rule (token &optional separator) - "Make a rule for a possibly empty list (* syntax) return it." - (make-optional-rule (make-nonempty-list-rule token separator))) - -(defun const-terminal-p (object) - (or (stringp object) - (keywordp object))) - -(defun expand-production-token (tok) - "Translate token of the type NAME? or NAME* or NAME+ into (? NAME) -or (* NAME) or (+ NAME). This is used by the DEFRULE macro." - (if (symbolp tok) - (let* ((name (symbol-name tok)) - (last (char name (1- (length name)))) - ;; this looks silly but we need to make sure that we - ;; return symbols interned in this package, no one else - (op (cadr (assoc last '((#\? ?) (#\+ +) (#\* *)))))) - (if (and (> (length name) 1) op) - (list op - (intern (subseq name 0 (1- (length name))))) - tok)) - tok)) - -(defun EBNF-to-SEBNF (tokens) - "Take a production as a list of TOKENS and expand it. This turns a -EBNF syntax into a sexp-based EBNF syntax or SEBNF." - (loop - for tok in tokens - for token = (expand-production-token tok) - with new-tokens = '() - do (cond ((member token '(* + ?)) - (setf (car new-tokens) - (list token (car new-tokens)))) - (t - (push token new-tokens))) - finally (return (nreverse new-tokens)))) - -(defun SEBNF-to-BNF (tokens) - "Take a production in SEBNF (Symbolic Extended BNF) syntax and turn -it into BNF. The production is simplified but the current grammar is -populated with additional rules." - (flet ((make-complex-token-rule (tok) - (ecase (car tok) - (* (apply #'make-list-rule (cdr tok))) - (+ (apply #'make-nonempty-list-rule (cdr tok))) - (? (make-optional-rule (cadr tok))) - (or (make-alternative-rule (cdr tok)))))) - (loop - for token in tokens - with new-tokens = '() - with keywords = '() - do (cond ((listp token) - (push (make-complex-token-rule token) new-tokens)) - (t - (push token new-tokens) - (when (const-terminal-p token) - (push token keywords)))) - finally (return (values (nreverse new-tokens) keywords))))) - -(defun make-default-action-function (name tokens) - "Create a sexp to be used as default action in case one is not -supplied in the production. This is usually a quite sensible -one. That is, only the non-constant tokens are returned in a -list and in case only a variable token is available that one is -returned (not included in a list). If all the tokens are -constant, then all of them are returned in a list." - (cond ((null tokens) - ;; if the production matched the empty list (no tokens) we - ;; return always nil, that is the function LIST applied to no - ;; arguments - #'list) - ((null (cdr tokens)) - ;; if the production matches just one token we simply return - ;; that - #'identity) - (*smart-default-reduction* - ;; If we are required to be "smart" then create a function - ;; that simply returns the non static tokens of the - ;; production. If the production doesn't have nonterminal, - ;; then return all the tokens. If the production has only - ;; one argument then return that one only. - (make-action-function name tokens '(cond - ((null $vars) $all) - ((null (cdr $vars)) (car $vars)) - (t $vars)))) - (t - ;; in all the other cases we return all the token matching - ;; the production - #'list))) - -(defun make-production-from-descr (name production-description) - "Take a production NAME and its description in the form of a sexp -and return a production structure object together with a list of used -keywords." - (destructuring-bind (tokens &optional action) production-description - (let ((expanded-tokens (EBNF-to-SEBNF tokens))) - (multiple-value-bind (production-tokens keywords) - (sebnf-to-bnf expanded-tokens) - (let ((funct - (cond ((not action) - (make-default-action-function name expanded-tokens)) - ((or (listp action) - ;; the case when the action is simply to - ;; return a token (ie $2) or a constant value - (symbolp action)) - (make-action-function name expanded-tokens action)) - ((functionp action) - action) - (t ; action is a constant - #'(lambda (&rest args) - (declare (ignore args)) - action))))) - (values - ;; Make a promise instead of actually resolving the - ;; nonterminals. This avoids endless recursion. - (make-production :tokens production-tokens - :tokens-length (length production-tokens) - :action funct) - keywords)))))) - -(defun remove-immediate-left-recursivity (rule) - "Turn left recursive rules of the type - A -> A x | y -into - A -> y A2 - A2 -> x A2 | E -where E is the empty production." - (let ((name (rule-name rule)) - (productions (rule-productions rule))) - (loop - for prod in productions - for tokens = (prod-tokens prod) - ;; when immediately left recursive - when (eq (car tokens) rule) - collect prod into left-recursive - else - collect prod into non-left-recursive - finally - ;; found any left recursive production? - (when left-recursive - (warn "rule ~S is left recursive" name) - (let ((new-rule (make-rule :name (gensym "REWRITE")))) - ;; A -> y A2 - (setf (rule-productions rule) - (mapcar #'(lambda (p) - (let ((tokens (prod-tokens p)) - (action (prod-action p))) - (make-production :tokens (append tokens (list new-rule)) - :tokens-length (1+ (prod-tokens-length p)) - :action #'(lambda (&rest args) - (let ((f-A2 (car (last args))) - (head (butlast args))) - (funcall f-A2 (apply action head))))))) - non-left-recursive)) - ;; A2 -> x A2 | E - (setf (rule-productions new-rule) - (append - (mapcar #'(lambda (p) - (let ((tokens (prod-tokens p)) - (action (prod-action p))) - (make-production :tokens (append (cdr tokens) (list new-rule)) - :tokens-length (prod-tokens-length p) - :action #'(lambda (&rest args) - (let ((f-A2 (car (last args))) - (head (butlast args))) - #'(lambda (x) - (funcall f-A2 (apply action x head)))))))) - left-recursive) - (list - (make-production :tokens nil - :tokens-length 0 - :action #'(lambda () #'(lambda (arg) arg))))))))))) - -(defun remove-left-recursivity-from-rules (rules) - (loop - for rule being each hash-value in rules - do - ;; More to be done here. For now only the trivial immediate left - ;; recursivity is removed -wcp18/11/03. - (remove-immediate-left-recursivity rule))) - -(defun resolve-all-nonterminals (rules) - (loop - for rule being each hash-value in rules - do (loop - for production in (rule-productions rule) - do (setf (prod-tokens production) - (resolve-nonterminals (prod-tokens production) rules))))) - -(defun make-rule-productions (rule-name production-descriptions) - "Return a production object that belongs to RULE-NAME made according -to PRODUCTION-DESCRIPTIONS. See also MAKE-PRODUCTION-FROM-DESCR." - (loop - for descr in production-descriptions - for i of-type fixnum from 1 by 1 - for prod-name = (intern (format nil "~:@(~A~)-PROD~A" rule-name i)) - with productions = '() - with keywords = '() - do (progn - (multiple-value-bind (production keyws) - (make-production-from-descr prod-name descr) - (push production productions) - (setf keywords (append keyws keywords)))) - finally (return - (values (nreverse productions) keywords)))) - -(defun create-rule (name production-descriptions) - "Return a new rule object together with a list of keywords making up -the production definitions." - (multiple-value-bind (productions keywords) - (make-rule-productions name production-descriptions) - (values (make-rule :name name :productions productions) - keywords))) - -(defun insert-rule-in-current-grammar (name productions) - "Add rule to the current grammar and its keywords to the keywords -hash table. You don't want to use this directly. See DEFRULE macro -instead." - (when (find-rule name *rules*) - (error "redefining rule ~A" name)) - (multiple-value-bind (rule keywords) - (create-rule name productions) - (add-rule name rule *rules*) - (dolist (term keywords) - (add-keyword term *keywords*)) - rule)) - -(defun resolve-nonterminals (tokens rules) - "Given a list of production tokens, try to expand the nonterminal -ones with their respective rule from the the RULES pool." - (flet ((resolve-symbol (sym) - (or (find-rule sym rules) - sym))) - (mapcar #'(lambda (tok) - (if (symbolp tok) - (resolve-symbol tok) - tok)) - tokens))) - -(defun reset-grammar () - "Empty the current grammar from any existing rule." - (setf *rules* (make-rules-table) - *keywords* (make-keywords-table))) - -(defun generate-grammar (&optional (equal-p #'string-equal)) - "Return a GRAMMAR structure suitable for the PARSE function, using -the current rules. EQUAL-P, if present, is a function to be used to -match the input tokens; it defaults to STRING-EQUAL." - (resolve-all-nonterminals *rules*) - (remove-left-recursivity-from-rules *rules*) - (make-grammar :rules *rules* - :keywords *keywords* - :equal-p equal-p)) diff --git a/third_party/lisp/npg/src/package.lisp b/third_party/lisp/npg/src/package.lisp deleted file mode 100644 index b405f7b5f..000000000 --- a/third_party/lisp/npg/src/package.lisp +++ /dev/null @@ -1,50 +0,0 @@ -;;; package.lisp --- backtracking parser package definition - -;;; Copyright (C) 2003-2006, 2009 by Walter C. Pelissero - -;;; Author: Walter C. Pelissero -;;; Project: NPG a Naive Parser Generator - -#+cmu (ext:file-comment "$Module: package.lisp $") - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -(in-package :cl-user) - -(defpackage :naive-parser-generator - (:nicknames :npg) - (:use :common-lisp) - (:export - #:parse ; The Parser - #:reset-grammar - #:generate-grammar - #:print-grammar-figures - #:grammar-keyword-p - #:keyword - #:grammar - #:make-token - #:token-value - #:token-type - #:token-position - #:later-position - #:defrule ; to define grammars - #:deftoken ; to define a lexer - #:input-cursor-mixin - #:copy-input-cursor-slots - #:dup-input-cursor - #:read-next-tokens - #:end-of-input - #:? #:+ #:* #:or - #:$vars #:$all #:$alist - #:$1 #:$2 #:$3 #:$4 #:$5 #:$6 #:$7 #:$8 #:$9 #:$10)) diff --git a/third_party/lisp/npg/src/parser.lisp b/third_party/lisp/npg/src/parser.lisp deleted file mode 100644 index c15d26fe3..000000000 --- a/third_party/lisp/npg/src/parser.lisp +++ /dev/null @@ -1,234 +0,0 @@ -;;; parser.lisp --- runtime parser - -;;; Copyright (C) 2003-2006, 2009 by Walter C. Pelissero - -;;; Author: Walter C. Pelissero -;;; Project: NPG a Naive Parser Generator - -#+cmu (ext:file-comment "$Module: parser.lisp $") - -;;; This library is free software; you can redistribute it and/or -;;; modify it under the terms of the GNU Lesser General Public License -;;; as published by the Free Software Foundation; either version 2.1 -;;; of the License, or (at your option) any later version. -;;; This library is distributed in the hope that it will be useful, -;;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -;;; Lesser General Public License for more details. -;;; You should have received a copy of the GNU Lesser General Public -;;; License along with this library; if not, write to the Free -;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA -;;; 02111-1307 USA - -;;; Commentary: -;;; -;;; This is the runtime part of the parser. The code that is -;;; responsible to execute the parser defined with the primitives -;;; found in define.lisp. - -(in-package :naive-parser-generator) - -(defvar *debug* nil - "Either nil or a stream where to write the debug informations.") -#+debug (declaim (fixnum *maximum-recursion-depth*)) -#+debug (defvar *maximum-recursion-depth* 1000 - "Maximum depth the parser is allowed to recursively call itself. -This is the only way for the parser to detect a loop in the grammar. -Tune this if your grammar is unusually complex.") - -(declaim (inline reduce-production)) -(defun reduce-production (production arguments) - "Apply PRODUCTION's action on ARGUMENTS. This has the effect of - \"reducing\" the production." - (when *debug* - (format *debug* "reducing ~S on ~S~%" production arguments)) - (flet ((safe-token-value (token) - (if (token-p token) - (token-value token) - token))) - (apply (prod-action production) (mapcar #'safe-token-value arguments)))) - -(defgeneric later-position (pos1 pos2) - (:documentation - "Compare two file postions and return true if POS1 is later than -POS2 in the input stream.")) - -;; This is meant to be overloaded in the lexer -(defmethod later-position ((pos1 integer) (pos2 integer)) - (> pos1 pos2)) - -;; this looks silly but turns out to be useful (see below) -(defmethod later-position (pos1 pos2) - (and (eq pos1 :eof) (not (eq pos2 :eof)))) - -(defgeneric read-next-tokens (tokens-source) - (:documentation "Read next token from a lexical analysed stream. The nature of -TOKENS-SOURCE is implementation dependent and any lexical analyzer is -supposed to specialise this method.")) - -;; This is the actual parser. the algorithm is pretty -;; straightforward, the execution of the reductions a bit less. Error -;; recovery is rather clumsy. - -(defun parse (grammar start tokenizer) - "Match a GRAMMAR against the list of input tokens coming from TOKENIZER. -Return the reduced values according to the nonterminal actions. Raise -an error on failure." - (declare (type grammar grammar) - (type symbol start)) - (labels - ((match-token (expected token) - (when *debug* - (format *debug* "match-token ~S ~S -> " expected token)) - (let ((res (cond ((symbolp expected) - ;; non-costant terminal (like identifiers) - (eq expected (token-type token))) - ((and (stringp expected) - (stringp (token-value token))) - ;; string costant terminal - (funcall (the function (grammar-equal-p grammar)) expected (token-value token))) - ((functionp expected) - ;; custom equality predicate (must be able - ;; to deal with token objects) - (funcall expected token)) - ;; all the rest - (t (equal expected (token-value token)))))) - (when *debug* - (format *debug* "~Amatched~%" (if res "" "not "))) - res)) - (match (expected matched #+debug depth) - (declare (list expected matched) - #+debug (fixnum depth)) - (let ((first-expected (car expected))) - (cond #+debug ((> depth *maximum-recursion-depth*) - (error "endless recursion on ~A ~A at ~A expecting ~S" - (token-type (car matched)) (token-value (car matched)) - (token-position (car matched)) expected)) - ((eq first-expected :any) - (match (cdr expected) (cdr matched) #+debug depth)) - ;; This is a trick to obtain partial parses. When we - ;; reach this expected token we assume we succeeded - ;; the parsing and return the remaining tokens as - ;; part of the match. - ((eq first-expected :rest) - ;; we could be at the end of input so we check this - (unless (cdr matched) - (setf (cdr matched) (list :rest))) - (list nil nil)) - ((rule-p first-expected) - ;; If it's a rule, then we try to match all its - ;; productions. We return the first that succeeds. - (loop - for production in (rule-productions first-expected) - for production-tokens of-type list = (prod-tokens production) - with last-error-position = nil - with last-error = nil - for (error-position error-descr) = - (progn - (when *debug* - (format *debug* "trying to match ~A: ~S~%" - (rule-name first-expected) production-tokens)) - (match (append production-tokens (cdr expected)) matched #+debug (1+ depth))) - do (cond ((not error-position) - (return (let ((args-count (prod-tokens-length production))) - (setf (cdr matched) - (cons (reduce-production - production - (subseq (the list (cdr matched)) 0 args-count)) - (nthcdr (1+ args-count) matched))) - (list nil nil)))) - ((or (not last-error) - (later-position error-position last-error-position)) - (setf last-error-position error-position - last-error error-descr))) - ;; if everything fails return the "best" error - finally (return (list last-error-position - (if *debug* - #'(lambda () - (format nil "~A, trying to match ~A" - (funcall (the function last-error)) - (rule-name first-expected))) - last-error))))) - (t - ;; if necessary load the next tokens - (when (null (cdr matched)) - (setf (cdr matched) (read-next-tokens tokenizer))) - (cond ((and (or (null expected) (eq first-expected :eof)) - (null (cdr matched))) - ;; This point is reached only once for each complete - ;; parsing. The expected tokens and the input - ;; tokens have been exhausted at the same time. - ;; Hence we succeeded the parsing. - (setf (cdr matched) (list :eof)) - (list nil nil)) - ((null expected) - ;; Garbage at end of parsing. This may mean that we - ;; have considered a production completed too soon. - (list (token-position (car matched)) - #'(lambda () - "garbage at end of parsing"))) - ((null (cdr matched)) - ;; EOF error - (list :eof - #'(lambda () - (format nil "end of input expecting ~S" expected)))) - (t ;; normal token - (let ((first-token (cadr matched))) - (if (match-token first-expected first-token) - (match (cdr expected) (cdr matched) #+debug depth) - ;; failed: we return the error - (list (token-position first-token) - #'(lambda () - (format nil "expected ~S but got ~S ~S" - first-expected (token-type first-token) - (token-value first-token))))))))))))) - (declare (inline match-token)) - (let ((result (list :head))) - (destructuring-bind (error-position error) - (match (list (find-rule start (grammar-rules grammar))) result #+debug 0) - (when error-position - (error "~A at ~A~%" (funcall (the function error)) error-position)) - (cadr result))))) - -(defgeneric terminals-in-grammar (grammar-or-hashtable) - (:documentation - "Find non constant terminal symbols in GRAMMAR.")) - -(defmethod terminals-in-grammar ((grammar hash-table)) - (loop - for rule being each hash-value of grammar - with terminals = '() - do (loop - for prod in (rule-productions rule) - do (loop - for tok in (prod-tokens prod) - when (symbolp tok) - do (pushnew tok terminals))) - finally (return terminals))) - -(defmethod terminals-in-grammar ((grammar grammar)) - (terminals-in-grammar (grammar-rules grammar))) - -(defun print-grammar-figures (grammar &optional (stream *standard-output*)) - (format stream "rules: ~A~%constant terminals: ~A~%variable terminals: ~S~%" - (hash-table-count (grammar-rules grammar)) - (hash-table-count (grammar-keywords grammar)) - (terminals-in-grammar (grammar-rules grammar)))) - - -(defun grammar-keyword-p (keyword grammar) - "Check if KEYWORD is part of this grammar." - (find-keyword keyword (grammar-keywords grammar))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defvar *grammars* (make-hash-table)) - -(defun find-grammar (name) - (gethash name *grammars*)) - -(defun delete-grammar (name) - (remhash name *grammars*)) - -(defun add-grammar (name grammar) - (setf (gethash name *grammars*) grammar)) diff --git a/third_party/lisp/parse-float.nix b/third_party/lisp/parse-float.nix deleted file mode 100644 index 310313cfc..000000000 --- a/third_party/lisp/parse-float.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.parse-float; -in depot.nix.buildLisp.library { - name = "parse-float"; - - deps = with depot.third_party.lisp; [ - alexandria - ]; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "parse-float.lisp" - ]; -} diff --git a/third_party/lisp/parse-number.nix b/third_party/lisp/parse-number.nix deleted file mode 100644 index a0c563fcf..000000000 --- a/third_party/lisp/parse-number.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.parse-number; -in depot.nix.buildLisp.library { - name = "parse-number"; - srcs = map (f: src + ("/" + f)) [ - "parse-number.lisp" - ]; -} diff --git a/third_party/lisp/parseq.nix b/third_party/lisp/parseq.nix deleted file mode 100644 index 081880af1..000000000 --- a/third_party/lisp/parseq.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.parseq; -in depot.nix.buildLisp.library { - name = "parseq"; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "conditions.lisp" - "utils.lisp" - "defrule.lisp" - ]; -} diff --git a/third_party/lisp/physical-quantities.nix b/third_party/lisp/physical-quantities.nix deleted file mode 100644 index 14b9aab02..000000000 --- a/third_party/lisp/physical-quantities.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.physical-quantities; -in depot.nix.buildLisp.library { - name = "physical-quantities"; - - deps = with depot.third_party.lisp; [ - parseq - ]; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "utils.lisp" - "conditions.lisp" - "unit-factor.lisp" - "unit-database.lisp" - "units.lisp" - "quantity.lisp" - "numeric.lisp" - "parse-rules.lisp" - "read-macro.lisp" - "si-units.lisp" - ]; -} diff --git a/third_party/lisp/postmodern.nix b/third_party/lisp/postmodern.nix deleted file mode 100644 index 61b590e54..000000000 --- a/third_party/lisp/postmodern.nix +++ /dev/null @@ -1,94 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.nix.buildLisp) bundled; - src = with pkgs; srcOnly sbcl.pkgs.postmodern; - - cl-postgres = depot.nix.buildLisp.library { - name = "cl-postgres"; - deps = with depot.third_party.lisp; [ - md5 - split-sequence - ironclad - cl-base64 - uax-15 - usocket - ]; - - srcs = map (f: src + ("/cl-postgres/" + f)) [ - "package.lisp" - "features.lisp" - "config.lisp" - "oid.lisp" - "errors.lisp" - "data-types.lisp" - "sql-string.lisp" - "trivial-utf-8.lisp" - "strings-utf-8.lisp" - "communicate.lisp" - "messages.lisp" - "ieee-floats.lisp" - "interpret.lisp" - "saslprep.lisp" - "scram.lisp" - "protocol.lisp" - "public.lisp" - "bulk-copy.lisp" - ]; - }; - - s-sql = depot.nix.buildLisp.library { - name = "s-sql"; - deps = with depot.third_party.lisp; [ - cl-postgres - alexandria - ]; - - srcs = map (f: src + ("/s-sql/" + f)) [ - "package.lisp" - "config.lisp" - "s-sql.lisp" - ]; - }; - - postmodern = depot.nix.buildLisp.library { - name = "postmodern"; - - deps = with depot.third_party.lisp; [ - alexandria - cl-postgres - s-sql - global-vars - split-sequence - cl-unicode - closer-mop - bordeaux-threads - ]; - - srcs = [ - "${src}/postmodern.asd" - ] ++ (map (f: src + ("/postmodern/" + f)) [ - "package.lisp" - "config.lisp" - "connect.lisp" - "json-encoder.lisp" - "query.lisp" - "prepare.lisp" - "roles.lisp" - "util.lisp" - "transaction.lisp" - "namespace.lisp" - "execute-file.lisp" - "table.lisp" - "deftable.lisp" - ]); - - brokenOn = [ - "ecl" # TODO(sterni): https://gitlab.com/embeddable-common-lisp/ecl/-/issues/651 - ]; - }; - -in -postmodern // { - inherit s-sql cl-postgres; -} diff --git a/third_party/lisp/prove.nix b/third_party/lisp/prove.nix deleted file mode 100644 index 21b32ee0e..000000000 --- a/third_party/lisp/prove.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.prove; -in depot.nix.buildLisp.library { - name = "prove"; - - deps = [ - depot.third_party.lisp.alexandria - depot.third_party.lisp.cl-ansi-text - depot.third_party.lisp.cl-colors - depot.third_party.lisp.cl-ppcre - (depot.nix.buildLisp.bundled "asdf") - ]; - - srcs = [ - "${src}/src/color.lisp" - "${src}/src/output.lisp" - "${src}/src/asdf.lisp" - "${src}/src/report.lisp" - "${src}/src/reporter.lisp" - "${src}/src/reporter/fiveam.lisp" - "${src}/src/reporter/list.lisp" - "${src}/src/reporter/dot.lisp" - "${src}/src/reporter/tap.lisp" - "${src}/src/suite.lisp" - "${src}/src/test.lisp" - "${src}/src/prove.lisp" - ]; -} diff --git a/third_party/lisp/puri.nix b/third_party/lisp/puri.nix deleted file mode 100644 index d0b0d87e2..000000000 --- a/third_party/lisp/puri.nix +++ /dev/null @@ -1,10 +0,0 @@ -# Portable URI library -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.puri; -in depot.nix.buildLisp.library { - name = "puri"; - srcs = [ - (src + "/src.lisp") - ]; -} diff --git a/third_party/lisp/qbase64/coreutils-base64.patch b/third_party/lisp/qbase64/coreutils-base64.patch deleted file mode 100644 index 5a2f2a9f0..000000000 --- a/third_party/lisp/qbase64/coreutils-base64.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/qbase64-test.lisp b/qbase64-test.lisp -index 310fdf3..b92abb5 100644 ---- a/qbase64-test.lisp -+++ b/qbase64-test.lisp -@@ -14,7 +14,7 @@ - (with-open-temporary-file (tmp :direction :output :element-type '(unsigned-byte 8)) - (write-sequence bytes tmp) - (force-output tmp) -- (let* ((encoded (uiop:run-program `("base64" "-b" ,(format nil "~A" linebreak) "-i" ,(namestring tmp)) :output (if (zerop linebreak) '(:string :stripped t) :string))) -+ (let* ((encoded (uiop:run-program `("base64" "-w" ,(format nil "~A" linebreak) ,(namestring tmp)) :output (if (zerop linebreak) '(:string :stripped t) :string) :error-output *error-output*)) - (length (length encoded))) - (cond ((and (> length 1) - (string= (subseq encoded (- length 2)) diff --git a/third_party/lisp/qbase64/default.nix b/third_party/lisp/qbase64/default.nix deleted file mode 100644 index 601430f02..000000000 --- a/third_party/lisp/qbase64/default.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ depot, pkgs, ... }: - -let - src = pkgs.applyPatches { - src = pkgs.srcOnly pkgs.sbcl.pkgs.qbase64; - - patches = [ - # qbase64 expects macOS base64 - ./coreutils-base64.patch - ]; - }; - - getSrcs = builtins.map (p: "${src}/${p}"); - -in - -depot.nix.buildLisp.library { - name = "qbase64"; - - srcs = getSrcs [ - "package.lisp" - "utils.lisp" - "stream-utils.lisp" - "qbase64.lisp" - ]; - - deps = [ - depot.third_party.lisp.trivial-gray-streams - depot.third_party.lisp.metabang-bind - ]; - - tests = { - name = "qbase64-tests"; - - srcs = getSrcs [ - "qbase64-test.lisp" - ]; - - deps = [ - { - sbcl = depot.nix.buildLisp.bundled "uiop"; - default = depot.nix.buildLisp.bundled "asdf"; - } - depot.third_party.lisp.fiveam - depot.third_party.lisp.cl-fad - ]; - - expression = '' - (fiveam:run! '(qbase64-test::encoder 'qbase64-test::decoder)) - ''; - }; -} diff --git a/third_party/lisp/quasiquote_2/README.md b/third_party/lisp/quasiquote_2/README.md deleted file mode 100644 index 2d590a056..000000000 --- a/third_party/lisp/quasiquote_2/README.md +++ /dev/null @@ -1,258 +0,0 @@ -quasiquote-2.0 -============== - -Why should it be hard to write macros that write other macros? -Well, it shouldn't! - -quasiquote-2.0 defines slightly different rules for quasiquotation, -that make writing macro-writing macros very smooth experience. - -NOTE: quasiquote-2.0 does horrible things to shared structure!!! -(it does a lot of COPY-TREE's, so shared-ness is destroyed). -So, it's indeed a tool to construct code (where it does not matter much if the -structure is shared or not) and not the data (or, at least, not the data with shared structure) - - -```lisp -(quasiquote-2.0:enable-quasiquote-2.0) - -(defmacro define-my-macro (name args &body body) - `(defmacro ,name ,args - `(sample-thing-to-expand-to - ,,@body))) ; note the difference from usual way - -(define-my-macro foo (x y) - ,x ; now here injections of quotation constructs work - ,y) - -(define-my-macro bar (&body body) - ,@body) ; splicing is also easy -``` - -The "injections" in macros FOO and BAR work as naively expected, as if I had written -```lisp -(defmacro foo (x y) - `(sample-thing-to-expand-to ,x ,y)) - -(defmacro bar (&body body) - `(sample-thing-to-expand-to ,@body)) - -(macroexpand-1 '(foo a b)) - - '(SAMPLE-THING-TO-EXPAND-TO A B) - -(macroexpand-1 '(bar a b c)) - - '(SAMPLE-THING-TO-EXPAND-TO A B C) -``` - - -So, how is this effect achieved? - - -DIG, INJECT and SPLICE -------------------------- - -The transformations of backquote occur at macroexpansion-time and not at read-time. -It is totally possible not to use any special reader syntax, but just -underlying macros directly! - -At the core is a macro DIG, which expands to the code that generates the -expression according to the rules, which are roughly these: - * each DIG increases "depth" by one (hence the name) - * each INJECT or SPLICE decreases "depth" by one - * if depth is 0, evaluation is turned on - * if depth if not zero (even if it's negative!) evaluation is off - * SPLICE splices the form, similarly to ordinary `,@`, INJECT simply injects, same as `,` - -```lisp -;; The example using macros, without special reader syntax - -(dig ; depth is 1 here - (a b - (dig ; depth is 2 here - ((inject c) ; this inject is not evaluated, because depth is nonzero - (inject (d ;depth becomes 1 here again - (inject e) ; and this inject is evaluated, because depth becomes zero - )) - (inject 2 f) ; this inject with level specification is evaluated, because it - ; decreases depth by 2 - )))) - - -;; the same example using ENABLE-QUASIQUOTE-2.0 syntax is written as -`(a b `(,c ,(d ,e) ,,f)) ; note double comma acts different than usually -``` - - -The ENABLE-QUASIQUOTE-2.0 macro just installs reader that reads -`FORM as (DIG FORM), ,FORM as (INJECT FORM) and ,@FORM as (SPLICE FORM). -You can just as well type DIG's, INJECT's and SPLICE's directly, -(in particular, when writing utility functions that generate macro-generating code) -or roll your own convenient reader syntax (pull requests are welcome). - -So, these two lines (with ENABLE-QUASIQUOTE-2.0) read the same -```lisp -`(a (,b `,,c) d) - -(dig (a ((inject b) (dig (inject 2 c))) d)) -``` - -You may notice the (INJECT 2 ...) form appearing, which is described below. - - -At "level 1", i.e. when only \` , and ,@ are used, and not, say \`\` ,, ,', ,,@ ,',@ -this behaves exactly as usual quasiquotation. - - -The optional N argument --------------- - -All quasiquote-2.0 operators accept optional "depth" argument, -which goes before the form for human readability. - -Namely, (DIG N FORM) increases depth by N instead of one and -(INJECT N FORM) decreases depth by N instead of one. - -```lisp -(DIG 2 (INJECT 2 A)) - -; gives the same result as - -(DIG (INJECT A)) -``` - - -In fact, with ENABLE-QUASIQUOTE-2.0, say, ,,,,,FORM (5 quotes) reads as (INJECT 5 FORM) -and ,,,,,@FORM as (SPLICE 5 FORM) - - -More examples -------------- - -For fairly complicated example, which uses ,,,@ and OINJECT (see below), - see DEFINE-BINOP-DEFINER macro -in CG-LLVM (https://github.com/mabragor/cg-llvm/src/basics.lisp), -desire to write which was the initial impulse for this project. - - -For macro, that is not a macro-writing macro, yet benefits from -ability to inject using `,` and `,@`, consider JOINING-WITH-COMMA-SPACE macro -(also from CG-LLVM) - -```lisp -(defmacro joining-with-comma-space (&body body) - ;; joinl just joins strings in the list with specified string - `(joinl ", " (mapcar #'emit-text-repr - (remove-if-not #'identity `(,,@body))))) - -;; the macro can be then used uniformly over strings and lists of strings -(defun foo (x y &rest z) - (joining-with-comma-space ,x ,y ,@z)) - -(foo "a" "b" "c" "d") - ;; produces - "a, b, c, d" -``` - - -ODIG and OINJECT and OSPLICE ----------------------------- - -Sometimes you don't want DIG's macroexpansion to look further into the structure of -some INJECT or SPLICE or DIG in its subform, -if the depth does not match. In these cases you need "opaque" versions of -DIG, INJECT and SPLICE, named, respectively, ODIG, OINJECT and OSPLICE. - -```lisp -;; here injection of B would occur -(defun foo (b) - (dig (dig (inject (a (inject b)))))) - -;; and here not, because macroexpansion does not look into OINJECT form -(defun bar (b) - (dig (dig (oinject (a (inject b)))))) - -(foo 1) - - '(DIG (INJECT (A 1))) - -(bar 1) - - '(DIG (OINJECT (A (INJECT B)))) -``` - -MACRO-INJECT and MACRO-SPLICE ------------------------------ - -Sometimes you just want to abstract-out some common injection patterns... -That is, you want macros, that expand into common injection patterns. -However, you want this only sometimes, and only in special circumstances. -So it won't do, if INJECT and SPLICE just expanded something, whenever it -turned out to be macro. For that, use MACRO-INJECT and MACRO-SPLICE. - -```lisp -;; with quasiquote-2.0 syntax turned on -(defmacro inject-n-times (form n) - (make-list n :initial-element `(inject ,form))) - -(let (x 0) - `(dig (a (macro-inject (inject-n-times (incf x) 3))))) -;; yields -'(a (1 2 3)) - -;;and same with MACRO-SPLICE -(let (x 0) - `(dig (a (macro-splice (inject-n-times (incf x) 3))))) -;; yields -'(a 1 2 3) -``` - -OMACRO-INJECT and OMACRO-SPLICE are, as usual, opaque variants of MACRO-INJECT and MACRO-SPLICE. - -Both MACRO-INJECT and MACRO-SPLICE expand their subform exactly once (using MACROEXPAND-1), -before plugging it into list. -If you want to expand as much as it's possible, use MACRO-INJECT-ALL and MACRO-SPLICE-ALL, -which expand using MACROEXPAND before injecting/splicing, respectively. -That implies, that while subform of MACRO-INJECT and MACRO-SPLICE is checked to be -macro-form, the subform of MACRO-INJECT-ALL is not. - - -Terse syntax of the ENABLE-QUASIQUOTE-2.0 ------------------------------------------ - -Of course, typing all those MACRO-INJECT-ALL, or OMACRO-SPLICE-ALL or whatever explicitly -every time you want this special things is kind of clumsy. For that, default reader -of quasiquote-2.0 provides extended syntax - -```lisp -',,,,!oma@x - -;; reads as -'(OMACRO-SPLICE-ALL 4 X) -``` - -That is, the regexp of the syntax is -[,]+![o][m][a][@] - -As usual, number of commas determine the anti-depth of the injector, exclamation mark -turns on the syntax, if `o` is present, opaque version of injector will be used, -if `m` is present, macro-expanding version of injector will be used and if -`a` is present, macro-all version of injector will be used. - -Note: it's possible to write ,!ax, which will read as (INJECT-ALL X), but -this will not correspond to the actual macro name. - -Note: it was necessary to introduce special escape-char for extended syntax, -since usual idioms like `,args` would otherwise be completely screwed. - - -TODO ----- - -* WITH-QUASIQUOTE-2.0 read-macro-token for local enabling of ` and , overloading -* wrappers for convenient definition of custom overloading schemes -* some syntax for opaque operations - -P.S. Name "quasiquote-2.0" comes from "patronus 2.0" spell from www.hpmor.com - and has nothing to do with being "the 2.0" version of quasiquote. \ No newline at end of file diff --git a/third_party/lisp/quasiquote_2/default.nix b/third_party/lisp/quasiquote_2/default.nix deleted file mode 100644 index 521c38478..000000000 --- a/third_party/lisp/quasiquote_2/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -# Quasiquote more suitable for macros that define other macros -{ depot, ... }: - -depot.nix.buildLisp.library { - name = "quasiquote-2.0"; - - deps = [ - depot.third_party.lisp.iterate - ]; - - srcs = [ - ./package.lisp - ./quasiquote-2.0.lisp - ./macros.lisp - ./readers.lisp - ]; -} diff --git a/third_party/lisp/quasiquote_2/macros.lisp b/third_party/lisp/quasiquote_2/macros.lisp deleted file mode 100644 index 6ebeb47d0..000000000 --- a/third_party/lisp/quasiquote_2/macros.lisp +++ /dev/null @@ -1,15 +0,0 @@ - -(in-package #:quasiquote-2.0) - -(defmacro define-dig-like-macro (name) - `(defmacro ,name (n-or-form &optional (form nil form-p) &environment env) - (if (not form-p) - `(,',name 1 ,n-or-form) - (let ((*env* env)) - (transform-dig-form `(,',name ,n-or-form ,form)))))) - - -(define-dig-like-macro dig) -(define-dig-like-macro odig) - - diff --git a/third_party/lisp/quasiquote_2/package.lisp b/third_party/lisp/quasiquote_2/package.lisp deleted file mode 100644 index 9b140ef84..000000000 --- a/third_party/lisp/quasiquote_2/package.lisp +++ /dev/null @@ -1,11 +0,0 @@ -;;;; package.lisp - -(defpackage #:quasiquote-2.0 - (:use #:cl #:iterate) - (:export #:%codewalk-dig-form #:transform-dig-form - #:dig #:inject #:splice #:odig #:oinject #:osplice - #:macro-inject #:omacro-inject #:macro-splice #:omacro-splice - #:macro-inject-all #:omacro-inject-all #:macro-splice-all #:omacro-splice-all - #:enable-quasiquote-2.0 #:disable-quasiquote-2.0)) - - diff --git a/third_party/lisp/quasiquote_2/quasiquote-2.0.asd b/third_party/lisp/quasiquote_2/quasiquote-2.0.asd deleted file mode 100644 index 3acfd32b8..000000000 --- a/third_party/lisp/quasiquote_2/quasiquote-2.0.asd +++ /dev/null @@ -1,30 +0,0 @@ -;;;; quasiquote-2.0.asd - -(defpackage :quasiquote-2.0-system - (:use :cl :asdf)) - -(in-package quasiquote-2.0-system) - -(asdf:defsystem #:quasiquote-2.0 - :serial t - :description "Writing macros that write macros. Effortless." - :author "Alexandr Popolitov " - :license "MIT" - :version "0.3" - :depends-on (#:iterate) - :components ((:file "package") - (:file "quasiquote-2.0") - (:file "macros") - (:file "readers"))) - -(defsystem :quasiquote-2.0-tests - :description "Tests for QUASIQUOTE-2.0" - :licence "MIT" - :depends-on (:quasiquote-2.0 :fiveam) - :components ((:file "tests") - (:file "tests-macro") - )) - -(defmethod perform ((op test-op) (sys (eql (find-system :quasiquote-2.0)))) - (load-system :quasiquote-2.0) - (funcall (intern "RUN-TESTS" :quasiquote-2.0))) diff --git a/third_party/lisp/quasiquote_2/quasiquote-2.0.lisp b/third_party/lisp/quasiquote_2/quasiquote-2.0.lisp deleted file mode 100644 index 10043fe0e..000000000 --- a/third_party/lisp/quasiquote_2/quasiquote-2.0.lisp +++ /dev/null @@ -1,340 +0,0 @@ -;;;; quasiquote-2.0.lisp - -(in-package #:quasiquote-2.0) - -(defparameter *env* nil) - -(defmacro nonsense-error (str) - `(error ,(concatenate 'string - str - " appears as a bare, non DIG-enclosed form. " - "For now I don't know how to make sense of this."))) - -(defmacro define-nonsense-when-bare (name) - `(defmacro ,name (n-or-form &optional form) - (declare (ignore n-or-form form)) - (nonsense-error ,(string name)))) - -(define-nonsense-when-bare inject) -(define-nonsense-when-bare oinject) -(define-nonsense-when-bare splice) -(define-nonsense-when-bare osplice) -(define-nonsense-when-bare macro-inject) - -(defparameter *depth* 0) - - -(defparameter *injectors* nil) - -(defparameter *void-elt* nil) -(defparameter *void-filter-needed* nil) - -;; (defmacro with-injector-parsed (form) -;; `(let ((kwd (intern (string - -(defun reset-injectors () - (setf *injectors* nil)) - -(defparameter *known-injectors* '(inject splice oinject osplice - macro-inject omacro-inject - macro-splice omacro-splice - macro-inject-all omacro-inject-all - macro-splice-all omacro-splice-all)) - -(defun injector-form-p (form) - (and (consp form) - (find (car form) *known-injectors* :test #'eq))) - -(defun injector-level (form) - (if (equal 2 (length form)) - 1 - (cadr form))) - -(defun injector-subform (form) - (if (equal 2 (length form)) - (values (cdr form) '(cdr)) - (values (cddr form) '(cddr)))) - -(defparameter *opaque-injectors* '(odig oinject osplice omacro-inject)) - -(defun transparent-p (form) - (not (find (car form) *opaque-injectors* :test #'eq))) - -(defun look-into-injector (form path) - (let ((*depth* (- *depth* (injector-level form)))) - (multiple-value-bind (subform subpath) (injector-subform form) - (search-all-active-sites subform (append subpath path) nil)))) - -(defparameter *known-diggers* '(dig odig)) - -(defun dig-form-p (form) - (and (consp form) - (find (car form) *known-diggers* :test #'eq))) - -(defun look-into-dig (form path) - (let ((*depth* (+ *depth* (injector-level form)))) - (multiple-value-bind (subform subpath) (injector-subform form) - (search-all-active-sites subform (append subpath path) nil)))) - -(defun handle-macro-1 (form) - (if (atom form) - (error "Sorry, symbol-macros are not implemented for now") - (let ((fun (macro-function (car form) *env*))) - (if (not fun) - (error "The subform of MACRO-1 injector is supposed to be macro, perhaps, something went wrong...")) - (macroexpand-1 form *env*)))) - -(defun handle-macro-all (form) - (if (atom form) - (error "Sorry, symbol-macros are not implemented for now") - (macroexpand form *env*))) - - -(defparameter *macro-handlers* `((macro-inject . ,#'handle-macro-1) - (omacro-inject . ,#'handle-macro-1) - (macro-splice . ,#'handle-macro-1) - (omacro-splice . ,#'handle-macro-1) - (macro-inject-all . ,#'handle-macro-all) - (omacro-inject-all . ,#'handle-macro-all) - (macro-splice-all . ,#'handle-macro-all) - (omacro-splice-all . ,#'handle-macro-all))) - -(defun get-macro-handler (sym) - (or (cdr (assoc sym *macro-handlers*)) - (error "Don't know how to handle this macro injector: ~a" sym))) - - - -(defun macroexpand-macroinjector (place) - (if (not (splicing-injector (car place))) - (progn (setf (car place) (funcall (get-macro-handler (caar place)) - (car (injector-subform (car place))))) - nil) - (let ((new-forms (funcall (get-macro-handler (caar place)) - (car (injector-subform (car place)))))) - (cond ((not new-forms) - (setf *void-filter-needed* t - (car place) *void-elt*)) - ((atom new-forms) (error "We need to splice the macroexpansion, but got atom: ~a" new-forms)) - (t (setf (car place) (car new-forms)) - (let ((tail (cdr place))) - (setf (cdr place) (cdr new-forms) - (cdr (last new-forms)) tail)))) - t))) - - -(defun search-all-active-sites (form path toplevel-p) - ;; (format t "SEARCH-ALL-ACTIVE-SITES: got form ~a~%" form) - (if (not form) - nil - (if toplevel-p - (cond ((atom (car form)) :just-quote-it!) - ((injector-form-p (car form)) (if (equal *depth* (injector-level (car form))) - :just-form-it! - (if (transparent-p (car form)) - (look-into-injector (car form) (cons 'car path))))) - ((dig-form-p (car form)) - ;; (format t "Got dig form ~a~%" form) - (if (transparent-p (car form)) - (look-into-dig (car form) (cons 'car path)))) - (t (search-all-active-sites (car form) (cons 'car path) nil) - (search-all-active-sites (cdr form) (cons 'cdr path) nil))) - (when (consp form) - (cond ((dig-form-p (car form)) - ;; (format t "Got dig form ~a~%" form) - (if (transparent-p (car form)) - (look-into-dig (car form) (cons 'car path)))) - ((injector-form-p (car form)) - ;; (format t "Got injector form ~a ~a ~a~%" form *depth* (injector-level (car form))) - (if (equal *depth* (injector-level (car form))) - (if (macro-injector-p (car form)) - (progn (macroexpand-macroinjector form) - (return-from search-all-active-sites - (search-all-active-sites form path nil))) - (progn (push (cons form (cons 'car path)) *injectors*) - nil)) - (if (transparent-p (car form)) - (look-into-injector (car form) (cons 'car path))))) - (t (search-all-active-sites (car form) (cons 'car path) nil))) - (search-all-active-sites (cdr form) (cons 'cdr path) nil))))) - - - -(defun codewalk-dig-form (form) - (reset-injectors) - (let ((it (search-all-active-sites form nil t))) - (values (nreverse *injectors*) it))) - -(defun %codewalk-dig-form (form) - (if (not (dig-form-p form)) - (error "Supposed to be called on dig form") - (let ((*depth* (+ (injector-level form) *depth*))) - (codewalk-dig-form (injector-subform form))))) - -(defun path->setfable (path var) - (let ((res var)) - ;; First element is artifact of extra CAR-ing - (dolist (spec (cdr (reverse path))) - (setf res (list spec res))) - res)) - -(defun tree->cons-code (tree) - (if (atom tree) - `(quote ,tree) - `(cons ,(tree->cons-code (car tree)) - ,(tree->cons-code (cdr tree))))) - -(defparameter *known-splicers* '(splice osplice - macro-splice omacro-splice - macro-splice-all omacro-splice-all)) - -(defun splicing-injector (form) - (and (consp form) - (find (car form) *known-splicers* :test #'eq))) - -(defparameter *known-macro-injectors* '(macro-inject omacro-inject - macro-splice omacro-splice - macro-inject-all omacro-inject-all - macro-splice-all omacro-splice-all - )) - -(defun macro-injector-p (form) - (and (consp form) - (find (car form) *known-macro-injectors* :test #'eq))) - -(defun filter-out-voids (lst void-sym) - (let (caars cadrs cdars cddrs) - ;; search for all occurences of VOID - (labels ((rec (x) - (if (consp x) - (progn (cond ((consp (car x)) - (cond ((eq void-sym (caar x)) (push x caars)) - ((eq void-sym (cdar x)) (push x cdars)))) - ((consp (cdr x)) - (cond ((eq void-sym (cadr x)) (push x cadrs)) - ((eq void-sym (cddr x)) (push x cddrs))))) - (rec (car x)) - (rec (cdr x)))))) - (rec lst)) - (if (or cdars cddrs) - (error "Void sym found on CDR position, which should not have happened")) - ;; destructively transform LST - (dolist (elt caars) - (setf (car elt) (cdar elt))) - (dolist (elt cadrs) - (setf (cdr elt) (cddr elt))) - ;; check that we indeed filtered-out all VOIDs - (labels ((rec (x) - (if (not (atom x)) - (progn (rec (car x)) - (rec (cdr x))) - (if (eq void-sym x) - (error "Not all VOIDs were filtered"))))) - (rec lst)) - lst)) - -(defun transform-dig-form (form) - (let ((the-form (copy-tree form))) - (let ((*void-filter-needed* nil) - (*void-elt* (gensym "VOID"))) - (multiple-value-bind (site-paths cmd) (%codewalk-dig-form the-form) - (cond ((eq cmd :just-quote-it!) - `(quote ,(car (injector-subform the-form)))) - ((eq cmd :just-form-it!) - (car (injector-subform (car (injector-subform the-form))))) - (t (let ((cons-code (if (not site-paths) - (tree->cons-code (car (injector-subform the-form))) - (really-transform-dig-form the-form site-paths)))) - (if (not *void-filter-needed*) - cons-code - `(filter-out-voids ,cons-code ',*void-elt*))))))))) - -(defmacro make-list-form (o!-n form) - (let ((g!-n (gensym "N")) - (g!-i (gensym "I")) - (g!-res (gensym "RES"))) - `(let ((,g!-n ,o!-n) - (,g!-res nil)) - (dotimes (,g!-i ,g!-n) - (push ,form ,g!-res)) - (nreverse ,g!-res)))) - -(defun mk-splicing-injector-let (x) - `(let ((it ,(car (injector-subform x)))) - (assert (listp it)) - (copy-list it))) - - - -(defun mk-splicing-injector-setf (path g!-list g!-splicee) - (assert (eq 'car (car path))) - (let ((g!-rest (gensym "REST"))) - `(let ((,g!-rest ,(path->setfable (cons 'cdr (cdr path)) g!-list))) - (assert (or (not ,g!-rest) (consp ,g!-rest))) - (if (not ,g!-splicee) - (setf ,(path->setfable (cdr path) g!-list) - ,g!-rest) - (progn (setf ,(path->setfable (cdr path) g!-list) ,g!-splicee) - (setf (cdr (last ,g!-splicee)) ,g!-rest)))))) - - -(defun really-transform-dig-form (the-form site-paths) - (let ((gensyms (make-list-form (length site-paths) (gensym "INJECTEE")))) - (let ((g!-list (gensym "LIST"))) - (let ((lets nil) - (splicing-setfs nil) - (setfs nil)) - (do ((site-path site-paths (cdr site-path)) - (gensym gensyms (cdr gensym))) - ((not site-path)) - (destructuring-bind (site . path) (car site-path) - (push `(,(car gensym) ,(if (not (splicing-injector (car site))) - (car (injector-subform (car site))) - (mk-splicing-injector-let (car site)))) - lets) - (if (not (splicing-injector (car site))) - (push `(setf ,(path->setfable path g!-list) ,(car gensym)) setfs) - (push (mk-splicing-injector-setf path g!-list (car gensym)) splicing-setfs)) - (setf (car site) nil))) - `(let ,(nreverse lets) - (let ((,g!-list ,(tree->cons-code (car (injector-subform the-form))))) - ,@(nreverse setfs) - ;; we apply splicing setf in reverse order for them not to bork the paths of each other - ,@splicing-setfs - ,g!-list)))))) - - -;; There are few types of recursive injection that may happen: -;; * compile-time injection: -;; (dig (inject (dig (inject a)))) -- this type will be handled automatically by subsequent macroexpansions -;; * run-time injection: -;; (dig (dig (inject 2 a))) -;; and A is '(dig (inject 3 'foo)) -- this one we guard against ? (probably, first we just ignore it -;; -- do not warn about it, and then it wont really happen. -;; * macroexpanded compile-time injection: -;; (dig (inject (my-macro a b c))), -;; where MY-MACRO expands into, say (splice (list 'a 'b 'c)) -;; This is *not* handled automatically, and therefore we must do it by hand. - - -;; OK, now how to implement splicing ? -;; (dig (a (splice (list b c)) d)) -;; should transform into code that yields -;; (a b c d) -;; what this code is? -;; (let ((#:a (copy-list (list b c)))) -;; (let ((#:res (cons 'a nil 'd))) -;; ;; all non-splicing injects go here, as they do not spoil the path-structure -;; (setf (cdr #:res) #:a) -;; (setf (cdr (last #:a)) (cdr (cdr #:res))) -;; #:res))) - - -;; How this macroexpansion should work in general? -;; * We go over the cons-tree, keeping track of the depth level, which is -;; controlled by DIG's -;; * Once we find the INJECT with matching level, we remember the place, where -;; this happens -;; * We have two special cases: -;; * cons-tree is an atom -;; * cons-tree is just a single INJECT diff --git a/third_party/lisp/quasiquote_2/readers.lisp b/third_party/lisp/quasiquote_2/readers.lisp deleted file mode 100644 index 7c4c5a30c..000000000 --- a/third_party/lisp/quasiquote_2/readers.lisp +++ /dev/null @@ -1,77 +0,0 @@ - - -(in-package #:quasiquote-2.0) - -(defun read-n-chars (stream char) - (let (new-char - (n 0)) - (loop - (setf new-char (read-char stream nil :eof t)) - (if (not (char= new-char char)) - (progn (unread-char new-char stream) - (return n)) - (incf n))))) - -(defmacro define-dig-reader (name symbol) - `(defun ,name (stream char) - (let ((depth (1+ (read-n-chars stream char)))) - (if (equal 1 depth) - (list ',symbol (read stream t nil t)) - (list ',symbol - depth - (read stream t nil t)))))) - -(define-dig-reader dig-reader dig) -(define-dig-reader odig-reader odig) - -(defun expect-char (char stream) - (let ((new-char (read-char stream t nil t))) - (if (char= char new-char) - t - (unread-char new-char stream)))) - -(defun guess-injector-name (opaque-p macro-p all-p splicing-p) - (intern (concatenate 'string - (if opaque-p "O" "") - (if macro-p "MACRO-" "") - (if splicing-p "SPLICE" "INJECT") - (if all-p "-ALL" "")) - "QUASIQUOTE-2.0")) - -(defun inject-reader (stream char) - (let ((anti-depth (1+ (read-n-chars stream char))) - (extended-syntax (expect-char #\! stream))) - (let ((injector-name (if (not extended-syntax) - (guess-injector-name nil nil nil (expect-char #\@ stream)) - (guess-injector-name (expect-char #\o stream) - (expect-char #\m stream) - (expect-char #\a stream) - (expect-char #\@ stream))))) - `(,injector-name ,@(if (not (equal 1 anti-depth)) `(,anti-depth)) - ,(read stream t nil t))))) - - - -(defvar *previous-readtables* nil) - -(defun %enable-quasiquote-2.0 () - (push *readtable* - *previous-readtables*) - (setq *readtable* (copy-readtable)) - (set-macro-character #\` #'dig-reader) - (set-macro-character #\, #'inject-reader) - (values)) - -(defun %disable-quasiquote-2.0 () - (if *previous-readtables* - (setf *readtable* (pop *previous-readtables*)) - (setf *readtable* (copy-readtable nil))) - (values)) - -(defmacro enable-quasiquote-2.0 () - `(eval-when (:compile-toplevel :load-toplevel :execute) - (%enable-quasiquote-2.0))) -(defmacro disable-quasiquote-2.0 () - `(eval-when (:compile-toplevel :load-toplevel :execute) - (%disable-quasiquote-2.0))) - diff --git a/third_party/lisp/quasiquote_2/tests-macro.lisp b/third_party/lisp/quasiquote_2/tests-macro.lisp deleted file mode 100644 index df6c43e21..000000000 --- a/third_party/lisp/quasiquote_2/tests-macro.lisp +++ /dev/null @@ -1,21 +0,0 @@ - -(in-package #:quasiquote-2.0-tests) - -(in-suite quasiquote-2.0) - -(enable-quasiquote-2.0) - -(defmacro define-sample-macro (name args &body body) - `(defmacro ,name ,args - `(sample-thing-to-macroexpand-to - ,,@body))) - -(define-sample-macro sample-macro-1 (x y) - ,x ,y) - -(define-sample-macro sample-macro-2 (&body body) - ,@body) - -(test macro-defined-macroexpansions - (is (equal '(sample-thing-to-macroexpand-to a b) (macroexpand-1 '(sample-macro-1 a b)))) - (is (equal '(sample-thing-to-macroexpand-to a b c) (macroexpand-1 '(sample-macro-2 a b c))))) \ No newline at end of file diff --git a/third_party/lisp/quasiquote_2/tests.lisp b/third_party/lisp/quasiquote_2/tests.lisp deleted file mode 100644 index 6c8ab08cc..000000000 --- a/third_party/lisp/quasiquote_2/tests.lisp +++ /dev/null @@ -1,143 +0,0 @@ -(in-package :cl-user) - -(defpackage :quasiquote-2.0-tests - (:use :cl :quasiquote-2.0 :fiveam) - (:export #:run-tests)) - -(in-package :quasiquote-2.0-tests) - -(def-suite quasiquote-2.0) -(in-suite quasiquote-2.0) - -(defun run-tests () - (let ((results (run 'quasiquote-2.0))) - (fiveam:explain! results) - (unless (fiveam:results-status results) - (error "Tests failed.")))) - -(test basic - (is (equal '(nil :just-quote-it!) (multiple-value-list (%codewalk-dig-form '(dig nil))))) - (is (equal '(nil :just-form-it!) (multiple-value-list (%codewalk-dig-form '(dig (inject a)))))) - (is (equal '(nil :just-form-it!) (multiple-value-list (%codewalk-dig-form '(dig 2 (inject 2 a)))))) - (is (equal '(((((inject b) c (inject d)) car cdr car) (((inject d)) car cdr cdr cdr car)) nil) - (multiple-value-list (%codewalk-dig-form '(dig (a (inject b) c (inject d))))))) - (is (equal '(nil nil) - (multiple-value-list (%codewalk-dig-form '(dig (dig (a (inject b) c (inject d)))))))) - (is (equal '(((((inject 2 d)) car cdr cdr cdr car cdr car)) nil) - (multiple-value-list (%codewalk-dig-form '(dig (dig (a (inject b) c (inject 2 d))))))))) - -(test transform - (is (equal '(quote a) (transform-dig-form '(dig a)))) - (is (equal '(quote a) (transform-dig-form '(dig 2 a)))) - (is (equal 'a (transform-dig-form '(dig (inject a))))) - (is (equal 'a (transform-dig-form '(dig 2 (inject 2 a)))))) - -(defun foo (b d) - (dig (a (inject b) c (inject d)))) - -(defun foo1-transparent (x) - (declare (ignorable x)) - (dig (dig (a (inject (b (inject x) c)))))) - -(defun foo1-opaque (x) - (declare (ignorable x)) - (dig (dig (a (oinject (b (inject x) c)))))) - -(defun foo-recursive (x y) - (dig (a (inject (list x (dig (c (inject y)))))))) - - -(test foos - (is (equal '(a 1 c 2) (foo 1 2))) - (is (equal '(a 100 c 200) (foo 100 200)))) - -(test opaque-vs-transparent - (is (equal '(quote a) (transform-dig-form '(odig a)))) - (is (equal '(quote a) (transform-dig-form '(odig 2 a)))) - (is (equal 'a (transform-dig-form '(odig (inject a))))) - (is (equal 'a (transform-dig-form '(odig 2 (inject 2 a))))) - (is (equal '(odig (inject 2 a)) (eval (transform-dig-form '(dig (odig (inject 2 a))))))) - (is (equal '(dig (a (inject (b 3 c)))) (foo1-transparent 3))) - (is (equal '(dig (a (oinject (b (inject x) c)))) (foo1-opaque 3)))) - -(test recursive-compile-time - (is (equal '(a (1 (c 2))) (foo-recursive 1 2)))) - - -(test splicing - (is (equal '(a b c d) (eval (transform-dig-form '(dig (a (splice '(b c)) d)))))) - (is (equal '(b c d) (eval (transform-dig-form '(dig ((splice '(b c)) d)))))) - (is (equal '(a b c) (eval (transform-dig-form '(dig (a (splice '(b c)))))))) - (is (equal '(a b) (eval (transform-dig-form '(dig (a (splice nil) b)))))) - (is (equal '(b) (eval (transform-dig-form '(dig ((splice nil) b)))))) - (is (equal '(a) (eval (transform-dig-form '(dig (a (splice nil))))))) - (is (equal '() (eval (transform-dig-form '(dig ((splice nil))))))) - (is (equal '(a b) (eval (transform-dig-form '(dig ((splice '(a b))))))))) - - -(test are-they-macro - (is (not (equal '(dig (a b)) (macroexpand-1 '(dig (a b)))))) - (is (not (equal '(odig (a b)) (macroexpand-1 '(odig (a b))))))) - - -(defmacro triple-var (x) - `((inject ,x) (inject ,x) (inject ,x))) - -(test correct-order-of-effects - (is (equal '(a 1 2 3) (let ((x 0)) - (dig (a (inject (incf x)) (inject (incf x)) (inject (incf x))))))) - (is (equal '(a (((1))) 2) - (let ((x 0)) - (dig (a ((((inject (incf x))))) (inject (incf x)))))))) - -(test macro-injects - (is (equal '(a (3 3 3)) (let ((x 3)) - (dig (a (macro-inject (triple-var x))))))) - (is (equal '(a (1 2 3)) (let ((x 0)) - (dig (a (macro-inject (triple-var (incf x)))))))) - (macrolet ((frob (form n) - (mapcar (lambda (x) - `(inject ,x)) - (make-list n :initial-element form))) - (frob1 (form) - `(frob ,form 4))) - (is (equal '(a (1 2 3 4 5)) - (let ((x 0)) - (dig (a (macro-inject (frob (incf x) 5))))))) - (is (equal '(a 1 2 3 4 5) - (let ((x 0)) - (dig (a (macro-splice (frob (incf x) 5))))))) - (is (equal '(a) - (let ((x 0)) - (declare (ignorable x)) - (dig (a (macro-splice (frob (incf x) 0))))))) - (is (equal '(a frob (incf x) 4) - (let ((x 0)) - (declare (ignorable x)) - (dig (a (macro-splice (frob1 (incf x)))))))) - (is (equal '(a 1 2 3 4) - (let ((x 0)) - (dig (a (macro-splice-all (frob1 (incf x)))))))))) - - -(quasiquote-2.0:enable-quasiquote-2.0) - -(test reader - (is (equal '(inject x) ',x)) - (is (equal '(inject 3 x) ',,,x)) - (is (equal '(splice x) ',@x)) - (is (equal '(splice 3 x) ',,,@x)) - (is (equal '(omacro-splice-all 4 x) ',,,,!oma@x)) - (is (equal '(inject 4 oma@x) ',,,,oma@x))) - -(test macro-splices - (macrolet ((splicer (x) - ``(splice ,x))) - (is (equal '(a 1 2 3) (let ((x '(1 2 3))) - `(a ,!m(splicer x))))))) - -(test repeated-splices - (is (equal '(a) `(a ,@nil ,@nil ,@nil ,@nil))) - (is (equal '(a b c d e f g) `(a ,@(list 'b 'c) ,@(list 'd 'e) ,@nil ,@(list 'f 'g))))) - - \ No newline at end of file diff --git a/third_party/lisp/rfc2388.nix b/third_party/lisp/rfc2388.nix deleted file mode 100644 index 8015f1326..000000000 --- a/third_party/lisp/rfc2388.nix +++ /dev/null @@ -1,12 +0,0 @@ -# Implementation of RFC2388 (multipart/form-data) -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.rfc2388; -in depot.nix.buildLisp.library { - name = "rfc2388"; - - srcs = map (f: src + ("/" + f)) [ - "packages.lisp" - "rfc2388.lisp" - ]; -} diff --git a/third_party/lisp/routes.nix b/third_party/lisp/routes.nix deleted file mode 100644 index 48a95c87a..000000000 --- a/third_party/lisp/routes.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ depot, pkgs, ... }: - -let - - src = pkgs.applyPatches { - name = "routes-source"; - src = pkgs.srcOnly pkgs.sbcl.pkgs.routes; - - patches = [ - (pkgs.fetchpatch { - name = "fix-build-with-ccl.patch"; - url = "https://github.com/archimag/cl-routes/commit/2296cdc316ef8e34310f2718b5d35a30040deee0.patch"; - sha256 = "007c19kmymalam3v6l6y2qzch8xs3xnphrcclk1jrpggvigcmhax"; - }) - ]; - }; - -in -depot.nix.buildLisp.library { - name = "routes"; - - deps = with depot.third_party.lisp; [ - puri - iterate - split-sequence - ]; - - srcs = map (f: src + ("/src/" + f)) [ - "package.lisp" - "uri-template.lisp" - "route.lisp" - "mapper.lisp" - ]; -} diff --git a/third_party/lisp/s-sysdeps.nix b/third_party/lisp/s-sysdeps.nix deleted file mode 100644 index 48ea929ac..000000000 --- a/third_party/lisp/s-sysdeps.nix +++ /dev/null @@ -1,18 +0,0 @@ -# A Common Lisp abstraction layer over platform dependent functionality. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.s-sysdeps; -in depot.nix.buildLisp.library { - name = "s-sysdeps"; - - srcs = [ - "${src}/src/package.lisp" - "${src}/src/sysdeps.lisp" - ]; - - deps = with depot.third_party.lisp; [ - bordeaux-threads - usocket - usocket-server - ]; -} diff --git a/third_party/lisp/s-xml/0001-fix-definition-order-in-xml.lisp.patch b/third_party/lisp/s-xml/0001-fix-definition-order-in-xml.lisp.patch deleted file mode 100644 index 9e5838c3c..000000000 --- a/third_party/lisp/s-xml/0001-fix-definition-order-in-xml.lisp.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 789dc38399f4039b114de28384c149721d66b030 Mon Sep 17 00:00:00 2001 -From: Vincent Ambo -Date: Thu, 16 Dec 2021 00:48:04 +0300 -Subject: [PATCH] fix definition order in xml.lisp - ---- - src/xml.lisp | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/src/xml.lisp b/src/xml.lisp -index 39c9b63..3232491 100644 ---- a/src/xml.lisp -+++ b/src/xml.lisp -@@ -19,6 +19,9 @@ - - ;;; error reporting - -+(defvar *ignore-namespaces* nil -+ "When t, namespaces are ignored like in the old version of S-XML") -+ - (define-condition xml-parser-error (error) - ((message :initarg :message :reader xml-parser-error-message) - (args :initarg :args :reader xml-parser-error-args) --- -2.34.0 - diff --git a/third_party/lisp/s-xml/default.nix b/third_party/lisp/s-xml/default.nix deleted file mode 100644 index 4cb4abad2..000000000 --- a/third_party/lisp/s-xml/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -# XML serialiser for Common Lisp. -{ depot, pkgs, ... }: - -let - src = pkgs.applyPatches { - name = "s-xml-source"; - src = pkgs.sbcl.pkgs.s-xml.src; - - patches = [ - ./0001-fix-definition-order-in-xml.lisp.patch - ]; - }; -in -depot.nix.buildLisp.library { - name = "s-xml"; - - srcs = map (f: src + ("/src/" + f)) [ - "package.lisp" - "xml.lisp" - "dom.lisp" - "lxml-dom.lisp" - "sxml-dom.lisp" - "xml-struct-dom.lisp" - ]; -} diff --git a/third_party/lisp/split-sequence.nix b/third_party/lisp/split-sequence.nix deleted file mode 100644 index 1610c7220..000000000 --- a/third_party/lisp/split-sequence.nix +++ /dev/null @@ -1,15 +0,0 @@ -# split-sequence is a library for, well, splitting sequences apparently. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.split-sequence; -in depot.nix.buildLisp.library { - name = "split-sequence"; - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "vector.lisp" - "list.lisp" - "extended-sequence.lisp" - "api.lisp" - "documentation.lisp" - ]; -} diff --git a/third_party/lisp/str.nix b/third_party/lisp/str.nix deleted file mode 100644 index 289117cca..000000000 --- a/third_party/lisp/str.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.nix) buildLisp; - src = with pkgs; srcOnly sbcl.pkgs.str; -in -buildLisp.library { - name = "str"; - - deps = with depot.third_party.lisp; [ - { - sbcl = buildLisp.bundled "uiop"; - default = buildLisp.bundled "asdf"; - } - cl-ppcre - cl-ppcre.unicode - cl-change-case - ]; - - srcs = [ - (pkgs.runCommand "str.lisp" { } '' - substitute ${src}/str.lisp $out \ - --replace-fail \ - '(asdf:component-version (asdf:find-system "str"))' \ - '"${pkgs.sbcl.pkgs.str.version}"' - '') - ]; - - brokenOn = [ - "ccl" # In REPLACE-USING: Shouldn't assign to variable I - ]; - - tests = { - name = "str-test"; - srcs = [ (src + "/test/test-str.lisp") ]; - deps = [ - { - sbcl = depot.nix.buildLisp.bundled "uiop"; - default = depot.nix.buildLisp.bundled "asdf"; - } - depot.third_party.lisp.prove - depot.third_party.lisp.fiveam - ]; - - expression = '' - (fiveam:run! 'str::test-str) - ''; - }; -} diff --git a/third_party/lisp/trivial-backtrace.nix b/third_party/lisp/trivial-backtrace.nix deleted file mode 100644 index 736c0db48..000000000 --- a/third_party/lisp/trivial-backtrace.nix +++ /dev/null @@ -1,15 +0,0 @@ -# Imported from http://common-lisp.net/project/trivial-backtrace/trivial-backtrace.git -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.trivial-backtrace; -in depot.nix.buildLisp.library { - name = "trivial-backtrace"; - - srcs = map (f: src + ("/dev/" + f)) [ - "packages.lisp" - "utilities.lisp" - "backtrace.lisp" - "map-backtrace.lisp" - "fallback.lisp" - ]; -} diff --git a/third_party/lisp/trivial-clock.nix b/third_party/lisp/trivial-clock.nix deleted file mode 100644 index dc15eebc5..000000000 --- a/third_party/lisp/trivial-clock.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.nix) buildLisp; - src = pkgs.srcOnly pkgs.sbcl.pkgs.trivial-clock; -in - -buildLisp.library { - name = "trivial-clock"; - - srcs = [ - "${src}/trivial-clock.lisp" - ]; - deps = [ - depot.third_party.lisp.cffi - ]; - - tests = { - name = "trivial-clock-tests"; - deps = [ - depot.third_party.lisp.fiveam - ]; - srcs = [ - "${src}/trivial-clock-test.lisp" - ]; - expression = '' - (fiveam:run! :trivial-clock) - ''; - }; - - brokenOn = [ - "ecl" # dyn cffi - ]; -} diff --git a/third_party/lisp/trivial-features.nix b/third_party/lisp/trivial-features.nix deleted file mode 100644 index 79cb16d4b..000000000 --- a/third_party/lisp/trivial-features.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.trivial-features; -in depot.nix.buildLisp.library { - name = "trivial-features"; - srcs = [ - { - sbcl = src + "/src/tf-sbcl.lisp"; - ecl = src + "/src/tf-ecl.lisp"; - ccl = src + "/src/tf-openmcl.lisp"; - } - ]; -} diff --git a/third_party/lisp/trivial-garbage.nix b/third_party/lisp/trivial-garbage.nix deleted file mode 100644 index b5b871a14..000000000 --- a/third_party/lisp/trivial-garbage.nix +++ /dev/null @@ -1,9 +0,0 @@ -# trivial-garbage provides a portable API to finalizers, weak -# hash-tables and weak pointers -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.trivial-garbage; -in depot.nix.buildLisp.library { - name = "trivial-garbage"; - srcs = [ (src + "/trivial-garbage.lisp") ]; -} diff --git a/third_party/lisp/trivial-gray-streams.nix b/third_party/lisp/trivial-gray-streams.nix deleted file mode 100644 index ff91bc6da..000000000 --- a/third_party/lisp/trivial-gray-streams.nix +++ /dev/null @@ -1,13 +0,0 @@ -# Portability library for CL gray streams. -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.trivial-gray-streams; -in depot.nix.buildLisp.library { - name = "trivial-gray-streams"; - srcs = [ - (src + "/package.lisp") - (src + "/streams.lisp") - ]; -} - - diff --git a/third_party/lisp/trivial-indent.nix b/third_party/lisp/trivial-indent.nix deleted file mode 100644 index 61aa5a609..000000000 --- a/third_party/lisp/trivial-indent.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ depot, pkgs, ... }: - -let src = with pkgs; srcOnly sbcl.pkgs.trivial-indent; -in depot.nix.buildLisp.library { - name = "trivial-indent"; - - srcs = map (f: src + ("/" + f)) [ - "indent.lisp" - ]; -} diff --git a/third_party/lisp/trivial-ldap.nix b/third_party/lisp/trivial-ldap.nix deleted file mode 100644 index ead6f1589..000000000 --- a/third_party/lisp/trivial-ldap.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ depot, pkgs, ... }: - -let - src = pkgs.srcOnly pkgs.sbcl.pkgs.trivial-ldap; -in -depot.nix.buildLisp.library { - name = "trivial-ldap"; - - deps = with depot.third_party.lisp; [ - usocket - cl-plus-ssl - cl-yacc - ]; - - srcs = map (f: src + ("/" + f)) [ - "package.lisp" - "trivial-ldap.lisp" - ]; - - brokenOn = [ - "ecl" # dynamic cffi - ]; -} diff --git a/third_party/lisp/trivial-mimes.nix b/third_party/lisp/trivial-mimes.nix deleted file mode 100644 index 16f6199f3..000000000 --- a/third_party/lisp/trivial-mimes.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ depot, pkgs, ... }: - -let - src = with pkgs; srcOnly sbcl.pkgs.trivial-mimes; - - mime-types = pkgs.runCommand "mime-types.lisp" { } '' - substitute ${src}/mime-types.lisp $out \ - --replace /etc/mime.types ${src}/mime.types \ - --replace "(asdf:system-source-directory :trivial-mimes)" '"/bogus-dir"' - # We want to prevent an ASDF lookup at build time since this will - # generally fail — we are not using ASDF after all. - ''; - -in -depot.nix.buildLisp.library { - name = "trivial-mimes"; - - deps = [ - { - sbcl = depot.nix.buildLisp.bundled "uiop"; - default = depot.nix.buildLisp.bundled "asdf"; - } - ]; - - srcs = [ mime-types ]; -} diff --git a/third_party/lisp/uax-15.nix b/third_party/lisp/uax-15.nix deleted file mode 100644 index 7773d29c3..000000000 --- a/third_party/lisp/uax-15.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (pkgs) runCommand; - inherit (depot.nix.buildLisp) bundled; - src = with pkgs; srcOnly sbcl.pkgs.uax-15; -in -depot.nix.buildLisp.library { - name = "uax-15"; - - deps = with depot.third_party.lisp; [ - split-sequence - cl-ppcre - (bundled "asdf") - ]; - - srcs = [ - "${src}/src/package.lisp" - "${src}/src/utilities.lisp" - "${src}/src/trivial-utf-16.lisp" - - # uax-15 has runtime data files that need to have their references - # replaced with store paths. - # - # additionally there are some wonky variable usages of variables - # that are never defined, for which we patch in defvar statements. - (runCommand "precomputed-tables.lisp" { } '' - substitute ${src}/src/precomputed-tables.lisp precomputed-tables.lisp \ - --replace "(asdf:system-source-directory (asdf:find-system 'uax-15 nil))" \ - '"${src}/"' - - sed -i precomputed-tables.lisp \ - -e '10i(defvar *canonical-decomp-map*)' \ - -e '10i(defvar *compatible-decomp-map*)' \ - -e '10i(defvar *canonical-combining-class*)' - - cp precomputed-tables.lisp $out - '') - - "${src}/src/normalize-backend.lisp" - "${src}/src/uax-15.lisp" - ]; -} diff --git a/third_party/lisp/unix-opts.nix b/third_party/lisp/unix-opts.nix deleted file mode 100644 index aa54b208f..000000000 --- a/third_party/lisp/unix-opts.nix +++ /dev/null @@ -1,12 +0,0 @@ -# unix-opts is a portable command line argument parser -{ depot, pkgs, ... }: - - -let src = with pkgs; srcOnly sbcl.pkgs.unix-opts; -in depot.nix.buildLisp.library { - name = "unix-opts"; - - srcs = [ - "${src}/unix-opts.lisp" - ]; -} diff --git a/third_party/lisp/usocket-server.nix b/third_party/lisp/usocket-server.nix deleted file mode 100644 index f83c974e5..000000000 --- a/third_party/lisp/usocket-server.nix +++ /dev/null @@ -1,19 +0,0 @@ -# Universal socket library for Common Lisp (server side) -{ depot, pkgs, ... }: - -let - inherit (depot.nix) buildLisp; - src = with pkgs; srcOnly sbcl.pkgs.usocket-server; -in -buildLisp.library { - name = "usocket-server"; - - deps = with depot.third_party.lisp; [ - usocket - bordeaux-threads - ]; - - srcs = [ - "${src}/server.lisp" - ]; -} diff --git a/third_party/lisp/usocket.nix b/third_party/lisp/usocket.nix deleted file mode 100644 index 5c8295326..000000000 --- a/third_party/lisp/usocket.nix +++ /dev/null @@ -1,46 +0,0 @@ -# Usocket is a portable socket library -{ depot, pkgs, ... }: - -let - inherit (depot.nix) buildLisp; - src = with pkgs; srcOnly sbcl.pkgs.usocket; -in -buildLisp.library { - name = "usocket"; - deps = with depot.third_party.lisp; [ - (buildLisp.bundled "asdf") - { - ecl = buildLisp.bundled "sb-bsd-sockets"; - sbcl = buildLisp.bundled "sb-bsd-sockets"; - } - split-sequence - ]; - - srcs = [ - # usocket also reads its version from ASDF, but there's further - # shenanigans happening there that I don't intend to support right - # now. Behold: - (builtins.toFile "usocket.asd" '' - (in-package :asdf) - (defsystem usocket - :version "0.8.3") - '') - ] ++ - # Now for the regularly scheduled programming: - (map (f: src + ("/" + f)) [ - "package.lisp" - "usocket.lisp" - "condition.lisp" - ] ++ [ - { sbcl = "${src}/backend/sbcl.lisp"; } - - # ECL actually has two files, it supports the SBCL backend, - # but usocket also has some ECL specific code - { ecl = "${src}/backend/sbcl.lisp"; } - { ecl = "${src}/backend/ecl.lisp"; } - - # Same for CCL - { ccl = "${src}/backend/openmcl.lisp"; } - { ccl = "${src}/backend/clozure.lisp"; } - ]); -} diff --git a/third_party/overlays/tvl.nix b/third_party/overlays/tvl.nix index bdc12d9c4..4530cdab0 100644 --- a/third_party/overlays/tvl.nix +++ b/third_party/overlays/tvl.nix @@ -1,124 +1,23 @@ # This overlay is used to make TVL-specific modifications in the # nixpkgs tree, where required. -{ lib, depot, localSystem, ... }: +{ lib +, depot +, localSystem +, ... +}: self: super: depot.nix.readTree.drvTargets { - nix_2_3 = (super.nix_2_3.override { - # flaky tests, long painful build, see https://github.com/NixOS/nixpkgs/pull/266443 - withAWS = false; - }).overrideAttrs (_: { - # use TVL maintenance branch for 2.3, which has more fixes than upstream - CXXFLAGS = "--std=c++20 -g"; - dontStrip = true; - src = self.fetchFromGitHub { - owner = "tvlfyi"; - repo = "nix"; - rev = "d516e2826128c09588535b67aa27fd3e24288b5f"; - sha256 = "04yxxhhq4542gakfh2kylnhq9fagfzv63shrq0qvf8rajflwxr22"; - }; - }); - - nix = self.nix_2_3 // { - # avoid duplicate pipeline step - meta = self.nix_2_3.meta or { } // { - ci = self.nix_2_3.meta.ci or { } // { - skip = true; + # Avoid builds of mkShell derivations in CI. + mkShell = super.lib.makeOverridable ( + args: + (super.mkShell args).overrideAttrs (_: { + passthru = { + meta.ci.skip = true; }; - }; - }; - - nix_latest_stable = super.nix.override ({ - # flaky tests, long painful build, see https://github.com/NixOS/nixpkgs/pull/266443 - withAWS = false; - }); - - # No longer builds with Nix 2.3 after - # https://github.com/nixos/nixpkgs/commit/5f9d2d95721cdf20ace744f2db75ad70a7aedd3a - nixos-option = super.nixos-option.override { - nix = self.nix_latest_stable; - }; - - home-manager = super.home-manager.overrideAttrs (_: { - src = depot.third_party.sources.home-manager; - patches = [ ./patches/0001-home-environment-fix-compatibility-with-Nix-2.3.patch ]; - version = "git-" - + builtins.substring 0 7 depot.third_party.sources.home-manager.rev; - }); - - niri = super.niri.overrideAttrs (_: { - doCheck = false; - }); - - # Add our Emacs packages to the fixpoint - emacsPackagesFor = emacs: ( - (super.emacsPackagesFor emacs).overrideScope (eself: esuper: { - tvlPackages = depot.tools.emacs-pkgs // depot.third_party.emacs; - - # Use the notmuch from nixpkgs instead of from the Emacs - # overlay, to avoid versions being out of sync. - notmuch = super.notmuch.emacs; - - # Build EXWM with the depot sources instead. - depotExwm = eself.callPackage depot.third_party.exwm.override { }; - - # Workaround for magit checking the git version at load time - magit = esuper.magit.overrideAttrs (_: { - propagatedNativeBuildInputs = [ - self.git - ]; - }); - - # Pin xelb to a newer one until the new maintainers do a release. - xelb = eself.trivialBuild { - pname = "xelb"; - version = "0.19-dev"; # invented version, last actual release was 0.18 - - src = self.fetchFromGitHub { - owner = "emacs-exwm"; - repo = "xelb"; - rev = "86089eba2de6c818bfa2fac075cb7ad876262798"; - sha256 = "1mmlrd2zpcwiv8gh10y7lrpflnbmsycdascrxjr3bfcwa8yx7901"; - }; - }; - - # Override telega sources to specific commits, and check its exact tdlib version requirement. - checkedTelega = - let - pinned = esuper.telega.overrideAttrs (_: { - version = "0.8.999"; # unstable - src = self.fetchFromGitHub { - owner = "zevlg"; - repo = "telega.el"; - rev = "431c8d8c6388b8e77548d68da70a1eb44f562a98"; - sha256 = "0q6ljzlfzkf59rd86qd47yilny17k9gq4plv20lisk4i3213fzdh"; - }; - }); - - requiredTdlibFile = self.runCommandNoCC "required-tdlib" { } '' - ${self.ripgrep}/bin/rg -o -r '$1' 'tdlib_version=v(.*)$' ${pinned.src}/etc/Dockerfile > $out - ''; - - requiredTdlib = self.lib.strings.trim (builtins.readFile "${requiredTdlibFile}"); - in - assert requiredTdlib == self.tdlib.version; pinned; # ping tazjin if this fails }) ); - # dottime support for notmuch - notmuch = super.notmuch.overrideAttrs (old: { - passthru = old.passthru // { - patches = old.patches ++ [ ./patches/notmuch-dottime.patch ]; - }; - }); - - # Avoid builds of mkShell derivations in CI. - mkShell = super.lib.makeOverridable (args: (super.mkShell args).overrideAttrs (_: { - passthru = { - meta.ci.skip = true; - }; - })); - crate2nix = super.crate2nix.overrideAttrs (old: { patches = old.patches or [ ] ++ [ # TODO(Kranzes): Remove in next release. @@ -136,14 +35,6 @@ depot.nix.readTree.drvTargets { ]; }); - # https://gcc.gnu.org/gcc-14/porting_to.html#warnings-as-errors - thttpd = super.thttpd.overrideAttrs (oldAttrs: { - NIX_CFLAGS_COMPILE = oldAttrs.NIX_CFLAGS_COMPILE or [ ] ++ [ - "-Wno-error=implicit-int" - "-Wno-error=implicit-function-declaration" - ]; - }); - # https://github.com/NixOS/nixpkgs/pull/329415/files grpc-health-check = super.rustPlatform.buildRustPackage { pname = "grpc-health-check"; @@ -163,11 +54,6 @@ depot.nix.readTree.drvTargets { doCheck = false; }; - # Dependency isn't supported by Python 3.12 - html5validator = super.html5validator.override { - python3 = self.python311; - }; - # macFUSE bump containing fix for https://github.com/osxfuse/osxfuse/issues/974 # https://github.com/NixOS/nixpkgs/pull/320197 fuse = @@ -179,40 +65,7 @@ depot.nix.readTree.drvTargets { url = "https://github.com/osxfuse/osxfuse/releases/download/macfuse-${version}/macfuse-${version}.dmg"; hash = "sha256-ucTzO2qdN4QkowMVvC3+4pjEVjbwMsB0xFk+bvQxwtQ="; }; - }) else super.fuse; - - # somebody renamed 'utillinux' upstream, but didn't rename all use-cases, - # leading to some packages being broken. - # - # temporarily restore the old name to make things work again. - utillinux = self.util-linux; - - # harmonia >2.0 broke compatibility with Nix 2.3; revert back for now - harmonia = self.rustPlatform.buildRustPackage rec { - pname = "harmonia"; - version = "1.0.2"; - doCheck = false; - cargoHash = "sha256-gW/OljEngDQddIovtgwghu7uHLFVZHvWIijPgbOOkDc="; - meta.mainProgram = "harmonia"; - - src = self.fetchFromGitHub { - owner = "nix-community"; - repo = "harmonia"; - rev = "refs/tags/harmonia-v${version}"; - hash = "sha256-72nDVSvUfZsLa2HbyricOpA0Eb8gxs/VST25b6DNBpM="; - }; - - nativeBuildInputs = with self; [ - pkg-config - nixVersions.nix_2_24 - ]; - - buildInputs = with self; [ - boost - libsodium - openssl - nlohmann_json - nixVersions.nix_2_24 - ]; - }; + }) + else + super.fuse; } diff --git a/third_party/public-inbox/0001-feat-always-set-the-List-ID-header-even-in-watch.patch b/third_party/public-inbox/0001-feat-always-set-the-List-ID-header-even-in-watch.patch deleted file mode 100644 index bff2d4c20..000000000 --- a/third_party/public-inbox/0001-feat-always-set-the-List-ID-header-even-in-watch.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 1719e904acf19499209b16a8a008f55390a7b5e2 Mon Sep 17 00:00:00 2001 -From: Vincent Ambo -Date: Sun, 29 Jan 2023 13:36:12 +0300 -Subject: [PATCH] feat: always set the List-ID header even in -watch - -Without bothering to figure out exactly how this code path is usually -triggered, always set a list ID when ingesting new emails in -public-inbox-watch. ---- - lib/PublicInbox/Watch.pm | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/lib/PublicInbox/Watch.pm b/lib/PublicInbox/Watch.pm -index 3f6fe21..147971c 100644 ---- a/lib/PublicInbox/Watch.pm -+++ b/lib/PublicInbox/Watch.pm -@@ -188,6 +188,10 @@ sub _remove_spam { - sub import_eml ($$$) { - my ($self, $ibx, $eml) = @_; - -+ # TVL-specific: always set the list-id header, regardless of -+ # any of the other logic below. -+ PublicInbox::MDA->set_list_headers($eml, $ibx); -+ - # any header match means it's eligible for the inbox: - if (my $watch_hdrs = $ibx->{-watchheaders}) { - my $ok; --- -2.39.0 - diff --git a/third_party/public-inbox/default.nix b/third_party/public-inbox/default.nix deleted file mode 100644 index 1a4b196f9..000000000 --- a/third_party/public-inbox/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ pkgs, ... }: - -pkgs.public-inbox.overrideAttrs (old: { - patches = (old.patches or [ ]) ++ [ - ./0001-feat-always-set-the-List-ID-header-even-in-watch.patch - ]; - - doCheck = false; # too slow, and nixpkgs already runs them -}) diff --git a/third_party/sources/sources.json b/third_party/sources/sources.json index 855aa1406..74ffff2a3 100644 --- a/third_party/sources/sources.json +++ b/third_party/sources/sources.json @@ -36,31 +36,6 @@ "url": "https://github.com/hercules-ci/gitignore.nix/archive/637db329424fd7e46cf4185293b9cc8c88c95394.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, - "home-manager": { - "branch": "master", - "description": "Manage a user environment using Nix [maintainer=@rycee] ", - "gcroot": true, - "homepage": "https://nix-community.github.io/home-manager/", - "owner": "nix-community", - "repo": "home-manager", - "rev": "cf47e7ea2182c5638fdd1b42de329cc7d185cf8b", - "sha256": "09igpxhchgfd7xjgr882wz2yssw67p8blf0v23pkys18k46l2f13", - "type": "tarball", - "url": "https://github.com/nix-community/home-manager/archive/cf47e7ea2182c5638fdd1b42de329cc7d185cf8b.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - }, - "impermanence": { - "branch": "master", - "description": "Modules to help you handle persistent state on systems with ephemeral root storage [maintainer=@talyz]", - "homepage": "", - "owner": "nix-community", - "repo": "impermanence", - "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", - "sha256": "04l16szln2x0ajq2x799krb53ykvc6vm44x86ppy1jg9fr82161c", - "type": "tarball", - "url": "https://github.com/nix-community/impermanence/archive/4b3e914cdf97a5b536a889e939fb2fd2b043a170.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - }, "naersk": { "branch": "master", "description": "Build rust crates in Nix. No configuration, no code generation, no IFD. Sandbox friendly. [maintainer: @Patryk27]", diff --git a/third_party/teleirc/default.nix b/third_party/teleirc/default.nix deleted file mode 100644 index 879151100..000000000 --- a/third_party/teleirc/default.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ pkgs, lib, ... }: - -pkgs.buildGoModule rec { - name = "teleirc"; - version = "2.3.0-4"; - - src = pkgs.fetchFromGitHub { - owner = "tvlfyi"; - repo = "teleirc"; - rev = "356ed1450840822172e7dff57965cc5371f63454"; - sha256 = "0s6rlixks7lar9js4q1drg742cy2p4n8l4pmlzjmskl5d04c15gq"; - }; - - vendorHash = "sha256:06f2wyxbphj73wknpp6dsn7rb4yhvdl6x0gj729cns7r4bsviscs"; - ldflags = [ "-s" "-w" "-X" "main.version=${version}" ]; - postInstall = "mv $out/bin/cmd $out/bin/teleirc"; - - meta = with lib; { - description = "IRC/Telegram bridge"; - homepage = "https://docs.teleirc.com/en/latest/"; - license = licenses.gpl3; - }; -} diff --git a/third_party/terraform-provider-glesys/default.nix b/third_party/terraform-provider-glesys/default.nix deleted file mode 100644 index 2eea7e190..000000000 --- a/third_party/terraform-provider-glesys/default.nix +++ /dev/null @@ -1,20 +0,0 @@ -# GleSYS Terraform provider -# -# Some TVL resources (DNS, object storage, ...) are hosted with them. -{ pkgs, ... }: - -pkgs.terraform-providers.mkProvider rec { - version = "0.9.0"; - spdx = "MPL-2.0"; - - owner = "glesys"; - repo = "terraform-provider-glesys"; - rev = "v${version}"; - hash = "sha256:0n2wb1gl0agc9agqlmhg4mh9kyfhw4zvrryyl8wfxlp1hkr0wz9y"; - - vendorHash = "sha256:13wdx7q5rsyjrm6cn030m5hgcvx0m17dhr16wmbfv71pmsszfdjm"; - - # This provider is not officially published in the TF registry, so - # we're giving it a fake source here. - provider-source-address = "registry.terraform.io/depot/glesys"; -} diff --git a/tools/depot-deps.nix b/tools/depot-deps.nix index 5fa1fe23b..96e584001 100644 --- a/tools/depot-deps.nix +++ b/tools/depot-deps.nix @@ -1,17 +1,15 @@ # Shell derivation to invoke //nix/lazy-deps with the dependencies # that should be lazily made available in depot. -{ pkgs, depot, ... }: +{ depot, ... }: depot.nix.lazy-deps { age-keygen.attr = "third_party.nixpkgs.age"; age.attr = "third_party.nixpkgs.age"; depotfmt.attr = "tools.depotfmt"; - fetch-depot-inbox.attr = "tools.fetch-depot-inbox"; git-r.attr = "tools.git-r"; git-review.attr = "third_party.nixpkgs.git-review"; gerrit-update.attr = "tools.gerrit-update"; gerrit.attr = "tools.gerrit-cli"; - hash-password.attr = "tools.hash-password"; josh-filter.attr = "third_party.nixpkgs.josh"; mg.attr = "tools.magrathea"; nint.attr = "nix.nint"; @@ -24,11 +22,6 @@ depot.nix.lazy-deps { cmd = "terraform"; }; - tf-glesys = { - attr = "ops.glesys.terraform"; - cmd = "terraform"; - }; - tf-keycloak = { attr = "ops.keycloak.terraform"; cmd = "terraform"; diff --git a/tools/eaglemode/commands/B.nix b/tools/eaglemode/commands/B.nix deleted file mode 100644 index bca3d3a87..000000000 --- a/tools/eaglemode/commands/B.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ depot, pkgs, ... }: - -let - em = depot.tools.eaglemode; -in -em.mkCommand { - name = "9 B"; - hotkey = "Ctrl+E"; - icon = "${./plan9.tga}"; - - description = '' - Plumb target to Sam or Acme - ''; - - code = '' - ErrorIfNotSingleTarget(); - - my @tgt=GetTgt(); - my $dir=$tgt[0]; - - ExecOrError('${pkgs.plan9port}/bin/9', 'B', $dir); - ''; -} diff --git a/tools/eaglemode/commands/emacsclient.nix b/tools/eaglemode/commands/emacsclient.nix deleted file mode 100644 index bac367412..000000000 --- a/tools/eaglemode/commands/emacsclient.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ depot, pkgs, ... }: - -let - em = depot.tools.eaglemode; - icon = em.mkTGA "emacs" "${pkgs.emacs}/share/icons/hicolor/128x128/apps/emacs.png"; -in -em.mkCommand { - name = "Emacsclient"; - hotkey = "Ctrl+E"; - icon = "${icon}"; - - description = '' - Open target in Emacsclient. - - Emacs server must be running already for this to have any effect. - ''; - - code = '' - ErrorIfNotSingleTarget(); - - my @tgt=GetTgt(); - my $dir=$tgt[0]; - - ExecOrError('${pkgs.emacs}/bin/emacsclient', '-n', $dir); - ''; -} diff --git a/tools/eaglemode/commands/plan9.tga b/tools/eaglemode/commands/plan9.tga deleted file mode 100644 index 55d002221..000000000 Binary files a/tools/eaglemode/commands/plan9.tga and /dev/null differ diff --git a/tools/eaglemode/default.nix b/tools/eaglemode/default.nix deleted file mode 100644 index 30983f5d5..000000000 --- a/tools/eaglemode/default.nix +++ /dev/null @@ -1,146 +0,0 @@ -# Helper functions for extending Eagle Mode with useful stuff. -# -# Eagle Mode's customisation usually expects people to copy the entire -# configuration into their user folder, which we can automate fairly easily -# using Nix, letting users choose whether to keep upstream config or not. -{ depot, lib, pkgs, ... }: - -let - mkDesc = d: lib.concatMapStringsSep "\n" - (x: "# Descr =${x}") - (builtins.filter (s: s != "") (lib.splitString "\n" d)); - - configWrapper = pkgs.runCommand "eaglemode-config-wrapper" { } '' - cp ${./wrapper.go} wrapper.go - export HOME=$PWD - ${pkgs.go}/bin/go build wrapper.go - install -Dm755 wrapper $out/bin/wrapper - ''; -in -rec { - # mkCommand creates an Eagle Mode command for the file browser. - # - # Commands are basically little Perl scripts with a command standard library - # available. They receive the user's selected target from Eagle Mode. - mkCommand = lib.makeOverridable ( - { - # Name of the command. - name - , # User-facing description, displayed in Eagle Mode UI. Can be multi-line. - description - , # Verbatim Perl code of the command. Command library is already available. - code - , # Caption for the UI button (defaults to name). - caption ? name - , icon ? "terminal.tga" - , # TODO: what's a good default? - hotkey ? "" - , order ? 1.0 - }: pkgs.writeTextDir "emFileMan/Commands/${name}.pl" ('' - #!${pkgs.perl}/bin/perl - #[[BEGIN PROPERTIES]] - # Type = Command - # Interpreter = perl - # DefaultFor = directory - # Caption = ${caption} - # Order = ${toString order} - # Icon = ${icon} - '' - + (lib.optionalString (description != "") "${mkDesc description}\n") - + (lib.optionalString (hotkey != "") "# Hotkey = ${hotkey}\n") - + '' - #[[END PROPERTIES]] - - use strict; - use warnings; - BEGIN { require "$ENV{'EM_DIR'}/res/emFileMan/scripts/cmd-util.pl"; } - - ${if builtins.isString code - then code - else (if builtins.isPath code - then builtins.readFile code - else throw "code must be a string (literal code) or path to file")} - '') - ); - - # mkTGA converts the given image to a TGA image. - mkTGA = name: path: pkgs.runCommand "${name}.tga" { } '' - ${pkgs.imagemagick}/bin/convert ${path} $out - ''; - - buildPlugin = lib.makeOverridable ( - { name - , src - , version - , eaglemode ? pkgs.eaglemode - , target ? name - , extraNativeBuildInputs ? [ ] - , extraBuildInputs ? [ ] - }: - pkgs.stdenv.mkDerivation { - pname = "eaglemode-plugin-${name}"; - inherit src version; - # inherit (eaglemode.drvAttrs) dontPatchELF; - - nativeBuildInputs = eaglemode.drvAttrs.nativeBuildInputs ++ extraNativeBuildInputs; - buildInputs = eaglemode.drvAttrs.buildInputs ++ extraBuildInputs ++ [ eaglemode ]; - - buildPhase = '' - runHook preBuild - - # merge eaglemode & plugin folders - cp -r ${pkgs.srcOnly eaglemode} merged-src && chmod -R u+rw merged-src - cp -r $src/* merged-src && chmod -R u+rw merged-src - cd merged-src - - export NIX_LDFLAGS="$NIX_LDFLAGS -lXxf86vm -lXext -lXinerama" - perl make.pl build projects=${target} continue=no - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - mkdir -p $out/lib - cp -r lib/lib${target}.so $out/lib - - if [ -d "$src/etc" ]; then - cp -r $src/etc/* $out - fi - - runHook postInstall - ''; - } - ); - - # etcDir creates a directory layout suitable for use in the EM_USER_CONFIG_DIR - # environment variable. - # - # Note that Eagle Mode requires the value of that variable to be mutable at - # runtime (it is the same place where it persists all of its user-controlled - # state), so the results of this function can not be used directly. - etcDir = - { eaglemode ? pkgs.eaglemode - , extraPaths ? [ ] - }: pkgs.runCommand "eaglemode-config" { } '' - mkdir $out - - ${ - lib.concatMapStringsSep "\n" (s: "cp -rT ${s} $out/\nchmod -R u+rw $out/\n") ([ "${eaglemode}/etc"] ++ extraPaths) - } - ''; - - # withConfig creates an Eagle Mode wrapper that runs it with the given - # configuration. - withConfig = { eaglemode ? pkgs.eaglemode, config }: pkgs.writeShellScriptBin "eaglemode" '' - ${configWrapper}/bin/wrapper --em-config "${config}" - - if [ -d "${config}/lib" ]; then - export LD_LIBRARY_PATH="${config}/lib:$LD_LIBRARY_PATH" - exec ${eaglemode}/bin/eaglemode "$@" - fi - - exec ${eaglemode}/bin/eaglemode "$@" - ''; -} diff --git a/tools/eaglemode/plugins/avif/default.nix b/tools/eaglemode/plugins/avif/default.nix deleted file mode 100644 index 07577c685..000000000 --- a/tools/eaglemode/plugins/avif/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ depot, pkgs, ... }: - -depot.tools.eaglemode.buildPlugin { - name = "avif"; - version = "canon"; - src = ./.; - target = "PlAvif"; - extraBuildInputs = [ pkgs.libavif ]; - extraNativeBuildInputs = [ pkgs.pkg-config ]; -} diff --git a/tools/eaglemode/plugins/avif/etc/emCore/FpPlugins/PlAvif.emFpPlugin b/tools/eaglemode/plugins/avif/etc/emCore/FpPlugins/PlAvif.emFpPlugin deleted file mode 100644 index 61615f9fd..000000000 --- a/tools/eaglemode/plugins/avif/etc/emCore/FpPlugins/PlAvif.emFpPlugin +++ /dev/null @@ -1,6 +0,0 @@ -#%rec:emFpPlugin%# - -FileTypes = { ".avif" } -Priority = 1.0 -Library = "PlAvif" -Function = "PlAvifFpPluginFunc" diff --git a/tools/eaglemode/plugins/avif/makers/PlAvif.maker.pm b/tools/eaglemode/plugins/avif/makers/PlAvif.maker.pm deleted file mode 100644 index 00b927805..000000000 --- a/tools/eaglemode/plugins/avif/makers/PlAvif.maker.pm +++ /dev/null @@ -1,64 +0,0 @@ -package PlAvif; - -use strict; -use warnings; - -sub GetDependencies -{ - return ('emCore'); -} - -sub IsEssential -{ - return 0; -} - -sub GetFileHandlingrules -{ - return (); -} - -sub GetExtraBuildOptions -{ - return (); -} - -sub Build -{ - shift; - my %options=@_; - - my @libAvifFlags=(); - if ($options{'avif-inc-dir'} eq '' && $options{'avif-lib-dir'} eq '') { - @libAvifFlags=split("\n",readpipe( - "perl \"".$options{'utils'}."/PkgConfig.pl\" libavif" - )); - } - if (!@libAvifFlags) { - if ($options{'avif-inc-dir'} ne '') { - push(@libAvifFlags, "--inc-search-dir", $options{'avif-inc-dir'}); - } - if ($options{'avif-lib-dir'} ne '') { - push(@libAvifFlags, "--lib-search-dir", $options{'avif-lib-dir'}); - } - push(@libAvifFlags, "--link", "avif"); - } - - system( - @{$options{'unicc_call'}}, - "--math", - "--rtti", - "--exceptions", - "--bin-dir" , "bin", - "--lib-dir" , "lib", - "--obj-dir" , "obj", - "--inc-search-dir", "include", - @libAvifFlags, - "--link" , "emCore", - "--type" , "dynlib", - "--name" , "PlAvif", - "src/PlAvif.cpp" - )==0 or return 0; - - return 1; -} diff --git a/tools/eaglemode/plugins/avif/src/PlAvif.cpp b/tools/eaglemode/plugins/avif/src/PlAvif.cpp deleted file mode 100644 index e4807bacd..000000000 --- a/tools/eaglemode/plugins/avif/src/PlAvif.cpp +++ /dev/null @@ -1,190 +0,0 @@ -#include -#include - -#include "avif/avif.h" - -class PlAvifImageFileModel : public emImageFileModel -{ -public: - - static emRef Acquire( - emContext & context, const emString & name, bool common=true - ); - -protected: - PlAvifImageFileModel(emContext & context, const emString & name); - virtual ~PlAvifImageFileModel(); - virtual void TryStartLoading(); - virtual bool TryContinueLoading(); - virtual void QuitLoading(); - virtual void TryStartSaving(); - virtual bool TryContinueSaving(); - virtual void QuitSaving(); - virtual emUInt64 CalcMemoryNeed(); - virtual double CalcFileProgress(); - -private: - struct LoadingState; - LoadingState * L = NULL; -}; - - -struct PlAvifImageFileModel::LoadingState { - avifRGBImage rgb; - avifDecoder * decoder; -}; - - -emRef PlAvifImageFileModel::Acquire( - emContext & context, const emString & name, bool common -) -{ - EM_IMPL_ACQUIRE(PlAvifImageFileModel, context, name, common) -} - - -PlAvifImageFileModel::PlAvifImageFileModel( - emContext & context, const emString & name -) - : emImageFileModel(context, name) -{ -} - - -PlAvifImageFileModel::~PlAvifImageFileModel() -{ - PlAvifImageFileModel::QuitLoading(); - PlAvifImageFileModel::QuitSaving(); -} - - -void PlAvifImageFileModel::TryStartLoading() -{ - avifResult result; - - L = new LoadingState; - memset(L, 0, sizeof(LoadingState)); - - L->decoder = avifDecoderCreate(); - if (L->decoder == NULL) { - throw emException("failed to create AVIF decoder"); - } - - result = avifDecoderSetIOFile(L->decoder, GetFilePath()); - if (result != AVIF_RESULT_OK) { - throw emException("%s", avifResultToString(result)); - } - - result = avifDecoderParse(L->decoder); - if (result != AVIF_RESULT_OK) { - throw emException("%s", avifResultToString(result)); - } - - FileFormatInfo = emString::Format( - "AVIF %s %ubpc", - avifPixelFormatToString(L->decoder->image->yuvFormat), - L->decoder->image->depth - ); - - - Signal(ChangeSignal); -} - - -bool PlAvifImageFileModel::TryContinueLoading() -{ - avifResult result; - - if (!Image.GetHeight()) { - Image.Setup( - L->decoder->image->width, - L->decoder->image->height, - L->decoder->alphaPresent ? 4 : 3 - ); - } - - result = avifDecoderNextImage(L->decoder); - if (result != AVIF_RESULT_OK) { - throw emException("%s", avifResultToString(result)); - } - - avifRGBImageSetDefaults(&L->rgb, L->decoder->image); - L->rgb.format = L->decoder->alphaPresent ? - AVIF_RGB_FORMAT_RGBA : AVIF_RGB_FORMAT_RGB; - L->rgb.pixels = Image.GetWritableMap(); - L->rgb.width = Image.GetWidth(); - L->rgb.height = Image.GetHeight(); - L->rgb.depth = 8; - L->rgb.rowBytes = Image.GetWidth() * Image.GetChannelCount(); - - result = avifImageYUVToRGB(L->decoder->image, &L->rgb); - if (result != AVIF_RESULT_OK) { - throw emException("%s", avifResultToString(result)); - } - - Signal(ChangeSignal); - return true; -} - - -void PlAvifImageFileModel::QuitLoading() -{ - if (L) { - if (L->decoder) avifDecoderDestroy(L->decoder); - delete L; - L = NULL; - } -} - - -void PlAvifImageFileModel::TryStartSaving() -{ - throw emException("PlAvifImageFileModel: Saving not implemented."); -} - - -bool PlAvifImageFileModel::TryContinueSaving() -{ - return false; -} - - -void PlAvifImageFileModel::QuitSaving() -{ -} - - -emUInt64 PlAvifImageFileModel::CalcMemoryNeed() -{ - return - (emUInt64) - L->decoder->image->width * - L->decoder->image->height * - (L->decoder->alphaPresent ? 4 : 3); -} - - -double PlAvifImageFileModel::CalcFileProgress() -{ - return 0.0; -} - -extern "C" { - emPanel * PlAvifFpPluginFunc( - emPanel::ParentArg parent, const emString & name, - const emString & path, emFpPlugin * plugin, - emString * errorBuf - ) - { - if (plugin->Properties.GetCount()) { - *errorBuf="PlAvifFpPlugin: No properties allowed."; - return NULL; - } - return new emImageFilePanel( - parent, name, - PlAvifImageFileModel::Acquire( - parent.GetRootContext(), path - ) - ); - } -} diff --git a/tools/eaglemode/plugins/example.nix b/tools/eaglemode/plugins/example.nix deleted file mode 100644 index b361971cc..000000000 --- a/tools/eaglemode/plugins/example.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ depot, pkgs, ... }: - -let - em = depot.tools.eaglemode; - emSrc = with pkgs; srcOnly eaglemode; -in -em.buildPlugin { - name = "example"; - version = "canon"; - - src = pkgs.runCommand "em-plugin-example-src" { } '' - set -ux - cp -r ${emSrc}/doc/examples/CppApiExamples/PluginExample $out - ''; - - target = "PlEx"; -} diff --git a/tools/eaglemode/plugins/qoi/default.nix b/tools/eaglemode/plugins/qoi/default.nix deleted file mode 100644 index 8764ac39e..000000000 --- a/tools/eaglemode/plugins/qoi/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ depot, pkgs, ... }: - -let - em = depot.tools.eaglemode; - emSrc = pkgs.srcOnly pkgs.em; -in -em.buildPlugin { - name = "qoi"; - version = "canon"; - src = ./.; - target = "PlQoi"; -} diff --git a/tools/eaglemode/plugins/qoi/etc/emCore/FpPlugins/PlQoi.emFpPlugin b/tools/eaglemode/plugins/qoi/etc/emCore/FpPlugins/PlQoi.emFpPlugin deleted file mode 100644 index e27f37261..000000000 --- a/tools/eaglemode/plugins/qoi/etc/emCore/FpPlugins/PlQoi.emFpPlugin +++ /dev/null @@ -1,6 +0,0 @@ -#%rec:emFpPlugin%# - -FileTypes = { ".qoi" } -Priority = 1.0 -Library = "PlQoi" -Function = "PlQoiFpPluginFunc" diff --git a/tools/eaglemode/plugins/qoi/makers/PlQoi.maker.pm b/tools/eaglemode/plugins/qoi/makers/PlQoi.maker.pm deleted file mode 100644 index c68b9bc63..000000000 --- a/tools/eaglemode/plugins/qoi/makers/PlQoi.maker.pm +++ /dev/null @@ -1,47 +0,0 @@ -package PlQoi; - -use strict; -use warnings; - -sub GetDependencies -{ - return ('emCore'); -} - -sub IsEssential -{ - return 0; -} - -sub GetFileHandlingrules -{ - return (); -} - -sub GetExtraBuildOptions -{ - return (); -} - -sub Build -{ - shift; - my %options=@_; - - system( - @{$options{'unicc_call'}}, - "--math", - "--rtti", - "--exceptions", - "--bin-dir" , "bin", - "--lib-dir" , "lib", - "--obj-dir" , "obj", - "--inc-search-dir", "include", - "--link" , "emCore", - "--type" , "dynlib", - "--name" , "PlQoi", - "src/PlQoi.cpp" - )==0 or return 0; - - return 1; -} diff --git a/tools/eaglemode/plugins/qoi/src/PlQoi.cpp b/tools/eaglemode/plugins/qoi/src/PlQoi.cpp deleted file mode 100644 index 1455712ef..000000000 --- a/tools/eaglemode/plugins/qoi/src/PlQoi.cpp +++ /dev/null @@ -1,273 +0,0 @@ -#include -#include - -/* -QOI Utilities - -Copyright (c) 2021, Dominic Szablewski - https://phoboslab.org -SPDX-License-Identifier: MIT -*/ - -#define QOI_OP_INDEX 0x00 /* 00xxxxxx */ -#define QOI_OP_DIFF 0x40 /* 01xxxxxx */ -#define QOI_OP_LUMA 0x80 /* 10xxxxxx */ -#define QOI_OP_RUN 0xc0 /* 11xxxxxx */ -#define QOI_OP_RGB 0xfe /* 11111110 */ -#define QOI_OP_RGBA 0xff /* 11111111 */ - -#define QOI_MASK_2 0xc0 /* 11000000 */ - -#define QOI_COLOR_HASH(C) (C.GetRed()*3 + C.GetGreen()*5 + C.GetBlue()*7 + C.GetAlpha()*11) - -#define QOI_MAGIC \ - (((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \ - ((unsigned int)'i') << 8 | ((unsigned int)'f')) - -#define QOI_HEADER_SIZE 14 - -static unsigned int qoi_read_32(const unsigned char *bytes, int *p) { - unsigned int a = bytes[(*p)++]; - unsigned int b = bytes[(*p)++]; - unsigned int c = bytes[(*p)++]; - unsigned int d = bytes[(*p)++]; - return a << 24 | b << 16 | c << 8 | d; -} - - -class PlQoiImageFileModel : public emImageFileModel -{ -public: - - static emRef Acquire( - emContext & context, const emString & name, bool common=true - ); - -protected: - PlQoiImageFileModel(emContext & context, const emString & name); - virtual ~PlQoiImageFileModel(); - virtual void TryStartLoading(); - virtual bool TryContinueLoading(); - virtual void QuitLoading(); - virtual void TryStartSaving(); - virtual bool TryContinueSaving(); - virtual void QuitSaving(); - virtual emUInt64 CalcMemoryNeed(); - virtual double CalcFileProgress(); - -private: - struct LoadingState; - LoadingState * L = NULL; -}; - - -struct PlQoiImageFileModel::LoadingState { - FILE * file; - unsigned int width, height, channels; - size_t file_len; -}; - - -emRef PlQoiImageFileModel::Acquire( - emContext & context, const emString & name, bool common -) -{ - EM_IMPL_ACQUIRE(PlQoiImageFileModel, context, name, common) -} - - -PlQoiImageFileModel::PlQoiImageFileModel( - emContext & context, const emString & name -) - : emImageFileModel(context, name) -{ -} - - -PlQoiImageFileModel::~PlQoiImageFileModel() -{ - PlQoiImageFileModel::QuitLoading(); - PlQoiImageFileModel::QuitSaving(); -} - - -void PlQoiImageFileModel::TryStartLoading() -{ - unsigned char header[QOI_HEADER_SIZE]; - unsigned int header_magic, colorspace; - int pos = 0; - - L = new LoadingState; - memset(L, 0, sizeof(LoadingState)); - L->file = fopen(GetFilePath(),"rb"); - if (!L->file) throw emException("%s",emGetErrorText(errno).Get()); - - if (fread(header, 1, sizeof(header), L->file) != sizeof(header)) { - if (ferror(L->file)) { - throw emException("%s",emGetErrorText(errno).Get()); - } - else { - throw emException("QOI header not found"); - } - } - - header_magic = qoi_read_32(header, &pos); - L->width = qoi_read_32(header, &pos); - L->height = qoi_read_32(header, &pos); - L->channels = header[pos++]; - colorspace = header[pos++]; - - if ( - L->width == 0 || L->height == 0 || - L->channels < 3 || L->channels > 4 || - colorspace > 1 || - header_magic != QOI_MAGIC - ) { - throw emException("QOI header not valid"); - } - - fseek(L->file, 0, SEEK_END); - L->file_len = ftell(L->file); - - if (L->file_len <= QOI_HEADER_SIZE || fseek(L->file, 0, SEEK_SET) != 0) { - throw emException("QOI data incomplete"); - } - - FileFormatInfo = "QOI "; - FileFormatInfo += ( - colorspace ? "all channels linear" : "sRGB with linear alpha" - ); - - Signal(ChangeSignal); -} - - -bool PlQoiImageFileModel::TryContinueLoading() -{ - emArray data; - emColor index[64]; - emColor px { 0, 0, 0, 255 }; - int pos = QOI_HEADER_SIZE; - int run = 0; - - if (!Image.GetHeight()) { - Image.Setup(L->width, L->height, L->channels); - } - - data.SetCount(L->file_len); - if (fread(data.GetWritable(), 1, L->file_len, L->file) < L->file_len) { - if (ferror(L->file)) { - throw emException("%s",emGetErrorText(errno).Get()); - } - else { - throw emException("QOI data incomplete"); - } - } - - memset(index, 0, sizeof(index)); - - for (int px_y = 0; px_y < L->height; px_y++) { - for (int px_x = 0; px_x < L->width; px_x++) { - if (run > 0) { - run--; - } else if (pos < data.GetCount()) { - int b1 = data.Get(pos++); - - if (b1 == QOI_OP_RGB) { - px.SetRed( data.Get(pos++)); - px.SetGreen( data.Get(pos++)); - px.SetBlue( data.Get(pos++)); - } else if (b1 == QOI_OP_RGBA) { - px.SetRed( data.Get(pos++)); - px.SetGreen( data.Get(pos++)); - px.SetBlue( data.Get(pos++)); - px.SetAlpha( data.Get(pos++)); - } else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) { - px = index[b1]; - } else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) { - px.SetRed( - px.GetRed() + ((b1 >> 4) & 0x03) - 2); - px.SetGreen( - px.GetGreen() + ((b1 >> 2) & 0x03) - 2); - px.SetBlue( - px.GetBlue() + ( b1 & 0x03) - 2); - } else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) { - int b2 = data.Get(pos++); - int vg = (b1 & 0x3f) - 32; - px.SetRed( - px.GetRed() + vg - 8 + ((b2 >> 4) & 0x0f)); - px.SetGreen( - px.GetGreen() + vg); - px.SetBlue( - px.GetBlue() + vg - 8 + (b2 & 0x0f)); - } else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) { - run = (b1 & 0x3f); - } - index[QOI_COLOR_HASH(px) % 64] = px; - } - Image.SetPixel(px_x, px_y, px); - } - } - - Signal(ChangeSignal); - return true; -} - - -void PlQoiImageFileModel::QuitLoading() -{ - if (L) { - if (L->file) fclose(L->file); - delete L; - L = NULL; - } -} - - -void PlQoiImageFileModel::TryStartSaving() -{ - throw emException("PlQoiImageFileModel: Saving not implemented."); -} - - -bool PlQoiImageFileModel::TryContinueSaving() -{ - return false; -} - - -void PlQoiImageFileModel::QuitSaving() -{ -} - - -emUInt64 PlQoiImageFileModel::CalcMemoryNeed() -{ - return - (emUInt64)L->width * L->height * L->channels + L->file_len; -} - - -double PlQoiImageFileModel::CalcFileProgress() -{ - return 0.0; -} - -extern "C" { - emPanel * PlQoiFpPluginFunc( - emPanel::ParentArg parent, const emString & name, - const emString & path, emFpPlugin * plugin, - emString * errorBuf - ) - { - if (plugin->Properties.GetCount()) { - *errorBuf="PlQoiFpPlugin: No properties allowed."; - return NULL; - } - return new emImageFilePanel( - parent, name, - PlQoiImageFileModel::Acquire( - parent.GetRootContext(), path - ) - ); - } -} diff --git a/tools/eaglemode/plugins/yatracker/default.nix b/tools/eaglemode/plugins/yatracker/default.nix deleted file mode 100644 index 3ffc42029..000000000 --- a/tools/eaglemode/plugins/yatracker/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ depot, pkgs, ... }: - -let - em = depot.tools.eaglemode; - emSrc = with pkgs; srcOnly eaglemode; -in -(em.buildPlugin { - name = "yatracker"; - version = "canon"; - src = ./.; - target = "PlYaTracker"; -}).overrideAttrs (_: { - postInstall = '' - mkdir -p $out/icons - ${pkgs.imagemagick}/bin/convert $src/logo.webp $out/icons/yandex-tracker.tga - ''; -}) - diff --git a/tools/eaglemode/plugins/yatracker/etc/emCore/FpPlugins/PlYaTracker.emFpPlugin b/tools/eaglemode/plugins/yatracker/etc/emCore/FpPlugins/PlYaTracker.emFpPlugin deleted file mode 100644 index 637878844..000000000 --- a/tools/eaglemode/plugins/yatracker/etc/emCore/FpPlugins/PlYaTracker.emFpPlugin +++ /dev/null @@ -1,6 +0,0 @@ -#%rec:emFpPlugin%# - -FileTypes = { ".YaTracker" } -Priority = 1.0 -Library = "PlYaTracker" -Function = "PlYaTrackerPluginFunc" diff --git a/tools/eaglemode/plugins/yatracker/logo.webp b/tools/eaglemode/plugins/yatracker/logo.webp deleted file mode 100644 index 460d57d72..000000000 Binary files a/tools/eaglemode/plugins/yatracker/logo.webp and /dev/null differ diff --git a/tools/eaglemode/plugins/yatracker/makers/PlYaTracker.maker.pm b/tools/eaglemode/plugins/yatracker/makers/PlYaTracker.maker.pm deleted file mode 100644 index ae954260a..000000000 --- a/tools/eaglemode/plugins/yatracker/makers/PlYaTracker.maker.pm +++ /dev/null @@ -1,47 +0,0 @@ -package PlYaTracker; - -use strict; -use warnings; - -sub GetDependencies -{ - return ('emCore'); -} - -sub IsEssential -{ - return 0; -} - -sub GetFileHandlingRules -{ - return (); -} - -sub GetExtraBuildOptions -{ - return (); -} - -sub Build -{ - shift; - my %options=@_; - - system( - @{$options{'unicc_call'}}, - "--math", - "--rtti", - "--exceptions", - "--bin-dir" , "bin", - "--lib-dir" , "lib", - "--obj-dir" , "obj", - "--inc-search-dir", "include", - "--link" , "emCore", - "--type" , "dynlib", - "--name" , "PlYaTracker", - "src/PlYaTracker/PlYaTracker.cpp" - )==0 or return 0; - - return 1; -} diff --git a/tools/eaglemode/plugins/yatracker/src/PlYaTracker/PlYaTracker.cpp b/tools/eaglemode/plugins/yatracker/src/PlYaTracker/PlYaTracker.cpp deleted file mode 100644 index 9bf05a171..000000000 --- a/tools/eaglemode/plugins/yatracker/src/PlYaTracker/PlYaTracker.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include - -class PlYaTrackerConfig final : public emRecFileModel, public emStructRec { - public: - static emRef Acquire(emContext& context, - const emString& name, - bool common = true); - - virtual const char* GetFormatName() const; - - emStringRec URL; - emStringRec Token; - - protected: - PlYaTrackerConfig(emContext& context, const emString& name); -}; - -emRef PlYaTrackerConfig::Acquire(emContext& context, - const emString& name, - bool common) { - EM_IMPL_ACQUIRE(PlYaTrackerConfig, context, name, common) -} - -const char* PlYaTrackerConfig::GetFormatName() const { return "PlYaTracker"; } - -PlYaTrackerConfig::PlYaTrackerConfig(emContext& context, const emString& name) - : emRecFileModel(context, name), - emStructRec(), - URL(this, "URL"), - Token(this, "Token") { - PostConstruct(*this); -} - -class PlYaTrackerFilePanel : public emFilePanel { - public: - PlYaTrackerFilePanel(ParentArg parent, const emString& name, - emRef config); - - private: - emRef Config; -}; - -PlYaTrackerFilePanel::PlYaTrackerFilePanel(ParentArg parent, - const emString& name, - emRef config) - : emFilePanel(parent, name, config), Config(config) {} - -extern "C" { -emPanel* PlYaTrackerPluginFunc(emPanel::ParentArg parent, const emString& name, - const emString& path, emFpPlugin* plugin, - emString* errorBuf) { - return new PlYaTrackerFilePanel( - parent, name, PlYaTrackerConfig::Acquire(parent.GetRootContext(), path)); -} -} diff --git a/tools/eaglemode/wrapper.go b/tools/eaglemode/wrapper.go deleted file mode 100644 index 841642b6d..000000000 --- a/tools/eaglemode/wrapper.go +++ /dev/null @@ -1,156 +0,0 @@ -// Eagle Mode configuration wrapper that recreates the required directory -// structure for Eagle Mode based on the output of depot.tools.eaglemode.etcDir -// -// This will replace *all* symlinks in the Eagle Mode configuration directory, -// but it will not touch actual files. Missing folders will be created. -package main - -import ( - "flag" - "fmt" - "io/fs" - "log" - "os" - "os/user" - "path" - "path/filepath" - "strings" -) - -func configDir() (string, error) { - v := os.Getenv("EM_USER_CONFIG_DIR") - if v != "" { - return v, nil - } - - usr, err := user.Current() - if err != nil { - return "", fmt.Errorf("failed to get current user: %w", err) - } - - return path.Join(usr.HomeDir, ".eaglemode"), nil -} - -// cleanupConfig removes *all* existing symlinks in the configuration which do -// not point into the right Nix store path. -func cleanupConfig(conf string, dir string) (map[string]bool, error) { - // In case of first launch, we might have to create the directory. - _ = os.MkdirAll(dir, 0755) - c := 0 - - currentFiles := map[string]bool{} - - walker := func(p string, d fs.DirEntry, e error) error { - if e != nil { - return fmt.Errorf("could not walk %s in config directory: %w", p, e) - } - - if d.Type()&fs.ModeSymlink != 0 { - target, err := os.Readlink(p) - if err != nil { - return fmt.Errorf("could not read link for %s: %w", p, err) - } - - if !strings.HasPrefix(target, conf) { - err = os.Remove(p) - c++ - if err != nil { - return fmt.Errorf("could not remove stale link %q: %w", p, err) - } - log.Printf("removed stale symlink %q", p) - } else { - currentFiles[p] = false - } - } - - if d.Type().IsRegular() { - currentFiles[p] = true - } - - return nil - } - - err := filepath.WalkDir(dir, walker) - if err != nil { - return nil, err - } - - if c > 0 { - log.Printf("removed %v stale symlinks", c) - } - - return currentFiles, nil -} - -// linkConfig traverses the given Eagle Mode configuration and links everything -// to the expected location in the user's configuration directory. -// -// If the user placed actual files in the configuration directory at paths that -// would be overwritten, they will not be touched. -func linkConfig(conf string, dir string, existing map[string]bool) error { - walker := func(p string, d fs.DirEntry, e error) error { - if e != nil { - return fmt.Errorf("could not walk %s in config directory: %w", p, e) - } - - target := path.Join(dir, strings.TrimPrefix(p, conf)) - - if d.Type().IsDir() { - err := os.MkdirAll(target, 0755) - if err != nil { - return fmt.Errorf("could not create directory %q: %w", target, err) - } - - return nil - } - - if shadow, exists := existing[target]; exists { - if shadow { - log.Printf("WARN: file %q already exists and shadows a file from configuration", target) - } - - return nil - } - - err := os.Symlink(p, target) - if err != nil { - return fmt.Errorf("failed to link %q: %w", target, err) - } - - return nil - } - - return filepath.WalkDir(conf, walker) -} - -func main() { - emConfig := flag.String("em-config", "", "path to em-config dir") - - flag.Parse() - log.Println("verifying current Eagle Mode configuration") - - if *emConfig == "" { - log.Fatalf("Eagle Mode configuration must be given") - } - - if !strings.HasPrefix(*emConfig, "/nix/store/") { - log.Fatalf("Eagle Mode configuration must be in Nix store") - } - - dir, err := configDir() - if err != nil { - log.Fatalf("could not determine Eagle Mode config dir: %v", err) - } - - currentFiles, err := cleanupConfig(*emConfig, dir) - if err != nil { - log.Fatalf("failed to remove stale symlinks: %v", err) - } - - err = linkConfig(*emConfig, dir, currentFiles) - if err != nil { - log.Fatalf("failed to link new configuration: %v", err) - } - - log.Println("Eagle Mode configuration updated") -} diff --git a/tools/emacs-pkgs/FSF_OWNERS b/tools/emacs-pkgs/FSF_OWNERS deleted file mode 100644 index 32a278ca7..000000000 --- a/tools/emacs-pkgs/FSF_OWNERS +++ /dev/null @@ -1,6 +0,0 @@ -# Users with approval powers for code that requires FSF copyright -# assignment. Users added here should have FSF paperwork on file, and -# should - if changes to a covered project are made - verify that the -# committers also have done the paperwork. - -tazjin diff --git a/tools/emacs-pkgs/buildEmacsPackage.nix b/tools/emacs-pkgs/buildEmacsPackage.nix deleted file mode 100644 index 990b53b76..000000000 --- a/tools/emacs-pkgs/buildEmacsPackage.nix +++ /dev/null @@ -1,38 +0,0 @@ -# Builder for depot-internal Emacs packages. Packages built using this -# builder are added into the Emacs packages fixpoint under -# `emacsPackages.tvlPackages`, which in turn makes it possible to use -# them with special Emacs features like native compilation. -# -# Arguments passed to the builder are the same as -# emacsPackages.trivialBuild, except: -# -# * packageRequires is not used -# -# * externalRequires takes a selection function for packages from -# emacsPackages -# -# * internalRequires takes other depot packages -{ pkgs, ... }: - -buildArgs: - -pkgs.callPackage - ({ emacsPackages }: - - let - # Select external dependencies from the emacsPackages set - externalDeps = (buildArgs.externalRequires or (_: [ ])) emacsPackages; - - # Override emacsPackages for depot-internal packages - internalDeps = map (p: p.override { inherit emacsPackages; }) - (buildArgs.internalRequires or [ ]); - - trivialBuildArgs = builtins.removeAttrs buildArgs [ - "externalRequires" - "internalRequires" - ] // { - packageRequires = externalDeps ++ internalDeps; - }; - in - emacsPackages.trivialBuild trivialBuildArgs) -{ } diff --git a/tools/emacs-pkgs/defzone/defzone.el b/tools/emacs-pkgs/defzone/defzone.el deleted file mode 100644 index ffd359e5f..000000000 --- a/tools/emacs-pkgs/defzone/defzone.el +++ /dev/null @@ -1,60 +0,0 @@ -;;; defzone.el --- Generate zone files from Elisp -*- lexical-binding: t; -*- - -(require 'dash) -(require 'dash-functional) -(require 's) - -(defun record-to-record (zone record &optional subdomain) - "Evaluate a record definition and turn it into a zone file - record in ZONE, optionally prefixed with SUBDOMAIN." - - (cl-labels ((plist->alist (plist) - (when plist - (cons - (cons (car plist) (cadr plist)) - (plist->alist (cddr plist)))))) - (let ((name (if subdomain (s-join "." (list subdomain zone)) zone))) - (pcase record - ;; SOA RDATA (RFC 1035; 3.3.13) - ((and `(SOA . (,ttl . ,keys)) - (let (map (:mname mname) (:rname rname) (:serial serial) - (:refresh refresh) (:retry retry) (:expire expire) - (:minimum min)) - (plist->alist keys))) - (if-let ((missing (-filter #'null (not (list mname rname serial - refresh retry expire min))))) - (error "Missing fields in SOA record: %s" missing) - (format "%s %s IN SOA %s %s %s %s %s %s %s" - name ttl mname rname serial refresh retry expire min))) - - (`(NS . (,ttl . ,targets)) - (->> targets - (-map (lambda (target) (format "%s %s IN NS %s" name ttl target))) - (s-join "\n"))) - - (`(MX . (,ttl . ,pairs)) - (->> pairs - (-map (-lambda ((preference . exchange)) - (format "%s %s IN MX %s %s" name ttl preference exchange))) - (s-join "\n"))) - - (`(TXT ,ttl ,text) (format "%s %s IN TXT %s" name ttl (prin1-to-string text))) - - (`(A . (,ttl . ,ips)) - (->> ips - (-map (lambda (ip) (format "%s %s IN A %s" name ttl ip))) - (s-join "\n"))) - - (`(CNAME ,ttl ,target) (format "%s %s IN CNAME %s" name ttl target)) - - ((and `(,sub . ,records) - (guard (stringp sub))) - (s-join "\n" (-map (lambda (r) (record-to-record zone r sub)) records))) - - (_ (error "Invalid record definition: %s" record)))))) - -(defmacro defzone (fqdn &rest records) - "Generate zone file for the zone at FQDN from a simple DSL." - (declare (indent defun)) - - `(s-join "\n" (-map (lambda (r) (record-to-record ,fqdn r)) (quote ,records)))) diff --git a/tools/emacs-pkgs/defzone/example.el b/tools/emacs-pkgs/defzone/example.el deleted file mode 100644 index e9c86d25e..000000000 --- a/tools/emacs-pkgs/defzone/example.el +++ /dev/null @@ -1,45 +0,0 @@ -;;; example.el - usage example for defzone macro - -(defzone "tazj.in." - (SOA 21600 - :mname "ns-cloud-a1.googledomains.com." - :rname "cloud-dns-hostmaster.google.com." - :serial 123 - :refresh 21600 - :retry 3600 - :expire 1209600 - :minimum 300) - - (NS 21600 - "ns-cloud-a1.googledomains.com." - "ns-cloud-a2.googledomains.com." - "ns-cloud-a3.googledomains.com." - "ns-cloud-a4.googledomains.com.") - - (MX 300 - (1 . "aspmx.l.google.com.") - (5 . "alt1.aspmx.l.google.com.") - (5 . "alt2.aspmx.l.google.com.") - (10 . "alt3.aspmx.l.google.com.") - (10 . "alt4.aspmx.l.google.com.")) - - (TXT 3600 "google-site-verification=d3_MI1OwD6q2OT42Vvh0I9w2u3Q5KFBu-PieNUE1Fig") - - (A 300 "34.98.120.189") - - ;; Nested record sets are indicated by a list that starts with a - ;; string (this is just joined, so you can nest multiple levels at - ;; once) - ("blog" - ;; Blog "storage engine" is in a separate DNS zone - (NS 21600 - "ns-cloud-c1.googledomains.com." - "ns-cloud-c2.googledomains.com." - "ns-cloud-c3.googledomains.com." - "ns-cloud-c4.googledomains.com.")) - - ("git" - (A 300 "34.98.120.189") - (TXT 300 "<3 edef")) - - ("files" (CNAME 300 "c.storage.googleapis.com."))) diff --git a/tools/emacs-pkgs/dottime/default.nix b/tools/emacs-pkgs/dottime/default.nix deleted file mode 100644 index b819e9c14..000000000 --- a/tools/emacs-pkgs/dottime/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage { - pname = "dottime"; - version = "1.0"; - src = ./dottime.el; -} diff --git a/tools/emacs-pkgs/dottime/dottime.el b/tools/emacs-pkgs/dottime/dottime.el deleted file mode 100644 index 2446f6488..000000000 --- a/tools/emacs-pkgs/dottime/dottime.el +++ /dev/null @@ -1,81 +0,0 @@ -;;; dottime.el --- use dottime in the modeline -;; -;; Copyright (C) 2019 Google Inc. -;; -;; Author: Vincent Ambo -;; Version: 1.0 -;; Package-Requires: (cl-lib) -;; -;;; Commentary: -;; -;; This package changes the display of time in the modeline to use -;; dottime (see https://dotti.me/) instead of the standard time -;; display. -;; -;; Modeline dottime display is enabled by calling -;; `dottime-display-mode' and dottime can be used in Lisp code via -;; `dottime-format'. - -(require 'cl-lib) -(require 'time) - -(defun dottime--format-string (&optional offset prefix) - "Creates the dottime format string for `format-time-string' - based on the local timezone." - - (let* ((offset-sec (or offset (car (current-time-zone)))) - (offset-hours (/ offset-sec 60 60)) - (base (concat prefix "%m-%dT%H·%M"))) - (if (/= offset-hours 0) - (concat base (format "%0+3d" offset-hours)) - base))) - -(defun dottime--display-time-update-advice (orig) - "Function used as advice to `display-time-update' with a - rebound definition of `format-time-string' that renders all - timestamps as dottime." - - (cl-letf* ((format-orig (symbol-function 'format-time-string)) - ((symbol-function 'format-time-string) - (lambda (&rest _) - (funcall format-orig (dottime--format-string) nil t)))) - (funcall orig))) - -(defun dottime-format (&optional time offset prefix) - "Format the given TIME in dottime at OFFSET. If TIME is nil, - the current time will be used. PREFIX is prefixed to the format - string verbatim. - - OFFSET can be an integer representing an offset in seconds, or - the argument can be elided in which case the system time zone - is used." - - (format-time-string (dottime--format-string offset prefix) time t)) - -(defun dottime-display-mode (arg) - "Enable time display as dottime. Disables dottime if called - with prefix 0 or nil." - - (interactive "p") - (if (or (eq arg 0) (eq arg nil)) - (advice-remove 'display-time-update #'dottime--display-time-update-advice) - (advice-add 'display-time-update :around #'dottime--display-time-update-advice)) - (display-time-update) - - ;; Amend the time display in telega.el to use dottime. - ;; - ;; This will never display offsets in the chat window, as those are - ;; always visible in the modeline anyways. - (when (featurep 'telega) - (defun telega-ins--dottime-advice (orig timestamp) - (let* ((dtime (decode-time timestamp t)) - (current-ts (time-to-seconds (current-time))) - (ctime (decode-time current-ts)) - (today00 (telega--time-at00 current-ts ctime))) - (if (> timestamp today00) - (telega-ins (format "%02d·%02d" (nth 2 dtime) (nth 1 dtime))) - (funcall orig timestamp)))) - - (advice-add 'telega-ins--date :around #'telega-ins--dottime-advice))) - -(provide 'dottime) diff --git a/tools/emacs-pkgs/niri/default.nix b/tools/emacs-pkgs/niri/default.nix deleted file mode 100644 index 995b1b620..000000000 --- a/tools/emacs-pkgs/niri/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage rec { - pname = "niri"; - version = "1.0"; - src = ./niri.el; -} diff --git a/tools/emacs-pkgs/niri/niri.el b/tools/emacs-pkgs/niri/niri.el deleted file mode 100644 index 32b65efdf..000000000 --- a/tools/emacs-pkgs/niri/niri.el +++ /dev/null @@ -1,181 +0,0 @@ -;;; niri.el --- seamless niri/emacs integration. -*- lexical-binding: t; -*- -;; -;; Copyright (C) 2024 The TVL Contributors -;; -;; Author: Vincent Ambo -;; Version: 1.0 -;; Package-Requires: ((emacs "27.1")) -;; -;;; Commentary: -;; -;; After having used EXWM for many years (7 or so?) it's become second nature -;; that there is no difference between windows and Emacs buffers. This means -;; that from any Emacs buffer (or, in the case of EXWM, from any X window) it's -;; possible to switch to any of the others. -;; -;; This implements similar logic for Emacs running in Niri, consisting of two -;; sides of the integration: -;; -;; # In Emacs -;; -;; Inside of Emacs, when switching buffers, populate the buffer-switching menu -;; additionally with all open Niri windows. Selecting a Niri window moves the -;; screen to that window. -;; -;; # Outside of Emacs -;; -;; Provides an interface for the same core functionality that can be used from -;; shell scripts, and bound to selectors like dmenu or rofi. -;; -;; # Switching to Emacs buffers -;; -;; Some special logic exists for handling the case of switching to an Emacs -;; buffer. There are several conditions that we can be in, that each have a -;; predictable result: -;; -;; In a non-Emacs window, selecting an Emacs buffer will either switch to an -;; Emacs frame already displaying this buffer, or launch a new frame for it. -;; -;; Inside of Emacs, if *another* frame is already displaying the buffer, switch -;; to it. Otherwise the behaviour is the same as standard buffer switching. - -(require 'seq) -(require 'map) - -(defun niri-list-windows () - "List all currently open Niri windows." - (json-parse-string - (shell-command-to-string "niri msg -j windows") - :false-object nil)) - -(defun niri--window-is-emacs (window) - (equal (map-elt window "app_id") "emacs")) - -(defun niri--list-selectables () - "Lists all currently selectable things in a format that can work -with completing-read. Selectable means all open Niri -windows (except Emacs windows) and all Emacs buffers. - -Emacs windows are returned separately, as they are required for -frame navigation." - (let* (;; all niri windows, with emacs/non-emacs windows split up - (all-windows (niri-list-windows)) - (windows (seq-filter (lambda (w) (not (niri--window-is-emacs w))) - all-windows)) - (emacs-windows (seq-filter #'niri--window-is-emacs all-windows)) - - ;; all non-hidden buffers - (buffers (seq-filter (lambda (b) (not (string-prefix-p " " (buffer-name b)))) - (buffer-list))) - (selectables (make-hash-table :test 'equal :size (+ (length windows) - (length buffers))))) - (seq-do (lambda (window) - (map-put! selectables (map-elt window "title") - (cons :niri window))) - windows) - - (seq-do (lambda (buf) - (map-put! selectables (buffer-name buf) - (cons :emacs buf))) - buffers) - (cons selectables emacs-windows))) - -(defun niri--focus-window (window) - (shell-command (format "niri msg action focus-window --id %d" - (map-elt window "id")))) - -(defun niri--target-action-internal (target) - "Focus the given TARGET (a Niri window or Emacs buffer). This is -used when called from inside of Emacs. It will NOT correctly -switch Niri windows when called from outside of Emacs." - (pcase (car target) - (:emacs (pop-to-buffer (cdr target) '((display-buffer-reuse-window - display-buffer-same-window) - (reusable-frames . 0)))) - (:niri (niri--focus-window (cdr target))))) - -(defun niri-go-anywhere () - "Interactively select and switch to an open Niri window, or an - Emacs buffer." - (interactive) - (let* ((selectables (car (niri--list-selectables))) - ;; Annotate buffers that display remote files. I frequently - ;; want to see it, because I might have identically named - ;; files open locally and remotely at the same time, and it - ;; helps with differentiating them. - (completion-extra-properties - '(:annotation-function - (lambda (name) - (let ((elt (map-elt selectables name))) - (pcase (car elt) - (:emacs - (if-let* ((file (buffer-file-name (cdr elt))) - (remote (file-remote-p file))) - (format " [%s]" remote))) - (:niri (format " [%s]" (map-elt (cdr elt) "app_id")))))))) - - (target-key (completing-read "Switch to: " (map-keys selectables))) - (target (map-elt selectables target-key))) - (if target - (niri--target-action-internal target) - (switch-to-buffer target-key nil t)))) - - -(defun niri--target-action-external (target frames) - "Focus the given TARGET (a Niri window or Emacs buffer). This -always behaves correctly, but does more work than the -internal -variant. It should only be called when invoking the switcher from -outside of Emacs (i.e. through `emacsclient'). - -FRAMES is the exact list of Emacs frames that existed at the time -the switcher was invoked." - (pcase (car target) - (:niri (niri--focus-window (cdr target))) - - ;; When switching to an Emacs buffer from outside of Emacs, we run into the - ;; additional complication that Wayland does not allow arbitrary - ;; applications to change the focused window. Calling e.g. - ;; `select-frame-set-input-focus' has no effect on Wayland when not called - ;; from within a focused Emacs frame. - ;; - ;; However, due to concurrency, frames may change between the moment when we - ;; start the switcher (and potentially wait for user input), and when the - ;; final selection happens. - ;; - ;; To get around this we try to match the target Emacs frame (if present) to - ;; a Niri window, switch to it optimistically, and *then* execute the final - ;; buffer switching command. - (:emacs - (if-let ((window (get-buffer-window (cdr target) t)) - (frame (window-frame window)) - (frame-name (frame-parameter frame 'name)) - (niri-window (seq-find (lambda (w) - (equal (map-elt w "title") frame-name)) - frames))) - ;; Target frame found and could be matched to a Niri window: Go there! - (progn (select-window window) ;; ensure the right window in the frame has focus - (niri--focus-window niri-window) - (message "Switched to existing window for \"%s\"" (buffer-name (cdr target)))) - - ;; Target frame not found; is Emacs the focused program? - (if (seq-find (lambda (w) (map-elt w "is_focused")) frames) - (switch-to-buffer (cdr target)) - ;; if not, just make a new frame - (display-buffer (cdr target) '(display-buffer-pop-up-frame))))))) - -(defun niri-go-anywhere-external () - "Use a dmenu-compatible launcher like `fuzzel' to achieve the same -effect as `niri-go-anywhere', but from outside of Emacs through -Emacsclient." - (interactive) ;; TODO no? - (let* ((all (niri--list-selectables)) - (selectables (car all)) - (target (with-temp-buffer - (dolist (key (map-keys selectables)) - (insert key "\n")) - (call-process-region nil nil "fuzzel" t t nil "-d") - (string-trim (buffer-string))))) - (when-let ((selectable (map-elt selectables target))) - (niri--target-action-external selectable (cdr all))))) - -(provide 'niri) diff --git a/tools/emacs-pkgs/nix-util/default.nix b/tools/emacs-pkgs/nix-util/default.nix deleted file mode 100644 index b167cb964..000000000 --- a/tools/emacs-pkgs/nix-util/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage { - pname = "nix-util"; - version = "1.0"; - src = ./nix-util.el; - externalRequires = epkgs: [ epkgs.s ]; -} diff --git a/tools/emacs-pkgs/nix-util/nix-util.el b/tools/emacs-pkgs/nix-util/nix-util.el deleted file mode 100644 index 4ddc81f56..000000000 --- a/tools/emacs-pkgs/nix-util/nix-util.el +++ /dev/null @@ -1,69 +0,0 @@ -;;; nix-util.el --- Utilities for dealing with Nix code. -*- lexical-binding: t; -*- -;; -;; Copyright (C) 2019 Google Inc. -;; Copyright (C) 2022 The TVL Authors -;; -;; Author: Vincent Ambo -;; Version: 1.0 -;; Package-Requires: (json map s) -;; -;;; Commentary: -;; -;; This package adds some functionality that I find useful when -;; working in Nix buffers or programs installed from Nix. - -(require 'json) -(require 'map) -(require 's) - -(defun nix/prefetch-github (owner repo) ; TODO(tazjin): support different branches - "Fetch the master branch of a GitHub repository and insert the - call to `fetchFromGitHub' at point." - - (interactive "sOwner: \nsRepository: ") - - (let* (;; Keep these vars around for output insertion - (point (point)) - (buffer (current-buffer)) - (name (concat "github-fetcher/" owner "/" repo)) - (outbuf (format "*%s*" name)) - (errbuf (get-buffer-create "*github-fetcher/errors*")) - (cleanup (lambda () - (kill-buffer outbuf) - (kill-buffer errbuf) - (with-current-buffer buffer - (read-only-mode -1)))) - (prefetch-handler - (lambda (_process event) - (unwind-protect - (pcase event - ("finished\n" - (let* ((json-string (with-current-buffer outbuf - (buffer-string))) - (result (json-read-from-string json-string))) - (with-current-buffer buffer - (goto-char point) - (map-let (("rev" rev) ("sha256" sha256)) result - (read-only-mode -1) - (insert (format "fetchFromGitHub { - owner = \"%s\"; - repo = \"%s\"; - rev = \"%s\"; - sha256 = \"%s\"; -};" owner repo rev sha256)) - (indent-region point (point)))))) - (_ (with-current-buffer errbuf - (error "Failed to prefetch %s/%s: %s" - owner repo (buffer-string))))) - (funcall cleanup))))) - - ;; Fetching happens asynchronously, but we'd like to make sure the - ;; point stays in place while that happens. - (read-only-mode) - (make-process :name name - :buffer outbuf - :command `("nix-prefetch-github" ,owner ,repo) - :stderr errbuf - :sentinel prefetch-handler))) - -(provide 'nix-util) diff --git a/tools/emacs-pkgs/notable/OWNERS b/tools/emacs-pkgs/notable/OWNERS deleted file mode 100644 index 45c922231..000000000 --- a/tools/emacs-pkgs/notable/OWNERS +++ /dev/null @@ -1 +0,0 @@ -tazjin diff --git a/tools/emacs-pkgs/notable/default.nix b/tools/emacs-pkgs/notable/default.nix deleted file mode 100644 index f57b1c66a..000000000 --- a/tools/emacs-pkgs/notable/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage rec { - pname = "notable"; - version = "1.0"; - src = ./notable.el; - - externalRequires = epkgs: with epkgs; [ - f - ht - s - ]; - - internalRequires = [ - depot.tools.emacs-pkgs.dottime - ]; -} diff --git a/tools/emacs-pkgs/notable/notable.el b/tools/emacs-pkgs/notable/notable.el deleted file mode 100644 index 4668dd333..000000000 --- a/tools/emacs-pkgs/notable/notable.el +++ /dev/null @@ -1,251 +0,0 @@ -;;; notable.el --- a simple note-taking app -*- lexical-binding: t; -*- -;; -;; Copyright (C) 2020 The TVL Contributors -;; -;; Author: Vincent Ambo -;; Version: 1.0 -;; Package-Requires: (cl-lib dash f rx s subr-x) -;; -;;; Commentary: -;; -;; This package provides a simple note-taking application which can be -;; invoked from anywhere in Emacs, with several interactive -;; note-taking functions included. -;; -;; As is tradition for my software, the idea here is to reduce -;; friction which I see even with tools like `org-capture', because -;; `org-mode' does a ton of things I don't care about. -;; -;; Notable stores its notes in simple JSON files in the folder -;; specified by `notable-note-dir'. - -(require 'cl-lib) -(require 'dottime) -(require 'f) -(require 'ht) -(require 'rx) -(require 's) -(require 'subr-x) - -;; User-facing customisation options - -(defgroup notable nil - "Simple note-taking application." - :group 'applications) - -;; TODO(tazjin): Use whatever the XDG state dir thing is for these by -;; default. -(defcustom notable-note-dir (expand-file-name "~/.notable/") - "File path to the directory containing notable's notes." - :type 'string - :group 'notable) - -;; Package internal definitions - -(cl-defstruct (notable--note (:constructor notable--make-note)) - "Structure containing the fields of a single notable note." - time ;; UNIX timestamp at which the note was taken - content ;; Textual content of the note - ) - -(defvar notable--note-lock (make-mutex "notable-notes") - "Exclusive lock for note operations with shared state.") - -(defvar notable--note-regexp - (rx "note-" - (group (one-or-more (any num))) - ".json") - "Regular expression to match note file names.") - -(defvar notable--next-note - (let ((next 0)) - (dolist (file (f-entries notable-note-dir)) - (when-let* ((match (string-match notable--note-regexp file)) - (id (string-to-number - (match-string 1 file))) - (larger (> id next))) - (setq next id))) - (+ 1 next)) - "Next ID to use for notes. Initial value is determined based on - the existing notes files.") - -(defun notable--serialize-note (note) - "Serialise NOTE into JSON format." - (check-type note notable--note) - (json-serialize (ht ("time" (notable--note-time note)) - ("content" (notable--note-content note))))) - -(defun notable--deserialize-note (json) - "Deserialise JSON into a notable note." - (check-type json string) - (let ((parsed (json-parse-string json))) - (unless (and (ht-contains? parsed "time") - (ht-contains-p parsed "content")) - (error "Missing required keys in note structure!")) - (notable--make-note :time (ht-get parsed "time") - :content (ht-get parsed "content")))) - -(defun notable--next-id () - "Return the next note ID and increment the counter." - (with-mutex notable--note-lock - (let ((id notable--next-note)) - (setq notable--next-note (+ 1 id)) - id))) - -(defun notable--note-path (id) - (check-type id integer) - (f-join notable-note-dir (format "note-%d.json" id))) - -(defun notable--archive-path (id) - (check-type id integer) - (f-join notable-note-dir (format "archive-%d.json" id))) - -(defun notable--add-note (content) - "Add a note with CONTENT to the note store." - (let* ((id (notable--next-id)) - (note (notable--make-note :time (time-convert nil 'integer) - :content content)) - (path (notable--note-path id))) - (when (f-exists? path) (error "Note file '%s' already exists!" path)) - (f-write-text (notable--serialize-note note) 'utf-8 path) - (message "Saved note %d" id))) - -(defun notable--archive-note (id) - "Archive the note with ID." - (check-type id integer) - - (unless (f-exists? (notable--note-path id)) - (error "There is no note with ID %d." id)) - - (when (f-exists? (notable--archive-path id)) - (error "Oh no, a note with ID %d has already been archived!" id)) - - (f-move (notable--note-path id) (notable--archive-path id)) - (message "Archived note with ID %d." id)) - -(defun notable--list-note-ids () - "List all note IDs (not contents) from `notable-note-dir'" - (cl-loop for file in (f-entries notable-note-dir) - with res = nil - if (string-match notable--note-regexp file) - do (push (string-to-number (match-string 1 file)) res) - finally return res)) - -(defun notable--get-note (id) - (let ((path (notable--note-path id))) - (unless (f-exists? path) - (error "No note with ID %s in note storage!" id)) - (notable--deserialize-note (f-read-text path 'utf-8)))) - -;; Note view buffer implementation - -(defvar-local notable--buffer-note nil "The note ID displayed by this buffer.") - -(define-derived-mode notable-note-mode fundamental-mode "notable-note" - "Major mode displaying a single Notable note." - (set (make-local-variable 'scroll-preserve-screen-position) t) - (setq truncate-lines t) - (setq buffer-read-only t) - (setq buffer-undo-list t)) - -(setq notable-note-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "q" 'kill-current-buffer) - map)) - -(defun notable--show-note (id) - "Display a single note in a separate buffer." - (check-type id integer) - - (let ((note (notable--get-note id)) - (buffer (get-buffer-create (format "*notable: %d*" id))) - (inhibit-read-only t)) - (with-current-buffer buffer - (notable-note-mode) - (erase-buffer) - (setq notable--buffer-note id) - (setq header-line-format - (format "Note from %s" - (dottime-format - (seconds-to-time (notable--note-time note)))))) - (switch-to-buffer buffer) - (goto-char (point-min)) - (insert (notable--note-content note)))) - -(defun notable--show-note-at-point () - (interactive) - (notable--show-note (get-text-property (point) 'notable-note-id))) - -(defun notable--archive-note-at-point () - (interactive) - (notable--archive-note (get-text-property (point) 'notable-note-id))) - -;; Note list buffer implementation - -(define-derived-mode notable-list-mode fundamental-mode "notable" - "Major mode displaying the Notable note list." - ;; TODO(tazjin): `imenu' functions? - - (set (make-local-variable 'scroll-preserve-screen-position) t) - (setq truncate-lines t) - (setq buffer-read-only t) - (setq buffer-undo-list t) - (hl-line-mode t)) - -(setq notable-list-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "a" 'notable--archive-note-at-point) - (define-key map "q" 'kill-current-buffer) - (define-key map "g" 'notable-list-notes) - (define-key map (kbd "RET") 'notable--show-note-at-point) - map)) - -(defun notable--render-note (id note) - (check-type id integer) - (check-type note notable--note) - - (let* ((start (point)) - (date (dottime-format (seconds-to-time - (notable--note-time note)))) - (first-line (truncate-string-to-width - (car (s-lines (notable--note-content note))) - ;; Length of the window, minus the date prefix: - (- (window-width) (+ 2 (length date))) - nil nil 1))) - (insert (propertize (s-concat date " " first-line) - 'notable-note-id id)) - (insert "\n"))) - -(defun notable--render-notes (notes) - "Retrieve each note in NOTES by ID and insert its contents into -the list buffer. - -For larger notes only the first line is displayed." - (dolist (id notes) - (notable--render-note id (notable--get-note id)))) - -;; User-facing functions - -(defun notable-take-note (content) - "Interactively prompt the user for a note that should be stored -in Notable." - (interactive "sEnter note: ") - (check-type content string) - (notable--add-note content)) - -(defun notable-list-notes () - "Open a buffer listing all active notes." - (interactive) - - (let ((buffer (get-buffer-create "*notable*")) - (notes (notable--list-note-ids)) - (inhibit-read-only t)) - (with-current-buffer buffer - (notable-list-mode) - (erase-buffer) - (setq header-line-format "Notable notes")) - (switch-to-buffer buffer) - (goto-char (point-min)) - (notable--render-notes notes))) - -(provide 'notable) diff --git a/tools/emacs-pkgs/passively/OWNERS b/tools/emacs-pkgs/passively/OWNERS deleted file mode 100644 index 45c922231..000000000 --- a/tools/emacs-pkgs/passively/OWNERS +++ /dev/null @@ -1 +0,0 @@ -tazjin diff --git a/tools/emacs-pkgs/passively/README.md b/tools/emacs-pkgs/passively/README.md deleted file mode 100644 index a5ac0d5a4..000000000 --- a/tools/emacs-pkgs/passively/README.md +++ /dev/null @@ -1,76 +0,0 @@ - -passively -========= - -Passively is an Emacs Lisp library for passively learning new -information in an Emacs instance. - -Passively works by displaying a random piece of information to be -learned in the Emacs echoline whenever Emacs is idle for a set amount -of time. - -It was designed to aid in language acquisition by passively displaying -new vocabulary to learn. - -Passively is configured with a corpus of information (a hash table -mapping string keys to string values) and maintains a set of terms -that the user already learned in a file on disk. - -## Configuration & usage - -Configure passively like this: - -```lisp -;; Configure the terms to learn. Each term should have a key and a -;; string value which is displayed. -(setq passively-learn-terms - (ht ("забыть" "забыть - to forget") - ("действительно" "действительно - indeed, really"))) - -;; Configure a file in which passively should store its state -;; (defaults to $user-emacs-directory/passively.el) -(setq passively-store-state "/persist/tazjin/passively.el") - -;; Configure after how many seconds of idle time passively should -;; display a new piece of information. -;; (defaults to 4 seconds) -(setq passively-show-after-idle-for 5) - -;; Once this configuration has been set up, start passively: -(passively-enable) - -;; Or, if it annoys you, disable it again: -(passively-disable) -``` - -These variables are registered with `customize` and may be customised -through its interface. - -### Known terms - -Passively exposes the interactive function -`passively-mark-last-as-known` which marks the previously displayed -term as known. This means that it will not be included in the random -selection anymore. - -### Last term - -Passively stores the key of the last known term in -`passively-last-displayed`. - -## Installation - -Inside of the TVL depot, you can install passively from -`pkgs.emacsPackages.tvlPackages.passively`. Outside of the depot, you -can clone passively like this: - - git clone https://code.tvl.fyi/depot.git:/tools/emacs-pkgs/passively.git - -Passively depends on `ht.el`. - -Feel free to contribute patches by emailing them to `depot@tvl.su`. - -## Use-cases - -I'm using passively to learn Russian vocabulary. Once I've cleaned up -my configuration for that, my Russian term list will be linked here. diff --git a/tools/emacs-pkgs/passively/default.nix b/tools/emacs-pkgs/passively/default.nix deleted file mode 100644 index ec59cc85f..000000000 --- a/tools/emacs-pkgs/passively/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage { - pname = "passively"; - version = "1.0"; - src = ./passively.el; - externalRequires = (epkgs: with epkgs; [ ht ]); -} diff --git a/tools/emacs-pkgs/passively/passively.el b/tools/emacs-pkgs/passively/passively.el deleted file mode 100644 index 0d871f26a..000000000 --- a/tools/emacs-pkgs/passively/passively.el +++ /dev/null @@ -1,121 +0,0 @@ -;;; passively.el --- Passively learn new information -*- lexical-binding: t; -*- -;; -;; SPDX-License-Identifier: MIT -;; Copyright (C) 2020 The TVL Contributors -;; -;; Author: Vincent Ambo -;; Version: 1.0 -;; Package-Requires: (ht seq) -;; URL: https://code.tvl.fyi/about/tools/emacs-pkgs/passively/ -;; -;; This file is not part of GNU Emacs. - -(require 'ht) -(require 'seq) - -;; Customisation options - -(defgroup passively nil - "Customisation options for passively" - :group 'applications) - -(defcustom passively-learn-terms nil - "Terms that passively should randomly display to the user. The -format of this variable is a hash table with a string key that -uniquely identifies the term, and a string value that is -displayed to the user. - -For example, a possible value could be: - - (ht (\"забыть\" \"забыть - to forget\") - (\"действительно\" \"действительно - indeed, really\"))) -" - ;; TODO(tazjin): No hash-table type in customization.el? - :type '(sexp) - :group 'passively) - -(defcustom passively-store-state (format "%spassively.el" user-emacs-directory) - "File in which passively should store its state (e.g. known terms)" - :type '(file) - :group 'passively) - -(defcustom passively-show-after-idle-for 4 - "Number of seconds after Emacs goes idle that passively should -wait before displaying a term." - :type '(integer) - :group 'passively) - -;; Implementation of state persistence -(defvar passively-last-displayed nil - "Key of the last displayed passively term.") - -(defvar passively--known-terms (make-hash-table) - "Set of terms that are already known.") - -(defun passively--persist-known-terms () - "Persist the set of known passively terms to disk." - (with-temp-file passively-store-state - (insert (prin1-to-string (ht-keys passively--known-terms))))) - -(defun passively--load-known-terms () - "Load the set of known passively terms from disk." - (with-temp-buffer - (insert-file-contents passively-store-state) - (let ((keys (read (current-buffer)))) - (setq passively--known-terms (make-hash-table)) - (seq-do - (lambda (key) (ht-set passively--known-terms key t)) - keys))) - (message "passively: loaded %d known words" - (seq-length (ht-keys passively--known-terms)))) - -(defun passively-mark-last-as-known () - "Mark the last term that passively displayed as known. It will -not be displayed again." - (interactive) - - (ht-set passively--known-terms passively-last-displayed t) - (passively--persist-known-terms) - (message "passively: Marked '%s' as known" passively-last-displayed)) - -;; Implementation of main display logic -(defvar passively--display-timer nil - "idle-timer used for displaying terms by passively") - -(defun passively--random-term (timeout) - ;; This is stupid, calculate set intersections instead. - (if (< 1000 timeout) - (error "It seems you already know all the terms?") - (seq-random-elt (ht-keys passively-learn-terms)))) - -(defun passively--display-random-term () - (let* ((timeout 1) - (term (passively--random-term timeout))) - (while (ht-contains? passively--known-terms term) - (setq timeout (+ 1 timeout)) - (setq term (passively--random-term timeout))) - (setq passively-last-displayed term) - (message (ht-get passively-learn-terms term)))) - -(defun passively-enable () - "Enable automatic display of terms via passively." - (interactive) - (if passively--display-timer - (error "passively: Already running!") - (passively--load-known-terms) - (setq passively--display-timer - (run-with-idle-timer passively-show-after-idle-for t - #'passively--display-random-term)) - (message "passively: Now running after %s seconds of idle time" - passively-show-after-idle-for))) - -(defun passively-disable () - "Turn off automatic display of terms via passively." - (interactive) - (unless passively--display-timer - (error "passively: Not running!")) - (cancel-timer passively--display-timer) - (setq passively--display-timer nil) - (message "passively: Now disabled")) - -(provide 'passively) diff --git a/tools/emacs-pkgs/term-switcher/default.nix b/tools/emacs-pkgs/term-switcher/default.nix deleted file mode 100644 index e775de5cd..000000000 --- a/tools/emacs-pkgs/term-switcher/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage { - pname = "term-switcher"; - version = "1.0"; - src = ./term-switcher.el; - externalRequires = epkgs: with epkgs; [ dash ivy s vterm ]; -} diff --git a/tools/emacs-pkgs/term-switcher/term-switcher.el b/tools/emacs-pkgs/term-switcher/term-switcher.el deleted file mode 100644 index c141a5e9c..000000000 --- a/tools/emacs-pkgs/term-switcher/term-switcher.el +++ /dev/null @@ -1,63 +0,0 @@ -;;; term-switcher.el --- Easily switch between open vterms -;; -;; Copyright (C) 2019-2020 Google Inc. -;; Copyright (C) 2021-2023 The TVL Authors -;; -;; Author: Vincent Ambo -;; Version: 1.1 -;; Package-Requires: (ivy s vterm) -;; -;;; Commentary: -;; -;; This package adds a function that lets users quickly switch between -;; different open vterms via ivy. - -(require 'ivy) -(require 's) -(require 'seq) -(require 'vterm) - -(defgroup term-switcher nil - "Customization options `term-switcher'.") - -(defcustom term-switcher-buffer-prefix "vterm<" - "String prefix for vterm terminal buffers. For example, if you - set your titles to match `vterm<...>' a useful prefix might be - `vterm<'." - :type '(string) - :group 'term-switcher) - -(defun ts/create-vterm () - "Launch vterm, but don't open semi-broken vterms over TRAMP." - (if (file-remote-p default-directory) - (let ((default-directory "~")) - (vterm)) - (vterm))) - -(defun ts/open-or-create-vterm (buffer) - "Switch to the terminal in BUFFER, or create a new one if buffer is nil." - (if buffer - (switch-to-buffer buffer) - (ts/create-vterm))) - -(defun ts/is-vterm-buffer (buffer) - "Determine whether BUFFER runs a vterm." - (equal 'vterm-mode (buffer-local-value 'major-mode buffer))) - -(defun ts/switch-to-terminal () - "Switch to an existing vterm buffer or create a new one." - - (interactive) - (let ((terms (seq-map (lambda (b) (cons (buffer-name b) b)) - (seq-filter #'ts/is-vterm-buffer (buffer-list))))) - (if terms - (ivy-read "Switch to vterm: " - (cons "New vterm" (seq-map #'car terms)) - :caller 'ts/switch-to-terminal - :preselect (s-concat "^" term-switcher-buffer-prefix) - :require-match t - :action (lambda (match) - (ts/open-or-create-vterm (cdr (assoc match terms))))) - (ts/create-vterm)))) - -(provide 'term-switcher) diff --git a/tools/emacs-pkgs/treecrumbs/OWNERS b/tools/emacs-pkgs/treecrumbs/OWNERS deleted file mode 100644 index 6049a2363..000000000 --- a/tools/emacs-pkgs/treecrumbs/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -set noparent -file:/tools/emacs-pkgs/FSF_OWNERS diff --git a/tools/emacs-pkgs/treecrumbs/default.nix b/tools/emacs-pkgs/treecrumbs/default.nix deleted file mode 100644 index 8895baab9..000000000 --- a/tools/emacs-pkgs/treecrumbs/default.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage { - pname = "treecrumbs"; - version = "1.0"; - src = ./treecrumbs.el; -} diff --git a/tools/emacs-pkgs/treecrumbs/treecrumbs.el b/tools/emacs-pkgs/treecrumbs/treecrumbs.el deleted file mode 100644 index cd49324ad..000000000 --- a/tools/emacs-pkgs/treecrumbs/treecrumbs.el +++ /dev/null @@ -1,202 +0,0 @@ -;; treecrumbs.el --- Fast, tree-sitter based breadcrumbs -*- lexical-binding: t; -*- -;; -;; Copyright (C) Free Software Foundation, Inc. -;; SPDX-License-Identifier: GPL-3.0-or-later -;; -;; Author: Vincent Ambo -;; Created: 2024-03-08 -;; Version: 1.0 -;; Keywords: convenience -;; Package-Requires: ((emacs "29.1")) -;; URL: https://code.tvl.fyi/tree/tools/emacs-pkgs/treecrumbs -;; -;; This file is not (yet) part of GNU Emacs. - -;;; Commentary: - -;; This package provides a tree-sitter based implementation of "breadcrumbs", -;; that is indicators displaying where in the semantic structure of a document -;; the point is currently located. -;; -;; Imagine a large YAML-document where the names of the parent keys are far out -;; of view: Treecrumbs can quickly display the hierarchy of keys (e.g. `foo < [] -;; < baz') and help figure out where point is. -;; -;; Treecrumbs only works if a tree-sitter parser for the target language is -;; available in the buffer, and the language is supported in the -;; `treecrumbs-languages'. Adding a new language is not difficult, and patches -;; for this are welcome. -;; -;; To active treecrumbs, enable `treecrumbs-mode'. This buffer-local minor mode -;; adds the crumbs to the buffer's `header-line-format'. Alternatively, users -;; can also use the `treecrumbs-line-segment' either in their own header-line, -;; tab-line or mode-line configuration. - -;;; Code: - -(require 'seq) -(require 'treesit) - -(defvar treecrumbs-languages nil - "Describes the tree-sitter language grammars supported by -treecrumbs, and how the breadcrumbs for their node types are -generated. - -Alist of symbols representing tree-sitter languages (e.g. `yaml') -to another alist (the \"node type list\") describing how -different node types should be displayed in the crumbs. - -See `define-treecrumbs-language' for more details on how to add a -language.") - -(defmacro define-treecrumbs-language (lang &rest clauses) - "Defines a new language for use in treecrumbs. LANG should be a -symbol representing the language as understood by treesit (e.g. -`yaml'). - -Each of CLAUSES is a cons cell mapping the name of a tree -node (in string format) to one of either: - -1. a static string, which will become the breadcrumb verbatim - -2. a tree-sitter query (in S-expression syntax) which must capture - exactly one argument named `@key' that will become the - breadcrumb (e.g. the name of a function, the key in a map, ...) - -Treecrumbs will only consider node types that are mentioned in -CLAUSES. All other nodes are ignored when constructing the -crumbs. - -The defined languages are stored in `treecrumbs-languages'." - - (declare (indent 1)) - (let ((compiled - (seq-map (lambda (clause) - (if (stringp (cdr clause)) - `(cons ,(car clause) ,(cdr clause)) - `(cons ,(car clause) - (treesit-query-compile ',lang ',(cdr clause))))) - clauses))) - `(setf (alist-get ',lang treecrumbs-languages nil nil #'equal) (list ,@compiled)))) - -(define-treecrumbs-language yaml - ;; In YAML documents, crumbs are generated from the keys of maps, and from - ;; elements of arrays. "block"-nodes are standard YAML syntax, "flow"-nodes - ;; are inline JSON-ish syntax. - ("block_mapping_pair" . ((block_mapping_pair key: (_) @key))) - ("block_sequence" . "[]") - - ;; TODO: Why can this query not match on to (flow_pair)? - ("flow_pair" . ((_) key: (_) @key)) - ("flow_sequence" . "[]")) - -(define-treecrumbs-language json - ;; In JSON documents, crumbs are generated from key names and array fields. - ("pair" . ((pair key: (string (string_content) @key)))) - ("array" . "[]")) - -(define-treecrumbs-language toml - ;; TOML has sections, key names and arrays. Sections are the only - ;; relevant difference to YAML. Nested keys are not parsed, and just - ;; displayed as-is. - ("table" . ((table (_) @key)) ) - ;; TODO: query cannot match on pair in inline_table, hence matching - ;; directly on keys - ("pair" . ([(dotted_key) - (quoted_key) - (bare_key)])) - ("array" . "[]")) - -(define-treecrumbs-language cpp - ;; In C++ files, crumbs are generated from namespaces and - ;; identifier declarations. - ("namespace_definition" . ([(namespace_definition - name: (namespace_identifier) @key) - (namespace_definition - "namespace" @key - !name)])) - - ("function_definition" . ((function_definition - declarator: - (function_declarator - declarator: (_) @key)))) - - ("class_specifier" . ((class_specifier - name: (type_identifier) @key))) - - ("struct_specifier" . ((struct_specifier - name: (type_identifier) @key))) - - ("field_declaration" . ((field_declaration - declarator: (_) @key))) - - ("init_declarator" . ((init_declarator - declarator: (_) @key)))) - -(defvar-local treecrumbs--current-crumbs nil - "Current crumbs to display in the header line. Only updated when -the node under point changes.") - -(defun treecrumbs--crumbs-for (node) - "Construct the crumbs for the given NODE, if its language is -supported in `treecrumbs-languages'. This functions return value -is undefined, it directly updates the buffer-local -`treecrumbs--current-crumbs'." - (let ((lang (cdr (assoc (treesit-node-language node) treecrumbs-languages)))) - (unless lang - (user-error "No supported treecrumbs language at point!")) - - (setq-local treecrumbs--current-crumbs "") - (treesit-parent-while - node - (lambda (parent) - (when-let ((query (cdr (assoc (treesit-node-type parent) lang)))) - - (setq-local treecrumbs--current-crumbs - (concat treecrumbs--current-crumbs - (if (string-empty-p treecrumbs--current-crumbs) "" - " < ") - - (if (stringp query) - query - (substring-no-properties - (treesit-node-text (cdar (treesit-query-capture parent query)))))))) - t)))) - - -(defvar-local treecrumbs--last-node nil - "Caches the node that was last seen at point.") - -(defun treecrumbs-at-point () - "Returns the treecrumbs at point as a string, if point is on a -node in a language supported in `treecrumbs-languages'. - -The last known crumbs in a given buffer are cached, and only if -the node under point changes are they updated." - (let ((node (treesit-node-at (point)))) - (when (or (not treecrumbs--current-crumbs) - (not (equal treecrumbs--last-node node))) - (setq-local treecrumbs--last-node node) - (treecrumbs--crumbs-for node))) - - treecrumbs--current-crumbs) - -(defvar treecrumbs-line-segment - '(:eval (treecrumbs-at-point)) - - "Treecrumbs segment for use in the header-line or mode-line.") - -;;;###autoload -(define-minor-mode treecrumbs-mode - "Display header line hints about current position in structure." - :init-value nil - :lighter " Crumbs" - (if treecrumbs-mode - (if (treesit-parser-list) - (push treecrumbs-line-segment header-line-format) - (user-error "Treecrumbs mode works only in tree-sitter based buffers!")) - (setq header-line-format - (delq treecrumbs-line-segment header-line-format)))) - -(provide 'treecrumbs) -;;; treecrumbs.el ends here diff --git a/tools/emacs-pkgs/tvl/OWNERS b/tools/emacs-pkgs/tvl/OWNERS deleted file mode 100644 index b381c4e66..000000000 --- a/tools/emacs-pkgs/tvl/OWNERS +++ /dev/null @@ -1 +0,0 @@ -aspen diff --git a/tools/emacs-pkgs/tvl/default.nix b/tools/emacs-pkgs/tvl/default.nix deleted file mode 100644 index 5dcc184bb..000000000 --- a/tools/emacs-pkgs/tvl/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ depot, ... }: - -depot.tools.emacs-pkgs.buildEmacsPackage { - pname = "tvl"; - version = "1.0"; - src = ./tvl.el; - externalRequires = (epkgs: with epkgs; [ magit s ]); -} diff --git a/tools/emacs-pkgs/tvl/tvl.el b/tools/emacs-pkgs/tvl/tvl.el deleted file mode 100644 index 8de70040b..000000000 --- a/tools/emacs-pkgs/tvl/tvl.el +++ /dev/null @@ -1,243 +0,0 @@ -;;; tvl.el --- description -*- lexical-binding: t; -*- -;; -;; Copyright (C) 2020 Griffin Smith -;; Copyright (C) 2020-2023, 2025 The TVL Contributors -;; -;; Author: Griffin Smith -;; Version: 0.0.1 -;; Package-Requires: (s magit) -;; -;; This file is not part of GNU Emacs. -;; -;;; Commentary: -;; -;; This file provides shared utilities for interacting with the TVL monorepo -;; -;;; Code: - -(require 'magit) -(require 's) - -(defgroup tvl nil - "Customisation options for TVL functionality.") - -(defcustom tvl-gerrit-remote "origin" - "Name of the git remote for gerrit." - :type '(string) - :group 'tvl) - -(defcustom tvl-depot-path "/depot" - "Location at which the TVL depot is checked out." - :type '(string) - :group 'tvl) - -(defcustom tvl-target-branch "canon" - "Branch to use to target CLs." - :group 'tvl - :type '(string) - :safe (lambda (_) t)) - -(defun tvl--gerrit-ref (target-branch &optional flags) - (let ((flag-suffix (if flags (format "%%%s" (s-join "," flags)) - ""))) - (format "HEAD:refs/for/%s%s" target-branch flag-suffix))) - -(transient-define-suffix magit-gerrit-push-for-review () - "Push to Gerrit for review." - (interactive) - (magit-push-refspecs tvl-gerrit-remote - (tvl--gerrit-ref tvl-target-branch) - nil)) - -(transient-append-suffix - #'magit-push ["r"] - (list "R" "push to Gerrit for review" #'magit-gerrit-push-for-review)) - -(transient-define-suffix magit-gerrit-push-wip () - "Push to Gerrit as a work-in-progress." - (interactive) - (magit-push-refspecs tvl-gerrit-remote - (tvl--gerrit-ref tvl-target-branch '("wip")) - nil)) - -(transient-append-suffix - #'magit-push ["r"] - (list "W" "push to Gerrit as a work-in-progress" #'magit-gerrit-push-wip)) - -(transient-define-suffix magit-gerrit-push-autosubmit () - "Push to Gerrit with autosubmit enabled." - (interactive) - (magit-push-refspecs tvl-gerrit-remote - (tvl--gerrit-ref tvl-target-branch '("l=Autosubmit+1")) - nil)) - -(transient-append-suffix - #'magit-push ["r"] - (list "A" "push to Gerrit with autosubmit enabled" #'magit-gerrit-push-autosubmit)) - -(transient-define-suffix magit-gerrit-submit () - "Push to Gerrit for review." - (interactive) - (magit-push-refspecs tvl-gerrit-remote - (tvl--gerrit-ref tvl-target-branch '("submit")) - nil)) - -(transient-append-suffix - #'magit-push ["r"] - (list "S" "push to Gerrit to submit" #'magit-gerrit-submit)) - - -(transient-define-suffix magit-gerrit-rubberstamp () - "Push, approve and autosubmit to Gerrit. CLs created via this -rubberstamp method will automatically be submitted after CI -passes. This is potentially dangerous, use with care." - (interactive) - (magit-push-refspecs tvl-gerrit-remote - (tvl--gerrit-ref tvl-target-branch - '("l=Code-Review+2" - "l=Autosubmit+1" - "publish-comments")) - nil)) - -(transient-append-suffix - #'magit-push ["r"] - (list "P" "push & rubberstamp to Gerrit" #'magit-gerrit-rubberstamp)) - -(transient-define-suffix magit-gerrit-push-private () - "Push a private change to Gerrit." - (interactive) - (magit-push-refspecs tvl-gerrit-remote - (tvl--gerrit-ref tvl-target-branch - '("private" - "publish-comments")) - nil)) - -(transient-append-suffix - #'magit-push ["r"] - (list "Q" "push private change to Gerrit" #'magit-gerrit-push-private)) - -(defvar magit-cl-history nil) -(defun magit-read-cl (prompt remote) - (let* ((refs (prog2 (message "Determining available refs...") - (magit-remote-list-refs remote) - (message "Determining available refs...done"))) - (change-refs (-filter - (apply-partially #'string-prefix-p "refs/changes/") - refs)) - (cl-number-to-refs - (-group-by - (lambda (change-ref) - ;; refs/changes/34/1234/1 - ;; ^ ^ ^ ^ ^ - ;; 1 2 3 4 5 - ;; ^-- this one - (cadddr - (split-string change-ref (rx "/")))) - change-refs)) - (cl-numbers - (-map - (lambda (cl-to-refs) - (let ((latest-patchset-ref - (-max-by - (-on #'> (lambda (ref) - (string-to-number - (nth 4 (split-string ref (rx "/")))))) - (-remove - (apply-partially #'s-ends-with-p "meta") - (cdr cl-to-refs))))) - (propertize (car cl-to-refs) 'ref latest-patchset-ref))) - cl-number-to-refs))) - (get-text-property - 0 - 'ref - (magit-completing-read - prompt cl-numbers nil t nil 'magit-cl-history)))) - -(transient-define-suffix magit-gerrit-checkout (remote cl-refspec) - "Prompt for a CL number and checkout the latest patchset of that CL with - detached HEAD" - (interactive - (let* ((remote tvl-gerrit-remote) - (cl (magit-read-cl "Checkout CL" remote))) - (list remote cl))) - (magit-fetch-refspec remote cl-refspec (magit-fetch-arguments)) - ;; That runs async, so wait for it to finish (this is how magit does it) - (while (and magit-this-process - (eq (process-status magit-this-process) 'run)) - (sleep-for 0.005)) - (magit--checkout "FETCH_HEAD" (magit-branch-arguments)) - (message "HEAD detached at %s" cl-refspec)) - - -(transient-append-suffix - #'magit-branch ["l"] - (list "g" "gerrit CL" #'magit-gerrit-checkout)) - -(transient-define-suffix magit-gerrit-cherry-pick (remote cl-refspec) - "Prompt for a CL number and cherry-pick the latest patchset of that CL" - (interactive - (let* ((remote tvl-gerrit-remote) - (cl (magit-read-cl "Cherry-pick CL" remote))) - (list remote cl))) - (magit-fetch-refspec remote cl-refspec (magit-fetch-arguments)) - ;; That runs async, so wait for it to finish (this is how magit does it) - (while (and magit-this-process - (eq (process-status magit-this-process) 'run)) - (sleep-for 0.005)) - (magit-cherry-copy (list "FETCH_HEAD")) - (message "HEAD detached at %s" cl-refspec)) - - -(transient-append-suffix - #'magit-cherry-pick ["m"] - (list "g" "Gerrit CL" #'magit-gerrit-cherry-pick)) - -(defun tvl-depot-status () - "Open the TVL monorepo in magit." - (interactive) - (magit-status-setup-buffer tvl-depot-path)) - -(eval-after-load 'sly - '(defun tvl-sly-from-depot (attribute only-deps) - "Start a Sly REPL configured with a Lisp matching a derivation - from the depot. - - The derivation invokes nix.buildLisp.sbclWith and is built - asynchronously. The build output is included in the error - thrown on build failures." - - ;; TODO(sterni): this function asumes that we are using SBCL - ;; - for determining the resulting wrapper's location - ;; - for creating the dep-only wrapper - - (interactive (list (read-string "Attribute: ") - (yes-or-no-p "Only include dependencies? "))) - (let* ((outbuf (get-buffer-create (format "*depot-out/%s*" attribute))) - (errbuf (get-buffer-create (format "*depot-errors/%s*" attribute))) - (attr-display (if only-deps attribute (format "dependencies of %s" attribute))) - (expression (if only-deps - (format "let d = import {}; in d.nix.buildLisp.sbcl.lispWith d.%s.lispDeps" - attribute) - (format "(import {}).%s.repl" attribute))) - (command (list "nix-build" "--no-out-link" "-I" (format "depot=%s" tvl-depot-path) "-E" expression))) - (message "Acquiring Lisp for .%s" attr-display) - (make-process :name (format "depot-nix-build/%s" attribute) - :buffer outbuf - :stderr errbuf - :command command - :sentinel - (lambda (_process event) - (unwind-protect - (pcase event - ("finished\n" - (let* ((outpath (s-trim (with-current-buffer outbuf (buffer-string)))) - (lisp-path (s-concat outpath "/bin/sbcl"))) - (message "Acquired Lisp for .%s at %s" attr-display lisp-path) - (sly lisp-path))) - (_ (with-current-buffer errbuf - (error "Failed to build %s:\nTried building '%s':\n%s" attr-display expression (buffer-string))))) - (kill-buffer outbuf) - (kill-buffer errbuf))))))) - -(provide 'tvl) -;;; tvl.el ends here diff --git a/tools/fetch-depot-inbox.nix b/tools/fetch-depot-inbox.nix deleted file mode 100644 index e14ddf20e..000000000 --- a/tools/fetch-depot-inbox.nix +++ /dev/null @@ -1,49 +0,0 @@ -# Wrapper script that uses offlineimap to fetch the depot inbox from -# inbox.tvl.su. -# -# Run with the desired output directory as the only argument. -# -# Alternatively, users can browse the inbox on https://inbox.tvl.su -# and interact with public-inbox in any other supported way (IMAP, -# NNTP, git, etc.). -{ pkgs, depot, ... }: - -let - config = pkgs.writeText "offlineimaprc" '' - [general] - accounts = depot - - [Account depot] - localrepository = Local - remoterepository = Remote - - [Repository Local] - type = Maildir - # localfolders set by CLI - - [Repository Remote] - type = IMAP - ssl = yes - sslcacertfile = /etc/ssl/certs/ca-bundle.crt - remotehost = inbox.tvl.su - remoteuser = anonymous - remotepass = anonymous - ''; -in -pkgs.writeShellScriptBin "fetch-depot-inbox" '' - readonly MAILDIR=''${1} - - if [ -z "''${MAILDIR}" ]; then - echo "[inbox] must specify target maildir as the first argument!" >&2 - exit 1 - fi - - if [ ! -d "''${MAILDIR}" ]; then - echo "[inbox] specified maildir must exist and be a directory!" >&2 - exit 1 - fi - - echo "[inbox] Synchronising TVL depot inbox into ''${MAILDIR}" - ${pkgs.offlineimap}/bin/offlineimap -c ${config} \ - -k "Repository_Local:localfolders=''${MAILDIR}" -'' diff --git a/tools/hash-password.nix b/tools/hash-password.nix deleted file mode 100644 index 583f1210b..000000000 --- a/tools/hash-password.nix +++ /dev/null @@ -1,17 +0,0 @@ -# Utility for invoking slappasswd with the correct options for -# creating an ARGON2 password hash. -# -# Users should generally use https://signup.tvl.fyi instead. -{ pkgs, ... }: - -let - script = pkgs.writeShellScriptBin "hash-password" '' - ${pkgs.openldap}/bin/slappasswd -o module-load=argon2 -h '{ARGON2}' "$@" - ''; -in -script.overrideAttrs (old: { - doCheck = true; - checkPhase = '' - ${pkgs.stdenv.shell} $out/bin/hash-password -s example-password > /dev/null - ''; -}) diff --git a/tools/nixery/.gitignore b/tools/nixery/.gitignore deleted file mode 100644 index 578eea392..000000000 --- a/tools/nixery/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -result -result-* -.envrc -debug/ - -# Just to be sure, since we're occasionally handling test keys: -*.pem -*.p12 -*.json - -# Created by the integration test -var-cache-nixery diff --git a/tools/nixery/.skip-subtree b/tools/nixery/.skip-subtree deleted file mode 100644 index 4948dd56e..000000000 --- a/tools/nixery/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -Imported subtree is not yet fully readTree-compatible. diff --git a/tools/nixery/LICENSE b/tools/nixery/LICENSE deleted file mode 100644 index d64569567..000000000 --- a/tools/nixery/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/tools/nixery/README.md b/tools/nixery/README.md deleted file mode 100644 index 40009b05e..000000000 --- a/tools/nixery/README.md +++ /dev/null @@ -1,156 +0,0 @@ -
    - -
    - ------------------ - -[![Build status](https://badge.buildkite.com/016bff4b8ae2704a3bbbb0a250784e6692007c582983b6dea7.svg?branch=refs/heads/canon)](https://buildkite.com/tvl/depot) - -**Nixery** is a Docker-compatible container registry that is capable of -transparently building and serving container images using [Nix][]. - -Images are built on-demand based on the *image name*. Every package that the -user intends to include in the image is specified as a path component of the -image name. - -The path components refer to top-level keys in `nixpkgs` and are used to build a -container image using a [layering strategy][] that optimises for caching popular -and/or large dependencies. - -A public instance as well as additional documentation is available at -[nixery.dev][public]. - -You can watch the NixCon 2019 [talk about -Nixery](https://www.youtube.com/watch?v=pOI9H4oeXqA) for more information about -the project and its use-cases. - -The canonical location of the Nixery source code is -[`//tools/nixery`][depot-link] in the [TVL](https://tvl.fyi) -monorepository. If cloning the entire repository is not desirable, the -Nixery subtree can be cloned like this: - - git clone https://code.tvl.fyi/depot.git:/tools/nixery.git - -The subtree is infrequently mirrored to `tazjin/nixery` on Github. - -## Demo - -Click the image to see an example in which an image containing an interactive -shell and GNU `hello` is downloaded. - -[![asciicast](https://asciinema.org/a/262583.png)](https://asciinema.org/a/262583?autoplay=1) - -To try it yourself, head to [nixery.dev][public]! - -The special meta-package `shell` provides an image base with many core -components (such as `bash` and `coreutils`) that users commonly expect in -interactive images. - -## Feature overview - -* Serve container images on-demand using image names as content specifications - - Specify package names as path components and Nixery will create images, using - the most efficient caching strategy it can to share data between different - images. - -* Use private package sets from various sources - - In addition to building images from the publicly available Nix/NixOS channels, - a private Nixery instance can be configured to serve images built from a - package set hosted in a custom git repository or filesystem path. - - When using this feature with custom git repositories, Nixery will forward the - specified image tags as git references. - - For example, if a company used a custom repository overlaying their packages - on the Nix package set, images could be built from a git tag `release-v2`: - - `docker pull nixery.thecompany.website/custom-service:release-v2` - -* Efficient serving of image layers from Google Cloud Storage - - After building an image, Nixery stores all of its layers in a GCS bucket and - forwards requests to retrieve layers to the bucket. This enables efficient - serving of layers, as well as sharing of image layers between redundant - instances. - -## Configuration - -Nixery supports the following configuration options, provided via environment -variables: - -* `PORT`: HTTP port on which Nixery should listen -* `NIXERY_CHANNEL`: The name of a Nix/NixOS channel to use for building -* `NIXERY_PKGS_REPO`: URL of a git repository containing a package set (uses - locally configured SSH/git credentials) -* `NIXERY_PKGS_PATH`: A local filesystem path containing a Nix package set to - use for building -* `NIXERY_STORAGE_BACKEND`: The type of backend storage to use, currently - supported values are `gcs` (Google Cloud Storage) and `filesystem`. - - For each of these additional backend configuration is necessary, see the - [storage section](#storage) for details. -* `NIX_TIMEOUT`: Number of seconds that any Nix builder is allowed to run - (defaults to 60) -* `NIX_POPULARITY_URL`: URL to a file containing popularity data for - the package set (see `popcount/`) - -If the `GOOGLE_APPLICATION_CREDENTIALS` environment variable is set to a service -account key, Nixery will also use this key to create [signed URLs][] for layers -in the storage bucket. This makes it possible to serve layers from a bucket -without having to make them publicly available. - -In case the `GOOGLE_APPLICATION_CREDENTIALS` environment variable is not set, a -redirect to storage.googleapis.com is issued, which means the underlying bucket -objects need to be publicly accessible. - -### Storage - -Nixery supports multiple different storage backends in which its build cache and -image layers are kept, and from which they are served. - -Currently the available storage backends are Google Cloud Storage and the local -file system. - -In the GCS case, images are served by redirecting clients to the storage bucket. -Layers stored on the filesystem are served straight from the local disk. - -These extra configuration variables must be set to configure storage backends: - -* `GCS_BUCKET`: Name of the Google Cloud Storage bucket to use (**required** for - `gcs`) -* `GOOGLE_APPLICATION_CREDENTIALS`: Path to a GCP service account JSON key - (**optional** for `gcs`) -* `STORAGE_PATH`: Path to a folder in which to store and from which to serve - data (**required** for `filesystem`) - -### Background - -The project started out inspired by the [buildLayeredImage][] blog post with the -intention of becoming a Kubernetes controller that can serve declarative image -specifications specified in CRDs as container images. The design for this was -outlined in [a public gist][gist]. - -## Roadmap - -### Kubernetes integration - -It should be trivial to deploy Nixery inside of a Kubernetes cluster with -correct caching behaviour, addressing and so on. - -See [issue #4](https://github.com/tazjin/nixery/issues/4). - -### Nix-native builder - -The image building and layering functionality of Nixery will be extracted into a -separate Nix function, which will make it possible to build images directly in -Nix builds. - -[Nix]: https://nixos.org/ -[layering strategy]: https://tazj.in/blog/nixery-layers -[gist]: https://gist.github.com/tazjin/08f3d37073b3590aacac424303e6f745 -[buildLayeredImage]: https://grahamc.com/blog/nix-and-layered-docker-images -[public]: https://nixery.dev -[depot-link]: https://code.tvl.fyi/tree/tools/nixery -[gcs]: https://cloud.google.com/storage/ diff --git a/tools/nixery/builder/archive.go b/tools/nixery/builder/archive.go deleted file mode 100644 index 8763e4cb8..000000000 --- a/tools/nixery/builder/archive.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 -package builder - -// This file implements logic for walking through a directory and creating a -// tarball of it. -// -// The tarball is written straight to the supplied reader, which makes it -// possible to create an image layer from the specified store paths, hash it and -// upload it in one reading pass. -import ( - "archive/tar" - "compress/gzip" - "crypto/sha256" - "fmt" - "io" - "os" - "path/filepath" - - "github.com/google/nixery/layers" -) - -// Create a new compressed tarball from each of the paths in the list -// and write it to the supplied writer. -// -// The uncompressed tarball is hashed because image manifests must -// contain both the hashes of compressed and uncompressed layers. -func packStorePaths(l *layers.Layer, w io.Writer) (string, error) { - shasum := sha256.New() - gz := gzip.NewWriter(w) - multi := io.MultiWriter(shasum, gz) - t := tar.NewWriter(multi) - - for _, path := range l.Contents { - err := filepath.Walk(path, tarStorePath(t)) - if err != nil { - return "", err - } - } - - if err := t.Close(); err != nil { - return "", err - } - - if err := gz.Close(); err != nil { - return "", err - } - - return fmt.Sprintf("sha256:%x", shasum.Sum([]byte{})), nil -} - -func tarStorePath(w *tar.Writer) filepath.WalkFunc { - return func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - - // If the entry is not a symlink or regular file, skip it. - if info.Mode()&os.ModeSymlink == 0 && !info.Mode().IsRegular() { - return nil - } - - // the symlink target is read if this entry is a symlink, as it - // is required when creating the file header - var link string - if info.Mode()&os.ModeSymlink != 0 { - link, err = os.Readlink(path) - if err != nil { - return err - } - } - - header, err := tar.FileInfoHeader(info, link) - if err != nil { - return err - } - - // The name retrieved from os.FileInfo only contains the file's - // basename, but the full path is required within the layer - // tarball. - header.Name = path - if err = w.WriteHeader(header); err != nil { - return err - } - - // At this point, return if no file content needs to be written - if !info.Mode().IsRegular() { - return nil - } - - f, err := os.Open(path) - if err != nil { - return err - } - - if _, err := io.Copy(w, f); err != nil { - return err - } - - f.Close() - - return nil - } -} diff --git a/tools/nixery/builder/builder.go b/tools/nixery/builder/builder.go deleted file mode 100644 index 7f0bd7fff..000000000 --- a/tools/nixery/builder/builder.go +++ /dev/null @@ -1,527 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Package builder implements the logic for assembling container -// images. It shells out to Nix to retrieve all required Nix-packages -// and assemble the symlink layer and then creates the required -// tarballs in-process. -package builder - -import ( - "bufio" - "bytes" - "compress/gzip" - "context" - "crypto/sha256" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "sort" - "strings" - - "github.com/google/nixery/config" - "github.com/google/nixery/layers" - "github.com/google/nixery/manifest" - "github.com/google/nixery/storage" - "github.com/im7mortal/kmutex" - log "github.com/sirupsen/logrus" -) - -// The maximum number of layers in an image is 125. To allow for -// extensibility, the actual number of layers Nixery is "allowed" to -// use up is set at a lower point. -const LayerBudget int = 94 - -// State holds the runtime state that is carried around in Nixery and -// passed to builder functions. -type State struct { - Storage storage.Backend - Cache *LocalCache - Cfg config.Config - Pop layers.Popularity - UploadMutex *kmutex.Kmutex -} - -// Architecture represents the possible CPU architectures for which -// container images can be built. -// -// The default architecture is amd64, but support for ARM platforms is -// available within nixpkgs and can be toggled via meta-packages. -type Architecture struct { - // Name of the system tuple to pass to Nix - nixSystem string - - // Name of the architecture as used in the OCI manifests - imageArch string -} - -var amd64 = Architecture{"x86_64-linux", "amd64"} -var arm64 = Architecture{"aarch64-linux", "arm64"} - -// Image represents the information necessary for building a container image. -// This can be either a list of package names (corresponding to keys in the -// nixpkgs set) or a Nix expression that results in a *list* of derivations. -type Image struct { - Name string - Tag string - - // Names of packages to include in the image. These must correspond - // directly to top-level names of Nix packages in the nixpkgs tree. - Packages []string - - // Architecture for which to build the image. Nixery defaults - // this to amd64 if not specified via meta-packages. - Arch *Architecture -} - -// BuildResult represents the data returned from the server to the -// HTTP handlers. Error information is propagated straight from Nix -// for errors inside of the build that should be fed back to the -// client (such as missing packages). -type BuildResult struct { - Error string `json:"error"` - Pkgs []string `json:"pkgs"` - Manifest json.RawMessage `json:"manifest"` -} - -// ImageFromName parses an image name into the corresponding structure which can -// be used to invoke Nix. -// -// It will expand convenience names under the hood (see the `convenienceNames` -// function below) and append packages that are always included (cacert, iana-etc). -// -// Once assembled the image structure uses a sorted representation of -// the name. This is to avoid unnecessarily cache-busting images if -// only the order of requested packages has changed. -func ImageFromName(name string, tag string) Image { - pkgs := strings.Split(name, "/") - arch, expanded := metaPackages(pkgs) - expanded = append(expanded, "cacert", "iana-etc") - - sort.Strings(pkgs) - sort.Strings(expanded) - - return Image{ - Name: strings.Join(pkgs, "/"), - Tag: tag, - Packages: expanded, - Arch: arch, - } -} - -// ImageResult represents the output of calling the Nix derivation -// responsible for preparing an image. -type ImageResult struct { - // These fields are populated in case of an error - Error string `json:"error"` - Pkgs []string `json:"pkgs"` - - // These fields are populated in case of success - Graph layers.RuntimeGraph `json:"runtimeGraph"` - SymlinkLayer struct { - Size int `json:"size"` - TarHash string `json:"tarHash"` - Path string `json:"path"` - } `json:"symlinkLayer"` -} - -// metaPackages expands package names defined by Nixery which either -// include sets of packages or trigger certain image-building -// behaviour. -// -// Meta-packages must be specified as the first packages in an image -// name. -// -// Currently defined meta-packages are: -// -// * `shell`: Includes bash, coreutils and other common command-line tools -// * `arm64`: Causes Nixery to build images for the ARM64 architecture -func metaPackages(packages []string) (*Architecture, []string) { - arch := &amd64 - - var metapkgs []string - lastMeta := 0 - for idx, p := range packages { - if p == "shell" || p == "arm64" { - metapkgs = append(metapkgs, p) - lastMeta = idx + 1 - } else { - break - } - } - - // Chop off the meta-packages from the front of the package - // list - packages = packages[lastMeta:] - - for _, p := range metapkgs { - switch p { - case "shell": - packages = append(packages, "bashInteractive", "coreutils", "moreutils", "nano") - case "arm64": - arch = &arm64 - } - } - - return arch, packages -} - -// logNix logs each output line from Nix. It runs in a goroutine per -// output channel that should be live-logged. -func logNix(image, cmd string, r io.ReadCloser) { - scanner := bufio.NewScanner(r) - for scanner.Scan() { - log.WithFields(log.Fields{ - "image": image, - "cmd": cmd, - }).Info("[nix] " + scanner.Text()) - } -} - -func callNix(program, image string, args []string) ([]byte, error) { - cmd := exec.Command(program, args...) - - outpipe, err := cmd.StdoutPipe() - if err != nil { - return nil, err - } - - errpipe, err := cmd.StderrPipe() - if err != nil { - return nil, err - } - go logNix(image, program, errpipe) - - if err = cmd.Start(); err != nil { - log.WithError(err).WithFields(log.Fields{ - "image": image, - "cmd": program, - }).Error("error invoking Nix") - - return nil, err - } - - log.WithFields(log.Fields{ - "cmd": program, - "image": image, - }).Info("invoked Nix build") - - stdout, _ := ioutil.ReadAll(outpipe) - - if err = cmd.Wait(); err != nil { - log.WithError(err).WithFields(log.Fields{ - "image": image, - "cmd": program, - "stdout": stdout, - }).Info("failed to invoke Nix") - - return nil, err - } - - resultFile := strings.TrimSpace(string(stdout)) - buildOutput, err := ioutil.ReadFile(resultFile) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "image": image, - "file": resultFile, - }).Info("failed to read Nix result file") - - return nil, err - } - - return buildOutput, nil -} - -// Call out to Nix and request metadata for the image to be built. All -// required store paths for the image will be realised, but layers -// will not yet be created from them. -// -// This function is only invoked if the manifest is not found in any -// cache. -func prepareImage(s *State, image *Image) (*ImageResult, error) { - packages, err := json.Marshal(image.Packages) - if err != nil { - return nil, err - } - - srcType, srcArgs := s.Cfg.Pkgs.Render(image.Tag) - - args := []string{ - "--timeout", s.Cfg.Timeout, - "--argstr", "packages", string(packages), - "--argstr", "srcType", srcType, - "--argstr", "srcArgs", srcArgs, - "--argstr", "system", image.Arch.nixSystem, - } - - output, err := callNix("nixery-prepare-image", image.Name, args) - if err != nil { - // granular error logging is performed in callNix already - return nil, err - } - - log.WithFields(log.Fields{ - "image": image.Name, - "tag": image.Tag, - }).Info("finished image preparation via Nix") - - var result ImageResult - err = json.Unmarshal(output, &result) - if err != nil { - return nil, err - } - - return &result, nil -} - -// Groups layers and checks whether they are present in the cache -// already, otherwise calls out to Nix to assemble layers. -// -// Newly built layers are uploaded to the bucket. Cache entries are -// added only after successful uploads, which guarantees that entries -// retrieved from the cache are present in the bucket. -func prepareLayers(ctx context.Context, s *State, image *Image, result *ImageResult) ([]manifest.Entry, error) { - grouped := layers.GroupLayers(&result.Graph, &s.Pop, LayerBudget) - - var entries []manifest.Entry - - // Splits the layers into those which are already present in - // the cache, and those that are missing. - // - // Missing layers are built and uploaded to the storage - // bucket. - for _, l := range grouped { - lh := l.Hash() - - // While packing store paths, the SHA sum of - // the uncompressed layer is computed and - // written to `tarhash`. - // - // TODO(tazjin): Refactor this to make the - // flow of data cleaner. - lw := func(w io.Writer) (string, error) { - tarhash, err := packStorePaths(&l, w) - if err != nil { - return "", err - } - - var pkgs []string - for _, p := range l.Contents { - pkgs = append(pkgs, layers.PackageFromPath(p)) - } - - log.WithFields(log.Fields{ - "layer": lh, - "packages": pkgs, - "tarhash": tarhash, - }).Info("created image layer") - - return tarhash, err - } - - entry, err := uploadHashLayer(ctx, s, lh, l.MergeRating, lw) - if err != nil { - return nil, err - } - - entries = append(entries, *entry) - } - - // Symlink layer (built in the first Nix build) needs to be - // included here manually: - slkey := result.SymlinkLayer.TarHash - entry, err := uploadHashLayer(ctx, s, slkey, 0, func(w io.Writer) (string, error) { - f, err := os.Open(result.SymlinkLayer.Path) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "image": image.Name, - "tag": image.Tag, - "layer": slkey, - }).Error("failed to open symlink layer") - - return "", err - } - defer f.Close() - - gz := gzip.NewWriter(w) - _, err = io.Copy(gz, f) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "image": image.Name, - "tag": image.Tag, - "layer": slkey, - }).Error("failed to upload symlink layer") - - return "", err - } - - return "sha256:" + slkey, gz.Close() - }) - - if err != nil { - return nil, err - } - - entries = append(entries, *entry) - - return entries, nil -} - -// layerWriter is the type for functions that can write a layer to the -// multiwriter used for uploading & hashing. -// -// This type exists to avoid duplication between the handling of -// symlink layers and store path layers. -type layerWriter func(w io.Writer) (string, error) - -// byteCounter is a special io.Writer that counts all bytes written to -// it and does nothing else. -// -// This is required because the ad-hoc writing of tarballs leaves no -// single place to count the final tarball size otherwise. -type byteCounter struct { - count int64 -} - -func (b *byteCounter) Write(p []byte) (n int, err error) { - b.count += int64(len(p)) - return len(p), nil -} - -// Upload a layer tarball to the storage bucket, while hashing it at -// the same time. The supplied function is expected to provide the -// layer data to the writer. -// -// The initial upload is performed in a 'staging' folder, as the -// SHA256-hash is not yet available when the upload is initiated. -// -// After a successful upload, the file is moved to its final location -// in the bucket and the build cache is populated. -// -// The return value is the layer's SHA256 hash, which is used in the -// image manifest. -func uploadHashLayer(ctx context.Context, s *State, key string, mrating uint64, lw layerWriter) (*manifest.Entry, error) { - s.UploadMutex.Lock(key) - defer s.UploadMutex.Unlock(key) - - if entry, cached := layerFromCache(ctx, s, key); cached { - return entry, nil - } - - path := "staging/" + key - var tarhash string - sha256sum, size, err := s.Storage.Persist(ctx, path, manifest.LayerType, func(sw io.Writer) (string, int64, error) { - // Sets up a "multiwriter" that simultaneously runs both hash - // algorithms and uploads to the storage backend. - shasum := sha256.New() - counter := &byteCounter{} - multi := io.MultiWriter(sw, shasum, counter) - - var err error - tarhash, err = lw(multi) - sha256sum := fmt.Sprintf("%x", shasum.Sum([]byte{})) - - return sha256sum, counter.count, err - }) - - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "layer": key, - "backend": s.Storage.Name(), - }).Error("failed to create and store layer") - - return nil, err - } - - // Hashes are now known and the object is in the bucket, what - // remains is to move it to the correct location and cache it. - err = s.Storage.Move(ctx, "staging/"+key, "layers/"+sha256sum) - if err != nil { - log.WithError(err).WithField("layer", key). - Error("failed to move layer from staging") - - return nil, err - } - - log.WithFields(log.Fields{ - "layer": key, - "sha256": sha256sum, - "size": size, - }).Info("created and persisted layer") - - entry := manifest.Entry{ - Digest: "sha256:" + sha256sum, - Size: size, - TarHash: tarhash, - MergeRating: mrating, - } - - cacheLayer(ctx, s, key, entry) - - return &entry, nil -} - -func BuildImage(ctx context.Context, s *State, image *Image) (*BuildResult, error) { - key := s.Cfg.Pkgs.CacheKey(image.Packages, image.Tag) - if key != "" { - if m, c := manifestFromCache(ctx, s, key); c { - return &BuildResult{ - Manifest: m, - }, nil - } - } - - imageResult, err := prepareImage(s, image) - if err != nil { - return nil, err - } - - if imageResult.Error != "" { - return &BuildResult{ - Error: imageResult.Error, - Pkgs: imageResult.Pkgs, - }, nil - } - - layers, err := prepareLayers(ctx, s, image, imageResult) - if err != nil { - return nil, err - } - - // If the requested packages include a shell, - // set cmd accordingly. - cmd := "" - for _, pkg := range image.Packages { - if pkg == "bashInteractive" { - cmd = "bash" - } - } - m, c := manifest.Manifest(image.Arch.imageArch, layers, cmd) - - lw := func(w io.Writer) (string, error) { - r := bytes.NewReader(c.Config) - _, err := io.Copy(w, r) - return "", err - } - - if _, err = uploadHashLayer(ctx, s, c.SHA256, 0, lw); err != nil { - log.WithError(err).WithFields(log.Fields{ - "image": image.Name, - "tag": image.Tag, - }).Error("failed to upload config") - - return nil, err - } - - if key != "" { - go cacheManifest(ctx, s, key, m) - } - - result := BuildResult{ - Manifest: m, - } - return &result, nil -} diff --git a/tools/nixery/builder/builder_test.go b/tools/nixery/builder/builder_test.go deleted file mode 100644 index 507f3eb15..000000000 --- a/tools/nixery/builder/builder_test.go +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 -package builder - -import ( - "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" - "testing" -) - -var ignoreArch = cmpopts.IgnoreFields(Image{}, "Arch") - -func TestImageFromNameSimple(t *testing.T) { - image := ImageFromName("hello", "latest") - expected := Image{ - Name: "hello", - Tag: "latest", - Packages: []string{ - "cacert", - "hello", - "iana-etc", - }, - } - - if diff := cmp.Diff(expected, image, ignoreArch); diff != "" { - t.Fatalf("Image(\"hello\", \"latest\") mismatch:\n%s", diff) - } -} - -func TestImageFromNameMultiple(t *testing.T) { - image := ImageFromName("hello/git/htop", "latest") - expected := Image{ - Name: "git/hello/htop", - Tag: "latest", - Packages: []string{ - "cacert", - "git", - "hello", - "htop", - "iana-etc", - }, - } - - if diff := cmp.Diff(expected, image, ignoreArch); diff != "" { - t.Fatalf("Image(\"hello/git/htop\", \"latest\") mismatch:\n%s", diff) - } -} - -func TestImageFromNameShell(t *testing.T) { - image := ImageFromName("shell", "latest") - expected := Image{ - Name: "shell", - Tag: "latest", - Packages: []string{ - "bashInteractive", - "cacert", - "coreutils", - "iana-etc", - "moreutils", - "nano", - }, - } - - if diff := cmp.Diff(expected, image, ignoreArch); diff != "" { - t.Fatalf("Image(\"shell\", \"latest\") mismatch:\n%s", diff) - } -} - -func TestImageFromNameShellMultiple(t *testing.T) { - image := ImageFromName("shell/htop", "latest") - expected := Image{ - Name: "htop/shell", - Tag: "latest", - Packages: []string{ - "bashInteractive", - "cacert", - "coreutils", - "htop", - "iana-etc", - "moreutils", - "nano", - }, - } - - if diff := cmp.Diff(expected, image, ignoreArch); diff != "" { - t.Fatalf("Image(\"shell/htop\", \"latest\") mismatch:\n%s", diff) - } -} - -func TestImageFromNameShellArm64(t *testing.T) { - image := ImageFromName("shell/arm64", "latest") - expected := Image{ - Name: "arm64/shell", - Tag: "latest", - Packages: []string{ - "bashInteractive", - "cacert", - "coreutils", - "iana-etc", - "moreutils", - "nano", - }, - } - - if diff := cmp.Diff(expected, image, ignoreArch); diff != "" { - t.Fatalf("Image(\"shell/arm64\", \"latest\") mismatch:\n%s", diff) - } - - if image.Arch.imageArch != "arm64" { - t.Fatal("Image(\"shell/arm64\"): Expected arch arm64") - } -} diff --git a/tools/nixery/builder/cache.go b/tools/nixery/builder/cache.go deleted file mode 100644 index 9e4283c0e..000000000 --- a/tools/nixery/builder/cache.go +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 -package builder - -import ( - "bytes" - "context" - "encoding/json" - "io" - "io/ioutil" - "os" - "sync" - - "github.com/google/nixery/manifest" - log "github.com/sirupsen/logrus" -) - -// LocalCache implements the structure used for local caching of -// manifests and layer uploads. -type LocalCache struct { - // Manifest cache - mmtx sync.RWMutex - mdir string - - // Layer cache - lmtx sync.RWMutex - lcache map[string]manifest.Entry -} - -// Creates an in-memory cache and ensures that the local file path for -// manifest caching exists. -func NewCache() (LocalCache, error) { - path := os.TempDir() + "/nixery" - err := os.MkdirAll(path, 0755) - if err != nil { - return LocalCache{}, err - } - - return LocalCache{ - mdir: path + "/", - lcache: make(map[string]manifest.Entry), - }, nil -} - -// Retrieve a cached manifest if the build is cacheable and it exists. -func (c *LocalCache) manifestFromLocalCache(key string) (json.RawMessage, bool) { - c.mmtx.RLock() - defer c.mmtx.RUnlock() - - f, err := os.Open(c.mdir + key) - if err != nil { - // This is a debug log statement because failure to - // read the manifest key is currently expected if it - // is not cached. - log.WithError(err).WithField("manifest", key). - Debug("failed to read manifest from local cache") - - return nil, false - } - defer f.Close() - - m, err := ioutil.ReadAll(f) - if err != nil { - log.WithError(err).WithField("manifest", key). - Error("failed to read manifest from local cache") - - return nil, false - } - - return json.RawMessage(m), true -} - -// Adds the result of a manifest build to the local cache, if the -// manifest is considered cacheable. -// -// Manifests can be quite large and are cached on disk instead of in -// memory. -func (c *LocalCache) localCacheManifest(key string, m json.RawMessage) { - c.mmtx.Lock() - defer c.mmtx.Unlock() - - err := ioutil.WriteFile(c.mdir+key, []byte(m), 0644) - if err != nil { - log.WithError(err).WithField("manifest", key). - Error("failed to locally cache manifest") - } -} - -// Retrieve a layer build from the local cache. -func (c *LocalCache) layerFromLocalCache(key string) (*manifest.Entry, bool) { - c.lmtx.RLock() - e, ok := c.lcache[key] - c.lmtx.RUnlock() - - return &e, ok -} - -// Add a layer build result to the local cache. -func (c *LocalCache) localCacheLayer(key string, e manifest.Entry) { - c.lmtx.Lock() - c.lcache[key] = e - c.lmtx.Unlock() -} - -// Retrieve a manifest from the cache(s). First the local cache is -// checked, then the storage backend. -func manifestFromCache(ctx context.Context, s *State, key string) (json.RawMessage, bool) { - if m, cached := s.Cache.manifestFromLocalCache(key); cached { - return m, true - } - - r, err := s.Storage.Fetch(ctx, "manifests/"+key) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "manifest": key, - "backend": s.Storage.Name(), - }).Error("failed to fetch manifest from cache") - - return nil, false - } - defer r.Close() - - m, err := ioutil.ReadAll(r) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "manifest": key, - "backend": s.Storage.Name(), - }).Error("failed to read cached manifest from storage backend") - - return nil, false - } - - go s.Cache.localCacheManifest(key, m) - log.WithField("manifest", key).Info("retrieved manifest from GCS") - - return json.RawMessage(m), true -} - -// Add a manifest to the bucket & local caches -func cacheManifest(ctx context.Context, s *State, key string, m json.RawMessage) { - go s.Cache.localCacheManifest(key, m) - - path := "manifests/" + key - _, size, err := s.Storage.Persist(ctx, path, manifest.ManifestType, func(w io.Writer) (string, int64, error) { - size, err := io.Copy(w, bytes.NewReader([]byte(m))) - return "", size, err - }) - - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "manifest": key, - "backend": s.Storage.Name(), - }).Error("failed to cache manifest to storage backend") - - return - } - - log.WithFields(log.Fields{ - "manifest": key, - "size": size, - "backend": s.Storage.Name(), - }).Info("cached manifest to storage backend") -} - -// Retrieve a layer build from the cache, first checking the local -// cache followed by the bucket cache. -func layerFromCache(ctx context.Context, s *State, key string) (*manifest.Entry, bool) { - if entry, cached := s.Cache.layerFromLocalCache(key); cached { - return entry, true - } - - r, err := s.Storage.Fetch(ctx, "builds/"+key) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "layer": key, - "backend": s.Storage.Name(), - }).Debug("failed to retrieve cached layer from storage backend") - - return nil, false - } - defer r.Close() - - jb := bytes.NewBuffer([]byte{}) - _, err = io.Copy(jb, r) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "layer": key, - "backend": s.Storage.Name(), - }).Error("failed to read cached layer from storage backend") - - return nil, false - } - - var entry manifest.Entry - err = json.Unmarshal(jb.Bytes(), &entry) - if err != nil { - log.WithError(err).WithField("layer", key). - Error("failed to unmarshal cached layer") - - return nil, false - } - - go s.Cache.localCacheLayer(key, entry) - return &entry, true -} - -func cacheLayer(ctx context.Context, s *State, key string, entry manifest.Entry) { - s.Cache.localCacheLayer(key, entry) - - j, _ := json.Marshal(&entry) - path := "builds/" + key - _, _, err := s.Storage.Persist(ctx, path, "", func(w io.Writer) (string, int64, error) { - size, err := io.Copy(w, bytes.NewReader(j)) - return "", size, err - }) - - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "layer": key, - "backend": s.Storage.Name(), - }).Error("failed to cache layer") - } - - return -} diff --git a/tools/nixery/cmd/server/main.go b/tools/nixery/cmd/server/main.go deleted file mode 100644 index 24aec6391..000000000 --- a/tools/nixery/cmd/server/main.go +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// The nixery server implements a container registry that transparently builds -// container images based on Nix derivations. -// -// The Nix derivation used for image creation is responsible for creating -// objects that are compatible with the registry API. The targeted registry -// protocol is currently Docker's. -// -// When an image is requested, the required contents are parsed out of the -// request and a Nix-build is initiated that eventually responds with the -// manifest as well as information linking each layer digest to a local -// filesystem path. -package main - -import ( - "context" - "crypto/sha256" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net/http" - "regexp" - - "github.com/google/nixery/builder" - "github.com/google/nixery/config" - "github.com/google/nixery/layers" - "github.com/google/nixery/logs" - mf "github.com/google/nixery/manifest" - "github.com/google/nixery/storage" - "github.com/im7mortal/kmutex" - log "github.com/sirupsen/logrus" -) - -// ManifestMediaType is the Content-Type used for the manifest itself. This -// corresponds to the "Image Manifest V2, Schema 2" described on this page: -// -// https://docs.docker.com/registry/spec/manifest-v2-2/ -const manifestMediaType string = "application/vnd.docker.distribution.manifest.v2+json" - -// This variable will be initialised during the build process and set -// to the hash of the entire Nixery source tree. -var version string = "devel" - -// Regexes matching the V2 Registry API routes. This only includes the -// routes required for serving images, since pushing and other such -// functionality is not available. -var ( - manifestRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/manifests/([\w|\-|\.|\_]+)$`) - blobRegex = regexp.MustCompile(`^/v2/([\w|\-|\.|\_|\/]+)/(blobs|manifests)/sha256:(\w+)$`) -) - -// Downloads the popularity information for the package set from the -// URL specified in Nixery's configuration. -func downloadPopularity(url string) (layers.Popularity, error) { - resp, err := http.Get(url) - if err != nil { - return nil, err - } - - if resp.StatusCode != 200 { - return nil, fmt.Errorf("popularity download from '%s' returned status: %s\n", url, resp.Status) - } - - j, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - var pop layers.Popularity - err = json.Unmarshal(j, &pop) - if err != nil { - return nil, err - } - - return pop, nil -} - -// Error format corresponding to the registry protocol V2 specification. This -// allows feeding back errors to clients in a way that can be presented to -// users. -type registryError struct { - Code string `json:"code"` - Message string `json:"message"` -} - -type registryErrors struct { - Errors []registryError `json:"errors"` -} - -func writeError(w http.ResponseWriter, status int, code, message string) { - err := registryErrors{ - Errors: []registryError{ - {code, message}, - }, - } - json, _ := json.Marshal(err) - - w.WriteHeader(status) - w.Header().Add("Content-Type", "application/json") - w.Write(json) -} - -type registryHandler struct { - state *builder.State -} - -// Serve a manifest by tag, building it via Nix and populating caches -// if necessary. -func (h *registryHandler) serveManifestTag(w http.ResponseWriter, r *http.Request, name string, tag string) { - log.WithFields(log.Fields{ - "image": name, - "tag": tag, - }).Info("requesting image manifest") - - image := builder.ImageFromName(name, tag) - buildResult, err := builder.BuildImage(r.Context(), h.state, &image) - - if err != nil { - writeError(w, 500, "UNKNOWN", "image build failure") - - log.WithError(err).WithFields(log.Fields{ - "image": name, - "tag": tag, - }).Error("failed to build image manifest") - - return - } - - // Some error types have special handling, which is applied - // here. - if buildResult.Error == "not_found" { - s := fmt.Sprintf("Could not find Nix packages: %v", buildResult.Pkgs) - writeError(w, 404, "MANIFEST_UNKNOWN", s) - - log.WithFields(log.Fields{ - "image": name, - "tag": tag, - "packages": buildResult.Pkgs, - }).Warn("could not find Nix packages") - - return - } - - // This marshaling error is ignored because we know that this - // field represents valid JSON data. - manifest, _ := json.Marshal(buildResult.Manifest) - w.Header().Add("Content-Type", manifestMediaType) - - // The manifest needs to be persisted to the blob storage (to become - // available for clients that fetch manifests by their hash, e.g. - // containerd) and served to the client. - // - // Since we have no stable key to address this manifest (it may be - // uncacheable, yet still addressable by blob) we need to separate - // out the hashing, uploading and serving phases. The latter is - // especially important as clients may start to fetch it by digest - // as soon as they see a response. - sha256sum := fmt.Sprintf("%x", sha256.Sum256(manifest)) - path := "layers/" + sha256sum - ctx := context.TODO() - - _, _, err = h.state.Storage.Persist(ctx, path, mf.ManifestType, func(sw io.Writer) (string, int64, error) { - // We already know the hash, so no additional hash needs to be - // constructed here. - written, err := sw.Write(manifest) - return sha256sum, int64(written), err - }) - - if err != nil { - writeError(w, 500, "MANIFEST_UPLOAD", "could not upload manifest to blob store") - - log.WithError(err).WithFields(log.Fields{ - "image": name, - "tag": tag, - }).Error("could not upload manifest") - - return - } - - w.Write(manifest) -} - -// serveBlob serves a blob from storage by digest -func (h *registryHandler) serveBlob(w http.ResponseWriter, r *http.Request, blobType, digest string) { - storage := h.state.Storage - err := storage.Serve(digest, r, w) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "type": blobType, - "digest": digest, - "backend": storage.Name(), - }).Error("failed to serve blob from storage backend") - } -} - -// ServeHTTP dispatches HTTP requests to the matching handlers. -func (h *registryHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - // Acknowledge that we speak V2 with an empty response - if r.RequestURI == "/v2/" { - return - } - - // Build & serve a manifest by tag - manifestMatches := manifestRegex.FindStringSubmatch(r.RequestURI) - if len(manifestMatches) == 3 { - h.serveManifestTag(w, r, manifestMatches[1], manifestMatches[2]) - return - } - - // Serve a blob by digest - layerMatches := blobRegex.FindStringSubmatch(r.RequestURI) - if len(layerMatches) == 4 { - h.serveBlob(w, r, layerMatches[2], layerMatches[3]) - return - } - - log.WithField("uri", r.RequestURI).Info("unsupported registry route") - - w.WriteHeader(404) -} - -func main() { - logs.Init(version) - cfg, err := config.FromEnv() - if err != nil { - log.WithError(err).Fatal("failed to load configuration") - } - - var s storage.Backend - - switch cfg.Backend { - case config.GCS: - s, err = storage.NewGCSBackend() - case config.FileSystem: - s, err = storage.NewFSBackend() - } - if err != nil { - log.WithError(err).Fatal("failed to initialise storage backend") - } - - log.WithField("backend", s.Name()).Info("initialised storage backend") - - cache, err := builder.NewCache() - if err != nil { - log.WithError(err).Fatal("failed to instantiate build cache") - } - - var pop layers.Popularity - if cfg.PopUrl != "" { - pop, err = downloadPopularity(cfg.PopUrl) - if err != nil { - log.WithError(err).WithField("popURL", cfg.PopUrl). - Fatal("failed to fetch popularity information") - } - } - - state := builder.State{ - Cache: &cache, - Cfg: cfg, - Pop: pop, - Storage: s, - UploadMutex: kmutex.New(), - } - - log.WithFields(log.Fields{ - "version": version, - "port": cfg.Port, - }).Info("starting Nixery") - - // All /v2/ requests belong to the registry handler. - http.Handle("/v2/", ®istryHandler{ - state: &state, - }) - - // All other roots are served by the static file server. - webDir := http.Dir(cfg.WebDir) - http.Handle("/", http.FileServer(webDir)) - - log.Fatal(http.ListenAndServe(":"+cfg.Port, nil)) -} diff --git a/tools/nixery/config/config.go b/tools/nixery/config/config.go deleted file mode 100644 index 73ff5c835..000000000 --- a/tools/nixery/config/config.go +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Package config implements structures to store Nixery's configuration at -// runtime as well as the logic for instantiating this configuration from the -// environment. -package config - -import ( - "os" - - log "github.com/sirupsen/logrus" -) - -func getConfig(key, desc, def string) string { - value := os.Getenv(key) - if value == "" && def == "" { - log.WithFields(log.Fields{ - "option": key, - "description": desc, - }).Fatal("missing required configuration envvar") - } else if value == "" { - return def - } - - return value -} - -// Backend represents the possible storage backend types -type Backend int - -const ( - GCS = iota - FileSystem -) - -// Config holds the Nixery configuration options. -type Config struct { - Port string // Port on which to launch HTTP server - Pkgs PkgSource // Source for Nix package set - Timeout string // Timeout for a single Nix builder (seconds) - WebDir string // Directory with static web assets - PopUrl string // URL to the Nix package popularity count - Backend Backend // Storage backend to use for Nixery -} - -func FromEnv() (Config, error) { - pkgs, err := pkgSourceFromEnv() - if err != nil { - return Config{}, err - } - - var b Backend - switch os.Getenv("NIXERY_STORAGE_BACKEND") { - case "gcs": - b = GCS - case "filesystem": - b = FileSystem - default: - log.WithField("values", []string{ - "gcs", - }).Fatal("NIXERY_STORAGE_BACKEND must be set to a supported value (gcs or filesystem)") - } - - return Config{ - Port: getConfig("PORT", "HTTP port", ""), - Pkgs: pkgs, - Timeout: getConfig("NIX_TIMEOUT", "Nix builder timeout", "60"), - WebDir: getConfig("WEB_DIR", "Static web file dir", ""), - PopUrl: os.Getenv("NIX_POPULARITY_URL"), - Backend: b, - }, nil -} diff --git a/tools/nixery/config/pkgsource.go b/tools/nixery/config/pkgsource.go deleted file mode 100644 index c7508a4d3..000000000 --- a/tools/nixery/config/pkgsource.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 -package config - -import ( - "crypto/sha1" - "encoding/json" - "fmt" - "os" - "regexp" - "strings" - - log "github.com/sirupsen/logrus" -) - -// PkgSource represents the source from which the Nix package set used -// by Nixery is imported. Users configure the source by setting one of -// the supported environment variables. -type PkgSource interface { - // Convert the package source into the representation required - // for calling Nix. - Render(tag string) (string, string) - - // Create a key by which builds for this source and image - // combination can be cached. - // - // The empty string means that this value is not cacheable due - // to the package source being a moving target (such as a - // channel). - CacheKey(pkgs []string, tag string) string -} - -type GitSource struct { - repository string -} - -// Regex to determine whether a git reference is a commit hash or -// something else (branch/tag). -// -// Used to check whether a git reference is cacheable, and to pass the -// correct git structure to Nix. -// -// Note: If a user creates a branch or tag with the name of a commit -// and references it intentionally, this heuristic will fail. -var commitRegex = regexp.MustCompile(`^[0-9a-f]{40}$`) - -func (g *GitSource) Render(tag string) (string, string) { - args := map[string]string{ - "url": g.repository, - } - - // The 'git' source requires a tag to be present. If the user - // has not specified one, it is assumed that the default - // 'master' branch should be used. - if tag == "latest" || tag == "" { - tag = "master" - } - - if commitRegex.MatchString(tag) { - args["rev"] = tag - } else { - args["ref"] = tag - } - - j, _ := json.Marshal(args) - - return "git", string(j) -} - -func (g *GitSource) CacheKey(pkgs []string, tag string) string { - // Only full commit hashes can be used for caching, as - // everything else is potentially a moving target. - if !commitRegex.MatchString(tag) { - return "" - } - - unhashed := strings.Join(pkgs, "") + tag - hashed := fmt.Sprintf("%x", sha1.Sum([]byte(unhashed))) - - return hashed -} - -type NixChannel struct { - channel string -} - -func (n *NixChannel) Render(tag string) (string, string) { - return "nixpkgs", n.channel -} - -func (n *NixChannel) CacheKey(pkgs []string, tag string) string { - // Since Nix channels are downloaded from the nixpkgs-channels - // Github, users can specify full commit hashes as the - // "channel", in which case builds are cacheable. - if !commitRegex.MatchString(n.channel) { - return "" - } - - unhashed := strings.Join(pkgs, "") + n.channel - hashed := fmt.Sprintf("%x", sha1.Sum([]byte(unhashed))) - - return hashed -} - -type PkgsPath struct { - path string -} - -func (p *PkgsPath) Render(tag string) (string, string) { - return "path", p.path -} - -func (p *PkgsPath) CacheKey(pkgs []string, tag string) string { - // Path-based builds are not currently cacheable because we - // have no local hash of the package folder's state easily - // available. - return "" -} - -// Retrieve a package source from the environment. If no source is -// specified, the Nix code will default to a recent NixOS channel. -func pkgSourceFromEnv() (PkgSource, error) { - if channel := os.Getenv("NIXERY_CHANNEL"); channel != "" { - log.WithField("channel", channel).Info("using Nix package set from Nix channel or commit") - - return &NixChannel{ - channel: channel, - }, nil - } - - if git := os.Getenv("NIXERY_PKGS_REPO"); git != "" { - log.WithField("repo", git).Info("using Nix package set from git repository") - - return &GitSource{ - repository: git, - }, nil - } - - if path := os.Getenv("NIXERY_PKGS_PATH"); path != "" { - log.WithField("path", path).Info("using Nix package set at local path") - - return &PkgsPath{ - path: path, - }, nil - } - - return nil, fmt.Errorf("no valid package source has been specified") -} diff --git a/tools/nixery/default.nix b/tools/nixery/default.nix deleted file mode 100644 index 91eabca96..000000000 --- a/tools/nixery/default.nix +++ /dev/null @@ -1,129 +0,0 @@ -# Copyright 2022 The TVL Contributors -# SPDX-License-Identifier: Apache-2.0 - -# This function header aims to provide compatibility between builds of -# Nixery taking place inside/outside of the TVL depot. -# -# In the future, Nixery will transition to using //nix/buildGo for its -# build system and this will need some major adaptations to support -# that. -{ depot ? { nix.readTree.drvTargets = x: x; } -, pkgs ? import { } -, preLaunch ? "" -, extraPackages ? [ ] -, maxLayers ? 20 -, commitHash ? null -, ... -}@args: - -with pkgs; - -let - inherit (pkgs) buildGoModule lib; - - # Avoid extracting this from git until we have a way to plumb - # through revision numbers. - nixery-commit-hash = "depot"; -in -depot.nix.readTree.drvTargets rec { - # Implementation of the Nix image building logic - nixery-prepare-image = import ./prepare-image { inherit pkgs; }; - - # Include the Nixery website into the Nix store, unless its being - # overridden to something else. Nixery will serve this as its front - # page when visited from a browser. - nixery-web = ./web; - - nixery-popcount = callPackage ./popcount { }; - - # Build Nixery's Go code, resulting in the binaries used for various - # bits of functionality. - # - # The server binary is wrapped to ensure that required environment - # variables are set at runtime. - nixery = buildGoModule rec { - name = "nixery"; - src = ./.; - doCheck = true; - - # Needs to be updated after every modification of go.mod/go.sum - vendorHash = "sha256-io9NCeZmjCZPLmII3ajXIsBWbT40XiW8ncXOuUDabbo="; - - ldflags = [ - "-s" - "-w" - "-X" - "main.version=${nixery-commit-hash}" - ]; - - nativeBuildInputs = [ makeWrapper ]; - postInstall = '' - wrapProgram $out/bin/server \ - --set-default WEB_DIR "${nixery-web}" \ - --prefix PATH : ${nixery-prepare-image}/bin - ''; - - # Nixery is mirrored to Github at tazjin/nixery; this is - # automatically updated from CI for canon builds. - passthru.meta.ci.extraSteps.github = depot.tools.releases.filteredGitPush { - filter = ":/tools/nixery"; - remote = "git@github.com:tazjin/nixery.git"; - ref = "refs/heads/master"; - }; - }; - - # Wrapper script for the wrapper script (meta!) which configures - # the container environment appropriately. - # - # Most importantly, sandboxing is disabled to avoid privilege - # issues in containers. - nixery-launch-script = writeShellScriptBin "nixery" '' - set -e - export PATH=${coreutils}/bin:$PATH - export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt - mkdir -p /tmp - - # Create the build user/group required by Nix - echo 'nixbld:x:30000:nixbld' >> /etc/group - echo 'nixbld:x:30000:30000:nixbld:/tmp:/bin/bash' >> /etc/passwd - echo 'root:x:0:0:root:/root:/bin/bash' >> /etc/passwd - echo 'root:x:0:' >> /etc/group - - # Disable sandboxing to avoid running into privilege issues - mkdir -p /etc/nix - echo 'sandbox = false' >> /etc/nix/nix.conf - - # In some cases users building their own image might want to - # customise something on the inside (e.g. set up an environment - # for keys or whatever). - # - # This can be achieved by setting a 'preLaunch' script. - ${preLaunch} - - exec ${nixery}/bin/server - ''; - - # Container image containing Nixery and Nix itself. This image can - # be run on Kubernetes, published on AppEngine or whatever else is - # desired. - nixery-image = dockerTools.buildLayeredImage { - name = "nixery"; - config.Cmd = [ "${nixery-launch-script}/bin/nixery" ]; - - inherit maxLayers; - contents = [ - bashInteractive - cacert - coreutils - git - gnutar - gzip - iana-etc - nix - nixery-prepare-image - nixery-launch-script - openssh - zlib - ] ++ extraPackages; - }; -} diff --git a/tools/nixery/go.mod b/tools/nixery/go.mod deleted file mode 100644 index 9e896ffb4..000000000 --- a/tools/nixery/go.mod +++ /dev/null @@ -1,14 +0,0 @@ -module github.com/google/nixery - -go 1.15 - -require ( - cloud.google.com/go/storage v1.22.1 - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/google/go-cmp v0.5.8 - github.com/im7mortal/kmutex v1.0.1 // indirect - github.com/pkg/xattr v0.4.7 - github.com/sirupsen/logrus v1.8.1 - golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 - gonum.org/v1/gonum v0.11.0 -) diff --git a/tools/nixery/go.sum b/tools/nixery/go.sum deleted file mode 100644 index 5b6054fb6..000000000 --- a/tools/nixery/go.sum +++ /dev/null @@ -1,708 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= -cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= -cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= -cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= -cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= -cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= -cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= -cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= -cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= -cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= -cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= -cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y= -cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= -cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= -cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= -cloud.google.com/go/compute v1.6.0 h1:XdQIN5mdPTSBVwSIVDuY5e8ZzVAccsHvD3qTEz4zIps= -cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc= -cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.22.1 h1:F6IlQJZrZM++apn9V5/VfS3gbTUYg98PS3EMQAzqtfg= -cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= -git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= -github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= -github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= -github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= -github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= -github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= -github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= -github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= -github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= -github.com/googleapis/gax-go/v2 v2.3.0 h1:nRJtk3y8Fm770D42QV6T90ZnvFZyk7agSo3Q+Z9p3WI= -github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= -github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= -github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/im7mortal/kmutex v1.0.1 h1:zAACzjwD+OEknDqnLdvRa/BhzFM872EBwKijviGLc9Q= -github.com/im7mortal/kmutex v1.0.1/go.mod h1:f71c/Ugk/+58OHRAgvgzPP3QEiWGUjK13fd8ozfKWdo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= -github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/xattr v0.4.7 h1:XoA3KzmFvyPlH4RwX5eMcgtzcaGBaSvgt3IoFQfbrmQ= -github.com/pkg/xattr v0.4.7/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= -go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20220302094943-723b81ca9867/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc= -golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401 h1:zwrSfklXn0gxyLRX/aR+q6cgHbV/ItVyzbPlbA+dkAw= -golang.org/x/oauth2 v0.0.0-20220524215830-622c5d57e401/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f h1:8w7RhxzTVgUzw/AH/9mUV5q0vMgy40SQRursCcfmkCw= -golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= -golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= -gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= -gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= -gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= -google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= -google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= -google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= -google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= -google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= -google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= -google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= -google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= -google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= -google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= -google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= -google.golang.org/api v0.74.0 h1:ExR2D+5TYIrMphWgs5JCgwRhEDlPDXXrLwHHMgPHTXE= -google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= -google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= -google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= -google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= -google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= -google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= -google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= -google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335 h1:2D0OT6tPVdrQTOnVe1VQjfJPTED6EZ7fdJ/f6Db6OsY= -google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.46.0 h1:oCjezcn6g6A75TGoKYBPgKmVBLexhYLM6MebdrPApP8= -google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/tools/nixery/layers/layers.go b/tools/nixery/layers/layers.go deleted file mode 100644 index 7251c61a8..000000000 --- a/tools/nixery/layers/layers.go +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// This package reads an export reference graph (i.e. a graph representing the -// runtime dependencies of a set of derivations) created by Nix and groups it in -// a way that is likely to match the grouping for other derivation sets with -// overlapping dependencies. -// -// This is used to determine which derivations to include in which layers of a -// container image. -// -// # Inputs -// -// - a graph of Nix runtime dependencies, generated via exportReferenceGraph -// - popularity values of each package in the Nix package set (in the form of a -// direct reference count) -// - a maximum number of layers to allocate for the image (the "layer budget") -// -// # Algorithm -// -// It works by first creating a (directed) dependency tree: -// -// img (root node) -// │ -// ├───> A ─────┐ -// │ v -// ├───> B ───> E -// │ ^ -// ├───> C ─────┘ -// │ │ -// │ v -// └───> D ───> F -// -// │ -// └────> G -// -// Each node (i.e. package) is then visited to determine how important -// it is to separate this node into its own layer, specifically: -// -// 1. Is the node within a certain threshold percentile of absolute -// popularity within all of nixpkgs? (e.g. `glibc`, `openssl`) -// -// 2. Is the node's runtime closure above a threshold size? (e.g. 100MB) -// -// In either case, a bit is flipped for this node representing each -// condition and an edge to it is inserted directly from the image -// root, if it does not already exist. -// -// For the rest of the example we assume 'G' is above the threshold -// size and 'E' is popular. -// -// This tree is then transformed into a dominator tree: -// -// img -// │ -// ├───> A -// ├───> B -// ├───> C -// ├───> E -// ├───> D ───> F -// └───> G -// -// Specifically this means that the paths to A, B, C, E, G, and D -// always pass through the root (i.e. are dominated by it), whilst F -// is dominated by D (all paths go through it). -// -// The top-level subtrees are considered as the initially selected -// layers. -// -// If the list of layers fits within the layer budget, it is returned. -// -// Otherwise, a merge rating is calculated for each layer. This is the -// product of the layer's total size and its root node's popularity. -// -// Layers are then merged in ascending order of merge ratings until -// they fit into the layer budget. -// -// # Threshold values -// -// Threshold values for the partitioning conditions mentioned above -// have not yet been determined, but we will make a good first guess -// based on gut feeling and proceed to measure their impact on cache -// hits/misses. -// -// # Example -// -// Using the logic described above as well as the example presented in -// the introduction, this program would create the following layer -// groupings (assuming no additional partitioning): -// -// Layer budget: 1 -// Layers: { A, B, C, D, E, F, G } -// -// Layer budget: 2 -// Layers: { G }, { A, B, C, D, E, F } -// -// Layer budget: 3 -// Layers: { G }, { E }, { A, B, C, D, F } -// -// Layer budget: 4 -// Layers: { G }, { E }, { D, F }, { A, B, C } -// -// ... -// -// Layer budget: 10 -// Layers: { E }, { D, F }, { A }, { B }, { C } -package layers - -import ( - "crypto/sha1" - "fmt" - "regexp" - "sort" - "strings" - - log "github.com/sirupsen/logrus" - "gonum.org/v1/gonum/graph/flow" - "gonum.org/v1/gonum/graph/simple" -) - -// runtimeGraph represents structured information from Nix about the runtime -// dependencies of a derivation. -// -// This is generated in Nix by using the exportReferencesGraph feature. -type RuntimeGraph struct { - References struct { - Graph []string `json:"graph"` - } `json:"exportReferencesGraph"` - - Graph []struct { - Size uint64 `json:"closureSize"` - Path string `json:"path"` - Refs []string `json:"references"` - } `json:"graph"` -} - -// Popularity data for each Nix package that was calculated in advance. -// -// Popularity is a number from 1-100 that represents the -// popularity percentile in which this package resides inside -// of the nixpkgs tree. -type Popularity = map[string]int - -// Layer represents the data returned for each layer that Nix should -// build for the container image. -type Layer struct { - Contents []string `json:"contents"` - MergeRating uint64 -} - -// Hash the contents of a layer to create a deterministic identifier that can be -// used for caching. -func (l *Layer) Hash() string { - sum := sha1.Sum([]byte(strings.Join(l.Contents, ":"))) - return fmt.Sprintf("%x", sum) -} - -func (a Layer) merge(b Layer) Layer { - a.Contents = append(a.Contents, b.Contents...) - a.MergeRating += b.MergeRating - return a -} - -// closure as pointed to by the graph nodes. -type closure struct { - GraphID int64 - Path string - Size uint64 - Refs []string - Popularity int -} - -func (c *closure) ID() int64 { - return c.GraphID -} - -var nixRegexp = regexp.MustCompile(`^/nix/store/[a-z0-9]+-`) - -// PackageFromPath returns the name of a Nix package based on its -// output store path. -func PackageFromPath(path string) string { - return nixRegexp.ReplaceAllString(path, "") -} - -// DOTID provides a human-readable package name. The name stems from -// the dot format used by GraphViz, into which the dependency graph -// can be rendered. -func (c *closure) DOTID() string { - return PackageFromPath(c.Path) -} - -// bigOrPopular checks whether this closure should be considered for -// separation into its own layer, even if it would otherwise only -// appear in a subtree of the dominator tree. -func (c *closure) bigOrPopular() bool { - const sizeThreshold = 100 * 1000000 // 100MB - - if c.Size > sizeThreshold { - return true - } - - // Threshold value is picked arbitrarily right now. The reason - // for this is that some packages (such as `cacert`) have very - // few direct dependencies, but are required by pretty much - // everything. - if c.Popularity >= 100 { - return true - } - - return false -} - -func insertEdges(graph *simple.DirectedGraph, cmap *map[string]*closure, node *closure) { - // Big or popular nodes get a separate edge from the top to - // flag them for their own layer. - if node.bigOrPopular() && !graph.HasEdgeFromTo(0, node.ID()) { - edge := graph.NewEdge(graph.Node(0), node) - graph.SetEdge(edge) - } - - for _, c := range node.Refs { - // Nix adds a self reference to each node, which - // should not be inserted. - if c != node.Path { - edge := graph.NewEdge(node, (*cmap)[c]) - graph.SetEdge(edge) - } - } -} - -// Create a graph structure from the references supplied by Nix. -func buildGraph(refs *RuntimeGraph, pop *Popularity) *simple.DirectedGraph { - cmap := make(map[string]*closure) - graph := simple.NewDirectedGraph() - - // Insert all closures into the graph, as well as a fake root - // closure which serves as the top of the tree. - // - // A map from store paths to IDs is kept to actually insert - // edges below. - root := &closure{ - GraphID: 0, - Path: "image_root", - } - graph.AddNode(root) - - for idx, c := range refs.Graph { - node := &closure{ - GraphID: int64(idx + 1), // inc because of root node - Path: c.Path, - Size: c.Size, - Refs: c.Refs, - } - - // The packages `nss-cacert` and `iana-etc` are added - // by Nixery to *every single image* and should have a - // very high popularity. - // - // Other popularity values are populated from the data - // set assembled by Nixery's popcount. - id := node.DOTID() - if strings.HasPrefix(id, "nss-cacert") || strings.HasPrefix(id, "iana-etc") { - // glibc has ~300k references, these packages need *more* - node.Popularity = 500000 - } else if p, ok := (*pop)[id]; ok { - node.Popularity = p - } else { - node.Popularity = 1 - } - - graph.AddNode(node) - cmap[c.Path] = node - } - - // Insert the top-level closures with edges from the root - // node, then insert all edges for each closure. - for _, p := range refs.References.Graph { - edge := graph.NewEdge(root, cmap[p]) - graph.SetEdge(edge) - } - - for _, c := range cmap { - insertEdges(graph, &cmap, c) - } - - return graph -} - -// Extracts a subgraph starting at the specified root from the -// dominator tree. The subgraph is converted into a flat list of -// layers, each containing the store paths and merge rating. -func groupLayer(dt *flow.DominatorTree, root *closure) Layer { - size := root.Size - contents := []string{root.Path} - children := dt.DominatedBy(root.ID()) - - // This iteration does not use 'range' because the list being - // iterated is modified during the iteration (yes, I'm sorry). - for i := 0; i < len(children); i++ { - child := children[i].(*closure) - size += child.Size - contents = append(contents, child.Path) - children = append(children, dt.DominatedBy(child.ID())...) - } - - // Contents are sorted to ensure that hashing is consistent - sort.Strings(contents) - - return Layer{ - Contents: contents, - MergeRating: uint64(root.Popularity) * size, - } -} - -// Calculate the dominator tree of the entire package set and group -// each top-level subtree into a layer. -// -// Layers are merged together until they fit into the layer budget, -// based on their merge rating. -func dominate(budget int, graph *simple.DirectedGraph) []Layer { - dt := flow.Dominators(graph.Node(0), graph) - - var layers []Layer - for _, n := range dt.DominatedBy(dt.Root().ID()) { - layers = append(layers, groupLayer(&dt, n.(*closure))) - } - - sort.Slice(layers, func(i, j int) bool { - return layers[i].MergeRating < layers[j].MergeRating - }) - - if len(layers) > budget { - log.WithFields(log.Fields{ - "layers": len(layers), - "budget": budget, - }).Info("ideal image exceeds layer budget") - } - - for len(layers) > budget { - merged := layers[0].merge(layers[1]) - layers[1] = merged - layers = layers[1:] - } - - return layers -} - -// groupLayers applies the algorithm described above the its input and returns a -// list of layers, each consisting of a list of Nix store paths that it should -// contain. -func GroupLayers(refs *RuntimeGraph, pop *Popularity, budget int) []Layer { - graph := buildGraph(refs, pop) - return dominate(budget, graph) -} diff --git a/tools/nixery/logs/logs.go b/tools/nixery/logs/logs.go deleted file mode 100644 index 06adc701e..000000000 --- a/tools/nixery/logs/logs.go +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 -package logs - -// This file configures different log formatters via logrus. The -// standard formatter uses a structured JSON format that is compatible -// with Stackdriver Error Reporting. -// -// https://cloud.google.com/error-reporting/docs/formatting-error-messages - -import ( - "bytes" - "encoding/json" - log "github.com/sirupsen/logrus" -) - -type stackdriverFormatter struct{} - -type serviceContext struct { - Service string `json:"service"` - Version string `json:"version"` -} - -type reportLocation struct { - FilePath string `json:"filePath"` - LineNumber int `json:"lineNumber"` - FunctionName string `json:"functionName"` -} - -var nixeryContext = serviceContext{ - Service: "nixery", -} - -// isError determines whether an entry should be logged as an error -// (i.e. with attached `context`). -// -// This requires the caller information to be present on the log -// entry, as stacktraces are not available currently. -func isError(e *log.Entry) bool { - l := e.Level - return (l == log.ErrorLevel || l == log.FatalLevel || l == log.PanicLevel) && - e.HasCaller() -} - -// logSeverity formats the entry's severity into a format compatible -// with Stackdriver Logging. -// -// The two formats that are being mapped do not have an equivalent set -// of severities/levels, so the mapping is somewhat arbitrary for a -// handful of them. -// -// https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry#LogSeverity -func logSeverity(l log.Level) string { - switch l { - case log.TraceLevel: - return "DEBUG" - case log.DebugLevel: - return "DEBUG" - case log.InfoLevel: - return "INFO" - case log.WarnLevel: - return "WARNING" - case log.ErrorLevel: - return "ERROR" - case log.FatalLevel: - return "CRITICAL" - case log.PanicLevel: - return "EMERGENCY" - default: - return "DEFAULT" - } -} - -func (f stackdriverFormatter) Format(e *log.Entry) ([]byte, error) { - msg := e.Data - msg["serviceContext"] = &nixeryContext - msg["message"] = &e.Message - msg["eventTime"] = &e.Time - msg["severity"] = logSeverity(e.Level) - - if e, ok := msg[log.ErrorKey]; ok { - if err, isError := e.(error); isError { - msg[log.ErrorKey] = err.Error() - } else { - delete(msg, log.ErrorKey) - } - } - - if isError(e) { - loc := reportLocation{ - FilePath: e.Caller.File, - LineNumber: e.Caller.Line, - FunctionName: e.Caller.Function, - } - msg["context"] = &loc - } - - b := new(bytes.Buffer) - err := json.NewEncoder(b).Encode(&msg) - - return b.Bytes(), err -} - -func Init(version string) { - nixeryContext.Version = version - log.SetReportCaller(true) - log.SetFormatter(stackdriverFormatter{}) -} diff --git a/tools/nixery/manifest/manifest.go b/tools/nixery/manifest/manifest.go deleted file mode 100644 index 5638b576e..000000000 --- a/tools/nixery/manifest/manifest.go +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Package image implements logic for creating the image metadata -// (such as the image manifest and configuration). -package manifest - -import ( - "crypto/sha256" - "encoding/json" - "fmt" - "sort" -) - -const ( - // manifest constants - schemaVersion = 2 - - // media types - ManifestType = "application/vnd.docker.distribution.manifest.v2+json" - LayerType = "application/vnd.docker.image.rootfs.diff.tar.gzip" - configType = "application/vnd.docker.container.image.v1+json" - - // image config constants - os = "linux" - fsType = "layers" -) - -type Entry struct { - MediaType string `json:"mediaType,omitempty"` - Size int64 `json:"size"` - Digest string `json:"digest"` - - // These fields are internal to Nixery and not part of the - // serialised entry. - MergeRating uint64 `json:"-"` - TarHash string `json:",omitempty"` -} - -type manifest struct { - SchemaVersion int `json:"schemaVersion"` - MediaType string `json:"mediaType"` - Config Entry `json:"config"` - Layers []Entry `json:"layers"` -} - -type imageConfig struct { - Architecture string `json:"architecture"` - OS string `json:"os"` - - RootFS struct { - FSType string `json:"type"` - DiffIDs []string `json:"diff_ids"` - } `json:"rootfs"` - - Config struct { - Cmd []string `json:",omitempty"` - Env []string `json:",omitempty"` - } `json:"config"` -} - -// ConfigLayer represents the configuration layer to be included in -// the manifest, containing its JSON-serialised content and SHA256 -// hash. -type ConfigLayer struct { - Config []byte - SHA256 string -} - -// imageConfig creates an image configuration with the values set to -// the constant defaults. -// -// Outside of this module the image configuration is treated as an -// opaque blob and it is thus returned as an already serialised byte -// array and its SHA256-hash. -func configLayer(arch string, hashes []string, cmd string) ConfigLayer { - c := imageConfig{} - c.Architecture = arch - c.OS = os - c.RootFS.FSType = fsType - c.RootFS.DiffIDs = hashes - if cmd != "" { - c.Config.Cmd = []string{cmd} - } - c.Config.Env = []string{"SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt"} - - j, _ := json.Marshal(c) - - return ConfigLayer{ - Config: j, - SHA256: fmt.Sprintf("%x", sha256.Sum256(j)), - } -} - -// Manifest creates an image manifest from the specified layer entries -// and returns its JSON-serialised form as well as the configuration -// layer. -// -// Callers do not need to set the media type for the layer entries. -func Manifest(arch string, layers []Entry, cmd string) (json.RawMessage, ConfigLayer) { - // Sort layers by their merge rating, from highest to lowest. - // This makes it likely for a contiguous chain of shared image - // layers to appear at the beginning of a layer. - // - // Due to moby/moby#38446 Docker considers the order of layers - // when deciding which layers to download again. - sort.Slice(layers, func(i, j int) bool { - return layers[i].MergeRating > layers[j].MergeRating - }) - - hashes := make([]string, len(layers)) - for i, l := range layers { - hashes[i] = l.TarHash - l.MediaType = LayerType - l.TarHash = "" - layers[i] = l - } - - c := configLayer(arch, hashes, cmd) - - m := manifest{ - SchemaVersion: schemaVersion, - MediaType: ManifestType, - Config: Entry{ - MediaType: configType, - Size: int64(len(c.Config)), - Digest: "sha256:" + c.SHA256, - }, - Layers: layers, - } - - j, _ := json.Marshal(m) - - return json.RawMessage(j), c -} diff --git a/tools/nixery/popcount/README.md b/tools/nixery/popcount/README.md deleted file mode 100644 index 3e56f99d5..000000000 --- a/tools/nixery/popcount/README.md +++ /dev/null @@ -1,39 +0,0 @@ -popcount -======== - -This script is used to count the popularity for each package in `nixpkgs`, by -determining how many other packages depend on it. - -It skips over all packages that fail to build, are not cached or are unfree - -but these omissions do not meaningfully affect the statistics. - -It currently does not evaluate nested attribute sets (such as -`haskellPackages`). - -## Usage - -1. Generate a list of all top-level attributes in `nixpkgs`: - - ```shell - nix eval '(with builtins; toJSON (attrNames (import {})))' | jq -r | jq > all-top-level.json - ``` - -2. Run `./popcount > all-runtime-deps.txt` - -3. Collect and count the results with the following magic incantation: - - ```shell - cat all-runtime-deps.txt \ - | sed -r 's|/nix/store/[a-z0-9]+-||g' \ - | sort \ - | uniq -c \ - | sort -n -r \ - | awk '{ print "{\"" $2 "\":" $1 "}"}' \ - | jq -c -s '. | add | with_entries(select(.value > 1))' \ - > your-output-file - ``` - - In essence, this will trim Nix's store paths and hashes from the output, - count the occurrences of each package and return the output as JSON. All - packages that have no references other than themselves are removed from the - output. diff --git a/tools/nixery/popcount/default.nix b/tools/nixery/popcount/default.nix deleted file mode 100644 index 4acf2e883..000000000 --- a/tools/nixery/popcount/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2022, 2024 The TVL Contributors -# SPDX-License-Identifier: Apache-2.0 - -{ buildGoModule }: - -buildGoModule { - name = "nixery-popcount"; - - src = ./.; - - vendorHash = null; - - # https://nixos.org/manual/nixpkgs/stable/#buildGoPackage-migration - postPatch = '' - go mod init github.com/google/nixery/popcount - ''; - - doCheck = true; -} diff --git a/tools/nixery/popcount/popcount.go b/tools/nixery/popcount/popcount.go deleted file mode 100644 index b83ac3ed1..000000000 --- a/tools/nixery/popcount/popcount.go +++ /dev/null @@ -1,280 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Popcount fetches popularity information for each store path in a -// given Nix channel from the upstream binary cache. -// -// It does this simply by inspecting the narinfo files, rather than -// attempting to deal with instantiation of the binary cache. -// -// This is *significantly* faster than attempting to realise the whole -// channel and then calling `nix path-info` on it. -// -// TODO(tazjin): Persist intermediate results (references for each -// store path) to speed up subsequent runs. -package main - -import ( - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "net/http" - "os" - "os/exec" - "regexp" - "strings" -) - -var client http.Client -var pathexp = regexp.MustCompile("/nix/store/([a-z0-9]{32})-(.*)$") -var refsexp = regexp.MustCompile("(?m:^References: (.*)$)") -var refexp = regexp.MustCompile("^([a-z0-9]{32})-(.*)$") - -type meta struct { - name string - url string - commit string -} - -type item struct { - name string - hash string -} - -func failOn(err error, msg string) { - if err != nil { - log.Fatalf("%s: %s", msg, err) - } -} - -func channelMetadata(channel string) meta { - // This needs an HTTP client that does not follow redirects - // because the channel URL is used explicitly for other - // downloads. - c := http.Client{ - CheckRedirect: func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - }, - } - - resp, err := c.Get(fmt.Sprintf("https://channels.nixos.org/%s", channel)) - failOn(err, "failed to retrieve channel metadata") - - loc, err := resp.Location() - failOn(err, "no redirect location given for channel") - - // TODO(tazjin): These redirects are currently served as 301s, but - // should (and used to) be 302s. Check if/when this is fixed and - // update accordingly. - if !(resp.StatusCode == 301 || resp.StatusCode == 302) { - log.Fatalf("Expected redirect for channel, but received '%s'\n", resp.Status) - } - - commitResp, err := c.Get(fmt.Sprintf("%s/git-revision", loc.String())) - failOn(err, "failed to retrieve commit for channel") - - defer commitResp.Body.Close() - commit, err := ioutil.ReadAll(commitResp.Body) - failOn(err, "failed to read commit from response") - if commitResp.StatusCode != 200 { - log.Fatalf("non-success status code when fetching commit: %s (%v)", string(commit), commitResp.StatusCode) - } - - return meta{ - name: channel, - url: loc.String(), - commit: string(commit), - } -} - -func downloadStorePaths(c *meta) []string { - resp, err := client.Get(fmt.Sprintf("%s/store-paths.xz", c.url)) - failOn(err, "failed to download store-paths.xz") - defer resp.Body.Close() - - cmd := exec.Command("xzcat") - stdin, err := cmd.StdinPipe() - failOn(err, "failed to open xzcat stdin") - stdout, err := cmd.StdoutPipe() - failOn(err, "failed to open xzcat stdout") - defer stdout.Close() - - go func() { - defer stdin.Close() - io.Copy(stdin, resp.Body) - }() - - err = cmd.Start() - failOn(err, "failed to start xzcat") - - paths, err := ioutil.ReadAll(stdout) - failOn(err, "failed to read uncompressed store paths") - - err = cmd.Wait() - failOn(err, "xzcat failed to decompress") - - return strings.Split(string(paths), "\n") -} - -func storePathToItem(path string) *item { - res := pathexp.FindStringSubmatch(path) - if len(res) != 3 { - return nil - } - - return &item{ - hash: res[1], - name: res[2], - } -} - -func narInfoToRefs(narinfo string) []string { - all := refsexp.FindAllStringSubmatch(narinfo, 1) - - if len(all) != 1 { - log.Fatalf("failed to parse narinfo:\n%s\nfound: %v\n", narinfo, all[0]) - } - - if len(all[0]) != 2 { - // no references found - return []string{} - } - - refs := strings.Split(all[0][1], " ") - for i, s := range refs { - if s == "" { - continue - } - - res := refexp.FindStringSubmatch(s) - refs[i] = res[2] - } - - return refs -} - -func fetchNarInfo(i *item) (string, error) { - file, err := ioutil.ReadFile("popcache/" + i.hash) - if err == nil { - return string(file), nil - } - - resp, err := client.Get(fmt.Sprintf("https://cache.nixos.org/%s.narinfo", i.hash)) - if err != nil { - return "", err - } - - defer resp.Body.Close() - - narinfo, err := ioutil.ReadAll(resp.Body) - - // best-effort write the file to the cache - ioutil.WriteFile("popcache/"+i.hash, narinfo, 0644) - - return string(narinfo), err -} - -// downloader starts a worker that takes care of downloading narinfos -// for all paths received from the queue. -// -// If there is no data remaining in the queue, the downloader exits -// and informs the finaliser queue about having exited. -func downloader(queue chan *item, narinfos chan string, downloaders chan struct{}) { - for i := range queue { - ni, err := fetchNarInfo(i) - if err != nil { - log.Printf("couldn't fetch narinfo for %s: %s\n", i.name, err) - continue - - } - narinfos <- ni - } - downloaders <- struct{}{} -} - -// finaliser counts the number of downloaders that have exited and -// closes the narinfos queue to signal to the counters that no more -// elements will arrive. -func finaliser(count int, downloaders chan struct{}, narinfos chan string) { - for range downloaders { - count-- - if count == 0 { - close(downloaders) - close(narinfos) - break - } - } -} - -func main() { - if len(os.Args) == 1 { - log.Fatalf("Nix channel must be specified as first argument") - } - - err := os.MkdirAll("popcache", 0755) - if err != nil { - log.Fatalf("Failed to create 'popcache' directory in current folder: %s\n", err) - } - - count := 42 // concurrent downloader count - channel := os.Args[1] - log.Printf("Fetching metadata for channel '%s'\n", channel) - - meta := channelMetadata(channel) - log.Printf("Pinned channel '%s' to commit '%s'\n", meta.name, meta.commit) - - paths := downloadStorePaths(&meta) - log.Printf("Fetching references for %d store paths\n", len(paths)) - - // Download paths concurrently and receive their narinfos into - // a channel. Data is collated centrally into a map and - // serialised at the /very/ end. - downloadQueue := make(chan *item, len(paths)) - for _, p := range paths { - if i := storePathToItem(p); i != nil { - downloadQueue <- i - } - } - close(downloadQueue) - - // Set up a task tracking channel for parsing & counting - // narinfos, as well as a coordination channel for signaling - // that all downloads have finished - narinfos := make(chan string, 50) - downloaders := make(chan struct{}, count) - for i := 0; i < count; i++ { - go downloader(downloadQueue, narinfos, downloaders) - } - - go finaliser(count, downloaders, narinfos) - - counts := make(map[string]int) - for ni := range narinfos { - refs := narInfoToRefs(ni) - for _, ref := range refs { - if ref == "" { - continue - } - - counts[ref] += 1 - } - } - - // Remove all self-references (i.e. packages not referenced by anyone else) - for k, v := range counts { - if v == 1 { - delete(counts, k) - } - } - - bytes, _ := json.Marshal(counts) - outfile := fmt.Sprintf("popularity-%s-%s.json", meta.name, meta.commit) - err = ioutil.WriteFile(outfile, bytes, 0644) - if err != nil { - log.Fatalf("Failed to write output to '%s': %s\n", outfile, err) - } - - log.Printf("Wrote output to '%s'\n", outfile) -} diff --git a/tools/nixery/prepare-image/default.nix b/tools/nixery/prepare-image/default.nix deleted file mode 100644 index efd9ed340..000000000 --- a/tools/nixery/prepare-image/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2022 The TVL Contributors -# SPDX-License-Identifier: Apache-2.0 - -# This file builds a wrapper script called by Nixery to ask for the -# content information for a given image. -# -# The purpose of using a wrapper script is to ensure that the paths to -# all required Nix files are set correctly at runtime. - -{ pkgs ? import { } }: - -pkgs.writeShellScriptBin "nixery-prepare-image" '' - exec ${pkgs.nix}/bin/nix-build \ - --show-trace \ - --no-out-link "$@" \ - --argstr loadPkgs ${./load-pkgs.nix} \ - ${./prepare-image.nix} -'' diff --git a/tools/nixery/prepare-image/load-pkgs.nix b/tools/nixery/prepare-image/load-pkgs.nix deleted file mode 100644 index 7f8ab5479..000000000 --- a/tools/nixery/prepare-image/load-pkgs.nix +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2022 The TVL Contributors -# SPDX-License-Identifier: Apache-2.0 - -# Load a Nix package set from one of the supported source types -# (nixpkgs, git, path). -{ srcType, srcArgs, importArgs ? { } }: - -with builtins; -let - # If a nixpkgs channel is requested, it is retrieved from Github (as - # a tarball) and imported. - fetchImportChannel = channel: - let - url = - "https://github.com/NixOS/nixpkgs/archive/${channel}.tar.gz"; - in - import (fetchTarball url) importArgs; - - # If a git repository is requested, it is retrieved via - # builtins.fetchGit which defaults to the git configuration of the - # outside environment. This means that user-configured SSH - # credentials etc. are going to work as expected. - fetchImportGit = spec: import (fetchGit spec) importArgs; - - # No special handling is used for paths, so users are expected to pass one - # that will work natively with Nix. - importPath = path: import (toPath path) importArgs; -in -if srcType == "nixpkgs" then - fetchImportChannel srcArgs -else if srcType == "git" then - fetchImportGit (fromJSON srcArgs) -else if srcType == "path" then - importPath srcArgs -else - throw ("Invalid package set source specification: ${srcType} (${srcArgs})") diff --git a/tools/nixery/prepare-image/prepare-image.nix b/tools/nixery/prepare-image/prepare-image.nix deleted file mode 100644 index 28022fe42..000000000 --- a/tools/nixery/prepare-image/prepare-image.nix +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright 2022 The TVL Contributors -# SPDX-License-Identifier: Apache-2.0 - -# This file contains a derivation that outputs structured information -# about the runtime dependencies of an image with a given set of -# packages. This is used by Nixery to determine the layer grouping and -# assemble each layer. -# -# In addition it creates and outputs a meta-layer with the symlink -# structure required for using the image together with the individual -# package layers. - -{ - # Description of the package set to be used (will be loaded by load-pkgs.nix) - srcType ? "nixpkgs" -, srcArgs ? "nixos-unstable" -, system ? "x86_64-linux" -, importArgs ? { } -, # Path to load-pkgs.nix - loadPkgs ? ./load-pkgs.nix -, # Packages to install by name (which must refer to top-level attributes of - # nixpkgs). This is passed in as a JSON-array in string form. - packages ? "[]" -}: - -let - inherit (builtins) - foldl' - fromJSON - hasAttr - length - match - readFile - toFile - toJSON; - - # Package set to use for sourcing utilities - nativePkgs = import loadPkgs { inherit srcType srcArgs importArgs; }; - inherit (nativePkgs) coreutils jq openssl lib runCommand writeText symlinkJoin; - - # Package set to use for packages to be included in the image. This - # package set is imported with the system set to the target - # architecture. - pkgs = import loadPkgs { - inherit srcType srcArgs; - importArgs = importArgs // { - inherit system; - }; - }; - - # deepFetch traverses the top-level Nix package set to retrieve an item via a - # path specified in string form. - # - # For top-level items, the name of the key yields the result directly. Nested - # items are fetched by using dot-syntax, as in Nix itself. - # - # Due to a restriction of the registry API specification it is not possible to - # pass uppercase characters in an image name, however the Nix package set - # makes use of camelCasing repeatedly (for example for `haskellPackages`). - # - # To work around this, if no value is found on the top-level a second lookup - # is done on the package set using lowercase-names. This is not done for - # nested sets, as they often have keys that only differ in case. - # - # For example, `deepFetch pkgs "xorg.xev"` retrieves `pkgs.xorg.xev` and - # `deepFetch haskellpackages.stylish-haskell` retrieves - # `haskellPackages.stylish-haskell`. - deepFetch = with lib; s: n: - let - path = splitString "." n; - err = { error = "not_found"; pkg = n; }; - # The most efficient way I've found to do a lookup against - # case-differing versions of an attribute is to first construct a - # mapping of all lowercased attribute names to their differently cased - # equivalents. - # - # This map is then used for a second lookup if the top-level - # (case-sensitive) one does not yield a result. - hasUpper = str: (match ".*[A-Z].*" str) != null; - allUpperKeys = filter hasUpper (attrNames s); - lowercased = listToAttrs (map - (k: { - name = toLower k; - value = k; - }) - allUpperKeys); - caseAmendedPath = map (v: if hasAttr v lowercased then lowercased."${v}" else v) path; - fetchLower = attrByPath caseAmendedPath err s; - in - attrByPath path fetchLower s; - - # Workaround for a workaround in nixpkgs: Unquoted language - # identifiers can not start with numbers in Nix, but some package - # names start with numbers (such as `1password`). - # - # In nixpkgs convention, these identifiers are prefixed with - # underscores (e.g. `_1password`), however this is not accepted by - # the Docker registry protocol. - # - # To make this work, we detect these kinds of packages and add the - # missing underscore. - needsUnderscore = pkg: (builtins.match "^[0-9].*" pkg) != null; - normalisedPackages = map (p: if needsUnderscore p then "_${p}" else p) (fromJSON packages); - - # allContents contains all packages successfully retrieved by name - # from the package set, as well as any errors encountered while - # attempting to fetch a package. - # - # Accumulated error information is returned back to the server. - allContents = - # Folds over the results of 'deepFetch' on all requested packages to - # separate them into errors and content. This allows the program to - # terminate early and return only the errors if any are encountered. - let - splitter = attrs: res: - if hasAttr "error" res - then attrs // { errors = attrs.errors ++ [ res ]; } - else attrs // { contents = attrs.contents ++ [ res ]; }; - init = { contents = [ ]; errors = [ ]; }; - fetched = (map (deepFetch pkgs) normalisedPackages); - in - foldl' splitter init fetched; - - # Contains the export references graph of all retrieved packages, - # which has information about all runtime dependencies of the image. - # - # This is used by Nixery to group closures into image layers. - runtimeGraph = runCommand "runtime-graph.json" - { - __structuredAttrs = true; - exportReferencesGraph.graph = allContents.contents; - PATH = "${coreutils}/bin"; - builder = toFile "builder" '' - . .attrs.sh - cp .attrs.json ''${outputs[out]} - ''; - } ""; - - # Create a symlink forest into all top-level store paths of the - # image contents. - contentsEnv = symlinkJoin { - name = "bulk-layers"; - paths = allContents.contents; - - # Provide a few essentials that many programs expect: - # - a /tmp directory, - # - a /usr/bin/env for shell scripts that require it. - # - # Note that in images that do not actually contain `coreutils`, - # /usr/bin/env will be a dangling symlink. - # - # TODO(tazjin): Don't link /usr/bin/env if coreutils is not included. - postBuild = '' - mkdir -p $out/tmp - mkdir -p $out/usr/bin - ln -s ${coreutils}/bin/env $out/usr/bin/env - ''; - }; - - # Image layer that contains the symlink forest created above. This - # must be included in the image to ensure that the filesystem has a - # useful layout at runtime. - symlinkLayer = runCommand "symlink-layer.tar" { } '' - cp -r ${contentsEnv}/ ./layer - tar --transform='s|^\./||' -C layer --sort=name --mtime="@$SOURCE_DATE_EPOCH" --owner=0 --group=0 -cf $out . - ''; - - # Metadata about the symlink layer which is required for serving it. - # Two different hashes are computed for different usages (inclusion - # in manifest vs. content-checking in the layer cache). - symlinkLayerMeta = fromJSON (builtins.unsafeDiscardStringContext (readFile (runCommand "symlink-layer-meta.json" - { - buildInputs = [ coreutils jq openssl ]; - } '' - tarHash=$(sha256sum ${symlinkLayer} | cut -d ' ' -f1) - layerSize=$(stat --printf '%s' ${symlinkLayer}) - - jq -n -c --arg tarHash $tarHash --arg size $layerSize --arg path ${symlinkLayer} \ - '{ size: ($size | tonumber), tarHash: $tarHash, path: $path }' >> $out - ''))); - - # Final output structure returned to Nixery if the build succeeded - buildOutput = { - runtimeGraph = fromJSON (builtins.unsafeDiscardStringContext (readFile runtimeGraph)); - symlinkLayer = symlinkLayerMeta; - }; - - # Output structure returned if errors occured during the build. Currently the - # only error type that is returned in a structured way is 'not_found'. - errorOutput = { - error = "not_found"; - pkgs = map (err: err.pkg) allContents.errors; - }; -in -writeText "build-output.json" (if (length allContents.errors) == 0 -then toJSON buildOutput -else toJSON errorOutput -) diff --git a/tools/nixery/scripts/integration-test.sh b/tools/nixery/scripts/integration-test.sh deleted file mode 100755 index 9d06e96ba..000000000 --- a/tools/nixery/scripts/integration-test.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -set -eou pipefail - -# This integration test makes sure that the container image built -# for Nixery itself runs fine in Docker, and that images pulled -# from it work in Docker. - -IMG=$(docker load -q -i "$(nix-build -A nixery-image)" | awk '{ print $3 }') -echo "Loaded Nixery image as ${IMG}" - -# Run the built nixery docker image in the background, but keep printing its -# output as it occurs. -# We can't just mount a tmpfs to /var/cache/nixery, as tmpfs doesn't support -# user xattrs. -# So create a temporary directory in the current working directory, and hope -# it's backed by something supporting user xattrs. -# We'll notice it isn't if nixery starts complaining about not able to set -# xattrs anyway. -if [ -d var-cache-nixery ]; then rm -Rf var-cache-nixery; fi -mkdir var-cache-nixery -docker run --privileged --rm -p 8080:8080 --name nixery \ - -e PORT=8080 \ - --mount "type=bind,source=${PWD}/var-cache-nixery,target=/var/cache/nixery" \ - -e NIXERY_CHANNEL=nixos-unstable \ - -e NIXERY_STORAGE_BACKEND=filesystem \ - -e STORAGE_PATH=/var/cache/nixery \ - "${IMG}" & - -# Give the container ~20 seconds to come up -set +e -attempts=0 -echo -n "Waiting for Nixery to start ..." -until curl --fail --silent "http://localhost:8080/v2/"; do - [[ attempts -eq 30 ]] && echo "Nixery container failed to start!" && exit 1 - ((attempts++)) - echo -n "." - sleep 1 -done -set -e - -# Pull and run an image of the current CPU architecture -case $(uname -m) in - x86_64) - docker run --rm localhost:8080/hello hello - ;; - aarch64) - docker run --rm localhost:8080/arm64/hello hello - ;; -esac - -# Pull an image of the opposite CPU architecture (but without running it) -case $(uname -m) in -x86_64) - docker pull localhost:8080/arm64/hello - ;; -aarch64) - docker pull localhost:8080/hello - ;; -esac diff --git a/tools/nixery/shell.nix b/tools/nixery/shell.nix deleted file mode 100644 index b91094722..000000000 --- a/tools/nixery/shell.nix +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright 2022 The TVL Contributors -# SPDX-License-Identifier: Apache-2.0 - -# Configures a shell environment that builds required local packages to -# run Nixery. -{ pkgs ? import { } }: - -let nixery = import ./default.nix { inherit pkgs; }; -in pkgs.stdenv.mkDerivation { - name = "nixery-dev-shell"; - - buildInputs = with pkgs; [ jq nixery.nixery-prepare-image ]; -} diff --git a/tools/nixery/storage/filesystem.go b/tools/nixery/storage/filesystem.go deleted file mode 100644 index 3df4420f0..000000000 --- a/tools/nixery/storage/filesystem.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Filesystem storage backend for Nixery. -package storage - -import ( - "context" - "fmt" - "io" - "net/http" - "os" - "path" - - "github.com/pkg/xattr" - log "github.com/sirupsen/logrus" -) - -type FSBackend struct { - path string -} - -func NewFSBackend() (*FSBackend, error) { - p := os.Getenv("STORAGE_PATH") - if p == "" { - return nil, fmt.Errorf("STORAGE_PATH must be set for filesystem storage") - } - - p = path.Clean(p) - err := os.MkdirAll(p, 0755) - if err != nil { - return nil, fmt.Errorf("failed to create storage dir: %s", err) - } - - return &FSBackend{p}, nil -} - -func (b *FSBackend) Name() string { - return fmt.Sprintf("Filesystem (%s)", b.path) -} - -func (b *FSBackend) Persist(ctx context.Context, key, contentType string, f Persister) (string, int64, error) { - full := path.Join(b.path, key) - dir := path.Dir(full) - err := os.MkdirAll(dir, 0755) - if err != nil { - log.WithError(err).WithField("path", dir).Error("failed to create storage directory") - return "", 0, err - } - - file, err := os.OpenFile(full, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - log.WithError(err).WithField("file", full).Error("failed to write file") - return "", 0, err - } - defer file.Close() - - err = xattr.Set(full, "user.mime_type", []byte(contentType)) - if err != nil { - log.WithError(err).WithField("file", full).Error("failed to store file type in xattrs") - return "", 0, err - } - - return f(file) -} - -func (b *FSBackend) Fetch(ctx context.Context, key string) (io.ReadCloser, error) { - full := path.Join(b.path, key) - return os.Open(full) -} - -func (b *FSBackend) Move(ctx context.Context, old, new string) error { - newpath := path.Join(b.path, new) - err := os.MkdirAll(path.Dir(newpath), 0755) - if err != nil { - return err - } - - return os.Rename(path.Join(b.path, old), newpath) -} - -func (b *FSBackend) Serve(digest string, r *http.Request, w http.ResponseWriter) error { - p := path.Join(b.path, "layers", digest) - - log.WithFields(log.Fields{ - "digest": digest, - "path": p, - }).Info("serving blob from filesystem") - - contentType, err := xattr.Get(p, "user.mime_type") - if err != nil { - log.WithError(err).WithField("file", p).Error("failed to read file type from xattrs") - return err - } - w.Header().Add("Content-Type", string(contentType)) - - http.ServeFile(w, r, p) - return nil -} diff --git a/tools/nixery/storage/gcs.go b/tools/nixery/storage/gcs.go deleted file mode 100644 index 752c6bbd8..000000000 --- a/tools/nixery/storage/gcs.go +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Google Cloud Storage backend for Nixery. -package storage - -import ( - "context" - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "os" - "time" - - "cloud.google.com/go/storage" - log "github.com/sirupsen/logrus" - "golang.org/x/oauth2/google" -) - -// HTTP client to use for direct calls to APIs that are not part of the SDK -var client = &http.Client{} - -// API scope needed for renaming objects in GCS -const gcsScope = "https://www.googleapis.com/auth/devstorage.read_write" - -type GCSBackend struct { - bucket string - handle *storage.BucketHandle - signing *storage.SignedURLOptions -} - -// Constructs a new GCS bucket backend based on the configured -// environment variables. -func NewGCSBackend() (*GCSBackend, error) { - bucket := os.Getenv("GCS_BUCKET") - if bucket == "" { - return nil, fmt.Errorf("GCS_BUCKET must be configured for GCS usage") - } - - ctx := context.Background() - client, err := storage.NewClient(ctx) - if err != nil { - log.WithError(err).Fatal("failed to set up Cloud Storage client") - } - - handle := client.Bucket(bucket) - - if _, err := handle.Attrs(ctx); err != nil { - log.WithError(err).WithField("bucket", bucket).Error("could not access configured bucket") - return nil, err - } - - signing, err := signingOptsFromEnv() - if err != nil { - log.WithError(err).Error("failed to configure GCS bucket signing") - return nil, err - } - - return &GCSBackend{ - bucket: bucket, - handle: handle, - signing: signing, - }, nil -} - -func (b *GCSBackend) Name() string { - return "Google Cloud Storage (" + b.bucket + ")" -} - -func (b *GCSBackend) Persist(ctx context.Context, path, contentType string, f Persister) (string, int64, error) { - obj := b.handle.Object(path) - w := obj.NewWriter(ctx) - - hash, size, err := f(w) - if err != nil { - log.WithError(err).WithField("path", path).Error("failed to write to GCS") - return hash, size, err - } - - err = w.Close() - if err != nil { - log.WithError(err).WithField("path", path).Error("failed to complete GCS upload") - return hash, size, err - } - - // GCS natively supports content types for objects, which will be - // used when serving them back. - if contentType != "" { - _, err = obj.Update(ctx, storage.ObjectAttrsToUpdate{ - ContentType: contentType, - }) - - if err != nil { - log.WithError(err).WithField("path", path).Error("failed to update object attrs") - return hash, size, err - } - } - - return hash, size, nil -} - -func (b *GCSBackend) Fetch(ctx context.Context, path string) (io.ReadCloser, error) { - obj := b.handle.Object(path) - - // Probe whether the file exists before trying to fetch it - _, err := obj.Attrs(ctx) - if err != nil { - return nil, err - } - - return obj.NewReader(ctx) -} - -// renameObject renames an object in the specified Cloud Storage -// bucket. -// -// The Go API for Cloud Storage does not support renaming objects, but -// the HTTP API does. The code below makes the relevant call manually. -func (b *GCSBackend) Move(ctx context.Context, old, new string) error { - creds, err := google.FindDefaultCredentials(ctx, gcsScope) - if err != nil { - return err - } - - token, err := creds.TokenSource.Token() - if err != nil { - return err - } - - // as per https://cloud.google.com/storage/docs/renaming-copying-moving-objects#rename - url := fmt.Sprintf( - "https://www.googleapis.com/storage/v1/b/%s/o/%s/rewriteTo/b/%s/o/%s", - url.PathEscape(b.bucket), url.PathEscape(old), - url.PathEscape(b.bucket), url.PathEscape(new), - ) - - req, err := http.NewRequest("POST", url, nil) - req.Header.Add("Authorization", "Bearer "+token.AccessToken) - _, err = client.Do(req) - if err != nil { - return err - } - - // It seems that 'rewriteTo' copies objects instead of - // renaming/moving them, hence a deletion call afterwards is - // required. - if err = b.handle.Object(old).Delete(ctx); err != nil { - log.WithError(err).WithFields(log.Fields{ - "new": new, - "old": old, - }).Warn("failed to delete renamed object") - - // this error should not break renaming and is not returned - } - - return nil -} - -func (b *GCSBackend) Serve(digest string, r *http.Request, w http.ResponseWriter) error { - url, err := b.constructLayerUrl(digest) - if err != nil { - log.WithError(err).WithFields(log.Fields{ - "digest": digest, - "bucket": b.bucket, - }).Error("failed to sign GCS URL") - - return err - } - - log.WithField("digest", digest).Info("redirecting blob request to GCS bucket") - - w.Header().Set("Location", url) - w.WriteHeader(303) - return nil -} - -// Configure GCS URL signing in the presence of a service account key -// (toggled if the user has set GOOGLE_APPLICATION_CREDENTIALS). -func signingOptsFromEnv() (*storage.SignedURLOptions, error) { - path := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS") - if path == "" { - // No credentials configured -> no URL signing - return nil, nil - } - - key, err := ioutil.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("failed to read service account key: %s", err) - } - - conf, err := google.JWTConfigFromJSON(key) - if err != nil { - return nil, fmt.Errorf("failed to parse service account key: %s", err) - } - - log.WithField("account", conf.Email).Info("GCS URL signing enabled") - - return &storage.SignedURLOptions{ - Scheme: storage.SigningSchemeV4, - GoogleAccessID: conf.Email, - PrivateKey: conf.PrivateKey, - Method: "GET", - }, nil -} - -// layerRedirect constructs the public URL of the layer object in the Cloud -// Storage bucket, signs it and redirects the user there. -// -// Signing the URL allows unauthenticated clients to retrieve objects from the -// bucket. -// -// In case signing is not configured, a redirect to storage.googleapis.com is -// issued, which means the underlying bucket objects need to be publicly -// accessible. -// -// The Docker client is known to follow redirects, but this might not be true -// for all other registry clients. -func (b *GCSBackend) constructLayerUrl(digest string) (string, error) { - log.WithField("layer", digest).Info("redirecting layer request to bucket") - object := "layers/" + digest - - if b.signing != nil { - opts := *b.signing - opts.Expires = time.Now().Add(5 * time.Minute) - return storage.SignedURL(b.bucket, object, &opts) - } else { - return ("https://storage.googleapis.com/" + b.bucket + "/" + object), nil - } -} diff --git a/tools/nixery/storage/storage.go b/tools/nixery/storage/storage.go deleted file mode 100644 index 5500d6164..000000000 --- a/tools/nixery/storage/storage.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2022 The TVL Contributors -// SPDX-License-Identifier: Apache-2.0 - -// Package storage implements an interface that can be implemented by -// storage backends, such as Google Cloud Storage or the local -// filesystem. -package storage - -import ( - "context" - "io" - "net/http" -) - -type Persister = func(io.Writer) (string, int64, error) - -type Backend interface { - // Name returns the name of the storage backend, for use in - // log messages and such. - Name() string - - // Persist provides a user-supplied function with a writer - // that stores data in the storage backend. - // - // It needs to return the SHA256 hash of the data written as - // well as the total number of bytes, as those are required - // for the image manifest. - Persist(ctx context.Context, path, contentType string, f Persister) (string, int64, error) - - // Fetch retrieves data from the storage backend. - Fetch(ctx context.Context, path string) (io.ReadCloser, error) - - // Move renames a path inside the storage backend. This is - // used for staging uploads while calculating their hashes. - Move(ctx context.Context, old, new string) error - - // Serve provides a handler function to serve HTTP requests - // for objects in the storage backend. - Serve(digest string, r *http.Request, w http.ResponseWriter) error -} diff --git a/tools/nixery/web/index.html b/tools/nixery/web/index.html deleted file mode 100644 index 25136af15..000000000 --- a/tools/nixery/web/index.html +++ /dev/null @@ -1,166 +0,0 @@ - - - - - - - - Nixery - - - Nixery -
    - -

    - Welcome to this instance of Nixery, an ad-hoc container image registry that provides - packages from the Nix package manager. -

    - -

    - You can pull container images from this registry - at nixery.dev by appending any - packages that you need in the URL, separated by slashes. -

    - - - -

    Demo

    - - - - - -

    Usage

    - -

    - These usage examples assume that you use Docker, but should not be much different for - other OCI-compatible platforms. -

    - -

    - Pull an image from this registry, separating each package you want included by a - slash: -

    - -
    docker pull nixery.dev/shell/git/htop
    - -

    - This gives you an image with git, htop and an interactively - configured shell. You could run it like this: -

    - -
    docker run -ti nixery.dev/shell/git/htop bash
    - -

    - Each path segment corresponds either to a key in the Nix package set, or a - meta-package that automatically expands to several other packages. -

    - -

    - Meta-packages must be the first path component if they are used. - Currently there are only two meta-packages: -

    - -
      -
    • -

      - shell, which provides a bash-shell with interactive - configuration and standard tools like coreutils

      -
    • -
    • -

      arm64, which provides ARM64 binaries

      -
    • -
    - -

    FAQ

    - -

    - - How does this work? -

    - -

    - The short version is that we use the Nix package manager and an optimised - layering strategy. -

    - -

    - Check out the Nixery talk - from NixCon 2019 for more information. -

    - -

    - - Should I depend on nixery.dev in production? -

    - -

    - While we appreciate the enthusiasm, if you would like to use Nixery in your production - project we recommend setting up a private instance. The public Nixery - at nixery.dev is run on a best-effort basis and we make no guarantees - about availability. -

    - -

    - - Who made this? -

    - -

    - Nixery was written by tazjin, originally at Google. - These days Nixery is maintained by TVL. -

    -

    - Nixery would not be possible without the many people that have contributed to Nix and - nixpkgs over time, maybe you could become one of them? -

    - -

    - - Where is the source code for this? -

    - -

    - Nixery lives in the TVL - monorepo. All development happens there and follows - the TVL contribution - guidelines. -

    - -

    - We mirror the source code to - Github but do not guarantee that anyone will look at PRs or issues there. -

    - -
    - - - - diff --git a/tools/nixery/web/nixery-logo.png b/tools/nixery/web/nixery-logo.png deleted file mode 100644 index fcf77df3d..000000000 Binary files a/tools/nixery/web/nixery-logo.png and /dev/null differ diff --git a/tools/nsfv-setup/default.nix b/tools/nsfv-setup/default.nix deleted file mode 100644 index 1e353e326..000000000 --- a/tools/nsfv-setup/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -# Configures a running Pulseaudio instance with an LADSP filter that -# creates a noise-cancelling sink. -# -# This can be used to, for example, cancel noise from an incoming -# video conferencing audio stream. -# -# There are some caveats, for example this will not distinguish -# between noise from different participants and I have no idea what -# happens if the default sink goes away. -# -# If this script is run while an NSFV sink exists, the existing sink -# will first be removed. -{ depot, pkgs, ... }: - -let - inherit (pkgs) ripgrep pulseaudio; - inherit (depot.third_party) nsfv; -in -pkgs.writeShellScriptBin "nsfv-setup" '' - export PATH="${ripgrep}/bin:${pulseaudio}/bin:$PATH" - - if pacmd list-sinks | rg librnnoise_ladspa.so >/dev/null; then - pactl unload-module module-ladspa-sink - fi - - SINK=$(${pulseaudio}/bin/pacmd info | ${ripgrep}/bin/rg -r '$1' '^Default sink name: (.*)$') - echo "Setting up NSFV filtering to sink ''${SINK}" - ${pulseaudio}/bin/pacmd load-module module-ladspa-sink sink_name=NSFV sink_master=''${SINK} label=noise_suppressor_mono plugin=${nsfv}/lib/ladspa/librnnoise_ladspa.so control=42 rate=48000 -'' diff --git a/tvix/README.md b/tvix/README.md deleted file mode 100644 index b66adda2b..000000000 --- a/tvix/README.md +++ /dev/null @@ -1,133 +0,0 @@ -
    - -
    - ------------------ - -Tvix is a new implementation of the Nix language and package manager. See the -[announcement post][post-1] for information about the background of this -project. - -Tvix is developed by [TVL][tvl] in our monorepo, the `depot`, at -[//tvix][tvix-src]. Code reviews take place on [Gerrit][tvix-gerrit], bugs are -filed in [our issue tracker][b]. - -For more information about Tvix, feel free to reach out. We are interested in -people who would like to help us review designs, brainstorm and describe -requirements that we may not yet have considered. - -Development discussion is focused around two IRC channels, which are also -available [via XMPP][hackint-xmpp] and [via Matrix][hackint-matrix]. - -1. TVL runs the [`#tvl` channel][tvl-getting-in-touch] on [hackint][]. - Tvix-related discussion in this channel is focused on eval, and on (almost) - 1:1 replacements of C++ Nix with Rust components. - -2. The separate [`#tvix-dev`][tvix-dev-irc] channel ([on - Matrix][tvix-dev-matrix]) focuses on the content-addressed store model, - innovating on the plain files approach used in C++ Nix. - -There is also a low-traffic [mailing list][] with occasional design discussions. - -Contributions to Tvix follow the TVL [review flow][review-docs] and -[contribution guidelines][contributing]. - -[post-1]: https://tvl.fyi/blog/rewriting-nix -[tvl]: https://tvl.fyi -[tvix-src]: https://code.tvl.fyi/tree/tvix/ -[tvix-gerrit]: https://cl.tvl.fyi/q/path:%255Etvix.* -[b]: https://b.tvl.fyi -[tvl-getting-in-touch]: https://tvl.fyi/#getting-in-touch -[mailing list]: https://inbox.tvl.su -[review-docs]: https://code.tvl.fyi/about/docs/REVIEWS.md -[contributing]: https://code.tvl.fyi/about/docs/CONTRIBUTING.md -[tvix-dev-irc]: ircs://irc.hackint.org:6697/#tvix-dev -[hackint]: https://hackint.org/ -[hackint-xmpp]: https://hackint.org/transport/xmpp -[tvix-dev-xmpp]: xmpp:#tvix-dev@irc.hackint.org?join -[hackint-matrix]: https://hackint.org/transport/matrix -[tvix-dev-matrix]: https://matrix.to/#/#tvix-dev:hackint.org -[tvix-dev-webchat]: https://webirc.hackint.org/#ircs://irc.hackint.org/#tvix-dev - -WARNING: Tvix is not ready for use in production. None of our current APIs -should be considered stable in any way. - -WARNING: Any other instances of this project or repository are -[`josh`-mirrors][josh]. We do not accept code contributions or issues outside of -the methods outlined above. - -[josh]: https://github.com/josh-project/josh - -## Components - -This folder contains the following components: - -* `//tvix/boot` - tooling to boot MicroVMs off of `tvix-[ca]store` -* `//tvix/build` - a generic (Nix-unaware) builder protocol and various implementations -* `//tvix/castore` - subtree storage/transfer in a content-addressed fashion -* `//tvix/cli` - preliminary REPL & CLI implementation for Tvix -* `//tvix/docs` - standalone documentation -* `//tvix/eval` - an implementation of the Nix programming language -* `//tvix/glue` - combines tvix-eval with tvix-[ca]store and tvix-build, implementation of build- and import-related builtins -* `//tvix/nar-bridge` - a HTTP webserver providing a Nix HTTP Binary Cache interface in front of a tvix-store -* `//tvix/nix-compat` - a Rust library for compatibility with C++ Nix, features like encodings and hashing schemes and formats -* `//tvix/nix-daemon` - a Nix-compatible store daemon backed by Tvix -* `//tvix/serde` - a Rust library for using the Nix language for app configuration -* `//tvix/store` - a "filesystem" linking Nix store paths and metadata with the content-addressed layer -* `//tvix/tracing` - unified library to configure logging, tracing, instrumentation and progress concerns - -Some additional folders with auxiliary things exist and can be explored at your -leisure. - -## Building the CLI - -The CLI can also be built with standard Rust tooling (i.e. `cargo build`), -as long as you are in a shell with the right dependencies. - - - If you cloned the full monorepo, it can be provided by - `mg shell //tvix:shell`. - - If you cloned the `tvix` workspace only - (`git clone https://code.tvl.fyi/depot.git:workspace=views/tvix.git`), - `nix-shell` provides it. - -If you're in the TVL monorepo, you can also run `mg build //tvix/cli` -(or `mg build` from inside that folder) for a more incremental build. - -Please follow the depot-wide instructions on how to get `mg` and use the depot -tooling. - -### Compatibility -**Important note:** We only use and test Nix builds of our software -against Nix 2.3. There are a variety of bugs and subtle problems in -newer Nix versions which we do not have the bandwidth to address, -builds in newer Nix versions may or may not work. - -## Rust projects, crate2nix - -Some parts of Tvix are written in Rust. To simplify the dependency -management on the Nix side of these builds, we use `crate2nix` in a -single Rust workspace in `//tvix` to maintain the Nix build -configuration. - -When making changes to Cargo dependency configuration in any of the -Rust projects under `//tvix`, be sure to run -`mg run //tools:crate2nix-generate` in `//tvix` itself and commit the changes -to the generated `Cargo.nix` file. This only applies to the full TVL checkout. - -When adding/removing a Cargo feature for a crate, you will want to add it to the -features power set that gets tested in CI. For each crate there's a default.nix with a -`mkFeaturePowerset` invocation, modify the list to include/remove the feature. -Note that you don't want to add "collection" features, such as `fs` for tvix-[ca]store or `default`. - -## License structure - -All code implemented for Tvix is licensed under the GPL-3.0, with the -exception of the protocol buffer definitions used for communication -between services which are available under a more permissive license -(MIT). - -The idea behind this structure is that any direct usage of our code -(e.g. linking to it, embedding the evaluator, etc.) will fall under -the terms of the GPL3, but users are free to implement their own -components speaking these protocols under the terms of the MIT -license. diff --git a/tvix/buildkite.yml b/tvix/buildkite.yml deleted file mode 100644 index 2a24ca426..000000000 --- a/tvix/buildkite.yml +++ /dev/null @@ -1,10 +0,0 @@ -# Build pipeline for the filtered //views/tvix workspace of depot. This -# pipeline is triggered by each build of canon. -# -# Pipeline status is visible on https://buildkite.com/tvl/tvix - -steps: - - label: ":crab: cargo build" - command: | - nix-shell --run "cargo build && cargo test" - timeout_in_minutes: 10 diff --git a/tvix/eval/default.nix b/tvix/eval/default.nix index 9370c81ce..72e21c966 100644 --- a/tvix/eval/default.nix +++ b/tvix/eval/default.nix @@ -5,7 +5,8 @@ runTests = true; # Make C++ Nix available, to compare eval results against. - testInputs = [ pkgs.nix ]; + # This needs Nix 2.3, as nix_oracle.rs fails with pkgs.nix + testInputs = [ pkgs.nix_2_3 ]; }).overrideAttrs (old: rec { meta.ci.targets = lib.filter (x: lib.hasPrefix "with-features" x || x == "no-features") (lib.attrNames passthru); passthru = old.passthru // (depot.tvix.utils.mkFeaturePowerset { diff --git a/tvix/scripts/bench-windtunnel.sh b/tvix/scripts/bench-windtunnel.sh deleted file mode 100755 index aa359a8a8..000000000 --- a/tvix/scripts/bench-windtunnel.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env nix-shell -#!nix-shell -i bash ../.. -A tvix.shell - -# Benchmark script that runs inside the Windtunnel build agent - -set -euo pipefail - -echo "Running benchmarks for tvix..." -pushd "$(dirname "$(dirname "$0")")" -cargo bench -windtunnel-cli report -f criterion-rust . -popd - -echo "Running tvix macrobenchmarks..." -pushd "$(dirname "$(dirname "$0")")" - -depot_nixpkgs_path="$(nix eval --raw '("${((import ../third_party/sources {}).nixpkgs)}")')" -pinned_nixpkgs_path="$(nix eval --raw '(builtins.fetchTarball {url = "https://github.com/NixOS/nixpkgs/archive/91050ea1e57e50388fa87a3302ba12d188ef723a.tar.gz"; sha256 = "1hf6cgaci1n186kkkjq106ryf8mmlq9vnwgfwh625wa8hfgdn4dm";})')" - -cargo build --release --bin tvix -hyperfine --export-json ./results.json \ - -n 'tvix-eval-depot-nixpkgs-hello' "target/release/tvix -E '(import ${depot_nixpkgs_path} {}).hello.outPath'" \ - -n 'tvix-eval-depot-nixpkgs-cross-hello' "target/release/tvix -E '(import ${depot_nixpkgs_path} {}).pkgsCross.aarch64-multiplatform.hello.outPath'" \ - -n 'tvix-eval-pinned-nixpkgs-hello' "target/release/tvix -E '(import ${pinned_nixpkgs_path} {}).hello.outPath'" \ - -n 'tvix-eval-pinned-nixpkgs-cross-hello' "target/release/tvix -E '(import ${pinned_nixpkgs_path} {}).pkgsCross.aarch64-multiplatform.hello.outPath'" -windtunnel-cli report -f hyperfine-json ./results.json -popd diff --git a/tvix/website/landing-en.md b/tvix/website/landing-en.md deleted file mode 100644 index 8f3e2c41c..000000000 --- a/tvix/website/landing-en.md +++ /dev/null @@ -1,39 +0,0 @@ - - ------------------- - -Tvix is a new implementation of Nix, a purely-functional package manager. It -aims to have a modular implementation, in which different components can be -reused or replaced based on the use-case. - -Tvix is developed as a GPLv3-licensed open-source project by -[TVL][], with source code available in the [TVL monorepo][]. - -There are several projects within Tvix, such as: - -* `//tvix/castore` - subtree storage/transfer in a content-addressed fashion -* `//tvix/cli` - preliminary REPL & CLI implementation for Tvix -* `//tvix/eval` - an implementation of the Nix programming language -* `//tvix/nar-bridge[-go]` - a HTTP webserver providing a Nix HTTP Binary Cache interface in front of a tvix-store -* `//tvix/nix-compat` - a Rust library for compatibility with C++ Nix, features like encodings and hashing schemes and formats -* `//tvix/serde` - a Rust library for using the Nix language for app configuration -* `//tvix/store` - a "filesystem" linking Nix store paths and metadata with the content-addressed layer -* ... and a handful others! - -The language evaluator can be toyed with in [Tvixbolt][], and you can check out -the [Tvix README][] ([GitHub mirror][gh]) for additional information on the -project and development workflows. - -Developer documentation for some parts of Tvix is [available online][docs]. - -[TVL]: https://tvl.fyi -[TVL monorepo]: https://code.tvl.fyi/tree/tvix -[Tvixbolt]: https://bolt.tvix.dev -[Tvix README]: https://code.tvl.fyi/about/tvix -[gh]: https://github.com/tvlfyi/tvix/ -[docs]: https://docs.tvix.dev - -------------------- - -Check out the latest Tvix-related blog posts from TVL's website: diff --git a/users/Profpatsch/.envrc b/users/Profpatsch/.envrc deleted file mode 100644 index c91f92375..000000000 --- a/users/Profpatsch/.envrc +++ /dev/null @@ -1,5 +0,0 @@ -if pass apps/declib/mastodon_access_token >/dev/null; then - export DECLIB_MASTODON_ACCESS_TOKEN=$(pass apps/declib/mastodon_access_token) -fi - -eval "$(lorri direnv)" diff --git a/users/Profpatsch/.gitignore b/users/Profpatsch/.gitignore deleted file mode 100644 index b13922700..000000000 --- a/users/Profpatsch/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -dist-newstyle/ -result-* - -/node-modules/ -# ignore all package-locks (for now?) -package-lock.json diff --git a/users/Profpatsch/.hlint.yaml b/users/Profpatsch/.hlint.yaml deleted file mode 100644 index 12b7c61b7..000000000 --- a/users/Profpatsch/.hlint.yaml +++ /dev/null @@ -1,359 +0,0 @@ -# HLint configuration file -# https://github.com/ndmitchell/hlint -# Run `hlint --default` to see the example configuration file. -########################## - -# WARNING: These need to be synced with the default-extensions field -# in the cabal file. -- arguments: [-XGHC2021, -XOverloadedRecordDot] - -# Ignore some builtin hints - -# often functions are more readable with explicit arguments -- ignore: { name: Eta reduce } - -# these redundancy warnings are just completely irrelevant -- ignore: { name: Redundant bracket } -- ignore: { name: Move brackets to avoid $ } -- ignore: { name: Redundant $ } -- ignore: { name: Redundant do } -- ignore: { name: Redundant multi-way if } - -# allow case-matching on bool, because why not -- ignore: { name: Use if } - -# hlint cannot distinguish actual newtypes from data types -# that accidentally have only one field -# (but might have more in the future). -# Since it’s a mostly irrelevant runtime optimization, we don’t care. -- ignore: { name: Use newtype instead of data } - -# these lead to harder-to-read/more implicit code -- ignore: { name: Use fmap } -- ignore: { name: Use <$> } -- ignore: { name: Use tuple-section } -- ignore: { name: Use forM_ } -- ignore: { name: Functor law } -- ignore: { name: Use maybe } - -# fst and snd are usually a code smell and should be explicit matches, _naming the ignored side. -- ignore: { name: Use fst } -- ignore: { name: Use snd } -- ignore: { name: Use fromMaybe } -- ignore: { name: Use const } -- ignore: { name: Replace case with maybe } -- ignore: { name: Replace case with fromMaybe } -- ignore: { name: Avoid lambda } -- ignore: { name: Avoid lambda using `infix` } -- ignore: { name: Use curry } -- ignore: { name: Use uncurry } -- ignore: { name: Use first } -- ignore: { name: Redundant first } -- ignore: { name: Use second } -- ignore: { name: Use bimap } -# just use `not x` -- ignore: { name: Use unless } -- ignore: { name: Redundant <&> } - -# list comprehensions are a seldomly used part of the Haskell language -# and they introduce syntactic overhead that is usually not worth the conciseness -- ignore: { name: Use list comprehension } - -# Seems to be buggy in cases -- ignore: { name: Use section } - -# multiple maps in a row are usually used for clarity, -# and the compiler will optimize them away, thank you very much. -- ignore: { name: Use map once } -- ignore: { name: Fuse foldr/map } -- ignore: { name: Fuse traverse/map } -- ignore: { name: Fuse traverse_/map } -- ignore: { name: Fuse traverse/<$> } - -# this is silly, why would I use a special function if I can just (heh) `== Nothing` -- ignore: { name: Use isNothing } - -# The duplication heuristic is not very smart -# and more annoying than helpful. -# see https://github.com/ndmitchell/hlint/issues/1009 -- ignore: { name: Reduce duplication } - -# Stops the pattern match trick -- ignore: { name: Use record patterns } -- ignore: { name: Use null } -- ignore: { name: Use uncurry } - -# we don’t want void, see below -- ignore: { name: Use void } - -- functions: - # disallow Enum instance functions, they are partial - - name: Prelude.succ - within: [Relude.Extra.Enum] - message: "Dangerous, will fail for highest element" - - name: Prelude.pred - within: [Relude.Extra.Enum] - message: "Dangerous, will fail for lowest element" - - name: Prelude.toEnum - within: [] - message: "Extremely partial" - - name: Prelude.fromEnum - within: [] - message: "Dangerous for most uses" - - name: Prelude.enumFrom - within: [] - - name: Prelude.enumFromThen - within: [] - - name: Prelude.enumFromThenTo - within: [] - - name: Prelude.oundedEnumFrom - within: [] - - name: Prelude.boundedEnumFromThen - within: [] - - - name: Text.Read.readMaybe - within: - # The BSON ObjectId depends on Read for parsing - - Milkmap.Milkmap - - Milkmap.FieldData.Value - message: "`readMaybe` is probably not what you want for parsing values, please use the `FieldParser` module." - - # `void` discards its argument and is polymorphic, - # thus making it brittle in the face of code changes. - # (see https://tech.freckle.com/2020/09/23/void-is-a-smell/) - # Use an explicit `_ <- …` instead. - - name: Data.Functor.void - within: [] - message: "`void` leads to bugs. Use an explicit `_ <- …` instead" - - - name: Data.Foldable.length - within: ["MyPrelude"] - message: "`Data.Foldable.length` is dangerous to use, because it also works on types you wouldn’t expect, like `length (3,4) == 1` and `length (Just 2) == 1`. Use the `length` function for your specific type instead, for example `List.length` or `Map.length`." - - - name: Prelude.length - within: ["MyPrelude"] - message: "`Prelude.length` is dangerous to use, because it also works on types you wouldn’t expect, like `length (3,4) == 1` and `length (Just 2) == 1`. Use the `length` function for your specific type instead, for example `List.length` or `Map.length`." - - # Using an explicit lambda with its argument “underscored” - # is more clear in every case. - # e.g. `const True` => `\_request -> True` - # shows the reader that the ignored argument was a request. - - name: Prelude.const - within: [] - message: "Replace `const` with an explicit lambda with type annotation for code clarity and type safety, e.g.: `const True` => `\\(_ :: Request) -> True`. If you really don’t want to spell out the type (which might lead to bugs!), you can also use something like `\_request -> True`." - - - name: Data.List.nub - within: [] - message: "O(n²), use `Data.Containers.ListUtils.nubOrd" - - - name: Prelude.maximum - within: [] - message: "`maximum` crashes on empty list; use non-empty lists and `maximum1`" - - - name: Data.List.maximum - within: [] - message: "`maximum` crashes on empty list; use non-empty lists and `maximum1`" - - - name: Prelude.minimum - within: [] - message: "`minimum` crashes on empty list; use non-empty lists and `minimum1`" - - - name: Data.List.minimum - within: [] - message: "`minimum` crashes on empty list; use non-empty lists and `minimum1`" - - - name: Data.Foldable.maximum - within: [] - message: "`maximum` crashes on empty foldable stucture; use Foldable1 and `maximum1`." - - - name: Data.Foldable.minimum - within: [] - message: "`minimum` crashes on empty foldable stucture; use Foldable1 and `minimum1`." - - # Using prelude functions instead of stdlib functions - - - name: "Data.Text.Encoding.encodeUtf8" - within: ["MyPrelude"] - message: "Use `textToBytesUtf8`" - - - name: "Data.Text.Lazy.Encoding.encodeUtf8" - within: ["MyPrelude"] - message: "Use `textToBytesUtf8Lazy`" - - - name: "Data.Text.Encoding.decodeUtf8'" - within: ["MyPrelude"] - message: "Use `bytesToTextUtf8`" - - - name: "Data.Text.Encoding.Lazy.decodeUtf8'" - within: ["MyPrelude"] - message: "Use `bytesToTextUtf8Lazy`" - - - name: "Data.Text.Encoding.decodeUtf8" - within: ["MyPrelude"] - message: "Either check for errors with `bytesToTextUtf8`, decode leniently with unicode replacement characters with `bytesToTextUtf8Lenient` or use the crashing version `bytesToTextUtf8Unsafe` (discouraged)." - - - name: "Data.Text.Encoding.Lazy.decodeUtf8" - within: ["MyPrelude"] - message: "Either check for errors with `bytesToTextUtf8Lazy`, decode leniently with unicode replacement characters with `bytesToTextUtf8LenientLazy` or use the crashing version `bytesToTextUtf8UnsafeLazy` (discouraged)." - - - name: "Data.Text.Lazy.toStrict" - within: ["MyPrelude"] - message: "Use `toStrict`" - - - name: "Data.Text.Lazy.fromStrict" - within: ["MyPrelude"] - message: "Use `toLazy`" - - - name: "Data.ByteString.Lazy.toStrict" - within: ["MyPrelude"] - message: "Use `toStrictBytes`" - - - name: "Data.ByteString.Lazy.fromStrict" - within: ["MyPrelude"] - message: "Use `toLazyBytes`" - - - name: "Data.Text.unpack" - within: ["MyPrelude"] - message: "Use `textToString`" - - - name: "Data.Text.pack" - within: ["MyPrelude"] - message: "Use `stringToText`" - - - name: "Data.Maybe.listToMaybe" - within: [] - message: | - `listToMaybe`` throws away everything but the first element of a list (it is essentially `safeHead`). - If that is what you want, please use a pattern match like - - ``` - case xs of - [] -> … - (x:_) -> … - ``` - - - name: "Data.List.head" - within: [] - message: | - `List.head` fails on an empty list. I didn’t think I have to say this, but please use a pattern match on the list, like: - - ``` - case xs of - [] -> … error handling … - (x:_) -> … - ``` - - Also think about why the rest of the list should be ignored. - - - name: "Prelude.head" - within: [] - message: | - `List.head` fails on an empty list. I didn’t think I have to say this, but please use a pattern match on the list, like. - - ``` - case xs of - [] -> … error handling … - (x:_) -> … - ``` - - Also think about why the rest of the list should be ignored. - - - name: "Data.Maybe.fromJust" - within: [] - message: | - `Maybe.fromJust` is obviously partial. Please use a pattern match. - - In case you actually want to throw an error on an empty list, - please add an error message, like so: - - ``` - myMaybe & annotate "my error message" & unwrapError - ``` - - If you are in `IO`, use `unwrapIOError` instead, - or throw a monad-specific error. - - - name: "Data.Either.fromLeft" - within: [] - message: | - `Either.fromLeft` is obviously partial. Please use a pattern match. - - - name: "Data.Either.fromRight" - within: [] - message: | - `Either.fromRight` is obviously partial. Please use a pattern match. - -# Make restricted functions into an error if found -- error: { name: "Avoid restricted function, see comment in .hlint.yaml" } - -# Some functions that have (more modern) aliases. -# They are not dangerous per se, -# but we want to make it easier to read our code so we should -# make sure we don’t use too many things that are renames. - -- hint: - lhs: "undefined" - rhs: "todo" - note: "`undefined` is a silent error, `todo` will display a warning as long as it exists in the code." - -- hint: - lhs: "return" - rhs: "pure" - note: "Use `pure` from `Applicative` instead, it’s the exact same function." - -- hint: - lhs: "mapM" - rhs: "traverse" - note: "Use `traverse` from `Traversable` instead. It’s the exact same function." - -- hint: - lhs: "mapM_" - rhs: "traverse_" - note: "Use `traverse_` from `Traversable` instead. It’s the exact same function." - -- hint: - lhs: "forM" - rhs: "for" - note: "Use `for` from `Traversable` instead. It’s the exact same function." - -- hint: - lhs: "forM_" - rhs: "for_" - note: "Use `for_` from `Traversable` instead. It’s the exact same function." - -- hint: - lhs: "stringToText (show x)" - rhs: "showToText x" - -- hint: - lhs: "Data.Set.toList (Data.Set.fromList x)" - rhs: "List.nubOrd x" - note: "`nubOrd` removes duplicate elements from a list." - -- modules: - # Disallowed Modules - - name: Data.Map - within: [] - message: "Lazy maps leak space, use `import Data.Map.Strict as Map` instead" - - name: Control.Monad.Writer - within: [] - message: "Lazy writers leak space, use `Control.Monad.Trans.Writer.CPS` instead" - - name: Control.Monad.Trans.Writer.Lazy - within: [] - message: "Lazy writers leak space, use `Control.Monad.Trans.Writer.CPS` instead" - - name: Control.Monad.Trans.Writer.Strict - within: [] - message: "Even strict writers leak space, use `Control.Monad.Trans.Writer.CPS` instead" - - # Qualified module imports - - { name: Data.Map.Strict, as: Map } - - { name: Data.HashMap.Strict, as: HashMap } - - { name: Data.Set, as: Set } - - { name: Data.ByteString.Char8, as: Char8 } - - { name: Data.ByteString.Lazy.Char8, as: Char8.Lazy } - - { name: Data.Text, as: Text } - - { name: Data.Vector, as: Vector } - - { name: Data.Vault.Lazy, as: Vault } - - { name: Data.Aeson, as: Json } - - { name: Data.Aeson.Types, as: Json } - - { name: Data.Aeson.BetterErrors as Json } diff --git a/users/Profpatsch/.prettierrc b/users/Profpatsch/.prettierrc deleted file mode 100644 index e97f84aba..000000000 --- a/users/Profpatsch/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "trailingComma": "all", - "tabWidth": 2, - "semi": true, - "singleQuote": true, - "printWidth": 90, - "arrowParens": "avoid" -} diff --git a/users/Profpatsch/.vscode/launch.json b/users/Profpatsch/.vscode/launch.json deleted file mode 100644 index dca6a4dc6..000000000 --- a/users/Profpatsch/.vscode/launch.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "node: Attach to running process", - "port": 9229, - "request": "attach", - "skipFiles": [ - "/**" - ], - "type": "node" - }, - { - "name": "run declib", - "type": "node", - "cwd": "${workspaceFolder}/declib", - "request": "launch", - "runtimeExecutable": "ninja", - "runtimeArgs": [ - "run", - ], - }, - { - "type": "node", - "name": "Run tap-bpm", - "skipFiles": [ - "/**" - ], - "request": "launch", - "program": "${workspaceFolder}/lyric/dist/index.js", - "preLaunchTask": "ninja build lyric", - "outFiles": [ - "${workspaceFolder}/lyric/dist/**/*.js" - ], - "args": [ - "tap-bpm" - ] - }, - { - "preLaunchTask": "npm build lyric extension", - "name": "Launch lyric vscode Extension", - "type": "extensionHost", - "request": "launch", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}/lyric/extension", - "${workspaceFolder}/lyric/extension" - ] - } - ] -} diff --git a/users/Profpatsch/.vscode/settings.json b/users/Profpatsch/.vscode/settings.json deleted file mode 100644 index 7984076c1..000000000 --- a/users/Profpatsch/.vscode/settings.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "sqltools.connections": [ - { - "previewLimit": 50, - "driver": "SQLite", - "name": "cas-serve", - "database": "${workspaceFolder:Profpatsch}/cas-serve/data.sqlite" - } - ], - "sqltools.useNodeRuntime": true, - "editor.formatOnSave": true, - "[typescript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[javascript]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode" - }, - "purescript.codegenTargets": [ - "corefn" - ], - "purescript.foreignExt": "nix" -} diff --git a/users/Profpatsch/OWNERS b/users/Profpatsch/OWNERS deleted file mode 100644 index ac23e7225..000000000 --- a/users/Profpatsch/OWNERS +++ /dev/null @@ -1,4 +0,0 @@ -set noparent - -Profpatsch -sterni diff --git a/users/Profpatsch/README.md b/users/Profpatsch/README.md deleted file mode 100644 index 0f2147e9a..000000000 --- a/users/Profpatsch/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Profpatsch’s assemblage of peculiarities and curiosities - -Welcome, Welcome. - -Welcome to my user dir, where we optimize f\*\*\*ing around, in order to optimize finding out. - -![fafo graph](./fafo.jpg) - -DISCLAIMER: All of this code is of the “do not try at work” sort, unless noted otherwise. -You might try at home, however. Get inspired or get grossed out, whichever you like. diff --git a/users/Profpatsch/alacritty-change-color-scheme/.gitignore b/users/Profpatsch/alacritty-change-color-scheme/.gitignore deleted file mode 100644 index 97e89a2d6..000000000 --- a/users/Profpatsch/alacritty-change-color-scheme/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/node_modules/ -/result diff --git a/users/Profpatsch/alacritty-change-color-scheme/alacritty-change-color-scheme.js b/users/Profpatsch/alacritty-change-color-scheme/alacritty-change-color-scheme.js deleted file mode 100644 index f0795a02c..000000000 --- a/users/Profpatsch/alacritty-change-color-scheme/alacritty-change-color-scheme.js +++ /dev/null @@ -1,1066 +0,0 @@ -'use strict'; -//@ts-check - -// Step 3: Create the script -const dbus = require('dbus-native'); -const fs = require('fs'); -const assert = require('assert'); -const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http'); -const { - BasicTracerProvider, - BatchSpanProcessor, - ConsoleSpanExporter, - SimpleSpanProcessor, -} = require('@opentelemetry/sdk-trace-base'); -const opentelemetry = require('@opentelemetry/api'); -const { hrTime } = require('@opentelemetry/core'); -const { AsyncHooksContextManager } = require('@opentelemetry/context-async-hooks'); -const { EventEmitter } = require('stream'); -const { setTimeout } = require('node:timers/promises'); -const { promisify } = require('util'); -const { pseudoRandomBytes } = require('crypto'); -const { execFile } = require('node:child_process'); -const { readdir, realpath, access } = require('fs/promises'); -const net = require('node:net'); - -// NB: this code is like 80% copilot generated, and seriously missing error handling. -// It might break at any time, but for now it seems to work lol. - -const programName = process.argv[1]; -let themeDir = process.argv[2]; -// read the dark alacritty theme file as first argument -let darkThemeName = process.argv[3] ?? 'alacritty_0_12'; -// read the light alacritty theme file as second argument -let lightThemeName = process.argv[4] ?? 'dayfox'; -assert(themeDir, 'Theme directory is required'); - -let darkTheme = getThemePathSync(darkThemeName); -let lightTheme = getThemePathSync(lightThemeName); - -console.log(`Dark theme: ${darkTheme}`); -console.log(`Light theme: ${lightTheme}`); - -class Bus { - /** - * @param {'session' | 'system'} type - * @param {string} name - */ - constructor(name, type) { - this._name = name; - this._type = type; - switch (type) { - case 'session': - this._bus = dbus.sessionBus(); - break; - case 'system': - this._bus = dbus.systemBus(); - break; - } - this._bus.connection.once( - 'error', - /** @param {Error} err */ - err => { - console.error(`${this._type} bus ${this._name} error: ${err}`); - throw new Error(`${this._type} bus ${this._name} error: ${err}`); - }, - ); - this._bus.connection.once('end', () => { - console.error(`${this._type} bus ${this._name} connection ended unexpectedly`); - throw new Error(`${this._type} bus ${this._name} connection ended unexpectedly`); - }); - } - - /** - * @param {string} what - */ - _busErrorMessages(what) { - return `Error getting ${what} from ${this._type} bus ${this._name}`; - } - - /** - * - * @param {string} name - * @param {number} flags - * @returns {Promise} - */ - requestName(name, flags) { - return promisifyMethodAnnotate( - this._bus, - // @ts-ignore - this._bus.requestName, - this._busErrorMessages(`requesting name ${name}`), - name, - flags, - ); - } - - /** - * @param {{ [key: string]: unknown }} iface - * @param {string} path - * @param {{ name: string; methods: { [key: string]: unknown }; }} opts - */ - exportInterface(iface, path, opts) { - // @ts-ignore - return this._bus.exportInterface(iface, path, opts); - } - - /** - /** Get object from bus, with the given interface (not checked!) - * @template {{[key: string]: (...args: any[]) => Promise}} Interface - * @param {string} serviceName - * @param {string} interfaceName - * @param {string} objectName object name - * @returns {Promise} - */ - async getObject(serviceName, interfaceName, objectName) { - //@ts-ignore - const s = this._bus.getService(serviceName); - - /** @type {{[key: string]: Function}} */ - // @ts-ignore - const iface = await promisifyMethodAnnotate( - s, - s.getInterface, - this._busErrorMessages(`interface ${interfaceName}`), - objectName, - interfaceName, - ); - - if (!iface) { - throw new Error( - `Interface ${interfaceName} not found on object ${objectName} of service ${serviceName}`, - ); - } - - // We need to promisify all methods on the interface - const methodNames = Object.keys(iface.$methods ?? {}); - /** @type {{[key: string]: any}} */ - const methods = {}; - /** @type {Record} */ - for (const methodName of methodNames) { - methods[methodName] = iface[methodName]; - iface[methodName] = (/** @type {any[]} */ ...args) => - promisifyMethodAnnotate( - iface, - methods[methodName], - this._busErrorMessages(`method ${methodName}`), - ...args, - ); - } - - // @ts-ignore - return iface; - } -} - -// Connect to the user session bus -const bus = new Bus('color-scheme', 'session'); - -opentelemetry.diag.setLogger({ ...console, verbose: console.log }); - -const exporter = new OTLPTraceExporter(); -const consoleExporter = new ConsoleSpanExporter(); -const provider = new BasicTracerProvider({ - //@ts-ignore - resource: { - attributes: { - 'service.name': 'alacritty-change-color-scheme', - // 'service.namespace': 'default', - // 'service.instance.id': 'alacritty-change-color-scheme-01', - // 'service.version': '0.0.1', - }, - }, - spanProcessors: [ - // new BatchSpanProcessor(exporter, { - // maxQueueSize: 100, - // scheduledDelayMillis: 5000, - // }), - new SimpleSpanProcessor(exporter), - new SimpleSpanProcessor(consoleExporter), - ], -}); -provider.register({ - contextManager: new AsyncHooksContextManager().enable(), -}); - -const dbusSpanEmitter = new EventEmitter(); - -dbusSpanEmitter.on('new-root-span', onNewRootSpan); - -/** @typedef {{spanId: string, name: string, parentId?: string, startTime?: opentelemetry.TimeInput, attributes?: opentelemetry.Attributes}} StartSpan */ -/** @typedef {{spanId: string, endTime?: opentelemetry.TimeInput}} EndSpan */ - -/** @param {opentelemetry.Tracer} tracer, - * @param {StartSpan} spanData */ -function emitNewRootSpanEvent(tracer, spanData) { - dbusSpanEmitter.emit('new-root-span', tracer, spanData); -} - -/** - * @param {StartSpan} childSpanData - * @param {string} parentSpanId - */ -function emitNewChildSpanEvent(parentSpanId, childSpanData) { - dbusSpanEmitter.emit(`new-child-span-for/${parentSpanId}`, childSpanData); -} - -/** @param {EndSpan} endSpanData */ -function emitEndSpanEvent(endSpanData) { - dbusSpanEmitter.emit(`end-span-for/${endSpanData.spanId}`, endSpanData); -} - -/** @param {opentelemetry.Tracer} tracer - * @param {StartSpan} spanData */ -function onNewRootSpan(tracer, spanData) { - console.log(`New span: ${spanData.spanId}`); - setupActiveSpan(tracer, spanData); -} - -/** @param {opentelemetry.Tracer} tracer - * @param {StartSpan} spanData */ -function setupActiveSpan(tracer, spanData) { - const SPAN_TIMEOUT = 1_000_000; // 1000 seconds - const SPAN_TIMEOUT_SHORT = 10_000; // 10 seconds - if (typeof spanData.startTime === 'number') { - console.warn( - 'startTime is a number, not a hrTime tuple. This would use perfomance.now() in the wrong context, so we are ignoring it.', - ); - spanData.startTime = undefined; - } - tracer.startActiveSpan( - spanData.name, - { startTime: spanData.startTime, attributes: spanData.attributes }, - span => { - let activeContext = opentelemetry.context.active(); - - /** @param {{spanId: string, name: string}} childSpanData */ - function onNewChildSpan(childSpanData) { - opentelemetry.context.with(activeContext, () => { - console.log(`New child span: ${childSpanData.spanId}`); - setupActiveSpan(tracer, childSpanData); - }); - } - dbusSpanEmitter.on(`new-child-span-for/${spanData.spanId}`, onNewChildSpan); - - const removeTimeoutOnEnd = new AbortController(); - - /** @param {{endTime?: opentelemetry.TimeInput}} endSpanData */ - function onEndSpan(endSpanData) { - opentelemetry.context.with(activeContext, () => { - console.log(`End span: ${spanData.spanId}`); - if (typeof endSpanData.endTime === 'number') { - console.warn( - 'endTime is a number, not a hrTime tuple. This would use perfomance.now() in the wrong context, so we are ignoring it.', - ); - endSpanData.endTime = undefined; - } - span.end(endSpanData.endTime); - // we don’t remove the child span listener here, because in theory child spans don’t have to be inside parent spans. - // However, we only want to keep the child span listener around for a little more, so let’s set a shorter timeout here - setTimeout(SPAN_TIMEOUT_SHORT).then(() => { - dbusSpanEmitter.off(`new-child-span-for/${spanData.spanId}`, onNewChildSpan); - }); - // remove the general long timeout belove - removeTimeoutOnEnd.abort(); - }); - } - dbusSpanEmitter.once(`end-span-for/${spanData.spanId}`, onEndSpan); - - // don't keep spans contexts open forever if we never get a second message - // but we don’t end the spans, just remove the listeners. - setTimeout(SPAN_TIMEOUT, undefined, { signal: removeTimeoutOnEnd.signal }) - .then(() => { - console.warn( - `Timeout for span ${spanData.spanId}, removing all event listeners`, - ); - dbusSpanEmitter.off(`new-child-span-for/${spanData.spanId}`, onNewChildSpan); - dbusSpanEmitter.off(`end-span-for/${spanData.spanId}`, onEndSpan); - }) - .catch(err => { - if (err.name === 'AbortError') { - // console.log(`Timeout for span ${spanData.spanId} was aborted`); - } else { - throw err; - } - }); - }, - ); -} - -// set XDG_CONFIG_HOME if it's not set -if (!process.env.XDG_CONFIG_HOME) { - process.env.XDG_CONFIG_HOME = process.env.HOME + '/.config'; -} - -/** get the path of the theme config file synchronously - * - * @param {string} theme - * @returns {string} - * */ -function getThemePathSync(theme) { - const path = `${themeDir}/${theme}.toml`; - const absolutePath = fs.realpathSync(path); - assert(fs.existsSync(absolutePath), `Theme file not found: ${absolutePath}`); - return absolutePath; -} - -/** get the path of the theme config file - * - * @param {string} theme - * @returns {Promise} null if the theme file does not exist - * */ -async function getThemePath(theme) { - const path = `${themeDir}/${theme}.toml`; - try { - const absolutePath = await realpath(path); - await access(absolutePath); - return absolutePath; - } catch (err) { - return null; - } -} - -/** write new color scheme - * - * @param {'prefer-dark' | 'prefer-light'} cs - */ -function writeAlacrittyColorConfig(cs) { - const theme = cs === 'prefer-dark' ? darkTheme : lightTheme; - console.log(` - Writing color scheme ${cs} with theme ${theme}`); - fs.writeFileSync( - process.env.XDG_CONFIG_HOME + '/alacritty/alacritty-colors-autogen.toml', - `# !! THIS FILE IS GENERATED BY ${programName} -general.import = ["${theme}"]`, - 'utf8', - ); -} - -/** Typescript type that returns the inner value type T from a Promise - * type PromiseVal = T extends Promise ? U : T; - * @template T - * @typedef {T extends Promise ? U : T } PromiseVal - */ - -/** - * @template {{[key: string]: (...args: any[]) => Promise}} T - * @typedef {typeof Bus.prototype.getObject} GetObject - */ - -/** - * @template {{[key: string]: (...args: any[]) => Promise}} T - * @typedef {PromiseVal>>} IfaceReturn */ - -/** get the current value of the color scheme from dbus - * - * @returns {Promise<'prefer-dark' | 'prefer-light'>} - */ -async function getColorScheme() { - /** @typedef {{ReadOne: (interface: string, settingName: string) => Promise<[unknown, ['prefer-dark' | 'prefer-light']]>}} ColorScheme */ - /** @type {IfaceReturn} */ - let iface = await bus.getObject( - 'org.freedesktop.portal.Desktop', - 'org.freedesktop.portal.Settings', - '/org/freedesktop/portal/desktop', - ); - - const [_, [value]] = await iface.ReadOne('org.gnome.desktop.interface', 'color-scheme'); - assert(value === 'prefer-dark' || value === 'prefer-light'); - return value; -} - -/** promisify an object method and annotate any errors that get thrown - * @template {Function} A - * @param {object} obj - * @param {A} method - * @param {string} msg - * @param {...any} args - * @returns {Promise>} - */ -function promisifyMethodAnnotate(obj, method, msg, ...args) { - return promisify(method.bind(obj))(...args).catch(annotateErr(msg)); -} - -/** write respective alacritty config if the colorscheme changes. - * Colorscheme changes are only tracked in-between calls to this function in-memory. - * - * @param {'prefer-dark' | 'prefer-light'} cs - */ -function writeAlacrittyColorConfigIfDifferent(cs) { - // only change the color scheme if it's different from the previous one - let previous = null; - if (previous === cs) { - console.log(`Color scheme already set to ${cs}`); - return; - } - previous = cs; - - console.log(`Color scheme changed to ${cs}`); - writeAlacrittyColorConfig(cs); -} - -/** Listen on the freedesktop SettingChanged dbus interface for the color-scheme setting to change. */ -async function listenForColorschemeChange() { - /** @type {PromiseVal>>} */ - const iface = await bus.getObject( - 'org.freedesktop.portal.Desktop', - 'org.freedesktop.portal.Settings', - '/org/freedesktop/portal/desktop', - ); - - // Listen for SettingChanged signals - iface.on('SettingChanged', (interfaceName, key, [_, [newValue]]) => { - if (interfaceName === 'org.gnome.desktop.interface' && key == 'color-scheme') { - writeAlacrittyColorConfigIfDifferent(newValue); - } - }); - - console.log('Listening for color scheme changes...'); -} - -/** Create a dbus service that binds against the interface de.profpatsch.alacritty.ColorScheme and implements the method SetColorScheme */ -async function exportColorSchemeDbusInterface() { - console.log('Exporting color scheme interface de.profpatsch.alacritty.ColorScheme'); - const ifaceName = 'de.profpatsch.alacritty.ColorScheme'; - const iface = { - name: 'de.profpatsch.alacritty.ColorScheme', - methods: { - SetColorScheme: ['s', ''], - // first argument: 'dark' | 'light' - // second argument: the theme name (one of the themes in the theme directory) - // will only be applied during the run-time of this program, and reset on restart - SetColorSchemeTheme: ['ss', ''], - }, - }; - - const ifaceImpl = { - /** @type {function('prefer-dark' | 'prefer-light'): void} */ - SetColorScheme: function (cs) { - console.log(`SetColorScheme called with ${cs}`); - writeAlacrittyColorConfigIfDifferent(cs); - }, - SetColorSchemeTheme: async function ( - /** @type {string} */ cs, - /** @type {string} */ theme, - ) { - console.log(`SetColorSchemeTheme called with ${cs} and theme ${theme}`); - if (cs !== 'dark' && cs !== 'light') { - console.warn(`Invalid color scheme ${cs}`); - return; - } - const themePath = await getThemePath(theme); - if (themePath === null) { - console.warn(`Theme ${theme} not found`); - return; - } - if (cs === 'dark') { - darkTheme = themePath; - } - if (cs === 'light') { - lightTheme = themePath; - } - console.log(`Setting color scheme ${cs} with theme ${themePath}`); - writeAlacrittyColorConfig(cs === 'dark' ? 'prefer-dark' : 'prefer-light'); - }, - }; - - try { - bus; - const retCode = await bus.requestName(ifaceName, 0); - console.log( - `Request name returned ${retCode} for interface de.profpatsch.alacritty.ColorScheme`, - ); - bus.exportInterface(ifaceImpl, '/de/profpatsch/alacritty/ColorScheme', iface); - console.log('Exported interface de.profpatsch.alacritty.ColorScheme'); - } catch (err) { - console.log('Error exporting interface de.profpatsch.alacritty.ColorScheme'); - console.error(err); - } -} - -/** Annotate an error as a promise .catch handler (rethrows the annotated error) - * @param {string} msg - * @returns {function(Error): void} - */ -function annotateErr(msg) { - return err => { - msg = err.message ? `${msg}: ${err.message}` : msg; - err.message = msg; - throw err; - }; -} - -const bus2 = new Bus('otel', 'session'); -async function exportOtelInterface() { - console.log('Exporting OpenTelemetry interface'); - - try { - const retCode = bus2.requestName('de.profpatsch.otel.Tracer', 0); - console.log( - `Request name returned ${retCode} for interface de.profpatsch.otel.Tracer`, - ); - - const traceIface = { - name: 'de.profpatsch.otel.Tracer', - methods: { - // These both just take a json string as input - StartSpan: ['s', ''], - EndSpan: ['s', ''], - // An array of [(isStartSpan: bool, span: Span)] - // So that you don’t have to call dbus for every span - BatchSpans: ['a(bs)', ''], - }, - }; - /** @type {(arg: {tracer: opentelemetry.Tracer, tracerName: string}) => {StartSpan: (input: string) => void, EndSpan: (input: string) => void, BatchSpans: (input: [boolean, string][]) => void }} */ - const traceImpl = tracer => ({ - StartSpan: function (input) { - // TODO: actually verify json input - /** @type {StartSpan} */ - const spanArgs = JSON.parse(input); - if (spanArgs.parentId === undefined) { - console.log( - `Tracing root span ${spanArgs.name} with tracer ${tracer.tracerName}`, - ); - emitNewRootSpanEvent(tracer.tracer, spanArgs); - } else { - console.log( - `Tracing child span ${spanArgs.name} with tracer ${tracer.tracerName}`, - ); - emitNewChildSpanEvent(spanArgs.parentId, spanArgs); - } - }, - EndSpan: function (input) { - // TODO: actually verify json input - /** @type {EndSpan} */ - const spanArgs = JSON.parse(input); - console.log(`Ending span ${spanArgs.spanId} with tracer ${tracer.tracerName}`); - emitEndSpanEvent(spanArgs); - }, - BatchSpans: function (input) { - // lol - for (const [isStartSpan, span] of input) { - if (isStartSpan) { - traceImpl(tracer).StartSpan(span); - } else { - traceImpl(tracer).EndSpan(span); - } - } - }, - }); - bus2.exportInterface( - { - /** @param {string} tracerName */ - CreateTracer: function (tracerName) { - console.log(`Creating tracer with name ${tracerName}`); - const tracer = opentelemetry.trace.getTracer(tracerName, '0.0.1'); - bus2.exportInterface( - traceImpl({ tracer, tracerName }), - `/de/profpatsch/otel/tracers/${tracerName}`, - traceIface, - ); - return `/de/profpatsch/otel/tracers/${tracerName}`; - }, - }, - '/de/profpatsch/otel/TracerFactory', - { - name: 'de.profpatsch.otel.TracerFactory', - methods: { - CreateTracer: ['s', 's'], - }, - }, - ); - console.log('Exported interface de.profpatsch.otel.TracerFactory'); - } catch (err) { - console.log('Error exporting interface de.profpatsch.alacritty.ColorScheme'); - console.error(err); - } -} - -/** Returns the callsite of the function calling `getParentCallsite`, if any. */ -async function getParentCallsite() { - const getCallsites = (await import('callsites')).default; - const cs = getCallsites(); - return cs[2] ?? cs[1] ?? null; -} - -/** @typedef {([true, StartSpan] | [false, EndSpan])} BatchSpan */ - -/** - * @typedef {{ - * StartSpan: (spanData: StartSpan) => Promise, - * EndSpan: (spanData: EndSpan) => Promise, - * BatchSpans: (spans: BatchSpan[]) => Promise - * }} TracerIface - */ - -/** Calls the tracer dbus interface, sets up a tracer - * - * @param {string} tracerName The name of the tracer to set up - * @returns {Promise} - */ -async function setupTracer(tracerName) { - const parentCallsite = await getParentCallsite(); - console.log(`Setting up tracer ${tracerName} from ${parentCallsite?.getFileName()}`); - - /** @typedef {{CreateTracer: (name: string) => Promise}} TracerFactory */ - /** @type {IfaceReturn} */ - const iface = await bus2.getObject( - 'de.profpatsch.otel.Tracer', - 'de.profpatsch.otel.TracerFactory', - '/de/profpatsch/otel/TracerFactory', - ); - const path = await iface.CreateTracer(tracerName); - - /** - * @typedef {{ - * StartSpan: (spanData: string) => Promise, - * EndSpan: (spanData: string) => Promise - * BatchSpans: (spans: [boolean, string][]) => Promise - * }} Tracer - * @type {IfaceReturn} - * */ - const tracerIface = await bus2.getObject( - 'de.profpatsch.otel.Tracer', - 'de.profpatsch.otel.Tracer', - path, - ); - - /** @param {StartSpan} spanData */ - function StartSpan(spanData) { - return tracerIface.StartSpan(JSON.stringify(spanData)); - } - /** - * @param {any} spanData - */ - function EndSpan(spanData) { - return tracerIface.EndSpan(JSON.stringify(spanData)); - } - /** @param {[boolean, unknown][]} spans */ - function BatchSpans(spans) { - return tracerIface.BatchSpans( - spans.map(([isStartSpan, span]) => [isStartSpan, JSON.stringify(span)]), - ); - } - return { - StartSpan, - EndSpan, - BatchSpans, - }; -} - -/** @typedef {{}} Span */ -/** @typedef {{name: string, attributes?: opentelemetry.Attributes, parentSpan?: Span}} SpanData */ - -class Tracer { - /** @param {string} tracerName */ - static async setup(tracerName) { - const iface = await setupTracer(tracerName); - return new Tracer(tracerName, iface); - } - - /** - * @param {string} tracerName - * @param {TracerIface} iface - */ - constructor(tracerName, iface) { - this.tracerName = tracerName; - - const batch = new EventEmitter(); - /** - * @type {BatchSpan[]} - */ - const batchQueue = []; - - async function sendBatch() { - if (batchQueue.length > 0) { - await iface.BatchSpans(batchQueue); - batchQueue.length = 0; - } - } - - /** - * @param {StartSpan} spanData - */ - function onNewSpan(spanData) { - batchQueue.push([true, spanData]); - if (batchQueue.length > 10) { - sendBatch(); - } - } - - /** - * @param {EndSpan} spanData - */ - function onEndSpan(spanData) { - batchQueue.push([false, spanData]); - if (batchQueue.length > 10) { - sendBatch(); - } - } - - batch.on('new-span', onNewSpan); - batch.on('end-span', onEndSpan); - - let errorCounter = 0; - async function batchTimeout() { - const BATCH_TIMEOUT = 100; - try { - await setTimeout(BATCH_TIMEOUT); - await sendBatch(); - } catch (e) { - errorCounter++; - throw e; - } finally { - if (errorCounter > 5) { - console.warn('Too many errors, stopping batchTimeout'); - throw new Error('Too many errors, had to stop batchTimeout'); - } - await setTimeout(BATCH_TIMEOUT).then(batchTimeout); - } - } - batchTimeout(); - /** @param {StartSpan} spanData */ - function startSpan(spanData) { - batch.emit('new-span', spanData); - } - /** @param {EndSpan} spanId */ - function endSpan(spanId) { - batch.emit('end-span', { spanId }); - } - - this.batch = { - startSpan, - endSpan, - }; - } - - /** - * @template A - * @param {SpanData} spanData - * @param {function(Span): A} f - */ - async withSpan(spanData, f) { - const spanId = this.tracerName + '-' + pseudoRandomBytes(16).toString('hex'); - const startTime = hrTime(); - // @ts-ignore spanId is an internal impl detaul to our Span type - const parentId = spanData.parentSpan?.spanId; - try { - this.batch.startSpan({ - spanId, - name: spanData.name, - attributes: spanData.attributes, - startTime, - parentId, - }); - const span = { spanId }; - return await f(span); - } finally { - this.batch.endSpan({ spanId }); - } - } -} - -const execFileP = promisify(execFile); - -/** actual brightness roughly (but not quite arghhhh) logarithmic on a ThinkPad T14s with effin ARM crap -/* @type {number[]} -*/ -const brightnessMappingInternal = [0, 2, 4, 6, 9, 14, 20, 35, 50, 84, 120, 147, 200, 255]; -const brightnessMappingExternal = [0, 0, 0, 0, 12, 24, 36, 48, 60, 72, 84, 100, 100, 100]; -const maxBrightnessVal = brightnessMappingInternal.length - 1; -async function getInitialInternalMonitorBrightness() { - const { stdout } = await execFileP(`blight`, [`get`, 'brightness'], {}); - const brightness = parseInt(stdout, 10); - - const brightnessVal = brightnessMappingInternal.findIndex(value => value >= brightness); - return brightnessVal; -} - -/** - * @param {number} brightnessVal number between 0 and `maxBrightnessVal` - * (the amount of steps we want) where 0 is “turn off if possible” and `maxBrightnessVal` is “full brightness” - * The steps should be roughly aligned (by human eye) between the internal and external monitor. - */ -async function SetBrightnessAllMonitors(brightnessVal) { - return Promise.all([ - (async () => { - const internalMonitorBrightness = brightnessMappingInternal[brightnessVal] ?? '255'; - // set the brightness for internal monitor with the `blight` command line util - console.log(`Setting internal monitor brightness to ${internalMonitorBrightness}`); - await execFileP(`blight`, [`set`, `${internalMonitorBrightness}`], {}); - })(), - (async () => { - // find external monitors by listing all directories in /dev/bus/ddcci and reading their numbers - // external monitor brightness (ddc) is between 0 and 100 - const externalBrightness = brightnessMappingExternal[brightnessVal] ?? '100'; - ddcutilNewBrightness(externalBrightness); - })(), - ]); -} - -const ddcutilEmitter = new EventEmitter(); -/** - * @param {number} brightness - */ -function ddcutilNewBrightness(brightness) { - ddcutilEmitter.emit('new-brightness', brightness); -} - -/** - * @type {number | null} - */ -let nextBrightness = null; -/** Set the brightness of the external monitor using ddcutil, - * but only if nothing else is already trying to set it. In that case schedule to set it later. - * Also debounce the brightness setting to avoid setting it multiple times in a short time. - * - * @param {number} externalBrightness - */ -async function onDdcutilBrightnessChange(externalBrightness) { - if (nextBrightness === externalBrightness) return; - if (nextBrightness !== null) { - nextBrightness = externalBrightness; - console.log(`Already running, will set brightness to ${externalBrightness} later`); - return; - } - nextBrightness = externalBrightness; - - // debounce for some ms if anything happens to nextBrightness in the meantime, use that value - await setTimeout(250); - if (nextBrightness !== externalBrightness) { - console.log( - `Newer brightness value ${nextBrightness} was requested, ignoring ${externalBrightness}`, - ); - const brightness = nextBrightness; - nextBrightness = null; - await onDdcutilBrightnessChange(brightness); - return; - } - - /** @param {string | null} device - * @param {number} externalBrightness - */ - const setDdcciBrightness = async function (device, externalBrightness) { - let deviceName = device !== null ? `device ${device}` : 'all devices'; - console.log( - `Setting external monitor brightness to ${externalBrightness} for ${deviceName}`, - ); - - await execFileP('ddcutil', [ - ...(device !== null ? [`--bus`, device] : []), - ...[`--sleep-multiplier`, '0.20', `setvcp`, `0x10`, `${externalBrightness}`], - ]).catch(err => { - /** @type {string} */ - let stdout = err.stdout; - // err.stdout contains "No monitor detected on bus" - if (stdout.includes('No monitor detected on bus')) { - console.log(`External monitor on bus ${deviceName} is gone, ignoring.`); - return; - } - console.warn(`Error setting brightness with ddcutil for ${deviceName}`, err); - }); - }; - - const ddcciDevices = await readdir('/dev/bus/ddcci').catch(err => ({ err: err })); - if ('err' in ddcciDevices) { - console.warn('Error reading /dev/bus/ddcci', ddcciDevices.err); - console.log('Trying to set external brightness without knowing the device'); - await setDdcciBrightness(null, externalBrightness); - } else { - console.log(`Found ddcci devices: ${ddcciDevices}`); - for (const device of ddcciDevices) { - await setDdcciBrightness(device, externalBrightness); - } - } - - if (nextBrightness !== externalBrightness) { - const brightness = nextBrightness; - nextBrightness = null; - await onDdcutilBrightnessChange(brightness); - } else { - nextBrightness = null; - console.log(`Finished setting external monitor brightness to ${externalBrightness}`); - } -} - -async function exportDisplayBrightnessDbusInterface() { - console.log('Exporting display brightness interface de.profpatsch.DisplayBrightness'); - const ifaceName = 'de.profpatsch.DisplayBrightness'; - const iface = { - name: 'de.profpatsch.DisplayBrightness', - methods: { - // between 0 and 10 - SetBrightnessAllMonitors: ['d', ''], - // either '+' or '-' - SetBrightnessAllMonitorsRelative: ['s', ''], - }, - }; - - let currentBrightness = await getInitialInternalMonitorBrightness(); - console.log(`Current brightness: ${currentBrightness}`); - - ddcutilEmitter.on('new-brightness', onDdcutilBrightnessChange); - - const ifaceImpl = { - /** @type {function(number): void} */ - SetBrightnessAllMonitors: function (brightness) { - console.log(`SetBrightnessAllMonitors called with ${brightness}`); - // set the brightness - SetBrightnessAllMonitors(brightness); - }, - - /** @type {function(string): void} */ - SetBrightnessAllMonitorsRelative: function (direction) { - console.log(`SetBrightnessAllMonitorsRelative called with ${direction}`); - switch (direction) { - case '+': - currentBrightness = Math.min(maxBrightnessVal, currentBrightness + 1); - break; - case '-': - currentBrightness = Math.max(0, currentBrightness - 1); - break; - default: - console.warn(`Invalid direction ${direction}`); - return; - } - ifaceImpl.SetBrightnessAllMonitors(currentBrightness); - }, - }; - - try { - const retCode = await bus.requestName(ifaceName, 0); - console.log( - `Request name returned ${retCode} for interface de.profpatsch.DisplayBrightness`, - ); - bus.exportInterface(ifaceImpl, '/de/profpatsch/DisplayBrightness', iface); - console.log('Exported interface de.profpatsch.DisplayBrightness'); - } catch (err) { - console.log('Error exporting interface de.profpatsch.DisplayBrightness'); - console.error(err); - } -} - -function exportVarlinkInterface() { - const varlinkSocket = '/run/user/1000/de.Profpatsch.alacritty.ColorScheme'; - - try { - fs.unlinkSync(varlinkSocket); - } catch (err) {} - const server = net.createServer(socket => { - console.log('Varlink Client connected'); - let leftover = Buffer.alloc(0); - socket.on('data', data => { - console.log(`Received data: ${data}`); - let buf = Buffer.concat([leftover, data]); - for (;;) { - // find \0 in buffer - let idx = buf.findIndex(value => value == 0); - if (idx == -1) { - leftover = buf; - return; - } - /** @type {{method: string, parameters?: {[key: string]: unknown}}} */ - const message = JSON.parse(buf.subarray(0, idx).toString('utf-8')); - switch (message.method) { - case 'org.varlink.service.GetInfo': - socket.write( - JSON.stringify({ - parameters: { - vendor: 'Profpatsch', - product: 'Alacritty Color Scheme', - version: '0.1', - url: 'none', - interfaces: ['de.profpatsch.alacritty.ColorScheme'], - }, - }) + '\0', - ); - break; - case 'org.varlink.service.GetInterfaceDescription': - switch (message.parameters?.['interface']) { - case 'de.profpatsch.alacritty.ColorScheme': - socket.write( - JSON.stringify({ - parameters: { - description: ` - interface de.profpatsch.alacritty.ColorScheme - - method SetColorScheme(colorScheme: string) -> () - `, - }, - }) + '\0', - ); - default: - console.warn(`Unknown interface ${message.parameters?.['interface']}`); - } - break; - case 'de.Profpatsch.alacritty.ColorScheme.SetColorScheme': - const colorScheme = message.parameters?.['colorScheme']; - if (colorScheme !== 'prefer-dark' && colorScheme !== 'prefer-light') { - console.warn(`Invalid color scheme ${colorScheme}`); - } else { - writeAlacrittyColorConfigIfDifferent(colorScheme); - } - socket.write(JSON.stringify({ parameters: {} }) + '\0'); - break; - default: - console.warn(`Unknown method ${message.method}`); - socket.write(JSON.stringify({ error: 'UnkownMethod' }) + '\0'); - } - buf = buf.subarray(idx + 1); - } - }); - socket.on('end', () => { - console.log('Varlink client disconnected'); - }); - socket.on('error', err => { - console.error('Socket error:', err); - }); - }); - server.listen(varlinkSocket); -} -async function main() { - await exportOtelInterface(); - await exportDisplayBrightnessDbusInterface(); - exportVarlinkInterface(); - - const tracer = await Tracer.setup('hello'); - await tracer.withSpan( - { - name: 'hello', - attributes: { - foo: 'bar', - }, - }, - async span => { - await tracer.withSpan( - { - parentSpan: span, - name: 'world', - attributes: { - bar: 'baz', - }, - }, - async () => { - // Code inside the nested span - }, - ); - // Code after the nested span - }, - ); - - await exportColorSchemeDbusInterface(); - - // get the current color scheme - const currentColorScheme = await getColorScheme(); - console.log(`Current color scheme: ${currentColorScheme}`); - - // write the color scheme - writeAlacrittyColorConfig(currentColorScheme); - - // listen for color scheme changes - await listenForColorschemeChange(); -} - -main().catch(err => { - console.error(err); -}); diff --git a/users/Profpatsch/alacritty-change-color-scheme/cool-themes b/users/Profpatsch/alacritty-change-color-scheme/cool-themes deleted file mode 100644 index 8d2a9a519..000000000 --- a/users/Profpatsch/alacritty-change-color-scheme/cool-themes +++ /dev/null @@ -1,15 +0,0 @@ -ayu_mirage -catppuccin -gruvbox_dark -inferno -monokai_pro - - -night_owlish_light -papercolor_light -everforest_light -github_light -gruvbox_light -one_light -papertheme -rose_pine_dawn diff --git a/users/Profpatsch/alacritty-change-color-scheme/dbus-native.d.ts b/users/Profpatsch/alacritty-change-color-scheme/dbus-native.d.ts deleted file mode 100644 index c55aeb511..000000000 --- a/users/Profpatsch/alacritty-change-color-scheme/dbus-native.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'dbus-native'; diff --git a/users/Profpatsch/alacritty-change-color-scheme/default.nix b/users/Profpatsch/alacritty-change-color-scheme/default.nix deleted file mode 100644 index 79cc26e4e..000000000 --- a/users/Profpatsch/alacritty-change-color-scheme/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ depot, pkgs, ... }: - -depot.users.Profpatsch.napalm.buildPackage ./. { } diff --git a/users/Profpatsch/alacritty-change-color-scheme/package-lock.json b/users/Profpatsch/alacritty-change-color-scheme/package-lock.json deleted file mode 100644 index 19f75c425..000000000 --- a/users/Profpatsch/alacritty-change-color-scheme/package-lock.json +++ /dev/null @@ -1,546 +0,0 @@ -{ - "name": "alacritty-change-color-scheme", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "alacritty-change-color-scheme", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.29.0", - "@opentelemetry/core": "^1.29.0", - "@opentelemetry/exporter-trace-otlp-http": "^0.56.0", - "@opentelemetry/sdk-trace-base": "^1.29.0", - "dbus-native": "^0.4.0" - }, - "bin": { - "alacritty-change-color-scheme": "alacritty-change-color-scheme.js" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.56.0.tgz", - "integrity": "sha512-Wr39+94UNNG3Ei9nv3pHd4AJ63gq5nSemMRpCd8fPwDL9rN3vK26lzxfH27mw16XzOSO+TpyQwBAMaLxaPWG0g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.29.0.tgz", - "integrity": "sha512-TKT91jcFXgHyIDF1lgJF3BHGIakn6x0Xp7Tq3zoS3TMPzT9IlP0xEavWP8C1zGjU9UmZP2VR1tJhW9Az1A3w8Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.29.0.tgz", - "integrity": "sha512-gmT7vAreXl0DTHD2rVZcw3+l2g84+5XiHIqdBUxXbExymPCvSsGOpiwMmn8nkiJur28STV31wnhIDrzWDPzjfA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.56.0.tgz", - "integrity": "sha512-vqVuJvcwameA0r0cNrRzrZqPLB0otS+95g0XkZdiKOXUo81wYdY6r4kyrwz4nSChqTBEFm0lqi/H2OWGboOa6g==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.29.0", - "@opentelemetry/otlp-exporter-base": "0.56.0", - "@opentelemetry/otlp-transformer": "0.56.0", - "@opentelemetry/resources": "1.29.0", - "@opentelemetry/sdk-trace-base": "1.29.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.56.0.tgz", - "integrity": "sha512-eURvv0fcmBE+KE1McUeRo+u0n18ZnUeSc7lDlW/dzlqFYasEbsztTK4v0Qf8C4vEY+aMTjPKUxBG0NX2Te3Pmw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.29.0", - "@opentelemetry/otlp-transformer": "0.56.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.56.0.tgz", - "integrity": "sha512-kVkH/W2W7EpgWWpyU5VnnjIdSD7Y7FljQYObAQSKdRcejiwMj2glypZtUdfq1LTJcv4ht0jyTrw1D3CCxssNtQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.56.0", - "@opentelemetry/core": "1.29.0", - "@opentelemetry/resources": "1.29.0", - "@opentelemetry/sdk-logs": "0.56.0", - "@opentelemetry/sdk-metrics": "1.29.0", - "@opentelemetry/sdk-trace-base": "1.29.0", - "protobufjs": "^7.3.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.29.0.tgz", - "integrity": "sha512-s7mLXuHZE7RQr1wwweGcaRp3Q4UJJ0wazeGlc/N5/XSe6UyXfsh1UQGMADYeg7YwD+cEdMtU1yJAUXdnFzYzyQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.29.0", - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-logs": { - "version": "0.56.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.56.0.tgz", - "integrity": "sha512-OS0WPBJF++R/cSl+terUjQH5PebloidB1Jbbecgg2rnCmQbTST9xsRes23bLfDQVRvmegmHqDh884h0aRdJyLw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.56.0", - "@opentelemetry/core": "1.29.0", - "@opentelemetry/resources": "1.29.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.29.0.tgz", - "integrity": "sha512-MkVtuzDjXZaUJSuJlHn6BSXjcQlMvHcsDV7LjY4P6AJeffMa4+kIGDjzsCf6DkAh6Vqlwag5EWEam3KZOX5Drw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.29.0", - "@opentelemetry/resources": "1.29.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.29.0.tgz", - "integrity": "sha512-hEOpAYLKXF3wGJpXOtWsxEtqBgde0SCv+w+jvr3/UusR4ll3QrENEGnSl1WDCyRrpqOQ5NCNOvZch9UFVa7MnQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.29.0", - "@opentelemetry/resources": "1.29.0", - "@opentelemetry/semantic-conventions": "1.28.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", - "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause" - }, - "node_modules/@types/node": { - "version": "22.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", - "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/abstract-socket": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/abstract-socket/-/abstract-socket-2.1.1.tgz", - "integrity": "sha512-YZJizsvS1aBua5Gd01woe4zuyYBGgSMeqDOB6/ChwdTI904KP6QGtJswXl4hcqWxbz86hQBe++HWV0hF1aGUtA==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "dependencies": { - "bindings": "^1.2.1", - "nan": "^2.12.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/dbus-native": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/dbus-native/-/dbus-native-0.4.0.tgz", - "integrity": "sha512-i3zvY3tdPEOaMgmK4riwupjDYRJ53rcE1Kj8rAgnLOFmBd0DekUih59qv8v+Oyils/U9p+s4sSsaBzHWLztI+Q==", - "license": "MIT", - "dependencies": { - "event-stream": "^4.0.0", - "hexy": "^0.2.10", - "long": "^4.0.0", - "optimist": "^0.6.1", - "put": "0.0.6", - "safe-buffer": "^5.1.1", - "xml2js": "^0.4.17" - }, - "bin": { - "dbus2js": "bin/dbus2js.js" - }, - "optionalDependencies": { - "abstract-socket": "^2.0.0" - } - }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "license": "MIT" - }, - "node_modules/event-stream": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-4.0.1.tgz", - "integrity": "sha512-qACXdu/9VHPBzcyhdOWR5/IahhGMf0roTeZJfzz077GwylcDd90yOHLouhmv7GJ5XzPi6ekaQWd8AvPP2nOvpA==", - "license": "MIT", - "dependencies": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT", - "optional": true - }, - "node_modules/from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", - "license": "MIT" - }, - "node_modules/hexy": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/hexy/-/hexy-0.2.11.tgz", - "integrity": "sha512-ciq6hFsSG/Bpt2DmrZJtv+56zpPdnq+NQ4ijEFrveKN0ZG1mhl/LdT1NQZ9se6ty1fACcI4d4vYqC9v8EYpH2A==", - "license": "MIT", - "bin": { - "hexy": "bin/hexy_cmd.js" - } - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", - "license": "Apache-2.0" - }, - "node_modules/map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==", - "license": "MIT" - }, - "node_modules/minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha512-iotkTvxc+TwOm5Ieim8VnSNvCDjCK9S8G3scJ50ZthspSxa7jx50jkhYduuAtAjvfDUwSgOwf8+If99AlOEhyw==", - "license": "MIT" - }, - "node_modules/nan": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", - "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", - "license": "MIT", - "optional": true - }, - "node_modules/optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha512-snN4O4TkigujZphWLN0E//nQmm7790RYaE53DdL7ZYwee2D8DDo9/EyYiKUfN3rneWUjhJnueija3G9I2i0h3g==", - "license": "MIT/X11", - "dependencies": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "node_modules/pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", - "license": [ - "MIT", - "Apache2" - ], - "dependencies": { - "through": "~2.3" - } - }, - "node_modules/protobufjs": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", - "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/protobufjs/node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", - "license": "Apache-2.0" - }, - "node_modules/put": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/put/-/put-0.0.6.tgz", - "integrity": "sha512-w0szIZ2NkqznMFqxYPRETCIi+q/S8UKis9F4yOl6/N9NDCZmbjZZT85aI4FgJf3vIPrzMPX60+odCLOaYxNWWw==", - "license": "MIT/X11", - "engines": { - "node": ">=0.3.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "license": "MIT", - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha512-6yHMqgLYDzQDcAkL+tjJDC5nSNuNIx0vZtRZeiPh7Saef7VHX9H5Ijn9l2VIol2zaNYlYEX6KyuT/237A58qEQ==", - "license": "MIT", - "dependencies": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "license": "MIT" - }, - "node_modules/wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - } - } -} diff --git a/users/Profpatsch/alacritty-change-color-scheme/package.json b/users/Profpatsch/alacritty-change-color-scheme/package.json deleted file mode 100644 index e1b4af0c0..000000000 --- a/users/Profpatsch/alacritty-change-color-scheme/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "alacritty-change-color-scheme", - "version": "1.0.0", - "main": "alacritty-change-color-scheme.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "bin": "alacritty-change-color-scheme.js", - "author": "", - "license": "ISC", - "description": "", - "dependencies": { - "@opentelemetry/api": "^1.9.0", - "@opentelemetry/context-async-hooks": "^1.29.0", - "@opentelemetry/core": "^1.29.0", - "@opentelemetry/exporter-trace-otlp-http": "^0.56.0", - "@opentelemetry/sdk-trace-base": "^1.29.0", - "dbus-native": "^0.4.0" - } -} diff --git a/users/Profpatsch/alacritty-change-color-scheme/tsconfig.json b/users/Profpatsch/alacritty-change-color-scheme/tsconfig.json deleted file mode 100644 index 1fe004828..000000000 --- a/users/Profpatsch/alacritty-change-color-scheme/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "noEmit": true, - "target": "ES2022", - "lib": [ - "ES2022" - ], - "module": "ES2022", - "strict": true, - "checkJs": true, - "moduleResolution": "node" - }, - "include": [ - "*.ts", - "*.js" - ], -} diff --git a/users/Profpatsch/alacritty.nix b/users/Profpatsch/alacritty.nix deleted file mode 100644 index a6a996358..000000000 --- a/users/Profpatsch/alacritty.nix +++ /dev/null @@ -1,93 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - bins = depot.nix.getBins pkgs.alacritty [ "alacritty" ] - // depot.nix.getBins pkgs.coreutils [ "mkdir" "cp" "install" ]; - - # https://github.com/alacritty/alacritty-theme - themes = { - # dark = "alacritty_0_12"; - dark = "google"; - light = "dayfox"; - }; - - config = - { - config = { - # sets the theme for this config (autogenerated file) - general.import = [ "~/.config/alacritty/alacritty-colors-autogen.toml" ]; - font.size = 18; - scrolling.history = 100000; - }; - # This disables the dpi-sensitive scaling (cause otherwise the font will be humongous on my laptop screen) - alacritty-env.WINIT_X11_SCALE_FACTOR = 1; - }; - - alacritty = depot.nix.writeExecline "alacritty" { } ( - (lib.concatLists (lib.mapAttrsToList (k: v: [ "export" k (toString v) ]) config.alacritty-env)) - ++ [ - "backtick" - "-E" - "config" - [ depot.users.Profpatsch.xdg-config-home ] - - bins.alacritty - "--config-file" - ((pkgs.formats.toml { }).generate "alacritty.conf" config.config) - "$@" - ] - ); - - alacritty-themes-upstream = pkgs.fetchFromGitHub { - owner = "alacritty"; - repo = "alacritty-theme"; - rev = "95a7d695605863ede5b7430eb80d9e80f5f504bc"; - sha256 = "sha256-D37MQtNS20ESny5UhW1u6ELo9czP4l+q0S8neH7Wdbc="; - }; - - alacritty-themes-modes-ef = pkgs.fetchFromGitHub { - owner = "anhsirk0"; - repo = "alacritty-themes"; - rev = "5a2c194a682ec75d46553f9a9d6c43fbf39c689d"; - sha256 = "sha256-x5QrtSXNc05DNexM+ZtRzd8T9FdthZUzjW/2uEBdRCk="; - }; - - alacritty-themes = depot.nix.runExecline "alacritty-themes-merged" { } [ - "importas" - "out" - "out" - "if" - [ bins.mkdir "-p" "$\{out}/themes" ] - "if" - [ - "elglob" - "-0" - "themes" - "${alacritty-themes-upstream}/themes/*" - bins.install - "-m644" - "-t" - "\${out}/themes" - "$themes" - ] - "if" - [ - "elglob" - "-0" - "themes" - "${alacritty-themes-modes-ef}/themes/*" - bins.install - "-m644" - "-t" - "\${out}/themes" - "$themes" - ] - ]; -in -{ - inherit - alacritty - alacritty-themes - themes; - -} diff --git a/users/Profpatsch/aliases.nix b/users/Profpatsch/aliases.nix deleted file mode 100644 index 109de8ce3..000000000 --- a/users/Profpatsch/aliases.nix +++ /dev/null @@ -1,88 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - bins = depot.nix.getBins pkgs.findutils [ "find" ]; - -in -depot.nix.readTree.drvTargets { - - findia = depot.nix.writeExecline "findia" - { - readNArgs = 1; - # TODO: comment out, thanks to sterni blocking the runExecline change - # meta.description = '' - # Find case-insensitive anywhere (globbing) - - # Usage: findia - # ''; - } [ - bins.find - "-iname" - "*\${1}*" - "$@" - ]; - - findial = depot.nix.writeExecline "findial" - { - readNArgs = 1; - # TODO: comment out, thanks to sterni blocking the runExecline change - # meta.description = '' - # Find case-insensitive anywhere (globbing), follow symlinks"; - - # Usage: findial - # ''; - } [ - bins.find - "-L" - "-iname" - "*\${1}*" - "$@" - ]; - - findian = depot.nix.writeExecline "findian" - { - readNArgs = 2; - # TODO: comment out, thanks to sterni blocking the runExecline change - # meta.description = '' - # Find case-insensitive anywhere (globbing) in directory - - # Usage: findian - # ''; - } [ - bins.find - "$1" - "-iname" - "*\${2}*" - "$@" - ]; - - findiap = depot.nix.writeExecline "findiap" - { - readNArgs = 2; - # TODO: comment out, thanks to sterni blocking the runExecline change - # meta.description = '' - # Find case-insensitive anywhere (globbing) in directory, the pattern allows for paths. - - # Usage: findiap - # ''; - } [ - bins.find - "$1" - "-ipath" - "*\${2}*" - "$@" - ]; - - bell = depot.nix.writeExecline "bell" { } [ - "if" - [ - "pactl" - "upload-sample" - "${pkgs.sound-theme-freedesktop}/share/sounds/freedesktop/stereo/complete.oga" - "bell-window-system" - ] - "pactl" - "play-sample" - "bell-window-system" - ]; -} diff --git a/users/Profpatsch/arglib/ArglibNetencode.hs b/users/Profpatsch/arglib/ArglibNetencode.hs deleted file mode 100644 index 4531151ca..000000000 --- a/users/Profpatsch/arglib/ArglibNetencode.hs +++ /dev/null @@ -1,22 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module ArglibNetencode where - -import Data.Attoparsec.ByteString qualified as Atto -import ExecHelpers -import Label -import Netencode qualified -import PossehlAnalyticsPrelude -import System.Posix.Env.ByteString qualified as ByteEnv - -arglibNetencode :: CurrentProgramName -> Maybe (Label "arglibEnvvar" Text) -> IO Netencode.T -arglibNetencode progName mEnvvar = do - let envvar = mEnvvar <&> (.arglibEnvvar) & fromMaybe "ARGLIB_NETENCODE" & textToBytesUtf8 - ByteEnv.getEnv envvar >>= \case - Nothing -> dieUserError progName [fmt|could not read args, envvar {envvar} not set|] - Just bytes -> - case Atto.parseOnly (Netencode.netencodeParser <* Atto.endOfInput) bytes of - Left err -> dieEnvironmentProblem progName [fmt|arglib parsing error: {err}|] - Right t -> do - ByteEnv.unsetEnv envvar - pure t diff --git a/users/Profpatsch/arglib/arglib-netencode.cabal b/users/Profpatsch/arglib/arglib-netencode.cabal deleted file mode 100644 index 42b524f40..000000000 --- a/users/Profpatsch/arglib/arglib-netencode.cabal +++ /dev/null @@ -1,65 +0,0 @@ -cabal-version: 3.0 -name: arglib-netencode -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - default-language: GHC2021 - - -library - import: common-options - exposed-modules: ArglibNetencode - - build-depends: - base >=4.15 && <5, - pa-prelude, - pa-label, - netencode, - exec-helpers, - attoparsec, - unix diff --git a/users/Profpatsch/arglib/netencode.nix b/users/Profpatsch/arglib/netencode.nix deleted file mode 100644 index 83a94ddd6..000000000 --- a/users/Profpatsch/arglib/netencode.nix +++ /dev/null @@ -1,81 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - - # Add the given nix arguments to the program as ARGLIB_NETENCODE envvar - # - # Calls `netencode.gen.dwim` on the provided nix args value. - with-args = name: args: prog: depot.nix.writeExecline "${name}-with-args" { } [ - "export" - "ARGLIB_NETENCODE" - (depot.users.Profpatsch.netencode.gen.dwim args) - prog - ]; - - rust = depot.nix.writers.rustSimpleLib - { - name = "arglib-netencode"; - dependencies = [ - depot.users.Profpatsch.execline.exec-helpers - depot.users.Profpatsch.netencode.netencode-rs - ]; - } '' - extern crate netencode; - extern crate exec_helpers; - - use netencode::{T}; - use std::os::unix::ffi::OsStrExt; - - pub fn arglib_netencode(prog_name: &str, env: Option<&std::ffi::OsStr>) -> T { - let env = match env { - None => std::ffi::OsStr::from_bytes("ARGLIB_NETENCODE".as_bytes()), - Some(a) => a - }; - let t = match std::env::var_os(env) { - None => exec_helpers::die_user_error(prog_name, format!("could not read args, envvar {} not set", env.to_string_lossy())), - // TODO: good error handling for the different parser errors - Some(soup) => match netencode::parse::t_t(soup.as_bytes()) { - Ok((remainder, t)) => match remainder.is_empty() { - true => t, - false => exec_helpers::die_environment_problem(prog_name, format!("arglib: there was some unparsed bytes remaining: {:?}", remainder)) - }, - Err(err) => exec_helpers::die_environment_problem(prog_name, format!("arglib parsing error: {:?}", err)) - } - }; - std::env::remove_var(env); - t - } - ''; - - haskell = pkgs.haskellPackages.mkDerivation { - pname = "arglib-netencode"; - version = "0.1.0"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./arglib-netencode.cabal - ./ArglibNetencode.hs - ]; - - libraryHaskellDepends = [ - pkgs.haskellPackages.pa-prelude - pkgs.haskellPackages.pa-label - pkgs.haskellPackages.pa-error-tree - depot.users.Profpatsch.netencode.netencode-hs - depot.users.Profpatsch.execline.exec-helpers-hs - ]; - - isLibrary = true; - license = lib.licenses.mit; - - - }; - - -in -depot.nix.readTree.drvTargets { - inherit - with-args - rust - haskell - ; -} diff --git a/users/Profpatsch/atomically-write.nix b/users/Profpatsch/atomically-write.nix deleted file mode 100644 index c4d07cfbb..000000000 --- a/users/Profpatsch/atomically-write.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ depot, pkgs, ... }: -# Atomically write a file (just `>` redirection in bash -# empties a file even if the command crashes). -# -# Maybe there is an existing tool for that? -# But it’s easy enough to implement. -# -# Example: -# atomically-write -# ./to -# echo "foo" -# -# will atomically write the string "foo" into ./to -let - atomically-write = pkgs.writers.writeDash "atomically-write" '' - set -e - to=$1 - shift - # assumes that the tempfile is on the same file system, (or in memory) - # for the `mv` at the end to be more-or-less atomic. - tmp=$(${pkgs.coreutils}/bin/mktemp -d) - trap 'rm -r "$tmp"' EXIT - "$@" \ - > "$tmp/out" - mv "$tmp/out" "$to" - ''; - -in -atomically-write diff --git a/users/Profpatsch/blog/README.md b/users/Profpatsch/blog/README.md deleted file mode 100644 index 0753ebdea..000000000 --- a/users/Profpatsch/blog/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# (Parts of) my website - -This is a part of https://profpatsch.de/, notably the blog posts. - -The other parts can be found in [vuizvui](https://github.com/openlab-aux/vuizvui/tree/master/pkgs/profpatsch/profpatsch.de). It’s a mess. - -And yes, this implements a webserver & routing engine with nix, execline & s6 utils. “Bis einer weint”, as we say in German. diff --git a/users/Profpatsch/blog/default.nix b/users/Profpatsch/blog/default.nix deleted file mode 100644 index f233eda9b..000000000 --- a/users/Profpatsch/blog/default.nix +++ /dev/null @@ -1,481 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - bins = depot.nix.getBins pkgs.lowdown [ "lowdown" ] - // depot.nix.getBins pkgs.cdb [ "cdbget" "cdbmake" "cdbdump" ] - // depot.nix.getBins pkgs.coreutils [ "mv" "cat" "printf" "test" ] - // depot.nix.getBins pkgs.s6-networking [ "s6-tcpserver" ] - // depot.nix.getBins pkgs.time [ "time" ] - ; - - # / - # TODO: use - toplevel = [ - { - route = [ "notes" ]; - name = "Notes"; - page = { cssFile }: router cssFile; - } - { - route = [ "projects" ]; - name = "Projects"; - # page = projects; - } - ]; - - # /notes/* - notes = [ - { - route = [ "notes" "private-trackers-are-markets" ]; - name = "Private bittorrent trackers are markets"; - page = { cssFile }: markdownToHtml { - name = "private-trackers-are-markets"; - markdown = ./notes/private-trackers-are-markets.md; - inherit cssFile; - }; - } - { - route = [ "notes" "an-idealized-conflang" ]; - name = "An Idealized Configuration Language"; - page = { cssFile }: markdownToHtml { - name = "an-idealized-conflang"; - markdown = ./notes/an-idealized-conflang.md; - inherit cssFile; - }; - } - { - route = [ "notes" "rust-string-conversions" ]; - name = "Converting between different String types in Rust"; - page = { cssFile }: markdownToHtml { - name = "rust-string-conversions"; - markdown = ./notes/rust-string-conversions.md; - inherit cssFile; - }; - } - { - route = [ "notes" "preventing-oom" ]; - name = "Preventing out-of-memory (OOM) errors on Linux"; - page = { cssFile }: markdownToHtml { - name = "preventing-oom"; - markdown = ./notes/preventing-oom.md; - inherit cssFile; - }; - } - ]; - - projects = [ - { - name = "lorri"; - description = "nix-shell replacement for projects"; - link = "https://github.com/nix-community/lorri"; - } - { - name = "netencode"; - description = ''A human-readble nested data exchange format inspired by netstrings and bencode.''; - link = depotCgitLink { relativePath = "users/Profpatsch/netencode/README.md"; }; - } - { - name = "yarn2nix"; - description = ''nix dependency generator for the yarn Javascript package manager''; - link = "https://github.com/Profpatsch/yarn2nix"; - } - ]; - - posts = [ - { - date = "2017-05-04"; - title = "Ligature Emulation in Emacs"; - subtitle = "It’s not pretty, but the results are"; - description = "How to set up ligatures using prettify-symbols-mode and the Hasklig/FiraCode fonts."; - page = { cssFile }: markdownToHtml { - name = "2017-05-04-ligature-emluation-in-emacs"; - markdown = ./posts/2017-05-04-ligature-emulation-in-emacs.md; - inherit cssFile; - }; - route = [ "posts" "2017-05-04-ligature-emluation-in-emacs" ]; - tags = [ "emacs" ]; - } - ]; - - # convert a markdown file to html via lowdown - markdownToHtml = - { name - , # the file to convert - markdown - , # css file to add to the final result, as { route } - cssFile - }: - depot.nix.runExecline "${name}.html" { } ([ - "importas" - "out" - "out" - (depot.users.Profpatsch.lib.debugExec "") - bins.lowdown - "-s" - "-Thtml" - ] ++ - (lib.optional (cssFile != null) ([ "-M" "css=${mkRoute cssFile.route}" ])) - ++ [ - "-o" - "$out" - markdown - ]); - - # takes a { route … } attrset and converts the route lists to an absolute path - fullRoute = attrs: lib.pipe attrs [ - (map (x@{ route, ... }: x // { route = mkRoute route; })) - ]; - - # a cdb from route to a netencoded version of data for each route - router = cssFile: lib.pipe (notes ++ posts) [ - (map (r: with depot.users.Profpatsch.lens; - lib.pipe r [ - (over (field "route") mkRoute) - (over (field "page") (_ { inherit cssFile; })) - ])) - (map (x: { - name = x.route; - value = depot.users.Profpatsch.netencode.gen.dwim x; - })) - lib.listToAttrs - (cdbMake "router") - ]; - - # Create a link to the given source file/directory, given the relative path in the depot repo. - # Checks that the file exists at evaluation time. - depotCgitLink = - { - # relative path from the depot root (without leading /). - relativePath - }: - assert - (lib.assertMsg - (builtins.pathExists (depot.path.origSrc + ("/" + relativePath))) - "depotCgitLink: path /${relativePath} does not exist in depot, and depot.path was ${toString depot.path}"); - "https://code.tvl.fyi/tree/${relativePath}"; - - # look up a route by path ($1) - router-lookup = cssFile: depot.nix.writeExecline "router-lookup" { readNArgs = 1; } [ - cdbLookup - (router cssFile) - "$1" - ]; - - runExeclineStdout = name: args: cmd: depot.nix.runExecline name args ([ - "importas" - "-ui" - "out" - "out" - "redirfd" - "-w" - "1" - "$out" - ] ++ cmd); - - notes-index-html = - let o = fullRoute notes; - in '' - - ''; - - notes-index = pkgs.writeText "notes-index.html" notes-index-html; - - # A simple mustache-inspired string interpolation combinator - # that takes an object and a template (a function from o to string) - # and returns a string. - scope = o: tpl: - if builtins.typeOf o == "list" then - lib.concatMapStringsSep "\n" tpl o - else if builtins.typeOf o == "set" then - tpl o - else throw "${lib.generators.toPretty {} o} not allowed in template"; - - # string-escape html (TODO) - str = s: s; - # html-escape (TODO) - esc = s: s; - html = s: s; - - projects-index-html = - let o = projects; - in '' -
    - ${scope o (o: '' -
    ${esc o.name}
    -
    ${html o.description}
    - '')} -
    - ''; - - projects-index = pkgs.writeText "projects-index.html" projects-index-html; - - posts-index-html = - let o = fullRoute posts; - in '' -
    - ${scope o (o: '' -
    ${str o.date} ${esc o.title}
    -
    ${html o.description}
    - '')} -
    - ''; - - posts-index = pkgs.writeText "projects-index.html" posts-index-html; - - arglibNetencode = val: depot.nix.writeExecline "arglib-netencode" { } [ - "export" - "ARGLIB_NETENCODE" - (depot.users.Profpatsch.netencode.gen.dwim val) - "$@" - ]; - - # A simple http server that serves the site. Yes, it’s horrible. - site-server = { cssFile, port }: depot.nix.writeExecline "blog-server" { } [ - (depot.users.Profpatsch.lib.runInEmptyEnv [ "PATH" ]) - bins.s6-tcpserver - "127.0.0.1" - port - bins.time - "--format=time: %es" - "--" - runOr - return400 - "pipeline" - [ - (arglibNetencode { - what = "request"; - }) - depot.users.Profpatsch.read-http - ] - depot.users.Profpatsch.netencode.record-splice-env - runOr - return500 - "importas" - "-i" - "path" - "path" - "if" - [ depot.tools.eprintf "GET \${path}\n" ] - runOr - return404 - "backtick" - "-ni" - "TEMPLATE_DATA" - [ - # TODO: factor this out of here, this is routing not serving - "ifelse" - [ bins.test "$path" "=" "/notes" ] - [ - "export" - "content-type" - "text/html" - "export" - "serve-file" - notes-index - depot.users.Profpatsch.netencode.env-splice-record - ] - "ifelse" - [ bins.test "$path" "=" "/projects" ] - [ - "export" - "content-type" - "text/html" - "export" - "serve-file" - projects-index - depot.users.Profpatsch.netencode.env-splice-record - ] - "ifelse" - [ bins.test "$path" "=" "/posts" ] - [ - "export" - "content-type" - "text/html" - "export" - "serve-file" - posts-index - depot.users.Profpatsch.netencode.env-splice-record - ] - # TODO: ignore potential query arguments. See 404 message - "pipeline" - [ (router-lookup cssFile) "$path" ] - depot.users.Profpatsch.netencode.record-splice-env - "importas" - "-ui" - "page" - "page" - "export" - "content-type" - "text/html" - "export" - "serve-file" - "$page" - depot.users.Profpatsch.netencode.env-splice-record - ] - runOr - return500 - "if" - [ - "pipeline" - [ - bins.printf - '' - HTTP/1.1 200 OK - Content-Type: {{{content-type}}}; charset=UTF-8 - Connection: close - - '' - ] - depot.users.Profpatsch.netencode.netencode-mustache - ] - "pipeline" - [ "importas" "t" "TEMPLATE_DATA" bins.printf "%s" "$t" ] - depot.users.Profpatsch.netencode.record-splice-env - "importas" - "-ui" - "serve-file" - "serve-file" - bins.cat - "$serve-file" - ]; - - # run argv or $1 if argv returns a failure status code. - runOr = depot.nix.writeExecline "run-or" { readNArgs = 1; } [ - "foreground" - [ "$@" ] - "importas" - "?" - "?" - "ifelse" - [ bins.test "$?" "-eq" "0" ] - [ ] - "if" - [ depot.tools.eprintf "runOr: exited \${?}, running \${1}\n" ] - "$1" - ]; - - return400 = depot.nix.writeExecline "return400" { } [ - bins.printf - "%s" - '' - HTTP/1.1 400 Bad Request - Content-Type: text/plain; charset=UTF-8 - Connection: close - - '' - ]; - - return404 = depot.nix.writeExecline "return404" { } [ - bins.printf - "%s" - '' - HTTP/1.1 404 Not Found - Content-Type: text/plain; charset=UTF-8 - Connection: close - - This page doesn’t exist! Query arguments are not handled at the moment. - '' - ]; - - return500 = depot.nix.writeExecline "return500" { } [ - bins.printf - "%s" - '' - HTTP/1.1 500 Internal Server Error - Content-Type: text/plain; charset=UTF-8 - Connection: close - - Encountered an internal server error. Please try again. - '' - ]; - - capture-stdin = depot.nix.writers.rustSimple - { - name = "capture-stdin"; - dependencies = [ depot.users.Profpatsch.execline.exec-helpers ]; - } '' - extern crate exec_helpers; - use std::io::Read; - fn main() { - let (args, prog) = exec_helpers::args_for_exec("capture-stdin", 1); - let valname = &args[1]; - let mut v : Vec = vec![]; - std::io::stdin().lock().read_to_end(&mut v).unwrap(); - exec_helpers::exec_into_args("capture-stdin", prog, vec![(valname, v)]); - } - ''; - - # go from a list of path elements to an absolute route string - mkRoute = route: "/" + lib.concatMapStringsSep "/" urlencodeAscii route; - - # urlencodes, but only ASCII characters - # https://en.wikipedia.org/wiki/Percent-encoding - urlencodeAscii = urlPiece: - let - raw = [ "!" "#" "$" "%" "&" "'" "(" ")" "*" "+" "," "/" ":" ";" "=" "?" "@" "[" "]" ]; - enc = [ "%21" "%23" "%24" "%25" "%26" "%27" "%28" "%29" "%2A" "%2B" "%2C" "%2F" "%3A" "%3B" "%3D" "%3F" "%40" "%5B" "%5D" ]; - rest = [ "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "-" "_" "." "~" ]; - in - assert lib.assertMsg (lib.all (c: builtins.elem c (raw ++ rest)) (lib.stringToCharacters urlPiece)) - "urlencodeAscii: the urlPiece must only contain valid url ASCII characters, was: ${urlPiece}"; - builtins.replaceStrings raw enc urlPiece; - - - # create a cdb record entry, as required by the cdbmake tool - cdbRecord = key: val: - "+${toString (builtins.stringLength key)},${toString (builtins.stringLength val)}:" - + "${key}->${val}\n"; - - # create a full cdbmake input from an attribute set of keys to values (strings) - cdbRecords = - with depot.nix.yants; - defun [ (attrs (either drv string)) string ] - (attrs: - (lib.concatStrings (lib.mapAttrsToList cdbRecord attrs)) + "\n"); - - # run cdbmake on a list of key/value pairs (strings - cdbMake = name: attrs: depot.nix.runExecline "${name}.cdb" - { - stdin = cdbRecords attrs; - } [ - "importas" - "out" - "out" - depot.users.Profpatsch.lib.eprint-stdin - "if" - [ bins.cdbmake "db" "tmp" ] - bins.mv - "db" - "$out" - ]; - - # look up a key ($2) in the given cdb ($1) - cdbLookup = depot.nix.writeExecline "cdb-lookup" { readNArgs = 2; } [ - # cdb ($1) on stdin - "redirfd" - "-r" - "0" - "$1" - # key ($2) lookup - bins.cdbget - "$2" - ]; - -in -depot.nix.readTree.drvTargets { - inherit - router - depotCgitLink - site-server - notes-index - notes-index-html - projects-index - projects-index-html - posts-index-html - ; - -} diff --git a/users/Profpatsch/blog/notes/an-idealized-conflang.md b/users/Profpatsch/blog/notes/an-idealized-conflang.md deleted file mode 100644 index 5c6b39f6e..000000000 --- a/users/Profpatsch/blog/notes/an-idealized-conflang.md +++ /dev/null @@ -1,298 +0,0 @@ -tags: netencode, json -date: 2022-03-31 -certainty: likely -status: initial -title: An idealized Configuration Language - -# An Idealized Configuration Language - -JSON brought us one step closer to what an idealized configuration language is, -which I define as “data, stripped of all externalities of the system it is working in”. - -Specifically, JSON is very close to what I consider the minimal properties to represent structured data. - -## A short history, according to me - -In the beginning, Lisp defined s-expressions as a stand-in for an actual syntax. -Then, people figured out that it’s also a way to represent structured data. -It has scalars, which can be nested into lists, recursively. - -``` -(this is (a (list) (of lists))) -``` - -This provides the first three rules of our idealized language: - -1. A **scalar** is a primitive value that is domain-specific. - We can assume a bunch of bytes here, or a text or an integer. - -2. A **list** gives an ordering to `0..n` (or `1..n`) values - -3. Both a scalar and a list are the *same kind* of “thing” (from here on called **value**), - lists can be created from arbitrary values *recursively* - (for example scalars, or lists of scalars and other lists) - - -Later, ASN.1 came and had the important insight that the same idealized data structure -can be represented in different fashions, -for example as a binary-efficient version and a human-readable format. - -Then, XML “graced” the world for a decade or two, and the main lesson from it was -that you don’t want to mix markup languages and configuration languages, -and that you don’t want a committee to design these things. - ---- - -In the meantime, Brendan Eich designed Javascript. Its prototype-based object system -arguably stripped down the rituals of existing OO-systems. -Douglas Crockford later extracted the object format (minus functions) into a syntax, and we got JSON. - -``` -{ - "foo": [ - { "nested": "attrs" }, - "some text" - ], - "bar": 42 -} -``` - -JSON adds another fundamental idea into the mix: - -4. **Records** are unordered collections of `name`/`value` pairs. - A `name` is defined to be a unicode string, so a semantic descriptor of the nested `value`. - -Unfortunately, the JSON syntax does not actually specify any semantics of records (`objects` in JSON lingo), -in particular it does not mention what the meaning is if a `name` appears twice in one record. - -If records can have multiple entries with the same `name`, suddenly ordering becomes important! -But wait, remember earlier we defined *lists* to impose ordering on two values. -So in order to rectify that problem, we say that - -5. A `name` can only appear in a record *once*, names must be unique. - -This is the current state of the programming community at large, -where most “modern” configuration languages basically use a version of the JSON model -as their underlying data structure. (However not all of them use the same version.) - -## Improving JSON’s data model - -We are not yet at the final “idealized” configuration language, though. - -Modern languages like Standard ML define their data types as a mixture of - -* *records* (“structs” in the C lingo) -* and *sums* (which you can think about as enums that can hold more `value`s inside them) - -This allows to express the common pattern where some fields in a record are only meaningful -if another field—the so-called `tag`-field—is set to a specific value. - -An easy example: if a request can fail with an error message or succeed with a result. - -You could model that as - -``` -{ - "was_error": true, - "error_message": "there was an error" -} -``` - -or - -``` -{ - "was_error": false, - "result": 42 -} -``` - -in your JSON representation. - -But in a ML-like language (like, for example, Rust), you would instead model it as - -``` -type RequestResult - = Error { error_message: String } - | Success { result: i64 } -``` - -where the distinction in `Error` or `Success` makes it clear that `error_message` and `result` -only exist in one of these cases, not the other. - -We *can* encode exactly that idea into JSON in multiple ways, but not a “blessed” way. - -For example, another way to encode the above would be - -``` -{ - "Error": { - "error_message": "there was an error" - } -} -``` - -and - -``` -{ - "Success": { - "result": 42 - } -} -``` - -Particularly notice the difference between the language representation, where the type is “closed”only `Success` or `Error` can happen— -and the data representation where the type is “open”, more cases could potentially exist. - -This is an important differentiation from a type system: -Our idealized configuration language just gives more structure to a bag of data, -it does not restrict which value can be where. -Think of a value in an unityped language, like Python. - - -So far we have the notion of - -1. a scalar (a primitive) -2. a list (ordering on values) -3. a record (unordered collection of named values) - -and in order to get the “open” `tag`ged enumeration values, we introduce - -4. a `tag`, which gives a name to a value - -We can then redefine `record` to mean “an unordered collection of `tag`ged values”, -which further reduces the amount of concepts needed. - -And that’s it, this is the full idealized configuration language. - - -## Some examples of data modelling with tags - -This is all well and good, but what does it look like in practice? - -For these examples I will be using JSON with a new `< "tag": value >` syntax -to represent `tag`s. - -From a compatibility standpoint, `tag`s (or sum types) have dual properties to record types. - -With a record, when you have a producer that *adds* a field to it, the consumer will still be able to handle the record (provided the semantics of the existing fields is not changed by the new field). - -With a tag, *removing* a tag from the producer will mean that the consumer will still be able to handle the tag. It might do one “dead” check on the removed `tag`, but can still handle the remaining ones just fine. - - - -An example of how that is applied in practice is that in `protobuf3`, fields of a record are *always* optional fields. - -We can model optional fields by wrapping them in `< "Some": value >` or `< "None": {} >` (where the actual value of the `None` is ignored or always an empty record). - -So a protobuf with the fields `foo: int` and `bar: string` has to be parsed by the receiver als containing *four* possibilities: - -№|foo|bar| -|--:|---|---| -|1|`<"None":{}>`|`<"None":{}>`| -|2|`<"Some":42>`|`<"None":{}>`| -|3|`<"None":{}>`|`<"Some":"x">`| -|4|`<"Some":42>`|`<"Some":"x">`| - -Now, iff the receiver actually handles all four possibilities -(and doesn’t just crash if a field is not set, as customary in million-dollar-mistake languages), -it’s easy to see how removing a field from the producer is semantically equal to always setting it to `<"None":{}>`. -Since all receivers should be ready to receive `None` for every field, this provides a simple forward-compatibility scheme. - -We can abstract this to any kind of tag value: -If you start with “more” tags, you give yourself space to remove them later without breaking compatibility, typically called “forward compatibility”. - - -## To empty list/record or not to - -Something to think about is whether records and fields should be defined -to always contain at least one element. - -As it stands, JSON has multiple ways of expressing the “empty value”: - -* `null` -* `[]` -* `{}` -* `""` -* *leave out the field* - -and two of those come from the possibility of having empty structured values. - -## Representations of this language - -This line of thought originally fell out of me designing [`netencode`](https://code.tvl.fyi/tree/users/Profpatsch/netencode/README.md) -as a small human-debuggable format for pipeline serialization. - -In addition to the concepts mentioned here (especially tags), -it provides a better set of scalars than JSON (specifically arbitrary bytestrings), -but it cannot practically be written or modified by hand, -which might be a good thing depending on how you look at it. - ---- - -The way that is compatible with the rest of the ecosystem is probably to use a subset of json -to represent our idealized language. - -There is multiple ways of encoding tags in json, which each have their pros and cons. - -The most common is probably the “tag field” variant, where the tag is pulled into the nested record: - -``` -{ - "_tag": "Success", - "result": 42 -} -``` - -Which has the advantage that people know how to deal with it and that it’s easy to “just add another field”, -plus it is backward-compatible when you had a record in the first place. - -It has multiple disadvantages however: - -* If your value wasn’t a record (e.g. an int) before, you have to put it in a record and assign an arbitrary name to its field -* People are not forced to “unwrap” the tag first, so they are going to forget to check it -* The magic “_tag” name cannot be used by any of the record’s fields - - -An in-between version of this with less downsides is to always push a json record onto the stack: - -``` -{ - "tag": "Success", - "value": { - "result": 42 - } -} -``` - -This makes it harder for people to miss checking the `tag`, but still possible of course. -It also makes it easily possible to inspect the contents of `value` without knowing the -exhaustive list of `tag`s, which can be useful in practice (though often not sound!). -It also gets rid of the “_tag” field name clash problem. - -Disadvantages: - -* Breaks the backwards-compatibility with an existing record-based approach if you want to introduce `tag`s -* Verbosity of representation -* hard to distinguish a record with the `tag` and `value` fields from a `tag`ed value (though you know the type layout of your data on a higher level, don’t you? ;) ) - - -The final, “most pure” representation is the one I gave in the original introduction: - -``` -{ - "Success": { - "result": 42 - } -} -``` - -Now you *have* to match on the `tag` name first, before you can actually access your data, -and it’s less verbose than the above representation. - -Disavantages: - -* You also have to *know* what `tag`s to expect, it’s harder to query cause you need to extract the keys and values from the dict and then take the first one. -* Doing a “tag backwards compat” check is harder, - because you can’t just check whether `_tag` or `tag`/`value` are the keys in the dict. diff --git a/users/Profpatsch/blog/notes/preventing-oom.md b/users/Profpatsch/blog/notes/preventing-oom.md deleted file mode 100644 index 59ea4f747..000000000 --- a/users/Profpatsch/blog/notes/preventing-oom.md +++ /dev/null @@ -1,33 +0,0 @@ -tags: linux -date: 2020-01-25 -certainty: likely -status: initial -title: Preventing out-of-memory (OOM) errors on Linux - -# Preventing out-of-memory (OOM) errors on Linux - -I’ve been running out of memory more and more often lately. I don’t use any swap space because I am of the opinion that 16GB of memory should be sufficient for most daily and professional tasks. Which is generally true, however sometimes I have a runaway filling my memory. Emacs is very good at doing this for example, prone to filling your RAM when you open json files with very long lines. - -In theory, the kernel OOM killer should come in and save the day, but the Linux OOM killer is notorious for being extremely … conservative. It will try to free every internal structure it can before even thinking about touching any userspace processes. At that point, the desktop usually stopped responding minutes ago. - -Luckily the kernel provides memory statistics for the whole system, as well as single process, and the [`earlyoom`](https://github.com/rfjakob/earlyoom) tool uses those to keep memory usage under a certain limit. It will start killing processes, “heaviest” first, until the given upper memory limit is satisfied again. - -On NixOS, I set: - -```nix -{ - services.earlyoom = { - enable = true; - freeMemThreshold = 5; # <%5 free - }; -} -``` - -and after activation, this simple test shows whether the daemon is working: - -```shell -$ tail /dev/zero -fish: “tail /dev/zero” terminated by signal SIGTERM (Polite quit request) -``` - -`tail /dev/zero` searches for the last line of the file `/dev/zero`, and since it cannot know that there is no next line and no end to the stream of `\0` this file produces, it will fill the RAM as quickly as physically possible. Before it can fill it completely, `earlyoom` recognizes that the limit was breached, singles out the `tail` command as the process using the most amount of memory, and sends it a `SIGTERM`. diff --git a/users/Profpatsch/blog/notes/private-trackers-are-markets.md b/users/Profpatsch/blog/notes/private-trackers-are-markets.md deleted file mode 100644 index 88fe5f07e..000000000 --- a/users/Profpatsch/blog/notes/private-trackers-are-markets.md +++ /dev/null @@ -1,46 +0,0 @@ -# Private bittorrent trackers are markets - -Private bittorrent trackers have a currency called ratio, -which is the bits you upload divided the bits you download. - -You have to keep the ratio above a certain lower limit, -otherwise you get banned from the market or have to cut a deal with the moderators → bancruptcy - -New liquidity (?) is introduced to the market by so-called “freeleech” events or tokens, -which essentially allow you to exchange a token (or some time in the case of time-restricted freeleech) -for some data, which can then be seeded to generate future profits without spending ratio. - -Sometimes, ratio is pulled from the market by allowing to exchange it into website perks, -like forum titles or other benefits like chat-memberships. This has a deflationary effect. -It could be compared to “vanity items” in MMOs, which don’t grant a mechanical advantage in the market. -Is there a real-world equivalent? i.e. allowing rich people to exchange some of their worth -for vanity items instead of investing it for future gain? - -Sometimes, ratio can be traded for more than just transferred bits, -for example by requesting a torrent for a certain album or movie, -paying some ratio for the fulfillment of the request. - ---- - -Based on how bittorrent works, usually multiple people “seed” a torrent. -This means multiple people can answer a request for trading ratio. -Part of the request (i.e. the first 30% of a movie) -can be fulfilled by one party, part of it by a second or even more parties. - -For small requests (e.g. albums), often the time between announcing the trade -and filling the trade is important for who is able to fill it. -Getting a 1 second head-start vastly increases your chance of a handshake -and starting the transmission, so on average you get a vastly higher ratio gain from that torrent. -Meaning that using a bittorrent client which is fast to answer as a seeder will lead to better outcomes. -This could be compared to mechanisms seen in high-speed trading. - ---- - -Of course these market-mechanisms are in service of a wider policy goal, -which is to ensure the constant availability of as much high-quality data as possible. -There is more mechanisms at play on these trackers that all contribute to this goal -(possible keywords to research: trumping, freeleech for underseeded torrents). - -In general, it is important to remember that markets are only a tool, -never an end in themselves, as neoliberalists would like us to believe. -They always are in service of a wider goal or policy. We live in a society. diff --git a/users/Profpatsch/blog/notes/rust-string-conversions.md b/users/Profpatsch/blog/notes/rust-string-conversions.md deleted file mode 100644 index 99071ef9d..000000000 --- a/users/Profpatsch/blog/notes/rust-string-conversions.md +++ /dev/null @@ -1,53 +0,0 @@ -# Converting between different String types in Rust - -``` -let s: String = ... -let st: &str = ... -let u: &[u8] = ... -let b: [u8; 3] = b"foo" -let v: Vec = ... -let os: OsString = ... -let ost: OsStr = ... - -From To Use Comment ----- -- --- ------- -&str -> String String::from(st) -&str -> &[u8] st.as_bytes() -&str -> Vec st.as_bytes().to_owned() via &[u8] -&str -> &OsStr OsStr::new(st) - -String -> &str &s alt. s.as_str() -String -> &[u8] s.as_bytes() -String -> Vec s.into_bytes() -String -> OsString OsString::from(s) - -&[u8] -> &str str::from_utf8(u).unwrap() -&[u8] -> String String::from_utf8(u).unwrap() -&[u8] -> Vec u.to_owned() -&[u8] -> &OsStr OsStr::from_bytes(u) use std::os::unix::ffi::OsStrExt; - -[u8; 3] -> &[u8] &b[..] byte literal -[u8; 3] -> &[u8] "foo".as_bytes() alternative via utf8 literal - -Vec -> &str str::from_utf8(&v).unwrap() via &[u8] -Vec -> String String::from_utf8(v) -Vec -> &[u8] &v -Vec -> OsString OsString::from_vec(v) use std::os::unix::ffi::OsStringExt; - -&OsStr -> &str ost.to_str().unwrap() -&OsStr -> String ost.to_os_string().into_string() via OsString - .unwrap() -&OsStr -> Cow ost.to_string_lossy() Unicode replacement characters -&OsStr -> OsString ost.to_os_string() -&OsStr -> &[u8] ost.as_bytes() use std::os::unix::ffi::OsStringExt; - -OsString -> String os.into_string().unwrap() returns original OsString on failure -OsString -> &str os.to_str().unwrap() -OsString -> &OsStr os.as_os_str() -OsString -> Vec os.into_vec() use std::os::unix::ffi::OsStringExt; -``` - - -## Source - -Original source is [this document on Pastebin](https://web.archive.org/web/20190710121935/https://pastebin.com/Mhfc6b9i) diff --git a/users/Profpatsch/blog/posts/2017-05-04-ligature-emulation-in-emacs.md b/users/Profpatsch/blog/posts/2017-05-04-ligature-emulation-in-emacs.md deleted file mode 100644 index ba80888ba..000000000 --- a/users/Profpatsch/blog/posts/2017-05-04-ligature-emulation-in-emacs.md +++ /dev/null @@ -1,123 +0,0 @@ -title: Ligature Emulation in Emacs -date: 2017-05-04 - -Monday was (yet another) -[NixOS hackathon][hackathon] at [OpenLab Augsburg][ola]. -[Maximilian][mhuber] was there and to my amazement -he got working ligatures in his Haskell files in Emacs! Ever since Hasklig -updated its format to use ligatures and private Unicode code points a while ago, -the hack I had used in my config stopped working. - -Encouraged by that I decided to take a look on Tuesday. Long story short, I was -able to [get it working in a pretty satisfying way][done]. - -[hackathon]: https://www.meetup.com/Munich-NixOS-Meetup/events/239077247/ -[mhuber]: https://github.com/maximilianhuber -[ola]: https://openlab-augsburg.de -[done]: https://github.com/i-tu/Hasklig/issues/84#issuecomment-298803495 - -What’s left to do is package it into a module and push to melpa. - - -### elisp still sucks, but it’s bearable, sometimes - -I’m the kind of person who, when trying to fix something elisp related, normally -gives up two hours later and three macro calls deep. Yes, homoiconic, -non-lexically-scoped, self-rewriting code is not exactly my fetish. -This time the task and the library (`prettify-symbols-mode`) were simple enough -for that to not happen. - -Some interesting technical trivia: - -- elisp literal character syntax is `?c`. `?\t` is the tab character -- You join characters by `(string c1 c2 c3 ...)` -- [dash.el][dash] is pretty awesome and does what a functional programmer - expects. Also, Rainbow Dash. -- Hasklig and FiraCode multi-column symbols actually [only occupy one column, on - the far right of the glyph][glyph]. `my-correct-symbol-bounds` fixes emacs’ - rendering in that case. - - -[dash]: https://github.com/magnars/dash.el -[glyph]: https://github.com/tonsky/FiraCode/issues/211#issuecomment-239082368 - - -## Appendix A - -For reference, here’s the complete code as it stands now. Feel free to paste -into your config; let’s make it [MIT][mit]. Maybe link to this site, in case there are -updates. - -[mit]: https://opensource.org/licenses/MIT - -```elisp - (defun my-correct-symbol-bounds (pretty-alist) - "Prepend a TAB character to each symbol in this alist, -this way compose-region called by prettify-symbols-mode -will use the correct width of the symbols -instead of the width measured by char-width." - (mapcar (lambda (el) - (setcdr el (string ?\t (cdr el))) - el) - pretty-alist)) - - (defun my-ligature-list (ligatures codepoint-start) - "Create an alist of strings to replace with -codepoints starting from codepoint-start." - (let ((codepoints (-iterate '1+ codepoint-start (length ligatures)))) - (-zip-pair ligatures codepoints))) - - ; list can be found at https://github.com/i-tu/Hasklig/blob/master/GlyphOrderAndAliasDB#L1588 - (setq my-hasklig-ligatures - (let* ((ligs '("&&" "***" "*>" "\\\\" "||" "|>" "::" - "==" "===" "==>" "=>" "=<<" "!!" ">>" - ">>=" ">>>" ">>-" ">-" "->" "-<" "-<<" - "<*" "<*>" "<|" "<|>" "<$>" "<>" "<-" - "<<" "<<<" "<+>" ".." "..." "++" "+++" - "/=" ":::" ">=>" "->>" "<=>" "<=<" "<->"))) - (my-correct-symbol-bounds (my-ligature-list ligs #Xe100)))) - - ;; nice glyphs for haskell with hasklig - (defun my-set-hasklig-ligatures () - "Add hasklig ligatures for use with prettify-symbols-mode." - (setq prettify-symbols-alist - (append my-hasklig-ligatures prettify-symbols-alist)) - (prettify-symbols-mode)) - - (add-hook 'haskell-mode-hook 'my-set-hasklig-ligatures) -``` - -## Appendix B (Update 1): FiraCode integration - -I also created a mapping for [FiraCode][fira]. You need to grab the [additional -symbol font][symbol] that adds (most) ligatures to the unicode private use area. -Consult your system documentation on how to add it to your font cache. -Next add `"Fira Code"` and `"Fira Code Symbol"` to your font preferences. Symbol -only contains the additional characters, so you need both. - -If you are on NixOS, the font package should be on the main branch shortly, [I -added a package][symbol-pkg]. - -[fira]: https://github.com/tonsky/FiraCode/ -[symbol]: https://github.com/tonsky/FiraCode/issues/211#issuecomment-239058632 -[symbol-pkg]: https://github.com/NixOS/nixpkgs/pull/25517 - -Here’s the mapping adjusted for FiraCode: - -```elisp - (setq my-fira-code-ligatures - (let* ((ligs '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\" - "{-" "[]" "::" ":::" ":=" "!!" "!=" "!==" "-}" - "--" "---" "-->" "->" "->>" "-<" "-<<" "-~" - "#{" "#[" "##" "###" "####" "#(" "#?" "#_" "#_(" - ".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*" - "/**" "/=" "/==" "/>" "//" "///" "&&" "||" "||=" - "|=" "|>" "^=" "$>" "++" "+++" "+>" "=:=" "==" - "===" "==>" "=>" "=>>" "<=" "=<<" "=/=" ">-" ">=" - ">=>" ">>" ">>-" ">>=" ">>>" "<*" "<*>" "<|" "<|>" - "<$" "<$>" "|] - Xml.NodeElement _ -> error "NodeElement not allowed here" - -prettyXmlName :: Xml.Name -> Text -prettyXmlName n = [fmt|{n.namePrefix & fromMaybe ""}{n.nameLocalName}|] - -prettyXmlElement :: Xml.Element -> Text -prettyXmlElement el = - if not $ null el.elementAttributes - then [fmt|<{prettyXmlName el.elementName}: {attrs el.elementAttributes}>|] - else [fmt|<{prettyXmlName el.elementName}>|] - where - attrs :: Map Xml.Name Text -> Text - attrs a = a & Map.toList <&> (\(k, v) -> [fmt|{prettyXmlName k}={v}|]) & Text.intercalate ", " & \s -> [fmt|({s})|] - -nodeElementMay :: Xml.Node -> Maybe Xml.Element -nodeElementMay = \case - Xml.NodeElement el -> Just el - _ -> Nothing - -element :: Text -> Parse Xml.Element Xml.Element -element name = Parse $ \(ctx, el) -> - if el.elementName.nameLocalName == name - then Success (ctx & addContext (prettyXmlName el.elementName), el) - else Failure $ singleton [fmt|Expected element named <{name}> but got {el & prettyXmlElement} at {showContext ctx}|] - -content :: Parse Xml.Node Text -content = Parse $ \(ctx, node) -> case node of - Xml.NodeContent t -> Success (ctx, t) - -- TODO: give an example of the node content? - n -> Failure $ singleton [fmt|Expected a content node, but got a {n & nodeType} node, at {showContext ctx}|] - where - nodeType = \case - Xml.NodeContent _ -> "content" :: Text - Xml.NodeComment _ -> "comment" - Xml.NodeInstruction _ -> "instruction" - Xml.NodeElement _ -> "element" - -attribute :: Text -> Parse Xml.Element Text -attribute name = Parse $ \(ctx, el) -> - case el.elementAttributes & Map.mapKeys (.nameLocalName) & Map.lookup name of - Just a -> Success (ctx & addContext [fmt|{{attr:{name}}}|], a) - Nothing -> Failure $ singleton [fmt|Attribute "{name}" missing at {showContext ctx}|] - -attributeMay :: Text -> Parse Xml.Element (Maybe Text) -attributeMay name = Parse $ \(ctx, el) -> - case el.elementAttributes & Map.mapKeys (.nameLocalName) & Map.lookup name of - Just a -> Success (ctx & addContext [fmt|{{attr:{name}}}|], Just a) - Nothing -> Success (ctx, Nothing) - -instance - ( Sqlite.FromField t1, - Sqlite.FromField t2, - Sqlite.FromField t3 - ) => - Sqlite.FromRow (T3 l1 t1 l2 t2 l3 t3) - where - fromRow = do - T3 - <$> (label @l1 <$> Sqlite.field) - <*> (label @l2 <$> Sqlite.field) - <*> (label @l3 <$> Sqlite.field) - -foldRows :: - forall row params b. - (Sqlite.FromRow row, Sqlite.ToRow params) => - Sqlite.Connection -> - Sqlite.Query -> - params -> - Fold.Fold row b -> - IO b -foldRows conn qry params = Fold.purely f - where - f :: forall x. (x -> row -> x) -> x -> (x -> b) -> IO b - f acc init extract = do - x <- Sqlite.fold conn qry params init (\a r -> pure $ acc a r) - pure $ extract x diff --git a/users/Profpatsch/jbovlaste-sqlite/default.nix b/users/Profpatsch/jbovlaste-sqlite/default.nix deleted file mode 100644 index ea59fdec3..000000000 --- a/users/Profpatsch/jbovlaste-sqlite/default.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - # bins = depot.nix.getBins pkgs.sqlite ["sqlite3"]; - - jbovlaste-sqlite = pkgs.haskellPackages.mkDerivation { - pname = "jbovlaste-sqlite"; - version = "0.1.0"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./jbovlaste-sqlite.cabal - ./JbovlasteSqlite.hs - ]; - - libraryHaskellDepends = [ - pkgs.haskellPackages.pa-prelude - pkgs.haskellPackages.pa-label - pkgs.haskellPackages.pa-error-tree - pkgs.haskellPackages.pa-field-parser - depot.users.Profpatsch.my-prelude - pkgs.haskellPackages.foldl - pkgs.haskellPackages.sqlite-simple - pkgs.haskellPackages.xml-conduit - - ]; - - isExecutable = true; - isLibrary = false; - license = lib.licenses.mit; - }; - -in -jbovlaste-sqlite diff --git a/users/Profpatsch/jbovlaste-sqlite/jbovlaste-sqlite.cabal b/users/Profpatsch/jbovlaste-sqlite/jbovlaste-sqlite.cabal deleted file mode 100644 index f677615a1..000000000 --- a/users/Profpatsch/jbovlaste-sqlite/jbovlaste-sqlite.cabal +++ /dev/null @@ -1,76 +0,0 @@ -cabal-version: 3.0 -name: jbovlaste-sqlite -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - default-language: GHC2021 - - -executable jbovlaste-sqlite - import: common-options - - main-is: JbovlasteSqlite.hs - - build-depends: - base >=4.15 && <5, - pa-prelude, - pa-label, - pa-error-tree, - pa-field-parser, - my-prelude, - containers, - selective, - semigroupoids, - validation-selective, - sqlite-simple, - foldl, - conduit, - bytestring, - text, - sqlite-simple, - xml-conduit, diff --git a/users/Profpatsch/lens.nix b/users/Profpatsch/lens.nix deleted file mode 100644 index 28f7506bd..000000000 --- a/users/Profpatsch/lens.nix +++ /dev/null @@ -1,137 +0,0 @@ -{ ... }: -let - id = x: x; - - const = x: y: x; - - comp = f: g: x: f (g x); - - _ = v: f: f v; - - # Profunctor (p :: Type -> Type -> Type) - Profunctor = rec { - # dimap :: (a -> b) -> (c -> d) -> p b c -> p a d - dimap = f: g: x: lmap f (rmap g x); - # lmap :: (a -> b) -> p b c -> p a c - lmap = f: dimap f id; - # rmap :: (c -> d) -> p b c -> p b d - rmap = g: dimap id g; - }; - - # Profunctor (->) - profunctorFun = Profunctor // { - # dimap :: (a -> b) -> (c -> d) -> (b -> c) -> a -> d - dimap = ab: cd: bc: a: cd (bc (ab a)); - # lmap :: (a -> b) -> (b -> c) -> (a -> c) - lmap = ab: bc: a: bc (ab a); - # rmap :: (c -> d) -> (b -> c) -> (b -> d) - rmap = cd: bc: b: cd (bc b); - }; - - tuple = fst: snd: { - inherit fst snd; - }; - - swap = { fst, snd }: { - fst = snd; - snd = fst; - }; - - # Profunctor p => Strong (p :: Type -> Type -> Type) - Strong = pro: pro // rec { - # firstP :: p a b -> p (a, c) (b, c) - firstP = pab: pro.dimap swap swap (pro.secondP pab); - # secondP :: p a b -> p (c, a) (c, b) - secondP = pab: pro.dimap swap swap (pro.firstP pab); - }; - - # Strong (->) - strongFun = Strong profunctorFun // { - # firstP :: (a -> b) -> (a, c) -> (b, c) - firstP = f: { fst, snd }: { fst = f fst; inherit snd; }; - # secondP :: (a -> b) -> (c, a) -> (c, b) - secondP = f: { snd, fst }: { snd = f snd; inherit fst; }; - }; - - # Iso s t a b :: forall p. Profunctor p -> p a b -> p s t - - # iso :: (s -> a) -> (b -> t) -> Iso s t a b - iso = pro: pro.dimap; - - # Lens s t a b :: forall p. Strong p -> p a b -> p s t - - # lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b - lens = strong: get: set: pab: - lensP - strong - (s: tuple (get s) (b: set s b)) - pab; - - # lensP :: (s -> (a, b -> t)) -> Lens s t a b - lensP = strong: to: pab: - strong.dimap - to - ({ fst, snd }: snd fst) - (strong.firstP pab); - - # first element of a tuple - # _1 :: Lens (a, c) (b, c) a b - _1 = strong: strong.firstP; - - # second element of a tuple - # _2 :: Lens (c, a) (c, b) a b - _2 = strong: strong.secondP; - - # a the given field in the record - # field :: (f :: String) -> Lens { f :: a; ... } { f :: b; ... } a b - field = name: strong: - lens - strong - (attrs: attrs.${name}) - (attrs: a: attrs // { ${name} = a; }); - - # Setter :: (->) a b -> (->) s t - # Setter :: (a -> b) -> (s -> t) - - - # Subclasses of profunctor for (->). - # We only have Strong for now, but when we implement Choice we need to add it here. - profunctorSubclassesFun = strongFun; - - # over :: Setter s t a b -> (a -> b) -> s -> t - over = setter: - # A setter needs to be instanced to the profunctor-subclass instances of (->). - (setter profunctorSubclassesFun); - - # set :: Setter s t a b -> b -> s -> t - set = setter: b: over setter (const b); - - # combine a bunch of optics, for the subclass instance of profunctor you give it. - optic = accessors: profunctorSubclass: - builtins.foldl' comp id - (map (accessor: accessor profunctorSubclass) accessors); - - -in -{ - inherit - id - _ - const - comp - Profunctor - profunctorFun - Strong - strongFun - iso - lens - optic - _1 - _2 - field - tuple - swap - over - set - ; -} diff --git a/users/Profpatsch/lib.nix b/users/Profpatsch/lib.nix deleted file mode 100644 index 879d87755..000000000 --- a/users/Profpatsch/lib.nix +++ /dev/null @@ -1,108 +0,0 @@ -{ depot, pkgs, ... }: -let - bins = depot.nix.getBins pkgs.coreutils [ "printf" "echo" "cat" "printenv" "tee" ] - // depot.nix.getBins pkgs.bash [ "bash" ] - // depot.nix.getBins pkgs.fdtools [ "multitee" ] - ; - - # Print `msg` and and argv to stderr, then execute into argv - debugExec = msg: depot.nix.writeExecline "debug-exec" { } [ - "if" - [ - "fdmove" - "-c" - "1" - "2" - "if" - [ bins.printf "%s: " msg ] - "if" - [ bins.echo "$@" ] - ] - "$@" - ]; - - # Print stdin to stderr and stdout - eprint-stdin = depot.nix.writeExecline "eprint-stdin" { } [ - "pipeline" - [ bins.multitee "0-1,2" ] - "$@" - ]; - - # Assume the input on stdin is netencode, pretty print it to stderr and forward it to stdout - eprint-stdin-netencode = depot.nix.writeExecline "eprint-stdin-netencode" { } [ - "pipeline" - [ - # move stdout to 3 - "fdmove" - "3" - "1" - # the multitee copies stdin to 1 (the other pipeline end) and 3 (the stdout of the outer pipeline block) - "pipeline" - [ bins.multitee "0-1,3" ] - # make stderr the stdout of pretty, merging with the stderr of pretty - "fdmove" - "-c" - "1" - "2" - depot.users.Profpatsch.netencode.pretty - ] - "$@" - ]; - - # print the given environment variable in $1 to stderr, then execute into the rest of argv - eprintenv = depot.nix.writeExecline "eprintenv" { readNArgs = 1; } [ - "ifelse" - [ "fdmove" "-c" "1" "2" bins.printenv "$1" ] - [ "$@" ] - "if" - [ depot.tools.eprintf "eprintenv: could not find \"\${1}\" in the environment\n" ] - "$@" - ]; - - # Split stdin into two commands, given by a block and the rest of argv - # - # Example (execline): - # - # pipeline [ echo foo ] - # split-stdin [ fdmove 1 2 foreground [ cat ] echo "bar" ] cat - # - # stdout: foo\n - # stderr: foo\nbar\n - split-stdin = depot.nix.writeExecline "split-stdin" { argMode = "env"; } [ - "pipeline" - [ - # this is horrible yes but the quickest way I knew how to implement it - "runblock" - "1" - bins.bash - "-c" - ''${bins.tee} >("$@")'' - "bash-split-stdin" - ] - "runblock" - "-r" - "1" - ]; - - # remove everything but a few selected environment variables - runInEmptyEnv = keepVars: - let - importas = pkgs.lib.concatMap (var: [ "importas" "-i" var var ]) keepVars; - # we have to explicitely call export here, because PATH is probably empty - export = pkgs.lib.concatMap (var: [ "${pkgs.execline}/bin/export" var ''''${${var}}'' ]) keepVars; - in - depot.nix.writeExecline "empty-env" { } - (importas ++ [ "emptyenv" ] ++ export ++ [ "${pkgs.execline}/bin/exec" "$@" ]); - - -in -{ - inherit - debugExec - eprint-stdin - eprint-stdin-netencode - eprintenv - split-stdin - runInEmptyEnv - ; -} diff --git a/users/Profpatsch/lorri-wait-for-eval/LorriWaitForEval.hs b/users/Profpatsch/lorri-wait-for-eval/LorriWaitForEval.hs deleted file mode 100644 index a1a458640..000000000 --- a/users/Profpatsch/lorri-wait-for-eval/LorriWaitForEval.hs +++ /dev/null @@ -1,173 +0,0 @@ -{-# LANGUAGE DerivingStrategies #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE NumericUnderscores #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# OPTIONS_GHC -Wall #-} - -module Main where - -import Conduit -import Conduit qualified as Cond -import Control.Concurrent -import Control.Concurrent.Async qualified as Async -import Control.Monad -import Data.Aeson.BetterErrors qualified as Json -import Data.Bifunctor -import Data.Conduit.Binary qualified as Conduit.Binary -import Data.Conduit.Combinators qualified as Cond -import Data.Conduit.Process -import Data.Error -import Data.Function -import Data.Functor -import Data.Text.IO (hPutStrLn) -import MyPrelude -import System.Directory qualified as Dir -import System.Environment qualified as Env -import System.Exit qualified as Exit -import System.FilePath (takeDirectory) -import System.FilePath.Posix qualified as FilePath -import System.IO (stderr) -import System.Posix qualified as Posix -import Prelude hiding (log) - -data LorriEvent = LorriEvent - { nixFile :: Text, - eventType :: LorriEventType - } - deriving stock (Show) - -data LorriEventType - = Completed - | Started - | EvalFailure - deriving stock (Show) - -main :: IO () -main = do - argv <- Env.getArgs <&> nonEmpty - - dir <- Dir.getCurrentDirectory - shellNix <- - findShellNix dir >>= \case - Nothing -> Exit.die [fmt|could not find any shell.nix in or above the directory {dir}|] - Just s -> pure s - getEventChan :: MVar (Chan LorriEvent) <- newEmptyMVar - Async.race_ - ( do - sendEventChan :: Chan LorriEvent <- newChan - (exitCode, ()) <- - sourceProcessWithConsumer - (proc "lorri" ["internal", "stream-events"]) - $ - -- first, we want to send a message over the chan that the process is running (for timeout) - liftIO (putMVar getEventChan sendEventChan) - *> Conduit.Binary.lines - .| Cond.mapC - ( \jsonBytes -> - (jsonBytes :: ByteString) - & Json.parseStrict - ( Json.key - "Completed" - ( do - nixFile <- Json.key "nix_file" Json.asText - pure LorriEvent {nixFile, eventType = Completed} - ) - Json.<|> Json.key - "Started" - ( do - nixFile <- Json.key "nix_file" Json.asText - pure LorriEvent {nixFile, eventType = Started} - ) - Json.<|> Json.key - "Failure" - ( do - nixFile <- Json.key "nix_file" Json.asText - pure LorriEvent {nixFile, eventType = EvalFailure} - ) - ) - & first Json.displayError' - & first (map newError) - & first (smushErrors [fmt|Cannot parse line returned by lorri: {jsonBytes & bytesToTextUtf8Lenient}|]) - & unwrapError - ) - .| (Cond.mapM_ (\ev -> writeChan sendEventChan ev)) - - log [fmt|lorri internal stream-events exited {show exitCode}|] - ) - ( do - let waitMs ms = threadDelay (ms * 1000) - - -- log [fmt|Waiting for lorri event for {shellNix}|] - - eventChan <- takeMVar getEventChan - - let isOurEvent ev = FilePath.normalise (ev & nixFile & textToString) == FilePath.normalise shellNix - - let handleEvent ev = - case ev & eventType of - Started -> - log [fmt|waiting for lorri build to finish|] - Completed -> do - log [fmt|build completed|] - exec (inDirenvDir (takeDirectory shellNix) <$> argv) - EvalFailure -> do - log [fmt|evaluation failed! for path {ev & nixFile}|] - Exit.exitWith (Exit.ExitFailure 111) - - -- wait for 100ms for the first message from lorri, - -- or else assume lorri is not building the project yet - Async.race - (waitMs 100) - ( do - -- find the first event that we can use - let go = do - ev <- readChan eventChan - if isOurEvent ev then pure ev else go - go - ) - >>= \case - Left () -> do - log [fmt|No event received from lorri, assuming this is the first evaluation|] - exec argv - Right ch -> handleEvent ch - - runConduit $ - repeatMC (readChan eventChan) - .| filterC isOurEvent - .| mapM_C handleEvent - ) - where - inDirenvDir dir' argv' = ("direnv" :| ["exec", dir']) <> argv' - exec = \case - Just (exe :| args') -> Posix.executeFile exe True args' Nothing - Nothing -> Exit.exitSuccess - -log :: Text -> IO () -log msg = hPutStrLn stderr [fmt|lorri-wait-for-eval: {msg}|] - --- | Searches from the current directory upwards, until it finds the `shell.nix`. -findShellNix :: FilePath -> IO (Maybe FilePath) -findShellNix curDir = do - let go :: (FilePath -> IO (Maybe FilePath)) - go dir = do - let file = dir FilePath. "shell.nix" - Dir.doesFileExist file >>= \case - True -> pure (Just file) - False -> do - let parent = FilePath.takeDirectory dir - if parent == dir - then pure Nothing - else go parent - go (FilePath.normalise curDir) - -smushErrors :: Foldable t => Text -> t Error -> Error -smushErrors msg errs = - errs - -- hrm, pretty printing and then creating a new error is kinda shady - & foldMap (\err -> "\n- " <> prettyError err) - & newError - & errorContext msg diff --git a/users/Profpatsch/lorri-wait-for-eval/README.md b/users/Profpatsch/lorri-wait-for-eval/README.md deleted file mode 100644 index 9c5d8ef9e..000000000 --- a/users/Profpatsch/lorri-wait-for-eval/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# lorri-wait-for-eval - -A helper script for [lorri](https://github.com/nix-community/lorri), which wraps a command and executes it once lorri is finished evaluating the current `shell.nix`, and uses the new environment. - -This is useful when you need the new shell environment to be in scope of the command, but don’t want to waste time waiting for it to finish. - -This should really be a feature of lorri, but I couldn’t be assed to touch rust :P diff --git a/users/Profpatsch/lorri-wait-for-eval/default.nix b/users/Profpatsch/lorri-wait-for-eval/default.nix deleted file mode 100644 index 90c6365fe..000000000 --- a/users/Profpatsch/lorri-wait-for-eval/default.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - lorri-wait-for-eval = pkgs.writers.writeHaskell "lorri-wait-for-eval" - { - libraries = [ - depot.users.Profpatsch.my-prelude - pkgs.haskellPackages.async - pkgs.haskellPackages.aeson-better-errors - pkgs.haskellPackages.conduit-extra - pkgs.haskellPackages.error - pkgs.haskellPackages.PyF - pkgs.haskellPackages.unliftio - ]; - ghcArgs = [ "-threaded" ]; - - } ./LorriWaitForEval.hs; - -in -lorri-wait-for-eval diff --git a/users/Profpatsch/lyric/.gitignore b/users/Profpatsch/lyric/.gitignore deleted file mode 100644 index 226235d62..000000000 --- a/users/Profpatsch/lyric/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -/dist/ -/.ninja/ -/node_modules/ - -# ignore for now -/package-lock.json diff --git a/users/Profpatsch/lyric/.prettierrc b/users/Profpatsch/lyric/.prettierrc deleted file mode 120000 index 5b5fb8c8b..000000000 --- a/users/Profpatsch/lyric/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -../.prettierrc \ No newline at end of file diff --git a/users/Profpatsch/lyric/build.ninja b/users/Profpatsch/lyric/build.ninja deleted file mode 100644 index a5752bef5..000000000 --- a/users/Profpatsch/lyric/build.ninja +++ /dev/null @@ -1,17 +0,0 @@ -builddir = .ninja - -outdir = ./dist -jsdir = $outdir/js - -rule tsc - command = node_modules/.bin/tsc - -build $outdir/index.js: tsc | src/index.ts tsconfig.json - -rule run - command = node $in - -build run: run $outdir/index.js - -build run-tap-bpm: run $outdir/index.js tap-bpm - pool = console diff --git a/users/Profpatsch/lyric/default.nix b/users/Profpatsch/lyric/default.nix deleted file mode 100644 index fee06e353..000000000 --- a/users/Profpatsch/lyric/default.nix +++ /dev/null @@ -1,149 +0,0 @@ -{ pkgs, depot, lib, ... }: - -let - bins = depot.nix.getBins pkgs.sqlite [ "sqlite3" ] - // depot.nix.getBins pkgs.util-linux [ "unshare" ] - // depot.nix.getBins pkgs.coreutils [ "echo" ] - // depot.nix.getBins pkgs.gnused [ "sed" ] - // depot.nix.getBins pkgs.squashfuse [ "squashfuse" ] - // depot.nix.getBins pkgs.jq [ "jq" ]; - - mpv-script = pkgs.writeTextFile { - name = "lyric.lua"; - text = - lib.replaceStrings - [ "@get_subtitles_command@" ] - [ (toString lyric-to-temp-file) ] - (builtins.readFile ./lyric-mpv-script.lua); - derivationArgs.passthru.scriptName = "lyric.lua"; - }; - - lyric-to-temp-file = depot.nix.writeExecline "lyric-to-temp-file" { readNArgs = 1; } [ - "backtick" - "-E" - "cache" - [ depot.users.Profpatsch.xdg-cache-home ] - "if" - [ "mkdir" "-p" "\${cache}/lyric/as-files" ] - "if" - [ - "redirfd" - "-w" - "1" - "\${cache}/lyric/as-files/\${1}.lrc" - lyric - "$1" - ] - "printf" - "\${cache}/lyric/as-files/\${1}.lrc" - ]; - - # looool - escapeSqliteString = depot.nix.writeExecline "escape-sqlite-string" { readNArgs = 1; } [ - "pipeline" - [ - "printf" - "%s" - "$1" - ] - bins.sed - "s/''/''''/g" - ]; - - # Display lyrics for the given search string; - # search string can contain a substring of band name, album name, song title - # - # Use the database dump from https://lrclib.net/db-dumps and place it in ~/.cache/lyric/lrclib-db-dump.sqlite3 - # - # TODO: put in the nodejs argh - lyric = - (depot.nix.writeExecline "lyric" { readNArgs = 1; } [ - "backtick" - "-E" - "cache" - [ depot.users.Profpatsch.xdg-cache-home ] - # make sure the squashfuse is only mounted while the command is running - bins.unshare - "--user" - "--mount" - "--pid" - "--map-root-user" - "--kill-child" - "if" - [ "mkdir" "-p" "\${cache}/lyric/dump" ] - # TODO: provide a command that takes an url of a lyric.gz and converts it to this here squash image - "if" - [ bins.squashfuse "-ononempty" "\${cache}/lyric/lyric-db.squash" "\${cache}/lyric/dump" ] - # please help me god - "backtick" - "-E" - "searchstring" - [ escapeSqliteString "$1" ] - "pipeline" - [ - "pipeline" - [ - "echo" - ('' - .mode json - select * from ( - -- first we try to find if we can find the track verbatim - select * from (select - synced_lyrics, - has_synced_lyrics, - plain_lyrics - from - tracks_fts('' + "'\${searchstring}'" + '') tf - join tracks t on t.rowid = tf.rowid - join lyrics l on t.rowid = l.track_id - order by - has_synced_lyrics desc, t.id - ) - UNION - select * from (select - synced_lyrics, - has_synced_lyrics, - plain_lyrics - from - tracks_fts('' + "'\${searchstring}'" + '') tf - join tracks t on t.rowid = tf.rowid - join lyrics l on t.rowid = l.track_id - order by - has_synced_lyrics desc, t.id - ) - ) - where synced_lyrics is not null and synced_lyrics != '''' - and plain_lyrics is not null and plain_lyrics != '''' - limit - 1; - '' - ) - ] - bins.sqlite3 - "file:\${cache}/lyric/dump/lrclib-db-dump.sqlite3?immutable=1" - ] - bins.jq - "-r" - '' - if .[0] == null - then "" - else - .[0] - | if .has_synced_lyrics == 1 - then .synced_lyrics - else .plain_lyrics - end - end - '' - ]); - - - js = depot.users.Profpatsch.napalm.buildPackage ./. { }; - -in -{ - inherit - lyric - js - mpv-script; -} diff --git a/users/Profpatsch/lyric/eslint.config.mjs b/users/Profpatsch/lyric/eslint.config.mjs deleted file mode 100644 index 60ee4ab9b..000000000 --- a/users/Profpatsch/lyric/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import config from '../eslint.config.mjs'; - -export default config; diff --git a/users/Profpatsch/lyric/extension/.gitignore b/users/Profpatsch/lyric/extension/.gitignore deleted file mode 100644 index d2405ad64..000000000 --- a/users/Profpatsch/lyric/extension/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/node_modules/ -/out/ - -# ignore for now -/package-lock.json diff --git a/users/Profpatsch/lyric/extension/.prettierrc b/users/Profpatsch/lyric/extension/.prettierrc deleted file mode 120000 index 73b7c6b3d..000000000 --- a/users/Profpatsch/lyric/extension/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -../../.prettierrc \ No newline at end of file diff --git a/users/Profpatsch/lyric/extension/LICENSE b/users/Profpatsch/lyric/extension/LICENSE deleted file mode 100644 index 4292032e6..000000000 --- a/users/Profpatsch/lyric/extension/LICENSE +++ /dev/null @@ -1 +0,0 @@ -same as toplevel diff --git a/users/Profpatsch/lyric/extension/eslint.config.mjs b/users/Profpatsch/lyric/extension/eslint.config.mjs deleted file mode 100644 index 9d3eef2c3..000000000 --- a/users/Profpatsch/lyric/extension/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import config from '../../eslint.config.mjs'; - -export default config; diff --git a/users/Profpatsch/lyric/extension/package.json b/users/Profpatsch/lyric/extension/package.json deleted file mode 100644 index 73bf53e81..000000000 --- a/users/Profpatsch/lyric/extension/package.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "name": "profpatsch-jump-to-lrc-position", - "displayName": "Jump to .lrc Position in mpv", - "description": "Reads a timestamp from the current file and pipes it to a mpv socket", - "version": "0.0.1", - "engines": { - "vscode": "^1.75.0" - }, - "categories": [ - "Other" - ], - "main": "./out/extension.js", - "activationEvents": [ - "onLanguage:lrc" - ], - "contributes": { - "commands": [ - { - "command": "extension.jumpToLrcPosition", - "title": "Jump to .lrc Position", - "category": "LRC" - }, - { - "command": "extension.shiftLyricsDown", - "title": "Shift Lyrics Down from Current Line", - "category": "LRC" - }, - { - "command": "extension.shiftLyricsUp", - "title": "Shift Lyrics Up from Current Line", - "category": "LRC" - }, - { - "command": "extension.tapBpm", - "title": "Add bpm header by tapping to the song", - "category": "LRC" - }, - { - "command": "extension.quantizeToEigthNote", - "title": "Quantize timestamps to nearest eighth note", - "category": "LRC" - }, - { - "command": "extension.fineTuneTimestampDown100MsAndPlay", - "title": "Remove 100 ms from current timestamp and play from shortly before the change", - "category": "LRC" - }, - { - "command": "extension.fineTuneTimestampUp100MsAndPlay", - "title": "Add 100 ms to current timestamp and play from shortly before the change", - "category": "LRC" - }, - { - "command": "extension.uploadLyricsToLrclibDotNet", - "title": "Upload Lyrics to lrclib.net", - "category": "LRC" - } - ], - "languages": [ - { - "id": "lrc", - "extensions": [ - ".lrc" - ], - "aliases": [ - "Lyric file" - ] - } - ] - }, - "scripts": { - "vscode:prepublish": "npm run compile", - "compile": "tsc", - "install-extension": "vsce package --allow-missing-repository --out ./jump-to-lrc-position.vsix && code --install-extension ./jump-to-lrc-position.vsix" - }, - "devDependencies": { - "vscode": "^1.1.37", - "@eslint/js": "^9.10.0", - "@types/eslint__js": "^8.42.3", - "@types/node": "^22.5.5", - "@typescript-eslint/parser": "^8.7.0", - "eslint": "^9.10.0", - "globals": "^15.9.0", - "typescript": "^5.6.2", - "typescript-eslint": "^8.6.0" - } -} diff --git a/users/Profpatsch/lyric/extension/src/extension.ts b/users/Profpatsch/lyric/extension/src/extension.ts deleted file mode 100644 index 35f76f3fe..000000000 --- a/users/Profpatsch/lyric/extension/src/extension.ts +++ /dev/null @@ -1,864 +0,0 @@ -import * as vscode from 'vscode'; -import * as net from 'net'; -import { adjustTimestampToEighthNote, bpmToEighthNoteDuration } from './quantize-lrc'; -import { publishLyrics, PublishRequest } from './upload-lrc'; - -const channel_global = vscode.window.createOutputChannel('LRC'); - -export function activate(context: vscode.ExtensionContext) { - context.subscriptions.push(...registerCheckLineTimestamp(context)); - context.subscriptions.push( - vscode.commands.registerCommand('extension.jumpToLrcPosition', jumpToLrcPosition), - vscode.commands.registerCommand('extension.shiftLyricsDown', shiftLyricsDown), - vscode.commands.registerCommand('extension.shiftLyricsUp', shiftLyricsUp), - vscode.commands.registerCommand('extension.tapBpm', tapBpm), - vscode.commands.registerCommand('extension.quantizeToEigthNote', quantizeToEigthNote), - vscode.commands.registerCommand( - 'extension.fineTuneTimestampDown100MsAndPlay', - fineTuneTimestampAndPlay(-100), - ), - vscode.commands.registerCommand( - 'extension.fineTuneTimestampUp100MsAndPlay', - fineTuneTimestampAndPlay(100), - ), - vscode.commands.registerCommand( - 'extension.uploadLyricsToLrclibDotNet', - uploadToLrclibDotNet, - ), - ); -} - -/** - * Jumps to the position in the lyric file corresponding to the current cursor position in the active text editor. - * Sends a command to a socket to seek to the specified position in mpv at the socket path `~/tmp/mpv-socket`. - * @remarks - * This function requires the following dependencies: - * - `vscode` module for accessing the active text editor and displaying messages. - * - `net` module for creating a socket connection. - * @throws {Error} If there is an error sending the command to the socket. - */ -function jumpToLrcPosition() { - const editor = vscode.window.activeTextEditor; - - if (!editor) { - vscode.window.showErrorMessage('No active editor found.'); - return; - } - - const ext = new Ext(editor.document); - const position = editor.selection.active; - const res = ext.getTimestampFromLine(position.line); - - if (!res) { - return; - } - const { milliseconds, seconds } = res; - - // Prepare JSON command to send to the socket - const seekCommand = { - command: ['seek', seconds, 'absolute'], - }; - const reloadSubtitlesCommand = { - command: ['sub-reload'], - }; - - const socket = new net.Socket(); - - const socketPath = process.env.HOME + '/tmp/mpv-socket'; - socket.connect(socketPath, () => { - socket.write(JSON.stringify(seekCommand)); - socket.write('\n'); - socket.write(JSON.stringify(reloadSubtitlesCommand)); - socket.write('\n'); - vscode.window.showInformationMessage( - `Sent command to jump to [${formatTimestamp(milliseconds)}] and sync subtitles.`, - ); - socket.end(); - }); - - socket.on('error', err => { - vscode.window.showErrorMessage(`Failed to send command: ${err.message}`); - }); -} - -/** - * Shifts the lyrics down by one line starting from the current cursor position in the active text editor. - * @remarks - * This function requires the following dependencies: - * - `vscode` module for accessing the active text editor and displaying messages. - */ -async function shiftLyricsDown() { - const editor = vscode.window.activeTextEditor; - - if (!editor) { - vscode.window.showErrorMessage('No active editor found.'); - return; - } - - const ext = new Ext(editor.document); - - const getLine = (line: number) => ({ - number: line, - range: editor.document.lineAt(line), - }); - - // get the document range from the beginning of the current line to the end of the file - const documentRange = new vscode.Range( - getLine(editor.selection.active.line).range.range.start, - editor.document.lineAt(editor.document.lineCount - 1).range.end, - ); - - let newLines: string = ''; - // iterate through all lines under the current line, save the lyric text from the current line, and replace it with the lyric text from the previous line - let previousLineText = ''; - for ( - // get the current line range - let line = getLine(editor.selection.active.line); - line.number < editor.document.lineCount - 1; - // next line as position from line number - line = getLine(line.number + 1) - ) { - const timestamp = ext.getTimestampFromLine(line.number); - if (timestamp === undefined) { - newLines += line.range.text + '\n'; - continue; - } - newLines += `[${formatTimestamp(timestamp.milliseconds)}]` + previousLineText + '\n'; - previousLineText = timestamp.text; - } - // replace documentRange with newLines - await editor.edit(editBuilder => { - editBuilder.replace(documentRange, newLines); - }); -} - -/** - * Shifts the lyrics up by one line starting from the current cursor position in the active text editor. - * @remarks - * This function requires the following dependencies: - * - `vscode` module for accessing the active text editor and displaying messages. - */ -async function shiftLyricsUp() { - const editor = vscode.window.activeTextEditor; - - if (!editor) { - vscode.window.showErrorMessage('No active editor found.'); - return; - } - - const ext = new Ext(editor.document); - - const getLine = (line: number) => ({ - number: line, - range: editor.document.lineAt(line), - }); - - // get the document range from the beginning of the current line to the end of the file - const documentRange = new vscode.Range( - getLine(editor.selection.active.line).range.range.start, - editor.document.lineAt(editor.document.lineCount - 1).range.end, - ); - - let newLines: string = ''; - // iterate through all lines under the current line, save the lyric text from the current line, and replace it with the lyric text from the next line - for ( - // get the current line range - let line = getLine(editor.selection.active.line); - line.number < editor.document.lineCount - 2; - // next line as position from line number - line = getLine(line.number + 1) - ) { - const nextLineText = - ext.getTimestampFromLine(line.number + 1)?.text ?? - ext.document.lineAt(line.number + 1).text; - const timestamp = ext.getTimestampFromLine(line.number); - if (timestamp === undefined) { - continue; - } - newLines += `[${formatTimestamp(timestamp.milliseconds)}]` + nextLineText + '\n'; - } - // replace documentRange with newLines - await editor.edit(editBuilder => { - editBuilder.replace(documentRange, newLines); - }); -} - -/** - * Tap the BPM of the track and write it to the header of the active text editor. - * @remarks - * This function requires the following dependencies: - * - `vscode` module for accessing the active text editor and displaying messages. - */ -async function tapBpm() { - const editor = vscode.window.activeTextEditor; - - if (!editor) { - vscode.window.showErrorMessage('No active editor found.'); - return; - } - - const ext = new Ext(editor.document); - const startBpm = ext.findBpmHeader(); - - const bpm = await timeInputBpm(startBpm); - - if (bpm === undefined) { - return; - } - - await ext.writeHeader('bpm', bpm.toString()); -} - -/** first ask the user for the BPM of the track, then quantize the timestamps in the active text editor to the closest eighth note based on the given BPM */ -async function quantizeToEigthNote() { - const editor = vscode.window.activeTextEditor; - - if (!editor) { - vscode.window.showErrorMessage('No active editor found.'); - return; - } - - const ext = new Ext(editor.document); - - const startBpm = ext.findBpmHeader(); - const bpm = await timeInputBpm(startBpm); - - if (bpm === undefined) { - return; - } - - await ext.writeHeader('bpm', bpm.toString()); - - const getLine = (line: number) => ({ - number: line, - range: editor.document.lineAt(line), - }); - - const documentRange = new vscode.Range( - getLine(0).range.range.start, - editor.document.lineAt(editor.document.lineCount - 1).range.end, - ); - - const eighthNoteDuration = bpmToEighthNoteDuration(bpm); - - let newLines: string = ''; - for ( - let line = getLine(0); - line.number < editor.document.lineCount - 1; - line = getLine(line.number + 1) - ) { - const timestamp = ext.getTimestampFromLine(line.number); - if (timestamp === undefined) { - newLines += line.range.text + '\n'; - continue; - } - const adjustedMs = adjustTimestampToEighthNote( - timestamp.milliseconds, - eighthNoteDuration, - ); - newLines += `[${formatTimestamp(adjustedMs)}]${timestamp.text}\n`; - } - - await editor.edit(editBuilder => { - editBuilder.replace(documentRange, newLines); - }); -} - -/** fine tune the timestamp of the current line by the given amount (in milliseconds) and play the track at slightly before the new timestamp */ -function fineTuneTimestampAndPlay(amountMs: number) { - return async () => { - const editor = vscode.window.activeTextEditor; - - if (!editor) { - vscode.window.showErrorMessage('No active editor found.'); - return; - } - - const ext = new Ext(editor.document); - - const position = editor.selection.active; - const res = ext.getTimestampFromLine(position.line); - - if (!res) { - return; - } - const { milliseconds } = res; - - const newMs = milliseconds + amountMs; - - // adjust the timestamp - const documentRange = editor.document.lineAt(position.line).range; - await editor.edit(editBuilder => { - editBuilder.replace(documentRange, `[${formatTimestamp(newMs)}]${res.text}`); - }); - - const PLAY_BEFORE_TIMESTAMP_MS = 2000; - const seekCommand = { - command: ['seek', (newMs - PLAY_BEFORE_TIMESTAMP_MS) / 1000, 'absolute'], - }; - const reloadSubtitlesCommand = { - command: ['sub-reload'], - }; - - const socket = new net.Socket(); - - const socketPath = process.env.HOME + '/tmp/mpv-socket'; - socket.connect(socketPath, () => { - socket.write(JSON.stringify(seekCommand)); - socket.write('\n'); - socket.write(JSON.stringify(reloadSubtitlesCommand)); - socket.write('\n'); - vscode.window.showInformationMessage( - `Sent command to jump to [${formatTimestamp(newMs)}] and sync subtitles.`, - ); - socket.end(); - }); - - socket.on('error', err => { - vscode.window.showErrorMessage(`Failed to send command: ${err.message}`); - }); - }; -} - -// convert the given bpm to miliseconds -function bpmToMs(bpm: number) { - return Math.floor((60 / bpm) * 1000); -} - -// Show input boxes in a loop, and record the time between each input, averaging the last 5 inputs over a sliding window, then calculate the BPM of the average -async function timeInputBpm(startBpm?: number) { - const startBpmMs = bpmToMs(startBpm ?? 120); - const timeDifferences: number[] = [ - startBpmMs, - startBpmMs, - startBpmMs, - startBpmMs, - startBpmMs, - ]; - // assign a weight to the time differences, so that the most recent time differences have more weight - const weights = [0.1, 0.1, 0.2, 0.3, 0.3]; - - const calculateBPM = () => { - // use a weighted average here - let avg = 0; - for (let i = 0; i < timeDifferences.length; i++) { - avg += timeDifferences[i] * weights[i]; - } - - return Math.floor(60000 / avg); - }; - - let lastPressTime = Date.now(); - let firstLoop = true; - while (true) { - const res = await vscode.window.showInputBox({ - prompt: `Press enter to record BPM (current BPM: ${calculateBPM()}), enter the final BPM once you know, or press esc to finish`, - placeHolder: 'BPM', - value: startBpm !== undefined && firstLoop ? startBpm.toString() : undefined, - }); - firstLoop = false; - if (res === undefined) { - return undefined; - } - if (res !== '') { - const resBpm = parseInt(res, 10); - if (isNaN(resBpm)) { - vscode.window.showErrorMessage('Invalid BPM'); - continue; - } - return resBpm; - } - - const now = Date.now(); - const timeDiff = now - lastPressTime; - // Add the time difference to the array (limit to last 5 key presses) - timeDifferences.shift(); // Remove the oldest time difference - timeDifferences.push(timeDiff); - - lastPressTime = now; - } -} - -/** - * Uploads the lyrics in the active text editor to the LrclibDotNet API. - * @remarks - * This function requires the following dependencies: - * - `vscode` module for accessing the active text editor and displaying messages. - * - `fetch` module for making HTTP requests. - * @throws {Error} If there is an HTTP error. - */ -async function uploadToLrclibDotNet() { - const editor = vscode.window.activeTextEditor; - - if (!editor) { - vscode.window.showErrorMessage('No active editor found.'); - return; - } - - const ext = new Ext(editor.document); - - const title = ext.findHeader('ti')?.value; - const artist = ext.findHeader('ar')?.value; - const album = ext.findHeader('al')?.value; - const lengthString = ext.findHeader('length')?.value; - - if ( - title === undefined || - artist === undefined || - album === undefined || - lengthString === undefined - ) { - vscode.window.showErrorMessage( - 'Missing required headers: title, artist, album, length', - ); - return; - } - // parse length as mm:ss - const [minutes, seconds] = lengthString?.split(':') ?? []; - if ( - !minutes || - !seconds || - isNaN(parseInt(minutes, 10)) || - isNaN(parseInt(seconds, 10)) - ) { - vscode.window.showErrorMessage('Invalid length header, expected format: mm:ss'); - return; - } - const length = parseInt(minutes, 10) * 60 + parseInt(seconds, 10); - - const syncedLyrics = ext.getLyricsPart(); - const plainLyrics = plainLyricsFromLyrics(syncedLyrics); - - // open a html preview with the lyrics saying - // - // Uploading these lyrics to lrclib.net: - // - // Lyrics: - // `````` - // Plain lyrics: - // `````` - // - // Is this ok? - // - `; - - const panel = vscode.window.createWebviewPanel( - 'lyricPreview', - previewTitle, - vscode.ViewColumn.One, - { enableScripts: true }, - ); - panel.webview.html = ` - - - - - - Markdown Preview - - - ${previewContent} - - - - `; - let isDisposed = false; - panel.onDidDispose(() => { - isDisposed = true; - }); - - await new Promise((resolve, _reject) => { - panel.webview.onDidReceiveMessage((message: { command: string }) => { - if (isDisposed) { - return; - } - if (message.command === 'upload') { - panel.dispose(); - resolve(true); - } - }); - }); - - const toUpload: PublishRequest = { - trackName: title, - artistName: artist, - albumName: album, - duration: length, - plainLyrics: plainLyrics, - syncedLyrics: syncedLyrics, - }; - - // log the data to our extension output buffer - channel_global.appendLine('Uploading lyrics to LrclibDotNet'); - const json = JSON.stringify(toUpload, null, 2); - channel_global.appendLine(json); - - const res = await publishLyrics(toUpload); - - if (res) { - vscode.window.showInformationMessage('Lyrics successfully uploaded.'); - channel_global.appendLine('Lyrics successfully uploaded.'); - } else { - vscode.window.showErrorMessage('Failed to upload lyrics.'); - channel_global.appendLine('Failed to upload lyrics.'); - } -} - -// If the difference to the timestamp on the next line is larger than 10 seconds (for 120 BPM), underline the next line and show a warning message on hover -export function registerCheckLineTimestamp(_context: vscode.ExtensionContext) { - const changesToCheck: Set = new Set(); - const everSeen = new Set(); - - return [ - vscode.workspace.onDidChangeTextDocument(e => { - changesToCheck.add(e.document); - if (vscode.window.activeTextEditor?.document === e.document) { - doEditorChecks(vscode.window.activeTextEditor.document, everSeen, changesToCheck); - } - }), - vscode.workspace.onDidOpenTextDocument(e => { - changesToCheck.add(e); - everSeen.add(e); - if (vscode.window.activeTextEditor?.document === e) { - doEditorChecks(vscode.window.activeTextEditor.document, everSeen, changesToCheck); - } - }), - - vscode.window.onDidChangeActiveTextEditor(editor => { - if (editor) { - doEditorChecks(editor.document, everSeen, changesToCheck); - } - }), - vscode.window.onDidChangeVisibleTextEditors(editors => { - for (const editor of editors) { - doEditorChecks(editor.document, everSeen, changesToCheck); - } - }), - ]; -} - -function doEditorChecks( - document: vscode.TextDocument, - everSeen: Set, - changesToCheck: Set, -) { - const ext = new Ext(document); - - if (!everSeen.has(document)) { - changesToCheck.add(document); - everSeen.add(document); - } - - if (!changesToCheck.has(document)) { - return; - } - changesToCheck.delete(document); - - const from = 0; - const to = document.lineCount - 1; - for (let line = from; line <= to; line++) { - const warnings: string[] = []; - const timeDiff = timeDifferenceTooLarge(ext, line); - if (timeDiff !== undefined) { - warnings.push(timeDiff); - } - const nextTimestampSmaller = nextLineTimestampSmallerThanCurrent(ext, line); - if (nextTimestampSmaller !== undefined) { - warnings.push(nextTimestampSmaller); - } - for (const warning of warnings) { - global_manageWarnings.setWarning(document, line, warning); - } - // unset any warnings if this doesn’t apply anymore - if (warnings.length === 0) { - global_manageWarnings.setWarning(document, line); - } - } -} - -/** Warn if the difference to the timestamp on the next line is larger than - * * 10 seconds at 120 BPM - * * 5 seconds at 240 BPM - * * 20 seconds at 60 BPM - * * etc - */ -function timeDifferenceTooLarge(ext: Ext, line: number): string | undefined { - const bpm = ext.findBpmHeader() ?? 120; - const maxTimeDifference = 10000 * (120 / bpm); - const timeDifference = ext.getTimeDifferenceToNextLineTimestamp( - new vscode.Position(line, 0), - ); - if ( - !timeDifference || - timeDifference.thisLineIsEmpty || - timeDifference.difference <= maxTimeDifference - ) { - return; - } - return `Time difference to next line is ${formatTimestamp( - timeDifference.difference, - )}, should there be silence here? At ${bpm} BPM, we assume anything more than ${( - maxTimeDifference / 1000 - ).toFixed(2)} seconds is a mistake.`; -} - -/** Warn if the timestamp on the next line is smaller or equal to the current timestamp */ -function nextLineTimestampSmallerThanCurrent(ext: Ext, line: number): string | undefined { - const timeDifference = ext.getTimeDifferenceToNextLineTimestamp( - new vscode.Position(line, 0), - ); - if (!timeDifference) { - return; - } - if (timeDifference.difference == 0) { - return `The timestamp to the next line is not increasing`; - } - if (timeDifference.difference < 0) { - return `The timestamp to the next line is decreasing`; - } -} - -class Ext { - constructor(public document: vscode.TextDocument) {} - - getTimeDifferenceToNextLineTimestamp(position: vscode.Position) { - const thisLineTimestamp = this.getTimestampFromLine(position.line); - const nextLineTimestamp = this.getTimestampFromLine(position.line + 1); - if (!thisLineTimestamp || !nextLineTimestamp) { - return; - } - return { - difference: nextLineTimestamp.milliseconds - thisLineTimestamp.milliseconds, - thisLineIsEmpty: thisLineTimestamp.text.trim() === '', - }; - } - - /** - * Retrieves the timestamp and text from the line at the given position in the active text editor. - * - * @param position - The position of the line in the editor. - * @returns An object containing the milliseconds, seconds, and text extracted from the line. - */ - getTimestampFromLine(line: number) { - const lineText = this.document.lineAt(line).text; - return this.getTimestampFromLineText(lineText); - } - - getTimestampFromLineText(lineText: string) { - // Extract timestamp [mm:ss.ms] from the current line - const match = lineText.match(/\[(\d+:\d+\.\d+)\](.*)/); - if (!match) { - return; - } - const [, timestamp, text] = match; - const milliseconds = parseTimestamp(timestamp); - const seconds = milliseconds / 1000; - return { milliseconds, seconds, text }; - } - - // Find a header line of the format - // [header:value] - // at the beginning of the lrc file (before the first empty line) - findHeader(headerName: string) { - for (let line = 0; line < this.document.lineCount; line++) { - const text = this.document.lineAt(line).text; - if (text.trim() === '') { - return; - } - const match = text.match(/^\[(\w+):(.*)\]$/); - if (match && match[1] === headerName) { - return { key: match[1], value: match[2], line: line }; - } - } - } - - /** Find the bpm header and return the bpm as number, if any */ - findBpmHeader() { - const startBpmStr = this.findHeader('bpm')?.value; - let bpm; - if (startBpmStr !== undefined) { - bpm = parseInt(startBpmStr, 10); - if (isNaN(bpm)) { - bpm = undefined; - } - } - return bpm; - } - - // check if the given line is a header line - isHeaderLine(line: string) { - return ( - line.trim() !== '' && - line.match(/^\[(\w+):(.*)\]$/) !== null && - line.match(/^\[\d\d:\d\d.\d+\]/) === null - ); - } - - // write the given header to the lrc file, if the header already exists, update the value - async writeHeader(headerName: string, value: string) { - const header = this.findHeader(headerName); - const editor = findActiveEditor(this.document); - if (!editor) { - return; - } - if (header) { - const lineRange = this.document.lineAt(header.line).range; - await editor.edit(editBuilder => { - editBuilder.replace(lineRange, `[${headerName}: ${value}]`); - }); - } else { - // insert before the first timestamp line if no header is found, or after the last header if there are multiple headers - let insertLine = 0; - let extraNewline = ''; - for (let line = 0; line < this.document.lineCount; line++) { - const text = this.document.lineAt(line).text; - // check if header - if (this.isHeaderLine(text)) { - insertLine = line + 1; - } else if (text.trim() === '') { - insertLine = line; - break; - } else { - insertLine = line; - if (line == 0) { - extraNewline = '\n'; - } - break; - } - } - await editor.edit(editBuilder => { - editBuilder.insert( - new vscode.Position(insertLine, 0), - `[${headerName}: ${value}]\n${extraNewline}`, - ); - }); - } - } - - // get the lyrics part of the lrc file (after the headers) - getLyricsPart() { - const first = this.document.lineAt(0).text; - let line = 0; - if (this.isHeaderLine(first)) { - // skip all headers (until the first empty line) - for (; line < this.document.lineCount; line++) { - const text = this.document.lineAt(line).text; - if (text.trim() === '') { - line++; - break; - } - } - } - - // get the range from the current line to the end of the file - const documentRange = new vscode.Range( - new vscode.Position(line, 0), - this.document.lineAt(this.document.lineCount - 1).range.end, - ); - return this.document.getText(documentRange); - } -} - -// find an active editor that has the given document opened -function findActiveEditor(document: vscode.TextDocument) { - return vscode.window.visibleTextEditors.find(editor => editor.document === document); -} - -function plainLyricsFromLyrics(lyrics: string) { - // remove the timestamp from the beginning of every line - return ( - lyrics - .replace(/\[\d\d:\d\d\.\d\d\]\s?/gm, '') - // remove empty lines - .replace(/\n{2,}/g, '\n') - ); -} - -function parseTimestamp(timestamp: string): number { - // Parse [mm:ss.ms] format into milliseconds - const [min, sec] = timestamp.split(':'); - - const minutes = parseInt(min, 10); - const seconds = parseFloat(sec); - - return minutes * 60 * 1000 + seconds * 1000; -} - -function formatTimestamp(ms: number): string { - // Format milliseconds back into [mm:ss.ms] - const minutes = Math.floor(ms / 60000); - ms %= 60000; - const seconds = (ms / 1000).toFixed(2); - - return `${String(minutes).padStart(2, '0')}:${seconds.padStart(5, '0')}`; -} - -class ManageWarnings { - private warnings: Map = new Map(); - private diagnostics: vscode.DiagnosticCollection; - - constructor() { - this.diagnostics = vscode.languages.createDiagnosticCollection(); - } - - /** Set a warning message on a line in a document, if null then unset */ - setWarning(document: vscode.TextDocument, line: number, message?: string) { - if (message !== undefined) { - this.warnings.set(line, message); - } else { - this.warnings.delete(line); - } - this.updateDiagnostics(document); - } - - private updateDiagnostics(document: vscode.TextDocument) { - const mkWarning = (line: number, message: string) => { - const lineRange = document.lineAt(line).range; - return new vscode.Diagnostic(lineRange, message, vscode.DiagnosticSeverity.Warning); - }; - const diagnostics: vscode.Diagnostic[] = []; - for (const [line, message] of this.warnings) { - diagnostics.push(mkWarning(line, message)); - } - this.diagnostics.delete(document.uri); - this.diagnostics.set(document.uri, diagnostics); - } -} - -const global_manageWarnings = new ManageWarnings(); diff --git a/users/Profpatsch/lyric/extension/src/quantize-lrc.ts b/users/Profpatsch/lyric/extension/src/quantize-lrc.ts deleted file mode 100644 index 83c31348e..000000000 --- a/users/Profpatsch/lyric/extension/src/quantize-lrc.ts +++ /dev/null @@ -1,82 +0,0 @@ -export function bpmToEighthNoteDuration(bpm: number): number { - // Convert BPM to eighth-note duration in milliseconds - const quarterNoteDuration = (60 / bpm) * 1000; // in ms - const eighthNoteDuration = quarterNoteDuration / 2; - return eighthNoteDuration; -} - -function parseTimestamp(timestamp: string): number { - // Parse [mm:ss.ms] format into milliseconds - const [min, sec] = timestamp.split(':'); - - const minutes = parseInt(min, 10); - const seconds = parseFloat(sec); - - return minutes * 60 * 1000 + seconds * 1000; -} - -function formatTimestamp(ms: number): string { - // Format milliseconds back into [mm:ss.ms] - const minutes = Math.floor(ms / 60000); - ms %= 60000; - const seconds = (ms / 1000).toFixed(2); - - return `${String(minutes).padStart(2, '0')}:${seconds}`; -} - -export function adjustTimestampToEighthNote( - timestampMs: number, - eighthNoteDuration: number, -): number { - // Find the closest multiple of the eighth-note duration - return Math.round(timestampMs / eighthNoteDuration) * eighthNoteDuration; -} - -function adjustTimestamps(bpm: number, timestamps: string[]): string[] { - const eighthNoteDuration = bpmToEighthNoteDuration(bpm); - - return timestamps.map(timestamp => { - const timestampMs = parseTimestamp(timestamp); - const adjustedMs = adjustTimestampToEighthNote(timestampMs, eighthNoteDuration); - return formatTimestamp(adjustedMs); - }); -} - -// Parse a .lrc file into an array of objects with timestamp and text -// Then adjust the timestamps to the closest eighth note -// Finally, format the adjusted timestamps back into [mm:ss.ms] format and put them back into the lrc object -// -// Example .lrc file: -// [01:15.66] And the reviewers bewail -// [01:18.18] There'll be no encore -// [01:21.65] 'Cause you're not begging for more -// [01:25.00] -// [01:34.64] She may seem self-righteous and holier-than-thou -// [01:39.77] She may sound like she has all the answers -// [01:45.20] But beyond she may feel just a bit anyhow -function parseLrc(lrc: string): { timestamp: string; text: string }[] { - return lrc - .trimEnd() - .split('\n') - .map(line => { - const match = line.match(/\[(\d+:\d+\.\d+)\](.*)/); - const [, timestamp, text] = match!; - return { timestamp, text }; - }); -} - -function formatLrc(lrc: { timestamp: string; text: string }[]): string { - return lrc.map(({ timestamp, text }) => `[${timestamp}] ${text}`).join('\n'); -} - -function adjustLrc(lrc: string, bpm: number): string { - const lrcArray = parseLrc(lrc); - const timestamps = lrcArray.map(({ timestamp }) => timestamp); - const adjustedTimestamps = adjustTimestamps(bpm, timestamps); - - lrcArray.forEach((line, i) => { - line.timestamp = adjustedTimestamps[i]; - }); - - return formatLrc(lrcArray); -} diff --git a/users/Profpatsch/lyric/extension/src/upload-lrc.ts b/users/Profpatsch/lyric/extension/src/upload-lrc.ts deleted file mode 100644 index 8627e3827..000000000 --- a/users/Profpatsch/lyric/extension/src/upload-lrc.ts +++ /dev/null @@ -1,117 +0,0 @@ -import * as crypto from 'crypto'; - -const USER_AGENT = - 'lyric tool (source: https://code.tvl.fyi/tree/users/Profpatsch/lyric, contact: https://mastodon.xyz/@Profpatsch)'; - -// Helper function to convert a hex string to a Buffer -function hexToBytes(hex: string): Buffer { - return Buffer.from(hex, 'hex'); -} - -// Function to verify the nonce -function verifyNonce(result: Buffer, target: Buffer): boolean { - if (result.length !== target.length) { - return false; - } - - for (let i = 0; i < result.length - 1; i++) { - if (result[i] > target[i]) { - return false; - } else if (result[i] < target[i]) { - break; - } - } - - return true; -} - -// Function to solve the challenge -function solveChallenge(prefix: string, targetHex: string): string { - let nonce = 0; - let hashed: Buffer; - const target = hexToBytes(targetHex); - - while (true) { - const input = `${prefix}${nonce}`; - hashed = crypto.createHash('sha256').update(input).digest(); - - if (verifyNonce(hashed, target)) { - break; - } else { - nonce += 1; - } - } - - return nonce.toString(); -} - -async function getUploadNonce() { - try { - const response = await fetch('https://lrclib.net/api/request-challenge', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'User-Agent': USER_AGENT, - 'Lrclib-Client': USER_AGENT, - }, - }); - - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - - const challengeData = (await response.json()) as { prefix: string; target: string }; - - return { - prefix: challengeData.prefix, - nonce: solveChallenge(challengeData.prefix, challengeData.target), - }; - } catch (error) { - console.error('Error fetching the challenge:', error); - } -} - -// Interface for the request body -/** - * Represents a request to publish a track with its associated information. - */ -export interface PublishRequest { - trackName: string; - artistName: string; - albumName: string; - /** In seconds? Milliseconds? mm:ss? */ - duration: number; - plainLyrics: string; - syncedLyrics: string; -} - -// Function to publish lyrics using the solved challenge -export async function publishLyrics( - requestBody: PublishRequest, -): Promise { - const challenge = await getUploadNonce(); - if (!challenge) { - return; - } - const publishToken = `${challenge.prefix}:${challenge.nonce}`; - - const response = await fetch('https://lrclib.net/api/publish', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'User-Agent': USER_AGENT, - 'Lrclib-Client': USER_AGENT, - 'X-Publish-Token': publishToken, - }, - body: JSON.stringify(requestBody), - }); - - if (response.status === 201) { - console.log('Lyrics successfully published.'); - return true; - } else { - const errorResponse = (await response.json()) as { [key: string]: string }; - console.error('Failed to publish lyrics:', errorResponse); - return; - } -} diff --git a/users/Profpatsch/lyric/extension/tsconfig.json b/users/Profpatsch/lyric/extension/tsconfig.json deleted file mode 100644 index 44a519579..000000000 --- a/users/Profpatsch/lyric/extension/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "ES6", - "module": "commonjs", - "lib": [ - "ES6" - ], - "outDir": "./out", - "rootDir": "./src", - "strict": true, - "sourceMap": true, - "esModuleInterop": true, - "skipLibCheck": true - }, - "include": [ - "src" - ], - "exclude": [ - "node_modules", - ".vscode-test" - ] -} diff --git a/users/Profpatsch/lyric/lyric-mpv-script.lua b/users/Profpatsch/lyric/lyric-mpv-script.lua deleted file mode 100644 index ba05c7c44..000000000 --- a/users/Profpatsch/lyric/lyric-mpv-script.lua +++ /dev/null @@ -1,66 +0,0 @@ --- get_lrc_subtitles.lua - --- Function to remove Unicode symbol characters -function remove_symbols(str) - -- This pattern matches anything that is not a letter, digit, or whitespace - return str:gsub("[%p%c%z]", "") -- remove punctuation, control, and zero-width characters -end - --- Asynchronous callback function to handle the result of the 'get_subtitles' command -function handle_subtitle_result(success, result) - if not success or result.status ~= 0 then - mp.msg.error("Failed to get subtitles") - mp.msg.error("Exit code: " .. tostring(result.exit_code)) - if result.stderr then - mp.msg.error("Error: " .. result.stderr) - end - return - end - - -- Extract the output from the external command - local subtitle_file = result.stdout:match("^%s*(.-)%s*$") -- trim any extra whitespace - - -- If no subtitle file was returned, stop - if not subtitle_file or subtitle_file == "" then - mp.msg.warn("No subtitle file found") - return - end - - -- Load the subtitle file in MPV - mp.commandv("sub-add", subtitle_file) - mp.msg.info("Loaded subtitle file: " .. subtitle_file) -end - --- Function to load the LRC subtitle file -function load_lrc_subtitles() - -- Retrieve metadata for the currently playing file - local artist = mp.get_property("metadata/by-key/artist") - local album = mp.get_property("metadata/by-key/album") - local title = mp.get_property("metadata/by-key/title") - - -- If any metadata is missing, print a warning and stop - if not artist or not album or not title then - mp.msg.warn("Artist, album, or title metadata is missing") - return - end - - -- Concatenate the metadata - local query = string.format("%s %s %s", artist, album, title) - - -- Remove Unicode symbols from the query string - query = remove_symbols(query) - - -- Create the command array - local cmd = {"@get_subtitles_command@", query} - - -- Run the external command asynchronously to get the subtitle file - mp.command_native_async({ - name = "subprocess", - args = cmd, - capture_stdout = true, - capture_stderr = true - }, handle_subtitle_result) -end - --- Register the event that triggers when a file is loaded -mp.register_event("file-loaded", load_lrc_subtitles) diff --git a/users/Profpatsch/lyric/lyric-timing-mpv-script.lua b/users/Profpatsch/lyric/lyric-timing-mpv-script.lua deleted file mode 100644 index dd74d3344..000000000 --- a/users/Profpatsch/lyric/lyric-timing-mpv-script.lua +++ /dev/null @@ -1,68 +0,0 @@ --- This function formats the current timestamp in the [mm:ss.ms] format -function format_timestamp(seconds) - local minutes = math.floor(seconds / 60) - local seconds = seconds % 60 - return string.format("[%02d:%05.2f]", minutes, seconds) -end - --- Get the user’s cache directory -local cache_dir = os.getenv("XDG_CACHE_HOME") or os.getenv("HOME") .. "/.cache" - --- This function writes the timestamp to the LRC file -function write_timestamp_to_lrc() - local filename = mp.get_property("path") - if not filename then - mp.msg.warn("No file currently playing.") - return - end - - -- Extract metadata for artist, title, and album - local artist = mp.get_property("metadata/by-key/ARTIST", "Unknown Artist") - local title = mp.get_property("metadata/by-key/TITLE", "Unknown Title") - local album = mp.get_property("metadata/by-key/ALBUM", "Unknown Album") - - -- Construct the lrc dir - local dir = cache_dir .. "/lyric/timed" - local lrc_filename = string.format("%s/%s - %s - %s.lrc", dir, artist, album, title) - - -- Get current playback time - local current_time = mp.get_property_number("time-pos", 0) - local formatted_time = format_timestamp(current_time) - - -- If the file does not exist, or is empty, create it and add metadata in the following format: - -- [ar: Chubby Checker oppure Beatles, The] - -- [al: Hits Of The 60's - Vol. 2 – Oldies] - -- [ti: Let's Twist Again] - -- [au: Written by Kal Mann / Dave Appell, 1961] - -- [length: 2:23] - local file = io.open(lrc_filename, "r+") - if not file then - file = io.open(lrc_filename, "w+") - end - - -- read the file and check whether it only contains whitespace - local content = file:read("*all") - if content:match("^%s*$") then - file:write("[ar: " .. artist .. "]\n") - file:write("[al: " .. album .. "]\n") - file:write("[ti: " .. title .. "]\n") - local duration = mp.get_property_number("duration", 0) - local formatted_duration = string.format("%02d:%02d", math.floor(duration / 60), duration % 60) - file:write("[length: " .. formatted_duration .. "]\n") - file:write("\n") - end - file:close() - - -- Append the timestamp to the LRC file - local file = io.open(lrc_filename, "a") - if file then - file:write(formatted_time .. "\n") - file:close() - mp.msg.info("Timestamp " .. formatted_time .. " added to " .. lrc_filename) - else - mp.msg.error("Failed to open " .. lrc_filename) - end -end - --- Bind Ctrl+l to the function that writes the timestamp -mp.add_key_binding("Ctrl+l", "insert_timestamp", write_timestamp_to_lrc) diff --git a/users/Profpatsch/lyric/package.json b/users/Profpatsch/lyric/package.json deleted file mode 100644 index 4621d087e..000000000 --- a/users/Profpatsch/lyric/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "lyric", - "version": "1.0.0", - "main": "dist/index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "type": "module", - "license": "GPL-3.0-or-later", - "description": "", - "dependencies": {}, - "devDependencies": { - "@eslint/js": "^9.10.0", - "@types/eslint__js": "^8.42.3", - "@types/node": "^22.5.5", - "@typescript-eslint/parser": "^8.7.0", - "eslint": "^9.10.0", - "globals": "^15.9.0", - "typescript": "^5.6.2", - "typescript-eslint": "^8.6.0" - } -} diff --git a/users/Profpatsch/lyric/src/index.ts b/users/Profpatsch/lyric/src/index.ts deleted file mode 100644 index 9501fa57b..000000000 --- a/users/Profpatsch/lyric/src/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { tapBpm } from './tap-bpm.js'; - -function main() { - // subcommand for tap-bpm - if (process.argv[2] === 'tap-bpm') { - tapBpm(); - } -} - -main(); - -// sleep in a loop to block nodejs -console.log('Blocking event loop...'); -while (true) { - await new Promise(resolve => setTimeout(resolve, 1000)); -} diff --git a/users/Profpatsch/lyric/src/tap-bpm.ts b/users/Profpatsch/lyric/src/tap-bpm.ts deleted file mode 100644 index b3c727df5..000000000 --- a/users/Profpatsch/lyric/src/tap-bpm.ts +++ /dev/null @@ -1,72 +0,0 @@ -// create a node command line listener that allows the user to press any key , and averages the distances between the key presses to determine the BPM (with a window of 4 key presses). If the user presses q, the program should exit and print the final BPM. - -// Import the necessary modules -import * as readline from 'readline'; - -export function tapBpm() { - // Set up readline interface to listen for keypresses - readline.emitKeypressEvents(process.stdin); - process.stdin.setRawMode(true); - // accept SIGINT on stdin - - // Array to store the time differences between the last 4 key presses - const timeDifferences: number[] = []; - let lastPressTime: number | null = null; - - // Function to calculate BPM based on average time between keypresses - function calculateBPM() { - if (timeDifferences.length < 1) { - return 0; - } - const averageTimeDiff = - timeDifferences.reduce((acc, curr) => acc + curr, 0) / timeDifferences.length; - return (60 * 1000) / averageTimeDiff; - } - - // Handle the SIGINT (Ctrl+C) event manually - process.on('SIGINT', () => { - console.log('\nExiting via SIGINT (Ctrl+C)... Final BPM:', calculateBPM().toFixed(2)); - process.exit(); - }); - - // Listen for keypress events - process.stdin.on('keypress', (str, key: { name: string; sequence: string }) => { - // Exit if 'q' is pressed - if (key.name === 'q') { - console.log('Exiting... Final BPM:', calculateBPM().toFixed(2)); - process.exit(); - } - - // Handle Ctrl+C (SIGINT) - if (key.sequence === '\u0003') { - // '\u0003' is the raw code for Ctrl+C - console.log('\nExiting via Ctrl+C... Final BPM:', calculateBPM().toFixed(2)); - process.exit(); - } - - // Capture the current time of the keypress - const currentTime = Date.now(); - - // If it's not the first keypress, calculate the time difference - if (lastPressTime !== null) { - const timeDiff = currentTime - lastPressTime; - - // Add the time difference to the array (limit to last 10 key presses) - if (timeDifferences.length >= 10) { - timeDifferences.shift(); // Remove the oldest time difference - } - timeDifferences.push(timeDiff); - - // Calculate and display the BPM - const bpm = calculateBPM(); - console.log('Current BPM:', bpm.toFixed(2)); - } else { - console.log('Waiting for more key presses to calculate BPM...'); - } - - // Update the lastPressTime to the current time - lastPressTime = currentTime; - }); - - console.log('Press any key to calculate BPM, press "q" to quit.'); -} diff --git a/users/Profpatsch/lyric/tsconfig.json b/users/Profpatsch/lyric/tsconfig.json deleted file mode 100644 index 26a6a0a82..000000000 --- a/users/Profpatsch/lyric/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "module": "ESNext", - "outDir": "dist", - "strict": true, - "skipLibCheck": true, - "sourceMap": true, - "esModuleInterop": true - }, - "include": [ - "src/**/*.ts", - ], - "exclude": [ - "node_modules" - ] -} diff --git a/users/Profpatsch/my-prelude/README.md b/users/Profpatsch/my-prelude/README.md deleted file mode 100644 index 2cc068579..000000000 --- a/users/Profpatsch/my-prelude/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# My Haskell Prelude - -Contains various modules I’ve found useful when writing Haskell. - -## Contents - -A short overview: - -### `MyPrelude.hs` - -A collection of re-exports and extra functions. This does *not* replace the `Prelude` module from `base`, but rather should be imported *in addition* to `Prelude`. - -Stuff like bad functions from prelude (partial stuff, or plain horrible stuff) are handled by a custom `.hlint` file, which you can find in [../.hlint.yaml](). - -The common style of haskell they try to enable is what I call “left-to-right Haskell”, -where one mostly prefers forward-chaining operators like `&`/`<&>`/`>>=` to backwards operators like `$`/`<$>`/`<=<`. In addition, all transformation function should follow the scheme of `aToB` instead of `B.fromA`, e.g. `Text.unpack`/`Text.pack` -> `textToString`/`stringToText`. Includes a bunch of text conversion functions one needs all the time, in the same style. - -These have been battle-tested in a production codebase of ~30k lines of Haskell. - -### `Label.hs` - -A very useful collection of anonymous labbeled tuples and enums of size 2 and 3. Assumes GHC >9.2 for `RecordDotSyntax` support. - -### `Pretty.hs` - -Colorful multiline pretty-printing of Haskell values. - -### `Test.hs` - -A wrapper around `hspec` which produces colorful test diffs. - -### `Aeson.hs` - -Helpers around Json parsing. - -### `Data.Error.Tree` - -Collect errors (from [`Data.Error`](https://hackage.haskell.org/package/error-1.0.0.0/docs/Data-Error.html)) into a tree, then display them in a nested fashion. Super useful for e.g. collecting and displaying nested parsing errors. - -### `RunCommand.hs` - -A module wrapping the process API with some helpful defaults for executing commands and printing what is executed to stderr. diff --git a/users/Profpatsch/my-prelude/default.nix b/users/Profpatsch/my-prelude/default.nix deleted file mode 100644 index a29dce8fb..000000000 --- a/users/Profpatsch/my-prelude/default.nix +++ /dev/null @@ -1,61 +0,0 @@ -{ depot, pkgs, lib, ... }: - -pkgs.haskellPackages.mkDerivation { - pname = "my-prelude"; - version = "0.0.1-unreleased"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./my-prelude.cabal - ./src/Aeson.hs - ./src/Builder.hs - ./src/Comparison.hs - ./src/Debug.hs - ./src/Divisive.hs - ./src/Json.hs - ./src/Json/Enc.hs - ./src/Arg.hs - ./src/AtLeast.hs - ./src/MyLabel.hs - ./src/MyPrelude.hs - ./src/Test.hs - ./src/Parse.hs - ./src/Pretty.hs - ./src/RevList.hs - ./src/Seconds.hs - ./src/Tool.hs - ./src/ValidationParseT.hs - ./src/Postgres/Decoder.hs - ./src/Postgres/MonadPostgres.hs - ]; - - isLibrary = true; - - libraryHaskellDepends = [ - pkgs.haskellPackages.pa-prelude - pkgs.haskellPackages.pa-label - pkgs.haskellPackages.pa-error-tree - pkgs.haskellPackages.pa-json - pkgs.haskellPackages.pa-pretty - pkgs.haskellPackages.pa-field-parser - pkgs.haskellPackages.aeson-better-errors - pkgs.haskellPackages.contravariant - pkgs.haskellPackages.foldl - pkgs.haskellPackages.resource-pool - pkgs.haskellPackages.error - pkgs.haskellPackages.hs-opentelemetry-api - pkgs.haskellPackages.hspec - pkgs.haskellPackages.hspec-expectations-pretty-diff - pkgs.haskellPackages.monad-logger - pkgs.haskellPackages.postgresql-simple - pkgs.haskellPackages.profunctors - pkgs.haskellPackages.PyF - pkgs.haskellPackages.semigroupoids - pkgs.haskellPackages.these - pkgs.haskellPackages.unliftio - pkgs.haskellPackages.validation-selective - pkgs.haskellPackages.vector - ]; - - license = lib.licenses.mit; - -} diff --git a/users/Profpatsch/my-prelude/my-prelude.cabal b/users/Profpatsch/my-prelude/my-prelude.cabal deleted file mode 100644 index 04d60ed42..000000000 --- a/users/Profpatsch/my-prelude/my-prelude.cabal +++ /dev/null @@ -1,131 +0,0 @@ -cabal-version: 3.0 -name: my-prelude -version: 0.0.1.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - -- allows defining pattern synonyms, but also the `import Foo (pattern FooPattern)` import syntax - PatternSynonyms - default-language: GHC2021 - - -library - import: common-options - hs-source-dirs: src - exposed-modules: - MyPrelude - Aeson - Arg - AtLeast - Builder - Comparison - Debug - Divisive - Json - Json.Enc - MyLabel - Test - Postgres.Decoder - Postgres.MonadPostgres - RevList - ValidationParseT - Parse - Pretty - Seconds - Tool - - -- Modules included in this executable, other than Main. - -- other-modules: - - -- LANGUAGE extensions used by modules in this package. - -- other-extensions: - build-depends: - base >=4.15 && <5 - , pa-prelude - , pa-label - , pa-error-tree - , pa-json - , pa-pretty - , pa-field-parser - , aeson - , aeson-better-errors - , base64-bytestring - , bytestring - , containers - , contravariant - , foldl - , unordered-containers - , resource-pool - , resourcet - , scientific - , time - , error - , exceptions - , filepath - , hspec - , hspec-expectations-pretty-diff - , hs-opentelemetry-api - , monad-logger - , mtl - , postgresql-simple - , profunctors - , PyF - , semigroupoids - , selective - , template-haskell - , text - , these - , unix - , unliftio - , validation-selective - , vector - , ghc-boot - -- for Pretty - , aeson-pretty - , hscolour - , ansi-terminal - , nicify-lib diff --git a/users/Profpatsch/my-prelude/src/Aeson.hs b/users/Profpatsch/my-prelude/src/Aeson.hs deleted file mode 100644 index 73d611608..000000000 --- a/users/Profpatsch/my-prelude/src/Aeson.hs +++ /dev/null @@ -1,176 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE GHC2021 #-} -{-# LANGUAGE KindSignatures #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE UndecidableInstances #-} - -module Aeson where - -import Data.Aeson (Value (..)) -import Data.Aeson.BetterErrors qualified as Json -import Data.Aeson.KeyMap qualified as KeyMap -import Data.Error.Tree -import Data.Maybe (catMaybes) -import Data.Vector qualified as Vector -import Label -import PossehlAnalyticsPrelude -import Test.Hspec (describe, it, shouldBe) -import Test.Hspec qualified as Hspec - --- | Convert a 'Json.ParseError' to a corresponding 'ErrorTree' -parseErrorTree :: Error -> Json.ParseError Error -> ErrorTree -parseErrorTree contextMsg errs = - errs - & Json.displayError prettyError - <&> newError - & nonEmpty - & \case - Nothing -> singleError contextMsg - Just errs' -> errorTree contextMsg errs' - --- | Parse a key from the object, à la 'Json.key', return a labelled value. --- --- We don’t provide a version that infers the json object key, --- since that conflates internal naming with the external API, which is dangerous. --- --- @@ --- do --- txt <- keyLabel @"myLabel" "jsonKeyName" Json.asText --- pure (txt :: Label "myLabel" Text) --- @@ -keyLabel :: - forall label err m a. - Monad m => - Text -> - Json.ParseT err m a -> - Json.ParseT err m (Label label a) -keyLabel = do - keyLabel' (Proxy @label) - --- | Parse a key from the object, à la 'Json.key', return a labelled value. --- Version of 'keyLabel' that requires a proxy. --- --- @@ --- do --- txt <- keyLabel' (Proxy @"myLabel") "jsonKeyName" Json.asText --- pure (txt :: Label "myLabel" Text) --- @@ -keyLabel' :: - forall label err m a. - Monad m => - Proxy label -> - Text -> - Json.ParseT err m a -> - Json.ParseT err m (Label label a) -keyLabel' Proxy key parser = label @label <$> Json.key key parser - --- | Parse an optional key from the object, à la 'Json.keyMay', return a labelled value. --- --- We don’t provide a version that infers the json object key, --- since that conflates internal naming with the external API, which is dangerous. --- --- @@ --- do --- txt <- keyLabelMay @"myLabel" "jsonKeyName" Json.asText --- pure (txt :: Label "myLabel" (Maybe Text)) --- @@ -keyLabelMay :: - forall label err m a. - Monad m => - Text -> - Json.ParseT err m a -> - Json.ParseT err m (Label label (Maybe a)) -keyLabelMay = do - keyLabelMay' (Proxy @label) - --- | Parse an optional key from the object, à la 'Json.keyMay', return a labelled value. --- Version of 'keyLabelMay' that requires a proxy. --- --- @@ --- do --- txt <- keyLabelMay' (Proxy @"myLabel") "jsonKeyName" Json.asText --- pure (txt :: Label "myLabel" (Maybe Text)) --- @@ -keyLabelMay' :: - forall label err m a. - Monad m => - Proxy label -> - Text -> - Json.ParseT err m a -> - Json.ParseT err m (Label label (Maybe a)) -keyLabelMay' Proxy key parser = label @label <$> Json.keyMay key parser - --- | Like 'Json.key', but allows a list of keys that are tried in order. --- --- This is intended for renaming keys in an object. --- The first key is the most up-to-date version of a key, the others are for backward-compatibility. --- --- If a key (new or old) exists, the inner parser will always be executed for that key. -keyRenamed :: Monad m => NonEmpty Text -> Json.ParseT err m a -> Json.ParseT err m a -keyRenamed (newKey :| oldKeys) inner = - keyRenamedTryOldKeys oldKeys inner >>= \case - Nothing -> Json.key newKey inner - Just parse -> parse - --- | Like 'Json.keyMay', but allows a list of keys that are tried in order. --- --- This is intended for renaming keys in an object. --- The first key is the most up-to-date version of a key, the others are for backward-compatibility. --- --- If a key (new or old) exists, the inner parser will always be executed for that key. -keyRenamedMay :: Monad m => NonEmpty Text -> Json.ParseT err m a -> Json.ParseT err m (Maybe a) -keyRenamedMay (newKey :| oldKeys) inner = - keyRenamedTryOldKeys oldKeys inner >>= \case - Nothing -> Json.keyMay newKey inner - Just parse -> Just <$> parse - --- | Helper function for 'keyRenamed' and 'keyRenamedMay' that returns the parser for the first old key that exists, if any. -keyRenamedTryOldKeys :: Monad m => [Text] -> Json.ParseT err m a -> Json.ParseT err m (Maybe (Json.ParseT err m a)) -keyRenamedTryOldKeys oldKeys inner = do - oldKeys & traverse tryOld <&> catMaybes <&> nonEmpty <&> \case - Nothing -> Nothing - Just (old :| _moreOld) -> Just old - where - tryOld key = - Json.keyMay key (pure ()) <&> \case - Just () -> Just $ Json.key key inner - Nothing -> Nothing - -test_keyRenamed :: Hspec.Spec -test_keyRenamed = do - describe "keyRenamed" $ do - let parser = keyRenamed ("new" :| ["old"]) Json.asText - let p = Json.parseValue @() parser - it "accepts the new key and the old key" $ do - p (Object (KeyMap.singleton "new" (String "text"))) - `shouldBe` (Right "text") - p (Object (KeyMap.singleton "old" (String "text"))) - `shouldBe` (Right "text") - it "fails with the old key in the error if the inner parser is wrong" $ do - p (Object (KeyMap.singleton "old" Null)) - `shouldBe` (Left (Json.BadSchema [Json.ObjectKey "old"] (Json.WrongType Json.TyString Null))) - it "fails with the new key in the error if the inner parser is wrong" $ do - p (Object (KeyMap.singleton "new" Null)) - `shouldBe` (Left (Json.BadSchema [Json.ObjectKey "new"] (Json.WrongType Json.TyString Null))) - it "fails if the key is missing" $ do - p (Object KeyMap.empty) - `shouldBe` (Left (Json.BadSchema [] (Json.KeyMissing "new"))) - describe "keyRenamedMay" $ do - let parser = keyRenamedMay ("new" :| ["old"]) Json.asText - let p = Json.parseValue @() parser - it "accepts the new key and the old key" $ do - p (Object (KeyMap.singleton "new" (String "text"))) - `shouldBe` (Right (Just "text")) - p (Object (KeyMap.singleton "old" (String "text"))) - `shouldBe` (Right (Just "text")) - it "allows the old and new key to be missing" $ do - p (Object KeyMap.empty) - `shouldBe` (Right Nothing) - --- | Create a json array from a list of json values. -jsonArray :: [Value] -> Value -jsonArray xs = xs & Vector.fromList & Array diff --git a/users/Profpatsch/my-prelude/src/Arg.hs b/users/Profpatsch/my-prelude/src/Arg.hs deleted file mode 100644 index a6ffa9092..000000000 --- a/users/Profpatsch/my-prelude/src/Arg.hs +++ /dev/null @@ -1,34 +0,0 @@ -module Arg where - -import Data.String (IsString) -import GHC.Exts (IsList) -import GHC.TypeLits (Symbol) - --- | Wrap a function argument into this helper to give it a better description for the caller without disturbing the callsite too much. --- --- This has instances for IsString and Num, meaning if the caller is usually a string or number literal, it should Just Work. --- --- e.g. --- --- @ --- myFoo :: Arg "used as the name in error message" Text -> IO () --- myFoo (Arg name) = … --- @ --- --- Will display the description in the inferred type of the callsite. --- --- Due to IsString you can call @myFoo@ like --- --- @myFoo "name in error"@ --- --- This is mostly intended for literals, if you want to wrap arbitrary data, use @Label@. -newtype Arg (description :: Symbol) a = Arg {unArg :: a} - deriving newtype - ( Show, - Eq, - IsString, - IsList, - Num, - Monoid, - Semigroup - ) diff --git a/users/Profpatsch/my-prelude/src/AtLeast.hs b/users/Profpatsch/my-prelude/src/AtLeast.hs deleted file mode 100644 index 3857c3a7c..000000000 --- a/users/Profpatsch/my-prelude/src/AtLeast.hs +++ /dev/null @@ -1,51 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module AtLeast where - -import Data.Aeson (FromJSON (parseJSON)) -import Data.Aeson.BetterErrors qualified as Json -import FieldParser (FieldParser) -import FieldParser qualified as Field -import GHC.Records (HasField (..)) -import GHC.TypeLits (KnownNat, natVal) -import PossehlAnalyticsPrelude - ( Natural, - Proxy (Proxy), - fmt, - prettyError, - (&), - ) - --- | A natural number that must be at least as big as the type literal. -newtype AtLeast (min :: Natural) num = AtLeast num - -- Just use the instances of the wrapped number type - deriving newtype (Eq, Show) - --- | This is the “destructor” for `AtLeast`, because of the phantom type (@min@) it cannot be inferred automatically. -instance HasField "unAtLeast" (AtLeast min num) num where - getField (AtLeast num) = num - -parseAtLeast :: - forall min num. - (KnownNat min, Integral num, Show num) => - FieldParser num (AtLeast min num) -parseAtLeast = - let minInt = natVal (Proxy @min) - in Field.FieldParser $ \from -> - if from >= (minInt & fromIntegral) - then Right (AtLeast from) - else Left [fmt|Must be at least {minInt & show} but was {from & show}|] - -instance - (KnownNat min, FromJSON num, Integral num, Bounded num, Show num) => - FromJSON (AtLeast min num) - where - parseJSON = - Json.toAesonParser - prettyError - ( do - num <- Json.fromAesonParser @_ @num - case Field.runFieldParser (parseAtLeast @min @num) num of - Left err -> Json.throwCustomError err - Right a -> pure a - ) diff --git a/users/Profpatsch/my-prelude/src/Builder.hs b/users/Profpatsch/my-prelude/src/Builder.hs deleted file mode 100644 index 80b43985c..000000000 --- a/users/Profpatsch/my-prelude/src/Builder.hs +++ /dev/null @@ -1,144 +0,0 @@ -module Builder - ( TextBuilder (..), - BytesBuilder (..), - buildText, - buildTextLazy, - buildBytes, - buildBytesLazy, - textT, - textLazyT, - bytesB, - bytesLazyB, - utf8B, - utf8LazyB, - utf8LenientT, - utf8LenientLazyT, - intDecimalT, - intDecimalB, - integerDecimalT, - integerDecimalB, - naturalDecimalT, - naturalDecimalB, - scientificDecimalT, - scientificDecimalB, - intersperseT, - intersperseB, - ) -where - -import Data.ByteString.Builder qualified as Bytes -import Data.ByteString.Builder.Scientific qualified as Scientific.Bytes -import Data.ByteString.Lazy qualified as Bytes.Lazy -import Data.Functor.Contravariant -import Data.Functor.Contravariant.Divisible -import Data.String -import Data.Text.Lazy qualified as Text.Lazy -import Data.Text.Lazy.Builder qualified as Text -import Data.Text.Lazy.Builder.Int qualified as Text -import Data.Text.Lazy.Builder.Scientific qualified as Scientific.Text -import MyPrelude - -newtype TextBuilder a = TextBuilder {unTextBuilder :: a -> Text.Builder} - deriving newtype (Semigroup, Monoid) - -instance IsString (TextBuilder a) where - fromString s = TextBuilder $ \_ -> s & fromString - -instance Contravariant TextBuilder where - contramap f (TextBuilder g) = TextBuilder $ g . f - -instance Divisible TextBuilder where - divide f (TextBuilder bb) (TextBuilder bc) = - TextBuilder $ \a -> let (b, c) = f a in bb b <> bc c - conquer = TextBuilder $ \_ -> mempty - --- | Convert a 'TextBuilder' to a strict 'Text' by applying it to a value. -buildText :: TextBuilder a -> a -> Text -buildText (TextBuilder f) a = f a & Text.toLazyText & toStrict - --- | Convert a 'TextBuilder' to a lazy 'Text' by applying it to a value. -buildTextLazy :: TextBuilder a -> a -> Text.Lazy.Text -buildTextLazy (TextBuilder f) a = f a & Text.toLazyText - -newtype BytesBuilder a = BytesBuilder {unBytesBuilder :: a -> Bytes.Builder} - -instance IsString (BytesBuilder a) where - fromString s = BytesBuilder $ \_ -> s & fromString - -instance Contravariant BytesBuilder where - contramap f (BytesBuilder g) = BytesBuilder $ g . f - -instance Divisible BytesBuilder where - divide f (BytesBuilder bb) (BytesBuilder bc) = - BytesBuilder $ \a -> let (b, c) = f a in bb b <> bc c - conquer = BytesBuilder $ \_ -> mempty - --- | Convert a 'BytesBuilder' to a strict 'ByteString' by applying it to a value. -buildBytes :: BytesBuilder a -> a -> ByteString -buildBytes (BytesBuilder b) a = b a & Bytes.toLazyByteString & toStrictBytes - --- | Convert a 'BytesBuilder' to a lazy 'ByteString' by applying it to a value. -buildBytesLazy :: BytesBuilder a -> a -> Bytes.Lazy.ByteString -buildBytesLazy (BytesBuilder b) a = b a & Bytes.toLazyByteString - -textT :: TextBuilder Text -textT = TextBuilder Text.fromText - -textLazyT :: TextBuilder Text.Lazy.Text -textLazyT = TextBuilder Text.fromLazyText - -bytesB :: BytesBuilder ByteString -bytesB = BytesBuilder Bytes.byteString - -bytesLazyB :: BytesBuilder Bytes.Lazy.ByteString -bytesLazyB = BytesBuilder Bytes.lazyByteString - -utf8LenientT :: TextBuilder ByteString -utf8LenientT = bytesToTextUtf8Lenient >$< textT - -utf8LenientLazyT :: TextBuilder Bytes.Lazy.ByteString -utf8LenientLazyT = bytesToTextUtf8LenientLazy >$< textLazyT - -utf8B :: BytesBuilder Text -utf8B = textToBytesUtf8 >$< bytesB - -utf8LazyB :: BytesBuilder Text.Lazy.Text -utf8LazyB = textToBytesUtf8Lazy >$< bytesLazyB - -intDecimalT :: TextBuilder Int -intDecimalT = TextBuilder Text.decimal - -intDecimalB :: BytesBuilder Int -intDecimalB = BytesBuilder Bytes.intDec - -integerDecimalT :: TextBuilder Integer -integerDecimalT = TextBuilder Text.decimal - -integerDecimalB :: BytesBuilder Integer -integerDecimalB = BytesBuilder Bytes.integerDec - -naturalDecimalT :: TextBuilder Natural -naturalDecimalT = TextBuilder Text.decimal - -naturalDecimalB :: BytesBuilder Natural -naturalDecimalB = toInteger >$< integerDecimalB - -scientificDecimalT :: TextBuilder Scientific -scientificDecimalT = TextBuilder Scientific.Text.scientificBuilder - -scientificDecimalB :: BytesBuilder Scientific -scientificDecimalB = BytesBuilder Scientific.Bytes.scientificBuilder - --- TODO: can these be abstracted over Divisible & Semigroup? Or something? - -intersperseT :: (forall b. TextBuilder b) -> TextBuilder a -> TextBuilder [a] -intersperseT sep a = ((),) >$< intersperseT' sep a - -intersperseT' :: TextBuilder b -> TextBuilder a -> TextBuilder (b, [a]) -intersperseT' (TextBuilder sep) (TextBuilder a) = TextBuilder $ \(b, as) -> mintersperse (sep b) (fmap a as) - -intersperseB :: (forall b. BytesBuilder b) -> BytesBuilder a -> BytesBuilder [a] -intersperseB sep a = ((),) >$< intersperseB' sep a - -intersperseB' :: BytesBuilder b -> BytesBuilder a -> BytesBuilder (b, [a]) -intersperseB' (BytesBuilder sep) (BytesBuilder a) = BytesBuilder $ \(b, as) -> mintersperse (sep b) (fmap a as) diff --git a/users/Profpatsch/my-prelude/src/Comparison.hs b/users/Profpatsch/my-prelude/src/Comparison.hs deleted file mode 100644 index 4ad38f746..000000000 --- a/users/Profpatsch/my-prelude/src/Comparison.hs +++ /dev/null @@ -1,61 +0,0 @@ --- | Helper module for working better with 'Comparison' contravariants. -module Comparison - ( module Data.Functor.Contravariant, - Comparison (..), - defaultComparison1, - down, - down1, - maybeDown, - groupAllWithComparison, - listIndexComparison, - ) -where - -import Data.Functor.Classes -import Data.Functor.Contravariant -import Data.List qualified as List -import Data.List.NonEmpty -import Data.List.NonEmpty qualified as NonEmpty - --- | Unlift an Ord1 to a `Comparison` function. Analogous to `defaultComparison`. -defaultComparison1 :: (Ord1 f) => Comparison a -> Comparison (f a) -defaultComparison1 = Comparison . liftCompare . getComparison - --- | Invert the ordering of the comparison -down :: Comparison a -> Comparison a -down c = Comparison $ \a b -> case getComparison c a b of - LT -> GT - EQ -> EQ - GT -> LT - --- | Invert the ordering of the outer comparison function but not the inner one --- --- Can be used to e.g. change the ordering of `Maybe` values, but not the ordering of the inner values. --- Example: --- --- > maybeDown = down1 (defaultComparison1 @Maybe) --- > maybeDown (Just 1) (Just 2) == LT --- > maybeDown (Just 1) Nothing == LT --- > maybeDown Nothing (Just 2) == GT -down1 :: (Comparison a -> Comparison b) -> Comparison a -> Comparison b -down1 inner = down . inner . down - --- | Sort every Nothing behind every Just -maybeDown :: Comparison a -> Comparison (Maybe a) -maybeDown = down1 (defaultComparison1 @Maybe) - --- | Group all items in the list that are equal according to the comparison function. Sort the list first so every equivalence class has at most one list in the output. -groupAllWithComparison :: Comparison a -> [a] -> [NonEmpty a] -groupAllWithComparison c xs = - NonEmpty.groupBy - (getEquivalence $ comparisonEquivalence c) - $ List.sortBy (getComparison c) xs - --- | Everything in the list is ordered in the order of equality in the list. --- --- Any item is not in the list is automatically GT to every item in the list, --- and EQ to every item not in the list. -listIndexComparison :: (Eq a) => [a] -> Comparison a -listIndexComparison xs = - (\x -> List.elemIndex x xs) - >$< maybeDown (defaultComparison @Int) diff --git a/users/Profpatsch/my-prelude/src/Debug.hs b/users/Profpatsch/my-prelude/src/Debug.hs deleted file mode 100644 index 8e0af7395..000000000 --- a/users/Profpatsch/my-prelude/src/Debug.hs +++ /dev/null @@ -1,30 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module Debug where - -import Data.Text qualified as Text -import Data.Text.IO qualified as Text.IO -import Debug.Trace as Debug -import PossehlAnalyticsPrelude -import Pretty qualified - --- | 'Debug.trace' a showable value when (and only if!) it is evaluated, and pretty print it. -traceShowPretty :: (Show a) => a -> a -traceShowPretty a = Debug.trace (textToString $ Pretty.showPretty a) a - --- | 'Debug.trace' a showable value when (and only if!) it is evaluated, and pretty print it. In addition, the given prefix is put before the value for easier recognition. -traceShowPrettyPrefix :: (Show a) => Text -> a -> a -traceShowPrettyPrefix prefix a = Debug.trace ([fmt|{prefix}: {Pretty.showPretty a}|]) a - --- | Display non-printable characters as their unicode Control Pictures --- https://en.wikipedia.org/wiki/Unicode_control_characters#Control_pictures --- --- Not all implemented. -putStrLnShowNPr :: Text -> IO () -putStrLnShowNPr t = - Text.IO.putStrLn $ - -- newlines will actually print a newline for convenience - t - & Text.replace "\n" "␤\n" - & Text.replace "\r\n" "␤\n" - & Text.replace "\t" "␉" diff --git a/users/Profpatsch/my-prelude/src/Divisive.hs b/users/Profpatsch/my-prelude/src/Divisive.hs deleted file mode 100644 index e4c31eb8b..000000000 --- a/users/Profpatsch/my-prelude/src/Divisive.hs +++ /dev/null @@ -1,44 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} - -module Divisive where - -import Data.Functor.Contravariant -import Data.Functor.Contravariant.Divisible -import GHC.Records (HasField (getField)) -import Label - --- | Combine two divisibles into a struct with any two labelled fields. -divide2 :: - forall l1 l2 t1 t2 d r. - (Divisible d, HasField l1 r t1, HasField l2 r t2) => - d t1 -> - d t2 -> - d r -divide2 = divide (\r -> (getField @l1 r, getField @l2 r)) - --- | Combine two divisibles into a 'T2' with any two labelled fields. -dt2 :: - forall l1 l2 t1 t2 d. - (Divisible d) => - d t1 -> - d t2 -> - d (T2 l1 t1 l2 t2) -dt2 = divide (\(T2 a b) -> (getField @l1 a, getField @l2 b)) - --- | Combine three divisibles into a struct with any three labelled fields. -divide3 :: forall l1 l2 l3 t1 t2 t3 d r. (Divisible d, HasField l1 r t1, HasField l2 r t2, HasField l3 r t3) => d t1 -> d t2 -> d t3 -> d r -divide3 a b c = adapt >$< a `divided` b `divided` c - where - adapt r = ((getField @l1 r, getField @l2 r), getField @l3 r) - --- | Combine three divisibles into a 'T3' with any three labelled fields. -dt3 :: - forall l1 l2 l3 t1 t2 t3 d. - (Divisible d) => - d t1 -> - d t2 -> - d t3 -> - d (T3 l1 t1 l2 t2 l3 t3) -dt3 a b c = adapt >$< a `divided` b `divided` c - where - adapt (T3 a' b' c') = ((getField @l1 a', getField @l2 b'), getField @l3 c') diff --git a/users/Profpatsch/my-prelude/src/Json.hs b/users/Profpatsch/my-prelude/src/Json.hs deleted file mode 100644 index 808395163..000000000 --- a/users/Profpatsch/my-prelude/src/Json.hs +++ /dev/null @@ -1,430 +0,0 @@ -{-# LANGUAGE KindSignatures #-} -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE UndecidableInstances #-} - -module Json where - -import Builder -import Data.Aeson (FromJSON (parseJSON), ToJSON (toEncoding, toJSON), Value (..), withObject) -import Data.Aeson qualified as Json -import Data.Aeson.BetterErrors qualified as Json -import Data.Aeson.Key qualified as Key -import Data.Aeson.KeyMap qualified as KeyMap -import Data.Aeson.Types qualified -import Data.ByteString.Base64 qualified as Base64 -import Data.Error.Tree -import Data.Map.Strict qualified as Map -import Data.Maybe (catMaybes) -import Data.Set (Set) -import Data.Set qualified as Set -import Data.Text qualified as Text -import Data.Time (UTCTime) -import Data.Vector qualified as Vector -import FieldParser (FieldParser) -import FieldParser qualified as Field -import Json.Enc (Enc) -import Json.Enc qualified as Enc -import Label -import MyPrelude - --- | Use a "Data.Aeson.BetterErrors" parser to implement 'FromJSON'’s 'parseJSON' method. --- --- @ --- instance FromJSON Foo where --- parseJSON = Json.toParseJSON parseFoo --- @ -toParseJSON :: - -- | the error type is 'Error', if you need 'ErrorTree' use 'toParseJSONErrorTree' - Json.Parse Error a -> - Value -> - Data.Aeson.Types.Parser a -toParseJSON = Json.toAesonParser prettyError - --- | Use a "Data.Aeson.BetterErrors" parser to implement 'FromJSON'’s 'parseJSON' method. --- --- @ --- instance FromJSON Foo where --- parseJSON = Json.toParseJSON parseFoo --- @ -toParseJSONErrorTree :: - -- | the error type is 'ErrorTree', if you need 'Error' use 'toParseJSON' - Json.Parse ErrorTree a -> - Value -> - Data.Aeson.Types.Parser a -toParseJSONErrorTree = Json.toAesonParser prettyErrorTree - --- | Convert a 'Json.ParseError' to a corresponding 'ErrorTree' --- --- TODO: build a different version of 'Json.displayError' so that we can nest 'ErrorTree' as well -parseErrorTree :: Error -> Json.ParseError ErrorTree -> ErrorTree -parseErrorTree contextMsg errs = - errs - & Json.displayError prettyErrorTree - & Text.intercalate "\n" - & newError - -- We nest this here because the json errors is multiline, so the result looks like - -- - -- @ - -- contextMsg - -- \| - -- `- At the path: ["foo"]["bar"] - -- Type mismatch: - -- Expected a value of type object - -- Got: true - -- @ - & singleError - & nestedError contextMsg - --- | Convert a 'Json.ParseError' to a pair of error message and a shrunken-down --- version of the value at the path where the error occurred. --- --- This version shows some of the value at the path where the error occurred. -parseErrorTreeValCtx :: Json.Value -> Json.ParseError ErrorTree -> T2 "errorMessage" Enc "valueAtErrorPath" (Maybe Json.Value) -parseErrorTreeValCtx origValue errs = do - let ctxPath = case errs of - Json.BadSchema path _spec -> Just path - _ -> Nothing - let getSubset (Json.Object o) (Json.ObjectKey k) = o & KeyMap.lookup (Key.fromText k) - getSubset (Json.Array a) (Json.ArrayIndex k) = a Vector.!? k - getSubset _ _ = Nothing - let go v = \case - IsEmpty -> v - IsNonEmpty (p :| path) -> case getSubset v p of - Nothing -> v - Just v' -> go v' path - - T2 - ( label @"errorMessage" $ - errs - & displayErrorCustom - ) - ( label @"valueAtErrorPath" $ - ctxPath - <&> ( go origValue - -- make sure we don’t explode the error message by showing too much of the value - >>> restrictJson restriction - ) - ) - where - restriction = - RestrictJsonOpts - { maxDepth = 2, - maxSizeObject = 10, - maxSizeArray = 3, - maxStringLength = 100 - } - displayErrorCustom :: Json.ParseError ErrorTree -> Enc - displayErrorCustom = \case - Json.InvalidJSON str -> - ["The input could not be parsed as JSON: " <> str & stringToText] - & Enc.list Enc.text - Json.BadSchema path spec -> do - let pieceEnc = \case - Json.ObjectKey k -> Enc.text k - Json.ArrayIndex i -> Enc.int i - case spec of - Json.WrongType t val -> - Enc.object - [ ("@", Enc.list pieceEnc path), - ( "error", - -- not showing the value here, because we are gonna show it anyway in the valueAtErrorPath - [fmt|Expected a value of type `{displayJSONType t}` but got one of type `{val & Json.jsonTypeOf & displayJSONType}`|] - ) - ] - other -> - Json.displaySpecifics prettyErrorTree other - & Text.intercalate "\n" - & Enc.text - - displayJSONType :: Json.JSONType -> Text - displayJSONType t = case t of - Json.TyObject -> "object" - Json.TyArray -> "array" - Json.TyString -> "string" - Json.TyNumber -> "number" - Json.TyBool -> "boolean" - Json.TyNull -> "null" - --- | Lift the parser error to an error tree -asErrorTree :: (Functor m) => Json.ParseT Error m a -> Json.ParseT ErrorTree m a -asErrorTree = Json.mapError singleError - --- | Parse the json array into a 'Set'. -asArraySet :: - (Ord a, Monad m) => - Json.ParseT err m a -> - Json.ParseT err m (Set a) -asArraySet inner = Set.fromList <$> Json.eachInArray inner - --- | Parse the json object into a 'Map'. -asObjectMap :: - (Monad m) => - Json.ParseT err m a -> - Json.ParseT err m (Map Text a) -asObjectMap inner = Map.fromList <$> Json.eachInObject inner - --- | Parse as json array and count the number of elements in the array. -countArrayElements :: (Monad m) => Json.ParseT Error m Natural -countArrayElements = Field.toJsonParser ((jsonArray <&> Vector.length) >>> Field.integralToNatural) - where - -- I don’t want to add this to the FieldParser module, cause users should not be dealing with arrays manually. - jsonArray :: FieldParser Json.Value (Vector Json.Value) - jsonArray = Field.FieldParser $ \case - Json.Array vec -> Right vec - _ -> Left "Not a json array" - --- | Parse as json number and convert it to a 'Double'. Throws an error if the number does not fit into a 'Double'. -asDouble :: (Monad m) => Json.ParseT Error m Double -asDouble = - Field.toJsonParser - ( Field.jsonNumber - >>> Field.boundedScientificRealFloat @Double - ) - -asInt :: (Monad m) => Json.ParseT Error m Int -asInt = - Field.toJsonParser - ( Field.jsonNumber - >>> Field.boundedScientificIntegral @Int "Cannot parse into Int" - ) - --- | Json string containing a UTC timestamp, --- @yyyy-mm-ddThh:mm:ss[.sss]Z@ (ISO 8601:2004(E) sec. 4.3.2 extended format) -asUtcTime :: (Monad m) => Json.ParseT Error m UTCTime -asUtcTime = Field.toJsonParser (Field.jsonString >>> Field.utcTime) - --- | Json string containing a UTC timestamp. --- | Accepts multiple timezone formats. --- Do not use this if you can force the input to use the `Z` UTC notation (e.g. in a CSV), use 'utcTime' instead. --- --- Accepts --- --- * UTC timestamps: @yyyy-mm-ddThh:mm:ss[.sss]Z@ --- * timestamps with time zone: @yyyy-mm-ddThh:mm:ss[.sss]±hh:mm@ --- --- ( both ISO 8601:2004(E) sec. 4.3.2 extended format) --- --- The time zone of the second kind of timestamp is taken into account, but normalized to UTC (it’s not preserved what the original time zone was) -asUtcTimeLenient :: (Monad m) => Json.ParseT Error m UTCTime -asUtcTimeLenient = Field.toJsonParser (Field.jsonString >>> Field.utcTimeLenient) - --- | Parse a key from the object, à la 'Json.key', return a labelled value. --- --- We don’t provide a version that infers the json object key, --- since that conflates internal naming with the external API, which is dangerous. --- --- @ --- do --- txt <- keyLabel @"myLabel" "jsonKeyName" Json.asText --- pure (txt :: Label "myLabel" Text) --- @ -keyLabel :: - forall label err m a. - (Monad m) => - Text -> - Json.ParseT err m a -> - Json.ParseT err m (Label label a) -keyLabel = do - keyLabel' (Proxy @label) - --- | Parse a key from the object, à la 'Json.key', return a labelled value. --- Version of 'keyLabel' that requires a proxy. --- --- @ --- do --- txt <- keyLabel' (Proxy @"myLabel") "jsonKeyName" Json.asText --- pure (txt :: Label "myLabel" Text) --- @ -keyLabel' :: - forall label err m a. - (Monad m) => - Proxy label -> - Text -> - Json.ParseT err m a -> - Json.ParseT err m (Label label a) -keyLabel' Proxy key parser = label @label <$> Json.key key parser - --- | Parse an optional key from the object, à la 'Json.keyMay', return a labelled value. --- --- We don’t provide a version that infers the json object key, --- since that conflates internal naming with the external API, which is dangerous. --- --- @ --- do --- txt <- keyLabelMay @"myLabel" "jsonKeyName" Json.asText --- pure (txt :: Label "myLabel" (Maybe Text)) --- @ -keyLabelMay :: - forall label err m a. - (Monad m) => - Text -> - Json.ParseT err m a -> - Json.ParseT err m (Label label (Maybe a)) -keyLabelMay = do - keyLabelMay' (Proxy @label) - --- | Parse an optional key from the object. The inner parser’s return value has to be a Monoid, --- and we collapse the missing key into its 'mempty'. --- --- For example, if the inner parser returns a list, the missing key will be parsed as an empty list. --- --- @ --- do --- txt <- keyMay' "jsonKeyName" (Json.eachInArray Json.asText) --- pure (txt :: [Text]) --- @ --- --- will return @[]@ if the key is missing or if the value is the empty array. -keyMayMempty :: - (Monad m, Monoid a) => - Text -> - Json.ParseT err m a -> - Json.ParseT err m a -keyMayMempty key parser = Json.keyMay key parser <&> fromMaybe mempty - --- | Parse an optional key from the object, à la 'Json.keyMay', return a labelled value. --- Version of 'keyLabelMay' that requires a proxy. --- --- @ --- do --- txt <- keyLabelMay' (Proxy @"myLabel") "jsonKeyName" Json.asText --- pure (txt :: Label "myLabel" (Maybe Text)) --- @ -keyLabelMay' :: - forall label err m a. - (Monad m) => - Proxy label -> - Text -> - Json.ParseT err m a -> - Json.ParseT err m (Label label (Maybe a)) -keyLabelMay' Proxy key parser = label @label <$> Json.keyMay key parser - --- NOTE: keyRenamed Test in "Json.JsonTest", due to import cycles. - --- | Like 'Json.key', but allows a list of keys that are tried in order. --- --- This is intended for renaming keys in an object. --- The first key is the most up-to-date version of a key, the others are for backward-compatibility. --- --- If a key (new or old) exists, the inner parser will always be executed for that key. -keyRenamed :: (Monad m) => NonEmpty Text -> Json.ParseT err m a -> Json.ParseT err m a -keyRenamed (newKey :| oldKeys) inner = - keyRenamedTryOldKeys oldKeys inner >>= \case - Nothing -> Json.key newKey inner - Just parse -> parse - --- | Like 'Json.keyMay', but allows a list of keys that are tried in order. --- --- This is intended for renaming keys in an object. --- The first key is the most up-to-date version of a key, the others are for backward-compatibility. --- --- If a key (new or old) exists, the inner parser will always be executed for that key. -keyRenamedMay :: (Monad m) => NonEmpty Text -> Json.ParseT err m a -> Json.ParseT err m (Maybe a) -keyRenamedMay (newKey :| oldKeys) inner = - keyRenamedTryOldKeys oldKeys inner >>= \case - Nothing -> Json.keyMay newKey inner - Just parse -> Just <$> parse - --- | Helper function for 'keyRenamed' and 'keyRenamedMay' that returns the parser for the first old key that exists, if any. -keyRenamedTryOldKeys :: (Monad m) => [Text] -> Json.ParseT err m a -> Json.ParseT err m (Maybe (Json.ParseT err m a)) -keyRenamedTryOldKeys oldKeys inner = do - oldKeys & traverse tryOld <&> catMaybes <&> nonEmpty <&> \case - Nothing -> Nothing - Just (old :| _moreOld) -> Just old - where - tryOld key = - Json.keyMay key (pure ()) <&> \case - Just () -> Just $ Json.key key inner - Nothing -> Nothing - --- | A simple type isomorphic to `()` that that transforms to an empty json object and parses -data EmptyObject = EmptyObject - deriving stock (Show, Eq) - -instance FromJSON EmptyObject where - -- allow any fields, as long as its an object - parseJSON = withObject "EmptyObject" (\_ -> pure EmptyObject) - -instance ToJSON EmptyObject where - toJSON EmptyObject = Object mempty - toEncoding EmptyObject = toEncoding $ Object mempty - --- | Create a json array from a list of json values. -mkJsonArray :: [Value] -> Value -mkJsonArray xs = xs & Vector.fromList & Array - --- | Encode a 'ByteString' as a base64-encoded json string -mkBase64Bytes :: ByteString -> Value -mkBase64Bytes = String . bytesToTextUtf8Unsafe . Base64.encode - -data RestrictJsonOpts = RestrictJsonOpts - { maxDepth :: Natural, - maxSizeObject :: Natural, - maxSizeArray :: Natural, - maxStringLength :: Natural - } - --- | Restrict a json object so that its depth and size are within the given bounds. --- --- Bounds are maximum 'Int' width. -restrictJson :: - RestrictJsonOpts -> - Value -> - Value -restrictJson opts = do - let maxSizeObject = opts.maxSizeObject & naturalToInteger & integerToBoundedClamped - let maxSizeArray = opts.maxSizeArray & naturalToInteger & integerToBoundedClamped - let maxStringLength = opts.maxStringLength & naturalToInteger & integerToBoundedClamped - go (opts.maxDepth, maxSizeObject, maxSizeArray, maxStringLength) - where - go (0, _, _, strLen) (Json.String s) = truncateString strLen s - go (0, _, _, _) (Json.Array arr) = Array $ Vector.singleton [fmt|<{Vector.length arr} elements elided>|] - go (0, _, _, _) (Json.Object obj) = - obj - & buildText (KeyMap.keys >$< (" intersperseT ", " (Key.toText >$< textT) <> "}>")) - & String - go (depth, sizeObject, sizeArray, strLen) val = case val of - Object obj -> - obj - & ( \m -> - if KeyMap.size m > sizeObject - then - m - & KeyMap.toList - & take sizeObject - & KeyMap.fromList - & KeyMap.map (go (depth - 1, sizeObject, sizeArray, strLen)) - & \smol -> - smol - & KeyMap.insert - "" - (m `KeyMap.difference` smol & KeyMap.keys & toJSON) - else - m - & KeyMap.map (go (depth - 1, sizeObject, sizeArray, strLen)) - ) - & Json.Object - Array arr -> - arr - & ( \v -> - if Vector.length v > sizeArray - then - v - & Vector.take sizeArray - & Vector.map (go (depth - 1, sizeObject, sizeArray, strLen)) - & (\v' -> Vector.snoc v' ([fmt|<{Vector.length v - sizeArray} more elements elided>|] & String)) - else - v - & Vector.map (go (depth - 1, sizeObject, sizeArray, strLen)) - ) - & Array - String txt -> truncateString strLen txt - other -> other - - truncateString strLen txt = - let truncatedTxt = Text.take strLen txt - finalTxt = - if Text.length txt > strLen - then Text.append truncatedTxt "…" - else truncatedTxt - in String finalTxt diff --git a/users/Profpatsch/my-prelude/src/Json/Enc.hs b/users/Profpatsch/my-prelude/src/Json/Enc.hs deleted file mode 100644 index 0d08bc46b..000000000 --- a/users/Profpatsch/my-prelude/src/Json/Enc.hs +++ /dev/null @@ -1,294 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE QuasiQuotes #-} - -module Json.Enc where - -import Data.Aeson (Encoding, Value (..)) -import Data.Aeson qualified as Json -import Data.Aeson.Encode.Pretty qualified as Aeson.Pretty -import Data.Aeson.Encoding qualified as AesonEnc -import Data.Aeson.Encoding qualified as Json.Enc -import Data.Aeson.Encoding qualified as Json.Encoding -import Data.Aeson.Key qualified as Key -import Data.Aeson.KeyMap (KeyMap) -import Data.Aeson.KeyMap qualified as KeyMap -import Data.ByteString.Base64 qualified as Base64 -import Data.ByteString.Lazy qualified as LazyBytes -import Data.Containers.ListUtils (nubOrdOn) -import Data.Int (Int64) -import Data.List qualified as List -import Data.Map.Strict qualified as Map -import Data.Scientific -import Data.String (IsString (fromString)) -import Data.Text.Lazy qualified as Lazy -import Data.Text.Lazy.Builder qualified as Text.Builder -import Data.Time qualified as Time -import Data.Time.Format.ISO8601 qualified as ISO8601 -import GHC.TypeLits (KnownSymbol, Symbol, symbolVal) -import PossehlAnalyticsPrelude -import Pretty (hscolour') - --- | A JSON encoder. --- --- It is faster than going through 'Value', because 'Encoding' is just a wrapper around a @Bytes.Builder@. --- But the @aeson@ interface for 'Encoding' is extremely bad, so let’s build a better one. -newtype Enc = Enc {unEnc :: Encoding} - deriving (Num, Fractional) via (NumLiteralOnly "Enc" Enc) - -instance Show Enc where - show e = e.unEnc & Json.Encoding.encodingToLazyByteString & bytesToTextUtf8UnsafeLazy & show - --- | You can create an @Enc any@ that renders a json string value with @OverloadedStrings@. -instance IsString Enc where - fromString = Enc . AesonEnc.string - --- | You can create an @Enc any@ that renders a json number value with an integer literal. -instance IntegerLiteral Enc where - integerLiteral = Enc . AesonEnc.integer - --- | You can create an @Enc any@ that renders a json number value with an floating point literal. --- --- __ATTN__: Bear in mind that this will crash on repeating rationals, so only use for literals in code! -instance RationalLiteral Enc where - rationalLiteral r = Enc $ AesonEnc.scientific (r & fromRational @Scientific) - --- | Convert an 'Enc' to a strict UTF8-bytestring which is valid JSON (minified). -encToBytesUtf8 :: Enc -> ByteString -encToBytesUtf8 enc' = enc' & encToBytesUtf8Lazy & toStrictBytes - --- | Convert an 'Enc' to a lazy UTF8-bytestring which is valid JSON (minified). -encToBytesUtf8Lazy :: Enc -> LazyBytes.ByteString -encToBytesUtf8Lazy enc' = enc'.unEnc & Json.Enc.encodingToLazyByteString - --- | Convert an 'Enc' to a strict Text which is valid JSON (prettyfied). --- --- __ATTN__: will re-parse the json through 'Json.Value', so only use for user-interactions like pretty-printing. -encToTextPretty :: Enc -> Text -encToTextPretty enc' = - enc' - & encToTextPrettyLazy - & toStrict - --- | Convert an 'Enc' to a lazy Text which is valid JSON (prettyfied). --- --- __ATTN__: will re-parse the json through 'Json.Value', so only use for user-interactions like pretty-printing. -encToTextPrettyLazy :: Enc -> Lazy.Text -encToTextPrettyLazy enc' = - enc' - & encToBytesUtf8Lazy - & Json.decode @Json.Value - & annotate "the json parser can’t parse json encodings??" - & unwrapError - & Aeson.Pretty.encodePrettyToTextBuilder - & Text.Builder.toLazyText - --- | Convert an 'Enc' to a strict Text which is valid JSON (prettyfied and colored). --- --- __ATTN__: will re-parse the json through 'Json.Value', so only use for user-interactions like pretty-printing. -encToTextPrettyColored :: Enc -> Text -encToTextPrettyColored enc' = - enc' - & encToTextPretty - & textToString - & hscolour' - & stringToText - --- | Embed a 'Json.Encoding' verbatim (it’s a valid JSON value) -encoding :: Encoding -> Enc -encoding = Enc - --- | Encode a 'Json.Value' verbatim (it’s a valid JSON value) -value :: Value -> Enc -value = Enc . AesonEnc.value - --- | Encode an Enc verbatim (for completeness’ sake) -enc :: Enc -> Enc -enc = id - --- | Encode an empty json list -emptyArray :: Enc -emptyArray = Enc AesonEnc.emptyArray_ - --- | Encode an empty json dict -emptyObject :: Enc -emptyObject = Enc AesonEnc.emptyObject_ - --- | Encode a 'Text' as a json string -text :: Text -> Enc -text = Enc . AesonEnc.text - --- | Encode a lazy 'Text' as a json string -lazyText :: Lazy.Text -> Enc -lazyText = Enc . AesonEnc.lazyText - --- | Encode a 'ByteString' as a base64-encoded json string -base64Bytes :: ByteString -> Enc -base64Bytes = Enc . AesonEnc.text . bytesToTextUtf8Unsafe . Base64.encode - --- | Encode a 'Text' as a base64-encoded json string -base64 :: Text -> Enc -base64 = Enc . AesonEnc.text . bytesToTextUtf8Unsafe . Base64.encode . textToBytesUtf8 - --- | Encode a 'Prelude.String' as a json string -string :: String -> Enc -string = Enc . AesonEnc.string - --- | Encode as json @null@ if 'Nothing', else use the given encoder for @Just a@ -nullOr :: (a -> Enc) -> Maybe a -> Enc -nullOr inner = \case - Nothing -> Enc AesonEnc.null_ - Just a -> inner a - --- | Encode a list as a json list -list :: (a -> Enc) -> [a] -> Enc -list f = Enc . AesonEnc.list (\a -> (f a).unEnc) - -tuple2 :: (a -> Enc) -> (b -> Enc) -> (a, b) -> Enc -tuple2 f g (a, b) = list id [f a, g b] - -tuple3 :: (a -> Enc) -> (b -> Enc) -> (c -> Enc) -> (a, b, c) -> Enc -tuple3 f g h (a, b, c) = list id [f a, g b, h c] - --- | Encode a 'NonEmpty' as a json list. -nonEmpty :: (a -> Enc) -> NonEmpty a -> Enc -nonEmpty f = list f . toList - --- | Encode the given list of keys and their encoders as json dict. --- --- If the list contains the same key multiple times, the first value in the list is retained: --- --- @ --- (object [ ("foo", 42), ("foo", 23) ]) --- ~= "{\"foo\":42}" --- @ -object :: (Foldable t) => t (Text, Enc) -> Enc -object m = - Enc $ - AesonEnc.dict - AesonEnc.text - (\recEnc -> recEnc.unEnc) - (\f -> List.foldr (\(k, v) -> f k v)) - (nubOrdOn fst $ toList m) - --- | A tag/value encoder; See 'choice' -data Choice = Choice Text Enc - --- | Encode a sum type as a @Choice@, an object with a @tag@/@value@ pair, --- which is the conventional json sum type representation in our codebase. --- --- @ --- foo :: Maybe Text -> Enc --- foo = choice $ \case --- Nothing -> Choice "no" emptyObject () --- Just t -> Choice "yes" text t --- --- ex = foo Nothing == "{\"tag\": \"no\", \"value\": {}}" --- ex2 = foo (Just "hi") == "{\"tag\": \"yes\", \"value\": \"hi\"}" --- @ -choice :: (from -> Choice) -> from -> Enc -choice f from = case f from of - Choice key encA -> singleChoice key encA - --- | Like 'choice', but simply encode a single possibility into a @tag/value@ object. --- This can be useful, but if you want to match on an enum, use 'choice' instead. -singleChoice :: Text -> Enc -> Enc -singleChoice key encA = - Enc $ - AesonEnc.pairs $ - mconcat - [ AesonEnc.pair "tag" (AesonEnc.text key), - AesonEnc.pair "value" encA.unEnc - ] - --- | Encode a 'Map' as a json dict --- --- We can’t really set the key to anything but text (We don’t keep the tag of 'Encoding') --- so instead we allow anything that’s coercible from text as map key (i.e. newtypes). -map :: forall k v. (Coercible k Text) => (v -> Enc) -> Map k v -> Enc -map valEnc m = - Enc $ - AesonEnc.dict - (AesonEnc.text . coerce @k @Text) - (\v -> (valEnc v).unEnc) - Map.foldrWithKey - m - --- | Encode a 'KeyMap' as a json dict -keyMap :: (v -> Enc) -> KeyMap v -> Enc -keyMap valEnc m = - Enc $ - AesonEnc.dict - (AesonEnc.text . Key.toText) - (\v -> (valEnc v).unEnc) - KeyMap.foldrWithKey - m - --- | Encode 'Json.Null' -null :: Enc -null = Enc AesonEnc.null_ - --- | Encode a 'Prelude.Bool' as a json boolean -bool :: Bool -> Enc -bool = Enc . AesonEnc.bool - --- | Encode an 'Integer' as a json number. --- TODO: is it okay to just encode an arbitrarily-sized integer into json? -integer :: Integer -> Enc -integer = Enc . AesonEnc.integer - --- | Encode a 'Scientific' as a json number. -scientific :: Scientific -> Enc -scientific = Enc . AesonEnc.scientific - --- | Encode a 'Natural' as a json number. -natural :: Natural -> Enc -natural = integer . toInteger @Natural - --- | Encode an 'Int' as a json number. -int :: Int -> Enc -int = Enc . AesonEnc.int - --- | Encode an 'Int64' as a json number. -int64 :: Int64 -> Enc -int64 = Enc . AesonEnc.int64 - --- | Encode 'Time.UTCTime' as a json string, as an ISO8601 timestamp with timezone (@yyyy-mm-ddThh:mm:ss[.sss]Z@) -utcTime :: Time.UTCTime -> Enc -utcTime = - text . stringToText . ISO8601.iso8601Show @Time.UTCTime - --- | Implement this class if you want your type to only implement the part of 'Num' --- that allows creating them from Integer-literals, then derive Num via 'NumLiteralOnly': --- --- @ --- data Foo = Foo Integer --- deriving (Num) via (NumLiteralOnly "Foo" Foo) --- --- instance IntegerLiteral Foo where --- integerLiteral i = Foo i --- @ -class IntegerLiteral a where - integerLiteral :: Integer -> a - --- | The same as 'IntegerLiteral' but for floating point literals. -class RationalLiteral a where - rationalLiteral :: Rational -> a - --- | Helper class for @deriving (Num) via …@, implements only literal syntax for integer and floating point numbers, --- and throws descriptive runtime errors for any other methods in 'Num'. --- --- See 'IntegerLiteral' and 'RationalLiteral' for examples. -newtype NumLiteralOnly (sym :: Symbol) num = NumLiteralOnly num - -instance (IntegerLiteral num, KnownSymbol sym) => Num (NumLiteralOnly sym num) where - fromInteger = NumLiteralOnly . integerLiteral - (+) = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to add (+) (NumLiteralOnly)|] - (*) = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to multiply (*) (NumLiteralOnly)|] - (-) = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to subtract (-) (NumLiteralOnly)|] - abs = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to use `abs` (NumLiteralOnly)|] - signum = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to use `signum` (NumLiteralOnly)|] - -instance (IntegerLiteral num, RationalLiteral num, KnownSymbol sym) => Fractional (NumLiteralOnly sym num) where - fromRational = NumLiteralOnly . rationalLiteral - recip = error [fmt|Only use as rational literal allowed for {symbolVal (Proxy @sym)}, you tried to use `recip` (NumLiteralOnly)|] - (/) = error [fmt|Only use as numeric literal allowed for {symbolVal (Proxy @sym)}, you tried to divide (/) (NumLiteralOnly)|] diff --git a/users/Profpatsch/my-prelude/src/MyLabel.hs b/users/Profpatsch/my-prelude/src/MyLabel.hs deleted file mode 100644 index ada0d8dc5..000000000 --- a/users/Profpatsch/my-prelude/src/MyLabel.hs +++ /dev/null @@ -1,55 +0,0 @@ -{-# OPTIONS_GHC -Wno-orphans #-} - -module MyLabel where - -import GHC.OverloadedLabels (IsLabel (fromLabel)) -import GHC.Records (HasField (..)) -import GHC.TypeLits (Symbol) -import Label -import MyPrelude -import Prelude hiding (span) - --- case-match on an e2 with a t2 that provides the relevant functions -caseE2 :: - forall l1 t1 l2 t2 matcher r. - ( HasField l1 matcher (t1 -> r), - HasField l2 matcher (t2 -> r) - ) => - matcher -> - E2 l1 t1 l2 t2 -> - r -{-# INLINE caseE2 #-} -caseE2 m e2 = do - let f1 = getField @l1 m - let f2 = getField @l2 m - case e2 of - E21 a -> f1 $ getField @l1 a - E22 b -> f2 $ getField @l2 b - -e21 :: forall l1 t1 l2 t2. LabelPrx l1 -> t1 -> E2 l1 t1 l2 t2 -{-# INLINE e21 #-} -e21 LabelPrx a = E21 (label @l1 a) - -e22 :: forall l1 t1 l2 t2. LabelPrx l2 -> t2 -> E2 l1 t1 l2 t2 -{-# INLINE e22 #-} -e22 LabelPrx b = E22 (label @l2 b) - -t2 :: forall l1 t1 l2 t2. LabelPrx l1 -> t1 -> LabelPrx l2 -> t2 -> T2 l1 t1 l2 t2 -{-# INLINE t2 #-} -t2 LabelPrx a LabelPrx b = T2 (label @l1 a) (label @l2 b) - -t3 :: forall l1 t1 l2 t2 l3 t3. LabelPrx l1 -> t1 -> LabelPrx l2 -> t2 -> LabelPrx l3 -> t3 -> T3 l1 t1 l2 t2 l3 t3 -{-# INLINE t3 #-} -t3 LabelPrx a LabelPrx b LabelPrx c = T3 (label @l1 a) (label @l2 b) (label @l3 c) - -lbl :: forall l t. LabelPrx l -> t -> Label l t -{-# INLINE lbl #-} -lbl LabelPrx a = label @l a - -data LabelPrx (l :: Symbol) = LabelPrx - -instance (l ~ l') => IsLabel l (LabelPrx l') where - fromLabel = LabelPrx - -instance (t ~ t') => IsLabel l (t -> (Label l t')) where - fromLabel = label @l diff --git a/users/Profpatsch/my-prelude/src/MyPrelude.hs b/users/Profpatsch/my-prelude/src/MyPrelude.hs deleted file mode 100644 index 569ec3e99..000000000 --- a/users/Profpatsch/my-prelude/src/MyPrelude.hs +++ /dev/null @@ -1,863 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE ImplicitParams #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MagicHash #-} -{-# LANGUAGE ViewPatterns #-} - -module MyPrelude - ( -- * Text conversions - Text, - ByteString, - Word8, - fmt, - textToString, - stringToText, - stringToBytesUtf8, - showToText, - textToBytesUtf8, - textToBytesUtf8Lazy, - bytesToTextUtf8, - bytesToTextUtf8Lazy, - bytesToTextUtf8Lenient, - bytesToTextUtf8LenientLazy, - bytesToTextUtf8Unsafe, - bytesToTextUtf8UnsafeLazy, - toStrict, - toLazy, - toStrictBytes, - toLazyBytes, - charToWordUnsafe, - - -- * IO - putStrLn, - putStderrLn, - exitWithMessage, - - -- * WIP code - todo, - - -- * Records - HasField, - - -- * Control flow - doAs, - (&), - (<&>), - (<|>), - foldMap1, - foldMap', - join, - when, - unless, - guard, - ExceptT (..), - runExceptT, - MonadThrow, - throwM, - MonadIO, - liftIO, - MonadReader, - asks, - Bifunctor, - first, - second, - bimap, - both, - foldMap, - fold, - foldl', - fromMaybe, - mapMaybe, - findMaybe, - Traversable, - for, - for_, - traverse, - traverse_, - traverseFold, - traverseFold1, - traverseFoldDefault, - MonadTrans, - lift, - - -- * Kinds - Type, - - -- * Data types - Coercible, - coerce, - Proxy (Proxy), - Map, - annotate, - hush, - Validation (Success, Failure), - failure, - successes, - failures, - traverseValidate, - traverseValidateM, - traverseValidateM_, - eitherToValidation, - eitherToListValidation, - validationToEither, - These (This, That, These), - eitherToThese, - eitherToListThese, - validationToThese, - thenThese, - thenValidate, - thenValidateM, - NonEmpty ((:|)), - pattern IsEmpty, - pattern IsNonEmpty, - singleton, - nonEmpty, - nonEmptyDef, - overNonEmpty, - zipNonEmpty, - zipWithNonEmpty, - zip3NonEmpty, - zipWith3NonEmpty, - zip4NonEmpty, - toList, - atMay, - lengthNatural, - maximum1, - minimum1, - maximumBy1, - minimumBy1, - Vector, - Generic, - Lift, - Semigroup, - sconcat, - Monoid, - mconcat, - ifTrue, - ifExists, - sintersperse, - mintersperse, - Void, - absurd, - Identity (Identity, runIdentity), - Natural, - naturalToInteger, - intToNatural, - integerToBounded, - integerToBoundedClamped, - Scientific, - Contravariant, - contramap, - (>$<), - (>&<), - module Divisive, - Profunctor, - dimap, - lmap, - rmap, - Semigroupoid, - Category, - (>>>), - (&>>), - cconst, - Any, - - -- * Enum definition - inverseFunction, - inverseMap, - enumerateAll, - - -- * Map helpers - mapFromListOn, - mapFromListOnMerge, - - -- * Error handling - HasCallStack, - module Data.Error, - symbolText, - unwrapErrorTree, - ) -where - -import Control.Applicative ((<|>)) -import Control.Category (Category, (>>>)) -import Control.Category qualified as Category -import Control.Foldl.NonEmpty qualified as Foldl1 -import Control.Monad (guard, join, unless, when) -import Control.Monad.Catch (MonadThrow (throwM)) -import Control.Monad.Except - ( ExceptT (..), - runExceptT, - ) -import Control.Monad.IO.Class (MonadIO, liftIO) -import Control.Monad.Identity (Identity (Identity)) -import Control.Monad.Reader (MonadReader, asks) -import Control.Monad.Trans (MonadTrans (lift)) -import Data.Bifunctor (Bifunctor, bimap, first, second) -import Data.ByteString - ( ByteString, - ) -import Data.ByteString.Lazy qualified -import Data.Char qualified -import Data.Coerce (Coercible, coerce) -import Data.Data (Proxy (Proxy)) -import Data.Error -import Data.Error.Tree (ErrorTree, prettyErrorTree) -import Data.Foldable (Foldable (foldMap', toList), fold, foldl', for_, sequenceA_, traverse_) -import Data.Foldable qualified as Foldable -import Data.Function ((&)) -import Data.Functor ((<&>)) -import Data.Functor.Contravariant (Contravariant (contramap), (>$<)) -import Data.Functor.Identity (Identity (runIdentity)) -import Data.Kind (Type) -import Data.List (zip4) -import Data.List qualified as List -import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty) -import Data.List.NonEmpty qualified as NonEmpty -import Data.Map.Strict - ( Map, - ) -import Data.Map.Strict qualified as Map -import Data.Maybe (fromMaybe, mapMaybe) -import Data.Maybe qualified as Maybe -import Data.Profunctor (Profunctor, dimap, lmap, rmap) -import Data.Scientific (Scientific) -import Data.Semigroup (sconcat) -import Data.Semigroup.Foldable (Foldable1 (fold1, toNonEmpty), foldMap1) -import Data.Semigroup.Traversable (Traversable1) -import Data.Semigroupoid (Semigroupoid (o)) -import Data.Text - ( Text, - ) -import Data.Text qualified -import Data.Text.Encoding qualified -import Data.Text.Encoding.Error qualified -import Data.Text.Lazy qualified -import Data.Text.Lazy.Encoding qualified -import Data.These (These (That, These, This)) -import Data.Traversable (for) -import Data.Vector (Vector) -import Data.Vector qualified as Vector -import Data.Void (Void, absurd) -import Data.Word (Word8) -import Divisive -import GHC.Exception (errorCallWithCallStackException) -import GHC.Exts (Any, RuntimeRep, TYPE, raise#) -import GHC.Generics (Generic) -import GHC.Natural (naturalToInteger) -import GHC.Records (HasField) -import GHC.Stack (HasCallStack) -import GHC.TypeLits -import GHC.Utils.Encoding qualified as GHC -import Language.Haskell.TH.Syntax (Lift) -import PyF (fmt) -import System.Exit qualified -import System.IO qualified -import Validation - ( Validation (Failure, Success), - eitherToValidation, - failure, - failures, - successes, - validationToEither, - ) - --- | Mark a `do`-block with the type of the Monad/Applicativ it uses. --- Only intended for reading ease and making code easier to understand, --- especially do-blocks that use unconventional monads (like Maybe or List). --- --- Example: --- --- @ --- doAs @Maybe $ do --- a <- Just 'a' --- b <- Just 'b' --- pure (a, b) --- @ -doAs :: forall m a. m a -> m a -doAs = id - --- | Forward-applying 'contramap', like '&'/'$' and '<&>'/'<$>' but for '>$<'. -(>&<) :: (Contravariant f) => f b -> (a -> b) -> f a -(>&<) = flip contramap - -infixl 5 >&< - --- | Forward semigroupoid application. The same as '(>>>)', but 'Semigroupoid' is not a superclass of 'Category' (yet). --- --- Specialized examples: --- --- @ --- for functions : (a -> b) -> (b -> c) -> (a -> c) --- for Folds: Fold a b -> Fold b c -> Fold a c --- @ -(&>>) :: (Semigroupoid s) => s a b -> s b c -> s a c -(&>>) = flip Data.Semigroupoid.o - --- like >>> -infixr 1 &>> - --- | Categorical constant function, --- like 'const' but works for anything that’s a category and profunctor. -cconst :: (Category c, Profunctor c) => b -> c a b -cconst b = Category.id & rmap (\_ -> b) - --- | encode a Text to a UTF-8 encoded Bytestring -textToBytesUtf8 :: Text -> ByteString -textToBytesUtf8 = Data.Text.Encoding.encodeUtf8 - --- | encode a lazy Text to a UTF-8 encoded lazy Bytestring -textToBytesUtf8Lazy :: Data.Text.Lazy.Text -> Data.ByteString.Lazy.ByteString -textToBytesUtf8Lazy = Data.Text.Lazy.Encoding.encodeUtf8 - -bytesToTextUtf8 :: ByteString -> Either Error Text -bytesToTextUtf8 = first exceptionToError . Data.Text.Encoding.decodeUtf8' - -bytesToTextUtf8Lazy :: Data.ByteString.Lazy.ByteString -> Either Error Data.Text.Lazy.Text -bytesToTextUtf8Lazy = first exceptionToError . Data.Text.Lazy.Encoding.decodeUtf8' - --- | decode a Text from a ByteString that is assumed to be UTF-8 (crash if that is not the case) -bytesToTextUtf8Unsafe :: ByteString -> Text -bytesToTextUtf8Unsafe = Data.Text.Encoding.decodeUtf8 - --- | decode a Text from a ByteString that is assumed to be UTF-8 (crash if that is not the case) -bytesToTextUtf8UnsafeLazy :: Data.ByteString.Lazy.ByteString -> Data.Text.Lazy.Text -bytesToTextUtf8UnsafeLazy = Data.Text.Lazy.Encoding.decodeUtf8 - --- | decode a Text from a ByteString that is assumed to be UTF-8, --- replace non-UTF-8 characters with the replacment char U+FFFD. -bytesToTextUtf8Lenient :: Data.ByteString.ByteString -> Data.Text.Text -bytesToTextUtf8Lenient = - Data.Text.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode - --- | decode a lazy Text from a lazy ByteString that is assumed to be UTF-8, --- replace non-UTF-8 characters with the replacment char U+FFFD. -bytesToTextUtf8LenientLazy :: Data.ByteString.Lazy.ByteString -> Data.Text.Lazy.Text -bytesToTextUtf8LenientLazy = - Data.Text.Lazy.Encoding.decodeUtf8With Data.Text.Encoding.Error.lenientDecode - --- | Make a lazy 'Text' strict. -toStrict :: Data.Text.Lazy.Text -> Text -toStrict = Data.Text.Lazy.toStrict - --- | Make a strict 'Text' lazy. -toLazy :: Text -> Data.Text.Lazy.Text -toLazy = Data.Text.Lazy.fromStrict - --- | Make a lazy 'ByteString' strict. -toStrictBytes :: Data.ByteString.Lazy.ByteString -> ByteString -toStrictBytes = Data.ByteString.Lazy.toStrict - --- | Make a strict 'ByteString' lazy. -toLazyBytes :: ByteString -> Data.ByteString.Lazy.ByteString -toLazyBytes = Data.ByteString.Lazy.fromStrict - --- | Convert a (performant) 'Text' into an (imperformant) list-of-char 'String'. --- --- Some libraries (like @time@ or @network-uri@) still use the `String` as their interface. We only want to convert to string at the edges, otherwise use 'Text'. --- --- ATTN: Don’t use `String` in code if you can avoid it, prefer `Text` instead. -textToString :: Text -> String -textToString = Data.Text.unpack - --- | Convert an (imperformant) list-of-char 'String' into a (performant) 'Text' . --- --- Some libraries (like @time@ or @network-uri@) still use the `String` as their interface. We want to convert 'String' to 'Text' as soon as possible and only use 'Text' in our code. --- --- ATTN: Don’t use `String` in code if you can avoid it, prefer `Text` instead. -stringToText :: String -> Text -stringToText = Data.Text.pack - --- | Encode a String to an UTF-8 encoded Bytestring --- --- ATTN: Don’t use `String` in code if you can avoid it, prefer `Text` instead. -stringToBytesUtf8 :: String -> ByteString --- TODO(Profpatsch): use a stable interface -stringToBytesUtf8 = GHC.utf8EncodeByteString - --- | Like `show`, but generate a 'Text' --- --- ATTN: This goes via `String` and thus is fairly inefficient. --- We should add a good display library at one point. --- --- ATTN: unlike `show`, this forces the whole @'a --- so only use if you want to display the whole thing. -showToText :: (Show a) => a -> Text -showToText = stringToText . show - --- | Unsafe conversion between 'Char' and 'Word8'. This is a no-op and --- silently truncates to 8 bits Chars > '\255'. It is provided as --- convenience for ByteString construction. --- --- Use if you want to get the 'Word8' representation of a character literal. --- Don’t use on arbitrary characters! --- --- >>> charToWordUnsafe ',' --- 44 -charToWordUnsafe :: Char -> Word8 -{-# INLINE charToWordUnsafe #-} -charToWordUnsafe = fromIntegral . Data.Char.ord - -pattern IsEmpty :: [a] -pattern IsEmpty <- (null -> True) - where - IsEmpty = [] - -pattern IsNonEmpty :: NonEmpty a -> [a] -pattern IsNonEmpty n <- (nonEmpty -> Just n) - where - IsNonEmpty n = toList n - -{-# COMPLETE IsEmpty, IsNonEmpty #-} - --- | Single element in a (non-empty) list. -singleton :: a -> NonEmpty a -singleton a = a :| [] - --- | If the given list is empty, use the given default element and return a non-empty list. -nonEmptyDef :: a -> [a] -> NonEmpty a -nonEmptyDef def xs = - xs & nonEmpty & \case - Nothing -> def :| [] - Just ne -> ne - --- | If the list is not empty, run the given function with a NonEmpty list, otherwise just return [] -overNonEmpty :: (Applicative f) => (NonEmpty a -> f [b]) -> [a] -> f [b] -overNonEmpty f xs = case xs of - IsEmpty -> pure [] - IsNonEmpty xs' -> f xs' - --- | Zip two non-empty lists. -zipNonEmpty :: NonEmpty a -> NonEmpty b -> NonEmpty (a, b) -{-# INLINE zipNonEmpty #-} -zipNonEmpty ~(a :| as) ~(b :| bs) = (a, b) :| zip as bs - --- | Zip two non-empty lists, combining them with the given function -zipWithNonEmpty :: (a -> b -> c) -> NonEmpty a -> NonEmpty b -> NonEmpty c -{-# INLINE zipWithNonEmpty #-} -zipWithNonEmpty = NonEmpty.zipWith - --- | Zip three non-empty lists. -zip3NonEmpty :: NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty (a, b, c) -{-# INLINE zip3NonEmpty #-} -zip3NonEmpty ~(a :| as) ~(b :| bs) ~(c :| cs) = (a, b, c) :| zip3 as bs cs - --- | Zip three non-empty lists, combining them with the given function -zipWith3NonEmpty :: (a -> b -> c -> d) -> NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty d -{-# INLINE zipWith3NonEmpty #-} -zipWith3NonEmpty f ~(x :| xs) ~(y :| ys) ~(z :| zs) = f x y z :| zipWith3 f xs ys zs - --- | Zip four non-empty lists -zip4NonEmpty :: NonEmpty a -> NonEmpty b -> NonEmpty c -> NonEmpty d -> NonEmpty (a, b, c, d) -{-# INLINE zip4NonEmpty #-} -zip4NonEmpty ~(a :| as) ~(b :| bs) ~(c :| cs) ~(d :| ds) = (a, b, c, d) :| zip4 as bs cs ds - --- | We don’t want to use Foldable’s `length`, because it is too polymorphic and can lead to bugs. --- Only list-y things should have a length. -class (Foldable f) => Lengthy f where - atMay :: Natural -> f a -> Maybe a - atMay = atMayDefault (\idx' xs -> xs & toList & (!! idx')) - {-# INLINE atMay #-} - -atMayDefault :: (Lengthy f) => (Int -> f a -> a) -> Natural -> f a -> Maybe a -atMayDefault lookupF idx f = do - let midx = integerToBounded @Int (idx & naturalToInteger) - if - | idx >= lengthNatural f -> Nothing - | Nothing <- midx -> Nothing - | Just idx' <- midx -> f & lookupF idx' & Just -{-# INLINE atMayDefault #-} - -instance Lengthy [] - -instance Lengthy NonEmpty - -instance Lengthy Vector where - atMay = atMayDefault (\idx' xs -> xs & (Vector.! idx')) - -lengthNatural :: (Lengthy f) => f a -> Natural -lengthNatural xs = - xs - & Foldable.length - -- length can never be negative or something went really, really wrong - & fromIntegral @Int @Natural - --- | @O(n)@. Get the maximum element from a non-empty structure (strict). -maximum1 :: (Foldable1 f, Ord a) => f a -> a -maximum1 = Foldl1.fold1 Foldl1.maximum - --- | @O(n)@. Get the maximum element from a non-empty structure, using the given comparator (strict). -maximumBy1 :: (Foldable1 f) => (a -> a -> Ordering) -> f a -> a -maximumBy1 f = Foldl1.fold1 (Foldl1.maximumBy f) - --- | @O(n)@. Get the minimum element from a non-empty structure (strict). -minimum1 :: (Foldable1 f, Ord a) => f a -> a -minimum1 = Foldl1.fold1 Foldl1.minimum - --- | @O(n)@. Get the minimum element from a non-empty structure, using the given comparator (strict). -minimumBy1 :: (Foldable1 f) => (a -> a -> Ordering) -> f a -> a -minimumBy1 f = Foldl1.fold1 (Foldl1.minimumBy f) - --- | Annotate a 'Maybe' with an error message and turn it into an 'Either'. -annotate :: err -> Maybe a -> Either err a -annotate err = \case - Nothing -> Left err - Just a -> Right a - --- | Turn Either into Maybe, ignoring the error. -hush :: Either e a -> Maybe a -hush = \case - Left _ -> Nothing - Right a -> Just a - --- | Map the same function over both sides of a Bifunctor (e.g. a tuple). -both :: (Bifunctor bi) => (a -> b) -> bi a a -> bi b b -both f = bimap f f - --- | Find the first element for which pred returns `Just a`, and return the `a`. --- --- Example: --- @ --- >>> :set -XTypeApplications --- >>> import qualified Text.Read --- --- >>> findMaybe (Text.Read.readMaybe @Int) ["foo"] --- Nothing --- >>> findMaybe (Text.Read.readMaybe @Int) ["foo", "34.40", "34", "abc"] --- Just 34 -findMaybe :: (Foldable t) => (a -> Maybe b) -> t a -> Maybe b -findMaybe mPred list = - let pred' x = Maybe.isJust $ mPred x - in case Foldable.find pred' list of - Just a -> mPred a - Nothing -> Nothing - --- | 'traverse' with a function returning 'Either' and collect all errors that happen, if they happen. --- --- Does not shortcut on error, so will always traverse the whole list/'Traversable' structure. --- --- This is a useful error handling function in many circumstances, --- because it won’t only return the first error that happens, but rather all of them. -traverseValidate :: forall t a err b. (Traversable t) => (a -> Either err b) -> t a -> Either (NonEmpty err) (t b) -traverseValidate f as = - as - & traverse @t @(Validation _) (eitherToListValidation . f) - & validationToEither - --- | 'traverse' with a function returning 'm Either' and collect all errors that happen, if they happen. --- --- Does not shortcut on error, so will always traverse the whole list/'Traversable' structure. --- --- This is a useful error handling function in many circumstances, --- because it won’t only return the first error that happens, but rather all of them. -traverseValidateM :: forall t m a err b. (Traversable t, Applicative m) => (a -> m (Either err b)) -> t a -> m (Either (NonEmpty err) (t b)) -traverseValidateM f as = - as - & traverse @t @m (\a -> a & f <&> eitherToListValidation) - <&> sequenceA @t @(Validation _) - <&> validationToEither - --- | 'traverse_' with a function returning 'm Either' and collect all errors that happen, if they happen. --- --- Does not shortcut on error, so will always traverse the whole list/'Traversable' structure. --- --- This is a useful error handling function in many circumstances, --- because it won’t only return the first error that happens, but rather all of them. -traverseValidateM_ :: forall t m a err. (Traversable t, Applicative m) => (a -> m (Either err ())) -> t a -> m (Either (NonEmpty err) ()) -traverseValidateM_ f as = - as - & traverse @t @m (\a -> a & f <&> eitherToListValidation) - <&> sequenceA_ @t @(Validation _) - <&> validationToEither - --- | Like 'eitherToValidation', but puts the Error side into a NonEmpty list --- to make it combine with other validations. --- --- See also 'validateEithers', if you have a list of Either and want to collect all errors. -eitherToListValidation :: Either a c -> Validation (NonEmpty a) c -eitherToListValidation = first singleton . eitherToValidation - --- | Convert an 'Either' to a 'These'. -eitherToThese :: Either err a -> These err a -eitherToThese (Left err) = This err -eitherToThese (Right a) = That a - --- | Like 'eitherToThese', but puts the Error side into a NonEmpty list --- to make it combine with other theses. -eitherToListThese :: Either err a -> These (NonEmpty err) a -eitherToListThese (Left e) = This (singleton e) -eitherToListThese (Right a) = That a - --- | Convert a 'Validation' to a 'These'. -validationToThese :: Validation err a -> These err a -validationToThese (Failure err) = This err -validationToThese (Success a) = That a - --- | Nested '>>=' of a These inside some other @m@. --- --- Use if you want to collect errors and successes, and want to chain multiple function returning 'These'. -thenThese :: - (Monad m, Semigroup err) => - (a -> m (These err b)) -> - m (These err a) -> - m (These err b) -thenThese f x = do - th <- x - join <$> traverse f th - --- | Nested validating bind-like combinator. --- --- Use if you want to collect errors, and want to chain multiple functions returning 'Validation'. -thenValidate :: - (a -> Validation err b) -> - Validation err a -> - Validation err b -thenValidate f = \case - Success a -> f a - Failure err -> Failure err - --- | Nested validating bind-like combinator inside some other @m@. --- --- Use if you want to collect errors, and want to chain multiple functions returning 'Validation'. -thenValidateM :: - (Monad m) => - (a -> m (Validation err b)) -> - m (Validation err a) -> - m (Validation err b) -thenValidateM f x = - eitherToValidation <$> do - x' <- validationToEither <$> x - case x' of - Left err -> pure $ Left err - Right a -> validationToEither <$> f a - --- | Put the text to @stderr@. -putStderrLn :: Text -> IO () -putStderrLn msg = - System.IO.hPutStrLn System.IO.stderr $ textToString msg - -exitWithMessage :: Text -> IO a -exitWithMessage msg = do - putStderrLn msg - System.Exit.exitWith $ System.Exit.ExitFailure (-1) - --- | Run some function producing applicative over a traversable data structure, --- then collect the results in a Monoid. --- --- Very helpful with side-effecting functions returning @(Validation err a)@: --- --- @ --- let --- f :: Text -> IO (Validation (NonEmpty Error) Text) --- f t = pure $ if t == "foo" then Success t else Failure (singleton ("not foo: " <> t)) --- --- in traverseFold f [ "foo", "bar", "baz" ] --- == Failure ("not foo bar" :| ["not foo baz"]) --- @ --- --- … since @(Semigroup err => Validation err a)@ is a @Semigroup@/@Monoid@ itself. -traverseFold :: (Applicative ap, Traversable t, Monoid m) => (a -> ap m) -> t a -> ap m -{-# INLINE traverseFold #-} -traverseFold f xs = - -- note: could be weakened to (Foldable t) via `getAp . foldMap (Ap . f)` - fold <$> traverse f xs - --- | Like 'traverseFold', but fold over a semigroup instead of a Monoid, by providing a starting element. -traverseFoldDefault :: (Applicative ap, Traversable t, Semigroup m) => m -> (a -> ap m) -> t a -> ap m -{-# INLINE traverseFoldDefault #-} -traverseFoldDefault def f xs = foldDef def <$> traverse f xs - where - foldDef = foldr (<>) - --- | Same as 'traverseFold', but with a 'Semigroup' and 'Traversable1' restriction. -traverseFold1 :: (Applicative ap, Traversable1 t, Semigroup s) => (a -> ap s) -> t a -> ap s -{-# INLINE traverseFold1 #-} --- note: cannot be weakened to (Foldable1 t) because there is no `Ap` for Semigroup (No `Apply` typeclass) -traverseFold1 f xs = fold1 <$> traverse f xs - --- | Use this in places where the code is still to be implemented. --- --- It always type-checks and will show a warning at compile time if it was forgotten in the code. --- --- Use instead of 'error' and 'undefined' for code that hasn’t been written. --- --- Uses the same trick as https://hackage.haskell.org/package/protolude-0.3.0/docs/src/Protolude.Error.html#error -{-# WARNING todo "'todo' (undefined code) remains in code" #-} -todo :: forall (r :: RuntimeRep). forall (a :: TYPE r). (HasCallStack) => a -todo = raise# (errorCallWithCallStackException "This code was not yet implemented: TODO" ?callStack) - --- | Convert an integer to a 'Natural' if possible --- --- Named the same as the function from "GHC.Natural", but does not crash. -intToNatural :: (Integral a) => a -> Maybe Natural -intToNatural i = - if i < 0 - then Nothing - else Just $ fromIntegral i - --- | Convert an Integer to a bounded type if possible. --- --- taken from 'Scientific.toBoundedInteger'. -integerToBounded :: forall i. (Bounded i, Integral i) => Integer -> Maybe i -integerToBounded i - | i < iMinBound || i > iMaxBound = Nothing - | otherwise = Just $ fromInteger i - where - iMinBound = toInteger (minBound :: i) - iMaxBound = toInteger (maxBound :: i) - --- | Convert an Integer to a bounded type, clamping to the bounds if necessary. -integerToBoundedClamped :: forall i. (Bounded i, Integral i) => Integer -> i -integerToBoundedClamped i - | i < iMinBound = minBound - | i > iMaxBound = maxBound - | otherwise = fromInteger i - where - iMinBound = toInteger (minBound :: i) - iMaxBound = toInteger (maxBound :: i) - --- | @inverseFunction f@ creates a function that is the inverse of a given function --- @f@. It does so by constructing 'M.Map' internally for each value @f a@. The --- implementation makes sure that the 'M.Map' is constructed only once and then --- shared for every call. --- --- __Memory usage note:__ don't inverse functions that have types like 'Int' --- as their result. In this case the created 'M.Map' will have huge size. --- --- The complexity of reversed mapping is \(\mathcal{O}(\log n)\). --- --- __Performance note:__ make sure to specialize monomorphic type of your functions --- that use 'inverseFunction' to avoid 'M.Map' reconstruction. --- --- One of the common 'inverseFunction' use-case is inverting the 'show' or a 'show'-like --- function. --- --- >>> data Color = Red | Green | Blue deriving (Show, Enum, Bounded) --- >>> parse = inverseFunction show :: String -> Maybe Color --- >>> parse "Red" --- Just Red --- >>> parse "Black" --- Nothing --- --- __Correctness note:__ 'inverseFunction' expects /injective function/ as its argument, --- i.e. the function must map distinct arguments to distinct values. --- --- Typical usage of this function looks like this: --- --- @ --- __data__ GhcVer --- = Ghc802 --- | Ghc822 --- | Ghc844 --- | Ghc865 --- | Ghc881 --- __deriving__ ('Eq', 'Ord', 'Show', 'Enum', 'Bounded') --- --- showGhcVer :: GhcVer -> 'Text' --- showGhcVer = \\__case__ --- Ghc802 -> "8.0.2" --- Ghc822 -> "8.2.2" --- Ghc844 -> "8.4.4" --- Ghc865 -> "8.6.5" --- Ghc881 -> "8.8.1" --- --- parseGhcVer :: 'Text' -> 'Maybe' GhcVer --- parseGhcVer = 'inverseFunction' showGhcVer --- --- Taken from relude’s @Relude.Extra.Enum@. -inverseFunction :: - forall a k. - (Bounded a, Enum a, Ord k) => - (a -> k) -> - (k -> Maybe a) -inverseFunction f k = Map.lookup k $ inverseMap f - --- | Like `inverseFunction`, but instead of returning the function --- it returns a mapping from all possible outputs to their possible inputs. --- --- This has the same restrictions of 'inverseFunction'. -inverseMap :: forall a k. (Bounded a, Enum a, Ord k) => (a -> k) -> Map k a -inverseMap f = enumerateAll <&> (\a -> (f a, a)) & Map.fromList - --- | All possible values in this enum. -enumerateAll :: (Enum a, Bounded a) => [a] -enumerateAll = [minBound .. maxBound] - --- | Create a 'Map' from a list of values, extracting the map key from each value. Like 'Map.fromList'. --- --- Attention: if the key is not unique, the earliest value with the key will be in the map. -mapFromListOn :: (Ord key) => (a -> key) -> [a] -> Map key a -mapFromListOn f xs = xs <&> (\x -> (f x, x)) & Map.fromList - --- | Create a 'Map' from a list of values, merging multiple values at the same key with '<>' (left-to-right) --- --- `f` has to extract the key and value. Value must be mergable. --- --- Attention: if the key is not unique, the earliest value with the key will be in the map. -mapFromListOnMerge :: (Ord key, Semigroup s) => (a -> (key, s)) -> [a] -> Map key s -mapFromListOnMerge f xs = - xs - <&> (\x -> f x) - & Map.fromListWith - -- we have to flip (`<>`) because `Map.fromListWith` merges its values “the other way around” - (flip (<>)) - --- | If the predicate is true, return the @m@, else 'mempty'. --- --- This can be used (together with `ifExists`) to e.g. create lists with optional elements: --- --- >>> import Data.Monoid (Sum(..)) --- --- >>> :{ mconcat [ --- ifTrue (1 == 1) [1], --- [2, 3, 4], --- ifTrue False [5], --- ] --- :} --- [1,2,3,4] --- --- Or any other Monoid: --- --- >>> mconcat [ Sum 1, ifTrue (1 == 1) (Sum 2), Sum 3 ] - --- Sum {getSum = 6} -ifTrue :: (Monoid m) => Bool -> m -> m -ifTrue pred' m = if pred' then m else mempty - --- | If the given @Maybe@ is @Just@, return the result of `f` wrapped in `pure`, else return `mempty`. - --- This can be used (together with `ifTrue`) to e.g. create lists with optional elements: --- --- >>> import Data.Monoid (Sum(..)) --- --- >>> :{ mconcat [ --- unknown command '{' --- --- Or any other Monoid: --- --- >>> mconcat [ Sum 1, ifExists id (Just 2), Sum 3 ] --- Sum {getSum = 6} -ifExists :: (Monoid (f b), Applicative f) => (a -> b) -> Maybe a -> f b -ifExists f m = m & foldMap @Maybe (pure . f) - --- | Intersperse a monoidal value between each element of a list. --- --- Generalization of 'Data.List.intersperse' to any 'Foldable' and 'Semigroup'. -sintersperse :: (Foldable1 t, Semigroup m) => m -> t m -> m -sintersperse sep xs = xs & toNonEmpty & NonEmpty.intersperse sep & sconcat - --- | Intersperse a monoidal value between each element of a list. If the list is empty, return 'mempty'. --- --- Generalization of 'Data.List.intersperse' to any 'Foldable' and 'Monoid'. -mintersperse :: (Foldable t, Monoid m) => m -> t m -> m -mintersperse sep xs = xs & toList & List.intersperse sep & mconcat - --- | Get the text of a symbol via TypeApplications -symbolText :: forall sym. (KnownSymbol sym) => Text -symbolText = do - symbolVal (Proxy :: Proxy sym) - & stringToText - --- | Like 'unwrapError', but for 'ErrorTree'. Will crash with an uncatchable exception if 'Left'. -unwrapErrorTree :: (HasCallStack) => Either ErrorTree a -> a -unwrapErrorTree e = e & first (newError . prettyErrorTree) & unwrapError diff --git a/users/Profpatsch/my-prelude/src/Parse.hs b/users/Profpatsch/my-prelude/src/Parse.hs deleted file mode 100644 index 758507d45..000000000 --- a/users/Profpatsch/my-prelude/src/Parse.hs +++ /dev/null @@ -1,210 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE TemplateHaskellQuotes #-} - -module Parse where - -import Control.Category qualified -import Control.Selective (Selective) -import Data.Error.Tree -import Data.Functor.Compose -import Data.List qualified as List -import Data.Map.Strict qualified as Map -import Data.Monoid (First (..)) -import Data.Semigroup.Traversable -import Data.Semigroupoid qualified as Semigroupoid -import Data.Text qualified as Text -import FieldParser (FieldParser) -import FieldParser qualified as Field -import Language.Haskell.TH.Syntax qualified as TH -import PossehlAnalyticsPrelude -import Validation (partitionValidations) -import Prelude hiding (init, maybe) -import Prelude qualified - --- | A generic applicative “vertical” parser. --- Similar to `FieldParser`, but made for parsing whole structures and collect all errors in an `ErrorTree`. -newtype Parse from to = Parse ((Context, from) -> Validation (NonEmpty ErrorTree) (Context, to)) - deriving - (Functor, Applicative, Selective) - via ( Compose - ( Compose - ((->) (Context, from)) - (Validation (NonEmpty ErrorTree)) - ) - ((,) Context) - ) - --- | Every parser can add to the context, like e.g. an element parser will add the name of the element it should be parsing. --- This should be added to the error message of each parser, with `showContext`. -newtype Context = Context (Maybe [Text]) - deriving stock (Show) - deriving (Semigroup, Monoid) via (First [Text]) - -instance Semigroupoid Parse where - o p2 p1 = Parse $ \from -> case runParse' p1 from of - Failure err -> Failure err - Success to1 -> runParse' p2 to1 - -instance Category Parse where - (.) = Semigroupoid.o - id = Parse $ \t -> Success t - -instance Profunctor Parse where - lmap f (Parse p) = Parse $ lmap (second f) p - rmap = (<$>) - -runParse :: Error -> Parse from to -> from -> Either ErrorTree to -runParse errMsg parser t = - (Context (Just ["$"]), t) - & runParse' parser - <&> snd - & first (nestedMultiError errMsg) - & validationToEither - -runParse' :: Parse from to -> (Context, from) -> Validation (NonEmpty ErrorTree) (Context, to) -runParse' (Parse f) from = f from - -showContext :: Context -> Text -showContext (Context context) = context & fromMaybe [] & List.reverse & Text.intercalate "." - -addContext :: Text -> Context -> Context -addContext x (Context mxs) = Context (Just $ x : (mxs & fromMaybe [])) - -mkParsePushContext :: Text -> ((Context, from) -> Either ErrorTree to) -> Parse from to -mkParsePushContext toPush f = Parse $ \(ctx, from) -> case f (ctx, from) of - Right to -> Success (addContext toPush ctx, to) - Left err -> Failure $ singleton err - -mkParseNoContext :: ((Context, from) -> Either ErrorTree to) -> Parse from to -mkParseNoContext f = Parse $ \(ctx, from) -> case f (ctx, from) of - Right to -> Success (ctx, to) - Left err -> Failure $ singleton err - --- | Accept only exactly the given value -exactly :: (Eq from) => (from -> Text) -> from -> Parse from from -exactly errDisplay from = Parse $ \(ctx, from') -> - if from == from' - then Success (ctx, from') - else Failure $ singleton [fmt|Field has to be exactly {errDisplay from}, was: {errDisplay from'} at {showContext ctx}|] - --- | Make a parser to parse the whole list -multiple :: Parse a1 a2 -> Parse [a1] [a2] -multiple inner = dimap nonEmpty (Prelude.maybe [] toList) (maybe $ multipleNE inner) - --- | Make a parser to parse the whole non-empty list -multipleNE :: Parse from to -> Parse (NonEmpty from) (NonEmpty to) -multipleNE inner = Parse $ \(ctx, from) -> - from - & zipIndex - & traverse (\(idx, f) -> runParse' inner (ctx, f) & first (singleton . nestedMultiError [fmt|{idx}|])) - -- we assume that, since the same parser is used everywhere, the context will be the same as well (TODO: correct?) - & second (\((ctx', y) :| ys) -> (ctx', y :| (snd <$> ys))) - --- | Like '(>>>)', but returns the intermediate result alongside the final parse result. -andParse :: Parse to to2 -> Parse from to -> Parse from (to, to2) -andParse outer inner = Parse $ \from -> case runParse' inner from of - Failure err -> Failure err - Success (ctx, to) -> runParse' outer (ctx, to) <&> (second (to,)) - --- | Lift a parser into an optional value -maybe :: Parse from to -> Parse (Maybe from) (Maybe to) -maybe inner = Parse $ \(ctx, m) -> case m of - Nothing -> Success (ctx, Nothing) - Just a -> runParse' inner (ctx, a) & second (fmap Just) - --- | Assert that there is exactly one element in the list -exactlyOne :: Parse [from] from -exactlyOne = Parse $ \(ctx, xs) -> case xs of - [] -> Failure $ singleton [fmt|Expected exactly 1 element, but got 0, at {ctx & showContext}|] - [one] -> Success (ctx, one) - _more -> Failure $ singleton [fmt|Expected exactly 1 element, but got 2, at {ctx & showContext}|] - --- | Assert that there is exactly zero or one element in the list -zeroOrOne :: Parse [from] (Maybe from) -zeroOrOne = Parse $ \(ctx, xs) -> case xs of - [] -> Success (ctx, Nothing) - [one] -> Success (ctx, Just one) - _more -> Failure $ singleton [fmt|Expected exactly 1 element, but got 2, at {ctx & showContext}|] - --- | Find the first element on which the sub-parser succeeds; if there was no match, return all error messages. -find :: Parse from to -> Parse [from] to -find inner = Parse $ \(ctx, xs) -> case xs of - [] -> failure [fmt|Wanted to get the first sub-parser that succeeds, but there were no elements in the list, at {ctx & showContext}|] - (y : ys) -> runParse' (findNE' inner) (ctx, y :| ys) - --- | Find the first element on which the sub-parser succeeds; if there was no match, return all error messages. -findNE' :: Parse from to -> Parse (NonEmpty from) to -findNE' inner = Parse $ \(ctx, xs) -> - xs - <&> (\x -> runParse' inner (ctx, x)) - & traverse1 - ( \case - Success a -> Left a - Failure e -> Right e - ) - & \case - Left a -> Success a - Right errs -> - errs - & zipIndex - <&> (\(idx, errs') -> nestedMultiError [fmt|{idx}|] errs') - & nestedMultiError [fmt|None of these sub-parsers succeeded|] - & singleton - & Failure - --- | Find all elements on which the sub-parser succeeds; if there was no match, return an empty list -findAll :: Parse from to -> Parse [from] [to] -findAll inner = Parse $ \(ctx, xs) -> - xs - <&> (\x -> runParse' inner (ctx, x)) - & partitionValidations - & \case - (_miss, []) -> - -- in this case we just arbitrarily forward the original context … - Success (ctx, []) - (_miss, (hitCtx, hit) : hits) -> Success (hitCtx, hit : (hits <&> snd)) - --- | Find the given element in the map, and parse it with the given parser. -mapLookup :: (Coercible Text key, Ord key) => key -> Parse from to -> Parse (Map key from) to -mapLookup key inner = do - let keyT :: Text = coerce key - Parse $ \(ctx, m) -> case Map.lookup (coerce key) m of - Nothing -> Failure $ singleton [fmt|Key "{keyT}" not found in map at {showContext ctx}|] - Just a -> runParse' inner (addContext keyT ctx, a) - --- | Find the given element in the map, and parse it with the given parser. --- --- Use this instead of `rmap` to add the map key to the error context. -mapLookupMay :: (Coercible Text key, Ord key) => key -> Parse from to -> Parse (Map key from) (Maybe to) -mapLookupMay key inner = do - let keyT :: Text = coerce key - Parse $ \(ctx, m) -> case Map.lookup (coerce key) m of - Nothing -> Success (addContext keyT ctx, Nothing) - Just a -> runParse' (Just <$> inner) (addContext keyT ctx, a) - --- | convert a 'FieldParser' into a 'Parse'. -fieldParser :: FieldParser from to -> Parse from to -fieldParser fp = Parse $ \(ctx, from) -> case Field.runFieldParser fp from of - Right a -> Success (ctx, a) - Left err -> Failure $ singleton (singleError err) - -zipNonEmpty :: NonEmpty a -> NonEmpty b -> NonEmpty (a, b) -zipNonEmpty (x :| xs) (y :| ys) = (x, y) :| zip xs ys - -zipIndex :: NonEmpty b -> NonEmpty (Natural, b) -zipIndex = zipNonEmpty (1 :| [2 :: Natural ..]) - --- | Parse a literal value at compile time. This is used with Template Haskell, like so: --- --- > $$("2023-07-27" & literal hyphenatedDay) :: Time.Day --- --- You need the double @$$@! --- --- ATTN: This needs an instance of the 'TH.Lift' class for the output type. --- Many library types don’t yet implement this class, so we have to provide the instances ourselves. --- See NOTE: Lift for library types -literal :: forall from to. (TH.Lift to) => Parse from to -> from -> TH.Code TH.Q to -literal parser s = do - case runParse "Literal parse failed" parser s of - Right a -> [||a||] - Left err -> TH.liftCode (err & prettyErrorTree & textToString & fail) diff --git a/users/Profpatsch/my-prelude/src/Postgres/Decoder.hs b/users/Profpatsch/my-prelude/src/Postgres/Decoder.hs deleted file mode 100644 index 6e07709d8..000000000 --- a/users/Profpatsch/my-prelude/src/Postgres/Decoder.hs +++ /dev/null @@ -1,187 +0,0 @@ -module Postgres.Decoder where - -import Control.Applicative (Alternative) -import Data.Aeson qualified as Json -import Data.Aeson.BetterErrors qualified as Json -import Data.Error.Tree -import Data.Typeable (Typeable) -import Database.PostgreSQL.Simple (Binary (fromBinary)) -import Database.PostgreSQL.Simple.FromField qualified as PG -import Database.PostgreSQL.Simple.FromRow qualified as PG -import FieldParser (FieldParser) -import FieldParser qualified as Field -import Json qualified -import Label -import Parse (Parse, runParse) -import PossehlAnalyticsPrelude - --- | A Decoder of postgres values. Allows embedding more complex parsers (like a 'Json.ParseT'). -newtype Decoder a = Decoder (PG.RowParser a) - deriving newtype (Functor, Applicative, Alternative, Monad) - --- | Parse a `bytea` field, equivalent to @Binary ByteString@ but avoids the pitfall of having to use 'Binary'. -bytea :: Decoder ByteString -bytea = fromField @(Binary ByteString) <&> (.fromBinary) - --- | Parse a nullable `bytea` field, equivalent to @Binary ByteString@ but avoids the pitfall of having to use 'Binary'. -byteaMay :: Decoder (Maybe ByteString) -byteaMay = fromField @(Maybe (Binary ByteString)) <&> fmap (.fromBinary) - --- | Parse a `text` field. -text :: Decoder Text -text = fromField @Text - --- | Parse a nullable `text` field. -textMay :: Decoder (Maybe Text) -textMay = fromField @(Maybe Text) - --- | Parse a `text` field, and then use a 'FieldParser' to convert the result further. -textParse :: (Typeable to) => FieldParser Text to -> Decoder to -textParse = parseField @Text - --- | Parse a nullable `text` field, and then use a 'FieldParser' to convert the result further. -textParseMay :: (Typeable to) => FieldParser Text to -> Decoder (Maybe to) -textParseMay = parseFieldMay @Text - --- | Parse a type implementing 'FromField', and then use a 'FieldParser' to convert the result further. -parseField :: - forall from to. - ( PG.FromField from, - Typeable to - ) => - FieldParser from to -> - Decoder to -parseField parser = Decoder $ PG.fieldWith $ \field bytes -> do - val <- PG.fromField @from field bytes - case Field.runFieldParser parser val of - Left err -> - PG.returnError - PG.ConversionFailed - field - (err & prettyError & textToString) - Right a -> pure a - --- | Parse a nullable type implementing 'FromField', and then use a 'FieldParser' to convert the result further. -parseFieldMay :: - forall from to. - ( PG.FromField from, - Typeable to - ) => - FieldParser from to -> - Decoder (Maybe to) -parseFieldMay parser = Decoder $ PG.fieldWith $ \field bytes -> do - val <- PG.fromField @(Maybe from) field bytes - case Field.runFieldParser parser <$> val of - Nothing -> pure Nothing - Just (Left err) -> - PG.returnError - PG.ConversionFailed - field - (err & prettyError & textToString) - Just (Right a) -> pure (Just a) - --- | Parse a type implementing 'FromField', and then use a 'Parse' to convert the result further. -parse :: - forall from to. - ( PG.FromField from, - Typeable to - ) => - Parse from to -> - Decoder to -parse parser = Decoder $ PG.fieldWith $ \field bytes -> do - val <- PG.fromField @from field bytes - case Parse.runParse "Cannot parse field" parser val of - Left err -> - PG.returnError - PG.ConversionFailed - field - (err & prettyErrorTree & textToString) - Right a -> pure a - --- | Parse a nullable type implementing 'FromField', and then use a 'Parse' to convert the result further. -parseMay :: - forall from to. - ( PG.FromField from, - Typeable to - ) => - Parse from to -> - Decoder (Maybe to) -parseMay parser = Decoder $ PG.fieldWith $ \field bytes -> do - val <- PG.fromField @(Maybe from) field bytes - case Parse.runParse "Cannot parse field" parser <$> val of - Nothing -> pure Nothing - Just (Left err) -> - PG.returnError - PG.ConversionFailed - field - (err & prettyErrorTree & textToString) - Just (Right a) -> pure (Just a) - --- | Turn any type that implements 'PG.fromField' into a 'Decoder'. Use type applications to prevent accidental conversions: --- --- @ --- fromField @Text :: Decoder Text --- @ -fromField :: (PG.FromField a) => Decoder a -fromField = Decoder $ PG.fieldWith PG.fromField - --- | Turn any type that implements 'PG.fromField' into a 'Decoder' and wrap the result into the given 'Label'. Use type applications to prevent accidental conversions: --- --- @ --- fromField @"myField" @Text :: Decoder (Label "myField" Text) --- @ -fromFieldLabel :: forall lbl a. (PG.FromField a) => Decoder (Label lbl a) -fromFieldLabel = label @lbl <$> fromField - --- | Parse fields out of a json value returned from the database. --- --- ATTN: The whole json record has to be transferred before it is parsed, --- so if you only need a tiny bit of it, use `->` and `->>` in your SQL statement --- and return only the fields you need from the query. --- --- In that case pay attention to NULL though: --- --- @ --- SELECT '{"foo": {}}'::jsonb->>'foo' IS NULL --- → TRUE --- @ --- --- Also note: `->>` will coerce the json value to @text@, regardless of the content. --- So the JSON object @{"foo": {}}"@ would be returned as the text: @"{\"foo\": {}}"@. -json :: (Typeable a) => Json.ParseT ErrorTree Identity a -> Decoder a -json parser = Decoder $ PG.fieldWith $ \field bytes -> do - val <- PG.fromField @Json.Value field bytes - case Json.parseValue parser val of - Left err -> - PG.returnError - PG.ConversionFailed - field - (err & Json.parseErrorTree "Cannot decode jsonb column" & prettyErrorTree & textToString) - Right a -> pure a - --- | Parse fields out of a nullable json value returned from the database. --- --- ATTN: The whole json record has to be transferred before it is parsed, --- so if you only need a tiny bit of it, use `->` and `->>` in your SQL statement --- and return only the fields you need from the query. --- --- In that case pay attention to NULL though: --- --- @ --- SELECT '{"foo": {}}'::jsonb->>'foo' IS NULL --- → TRUE --- @ --- --- Also note: `->>` will coerce the json value to @text@, regardless of the content. --- So the JSON object @{"foo": {}}"@ would be returned as the text: @"{\"foo\": {}}"@. -jsonMay :: (Typeable a) => Json.ParseT ErrorTree Identity a -> Decoder (Maybe a) -jsonMay parser = Decoder $ PG.fieldWith $ \field bytes -> do - val <- PG.fromField @(Maybe Json.Value) field bytes - case Json.parseValue parser <$> val of - Nothing -> pure Nothing - Just (Left err) -> - PG.returnError - PG.ConversionFailed - field - (err & Json.parseErrorTree "Cannot decode jsonb column" & prettyErrorTree & textToString) - Just (Right a) -> pure (Just a) diff --git a/users/Profpatsch/my-prelude/src/Postgres/MonadPostgres.hs b/users/Profpatsch/my-prelude/src/Postgres/MonadPostgres.hs deleted file mode 100644 index 2f653bcf2..000000000 --- a/users/Profpatsch/my-prelude/src/Postgres/MonadPostgres.hs +++ /dev/null @@ -1,1039 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE QuasiQuotes #-} -{-# OPTIONS_GHC -Wno-orphans #-} - -module Postgres.MonadPostgres where - -import Arg -import AtLeast (AtLeast) -import Control.Exception - ( Exception (displayException), - Handler (Handler), - catches, - try, - ) -import Control.Foldl qualified as Fold -import Control.Monad.Logger.CallStack (MonadLogger, logDebug, logWarn) -import Control.Monad.Reader (MonadReader (ask), ReaderT (..)) -import Control.Monad.Trans.Resource -import Data.Aeson (FromJSON) -import Data.ByteString qualified as ByteString -import Data.Error.Tree -import Data.HashMap.Strict qualified as HashMap -import Data.Int (Int64) -import Data.Kind (Type) -import Data.List qualified as List -import Data.Pool (Pool) -import Data.Pool qualified as Pool -import Data.Text qualified as Text -import Data.Typeable (Typeable) -import Database.PostgreSQL.Simple (Connection, FormatError, FromRow, Query, QueryError, ResultError, SqlError, ToRow) -import Database.PostgreSQL.Simple qualified as PG -import Database.PostgreSQL.Simple qualified as Postgres -import Database.PostgreSQL.Simple.FromRow qualified as PG -import Database.PostgreSQL.Simple.ToField (ToField) -import Database.PostgreSQL.Simple.ToRow (ToRow (toRow)) -import Database.PostgreSQL.Simple.Types (PGArray (PGArray), Query (..)) -import GHC.IO.Handle (Handle) -import GHC.Records (getField) -import Label -import Language.Haskell.TH.Quote (QuasiQuoter) -import OpenTelemetry.Trace.Core (NewEvent (newEventName)) -import OpenTelemetry.Trace.Core qualified as Otel hiding (inSpan, inSpan') -import OpenTelemetry.Trace.Monad qualified as Otel -import PossehlAnalyticsPrelude -import Postgres.Decoder -import Postgres.Decoder qualified as Dec -import Pretty (showPretty) -import PyF qualified -import Seconds -import System.Exit (ExitCode (..)) -import Tool -import UnliftIO (MonadUnliftIO (withRunInIO), bracket, hClose, mask_) -import UnliftIO.Concurrent (forkIO) -import UnliftIO.Process (ProcessHandle) -import UnliftIO.Process qualified as Process -import UnliftIO.Resource qualified as Resource -import Prelude hiding (init, span) - --- | Postgres queries/commands that can be executed within a running transaction. --- --- These are implemented with the @postgresql-simple@ primitives of the same name --- and will behave the same unless othewise documented. -class (Monad m) => MonadPostgres (m :: Type -> Type) where - -- | Execute an INSERT, UPDATE, or other SQL query that is not expected to return results. - - -- Returns the number of rows affected. - execute :: - (ToRow params, Typeable params) => - Query -> - params -> - Transaction m (Label "numberOfRowsAffected" Natural) - - -- | Execute a multi-row INSERT, UPDATE, or other SQL query that is not expected to return results. - -- - -- Returns the number of rows affected. If the list of parameters is empty, - -- this function will simply return 0 without issuing the query to the backend. - -- If this is not desired, consider using the 'PG.Values' constructor instead. - executeMany :: - (ToRow params, Typeable params) => - Query -> - NonEmpty params -> - Transaction m (Label "numberOfRowsAffected" Natural) - - -- | Execute INSERT ... RETURNING, UPDATE ... RETURNING, - -- or other SQL query that accepts multi-row input and is expected to return results. - -- Note that it is possible to write query conn "INSERT ... RETURNING ..." ... - -- in cases where you are only inserting a single row, - -- and do not need functionality analogous to 'executeMany'. - -- - -- If the list of parameters is empty, this function will simply return [] without issuing the query to the backend. If this is not desired, consider using the 'PG.Values' constructor instead. - executeManyReturningWith :: (ToRow q) => Query -> NonEmpty q -> Decoder r -> Transaction m [r] - - -- | Run a query, passing parameters and result row parser. - queryWith :: - (PG.ToRow params, Typeable params, Typeable r) => - PG.Query -> - params -> - Decoder r -> - Transaction m [r] - - -- | Run a query without any parameters and result row parser. - queryWith_ :: - (Typeable r) => - PG.Query -> - Decoder r -> - Transaction m [r] - - -- | Run a query, passing parameters, and fold over the resulting rows. - -- - -- This doesn’t have to realize the full list of results in memory, - -- rather results are streamed incrementally from the database. - -- - -- When dealing with small results, it may be simpler (and perhaps faster) to use query instead. - -- - -- This fold is _not_ strict. The stream consumer is responsible - -- for forcing the evaluation of its result to avoid space leaks. - -- - -- If you can, prefer aggregating in the database itself. - foldRowsWithAcc :: - (ToRow params, Typeable row, Typeable params) => - Query -> - params -> - Decoder row -> - a -> - (a -> row -> Transaction m a) -> - Transaction m a - - -- | Run a given transaction in a transaction block, rolling back the transaction - -- if any exception (postgres or Haskell Exception) is thrown during execution. - -- - -- Re-throws the exception. - -- - -- Don’t do any long-running things on the Haskell side during a transaction, - -- because it will block a database connection and potentially also lock - -- database tables from being written or read by other clients. - -- - -- Nonetheless, try to push transactions as far out to the handlers as possible, - -- don’t do something like @runTransaction $ query …@, because it will lead people - -- to accidentally start nested transactions (the inner transaction is run on a new connections, - -- thus can’t see any changes done by the outer transaction). - -- Only handlers should run transactions. - runTransaction :: Transaction m a -> m a - --- | Quasi-Quoter for multi-line SQL literals. Trims leading whitespace up to the least-indented line. -sql :: QuasiQuoter -sql = PyF.fmtTrim - --- | Run a query, passing parameters. Prefer 'queryWith' if possible. -query :: - forall m params r. - (PG.ToRow params, PG.FromRow r, Typeable params, Typeable r, MonadPostgres m) => - PG.Query -> - params -> - Transaction m [r] -query qry params = queryWith qry params (Decoder PG.fromRow) - --- | Run a query without any parameters. Prefer 'queryWith' if possible. --- --- TODO: I think(?) this can always be replaced by passing @()@ to 'query', remove? -query_ :: - forall m r. - (Typeable r, PG.FromRow r, MonadPostgres m) => - PG.Query -> - Transaction m [r] -query_ qry = queryWith_ qry (Decoder PG.fromRow) - --- TODO: implement via fold, so that the result doesn’t have to be realized in memory -querySingleRow :: - ( MonadPostgres m, - ToRow qParams, - Typeable qParams, - FromRow a, - Typeable a, - MonadThrow m - ) => - Query -> - qParams -> - Transaction m a -querySingleRow qry params = do - query qry params >>= ensureSingleRow - --- TODO: implement via fold, so that the result doesn’t have to be realized in memory -querySingleRowWith :: - ( MonadPostgres m, - ToRow qParams, - Typeable qParams, - Typeable a, - MonadThrow m - ) => - Query -> - qParams -> - Decoder a -> - Transaction m a -querySingleRowWith qry params decoder = do - queryWith qry params decoder >>= ensureSingleRow - --- | Return the first row, if any. -queryFirstRowWithMaybe :: - ( MonadPostgres m, - ToRow qParams, - Typeable qParams, - Typeable a - ) => - Query -> - qParams -> - Decoder a -> - Transaction m (Maybe a) -queryFirstRowWithMaybe qry params decoder = do - queryWith qry params decoder >>= \case - [] -> pure Nothing - (one : _) -> pure $ Just one - --- TODO: implement via fold, so that the result doesn’t have to be realized in memory -querySingleRowMaybe :: - ( MonadPostgres m, - ToRow qParams, - Typeable qParams, - FromRow a, - Typeable a, - MonadThrow m - ) => - Query -> - qParams -> - Transaction m (Maybe a) -querySingleRowMaybe qry params = do - rows <- query qry params - case rows of - [] -> pure Nothing - [one] -> pure (Just one) - -- TODO: Should we MonadThrow this here? It’s really an implementation detail of MonadPostgres - -- that a database function can error out, should probably handled by the instances. - more -> throwM $ SingleRowError {numberOfRowsReturned = (List.length more)} - -ensureSingleRow :: - (MonadThrow m) => - [a] -> - m a -ensureSingleRow = \case - -- TODO: Should we MonadThrow this here? It’s really an implementation detail of MonadPostgres - -- that a database function can error out, should probably handled by the instances. - [] -> throwM (SingleRowError {numberOfRowsReturned = 0}) - [one] -> pure one - more -> - throwM $ - SingleRowError - { numberOfRowsReturned = - -- TODO: this is VERY bad, because it requires to parse the full database output, even if there’s 10000000000 elements - List.length more - } - -ensureNoneOrSingleRow :: - (MonadThrow m) => - [a] -> - m (Maybe a) -ensureNoneOrSingleRow = \case - -- TODO: Should we MonadThrow this here? It’s really an implementation detail of MonadPostgres - -- that a database function can error out, should probably handled by the instances. - [] -> pure Nothing - [one] -> pure $ Just one - more -> - throwM $ - SingleRowError - { numberOfRowsReturned = - -- TODO: this is VERY bad, because it requires to parse the full database output, even if there’s 10000000000 elements - List.length more - } - --- | Run a query, passing parameters, and fold over the resulting rows. --- --- This doesn’t have to realize the full list of results in memory, --- rather results are streamed incrementally from the database. --- --- When dealing with small results, it may be simpler (and perhaps faster) to use query instead. --- --- The results are folded strictly into the Monoid returned by the decoder. --- --- If you need more complex folding logic, use 'foldRowsWith' with a 'Fold'. --- --- If you can, prefer aggregating in the database itself. -foldRowsWithMonoid :: - forall row params m. - ( MonadPostgres m, - PG.ToRow params, - Typeable row, - Typeable params, - Monoid row - ) => - PG.Query -> - params -> - Decoder row -> - Transaction m row -foldRowsWithMonoid qry params decoder = foldRowsWith qry params decoder Fold.mconcat - --- | Run a query, passing parameters, and fold over the resulting rows. --- --- This doesn’t have to realize the full list of results in memory, --- rather results are streamed incrementally from the database. --- --- When dealing with small results, it may be simpler (and perhaps faster) to use query instead. --- --- The results are folded strictly by the 'Fold.Fold' that is passed. --- --- If you can, prefer aggregating in the database itself. -foldRowsWith :: - forall row params m b. - ( MonadPostgres m, - PG.ToRow params, - Typeable row, - Typeable params - ) => - PG.Query -> - params -> - Decoder row -> - Fold.Fold row b -> - Transaction m b -foldRowsWith qry params decoder = Fold.purely f - where - f :: forall x. (x -> row -> x) -> x -> (x -> b) -> Transaction m b - f acc init extract = do - x <- foldRowsWithAcc qry params decoder init (\a r -> pure $ acc a r) - pure $ extract x - -newtype Transaction m a = Transaction {unTransaction :: (ReaderT Connection m a)} - deriving newtype - ( Functor, - Applicative, - Monad, - MonadThrow, - MonadLogger, - MonadIO, - MonadUnliftIO, - MonadTrans, - Otel.MonadTracer - ) - --- | [Resource Pool](http://hackage.haskell.org/package/resource-pool-0.2.3.2/docs/Data-Pool.html) configuration. -data PoolingInfo = PoolingInfo - { -- | Minimal amount of resources that are - -- always available. - numberOfStripes :: AtLeast 1 Int, - -- | Time after which extra resources - -- (above minimum) can stay in the pool - -- without being used. - unusedResourceOpenTime :: Seconds, - -- | Max number of resources that can be - -- in the Pool at any time - maxOpenResourcesAcrossAllStripes :: AtLeast 1 Int - } - deriving stock (Generic, Eq, Show) - deriving anyclass (FromJSON) - -initMonadPostgres :: - (Text -> IO ()) -> - -- | Info describing the connection to the Postgres DB - Postgres.ConnectInfo -> - -- | Configuration info for pooling attributes - PoolingInfo -> - -- | Created Postgres connection pool - ResourceT IO (Pool Postgres.Connection) -initMonadPostgres logInfoFn connectInfo poolingInfo = do - (_releaseKey, connPool) <- - Resource.allocate - (logInfoFn "Creating Postgres Connection Pool" >> createPGConnPool) - (\pool -> logInfoFn "Destroying Postgres Connection Pool" >> destroyPGConnPool pool) - pure connPool - where - -- \| Create a Postgres connection pool - createPGConnPool :: - IO (Pool Postgres.Connection) - createPGConnPool = - Pool.newPool $ - Pool.defaultPoolConfig - {- resource init action -} poolCreateResource - {- resource destruction -} poolfreeResource - ( poolingInfo.unusedResourceOpenTime.unSeconds - & fromIntegral @Natural @Double - ) - (poolingInfo.maxOpenResourcesAcrossAllStripes.unAtLeast) - where - poolCreateResource = Postgres.connect connectInfo - poolfreeResource = Postgres.close - - -- \| Destroy a Postgres connection pool - destroyPGConnPool :: - -- \| Pool to be destroyed - (Pool Postgres.Connection) -> - IO () - destroyPGConnPool p = Pool.destroyAllResources p - --- | Improve a possible error message, by adding some context to it. --- --- The given Exception type is caught, 'show'n and pretty-printed. --- --- In case we get an `IOError`, we display it in a reasonable fashion. -addErrorInformation :: - forall exc a. - (Exception exc) => - Text.Text -> - IO a -> - IO a -addErrorInformation msg io = - io - & try @exc - <&> first (showPretty >>> newError >>> errorContext msg) - & try @IOError - <&> first (showToError >>> errorContext "IOError" >>> errorContext msg) - <&> join @(Either Error) - >>= unwrapIOError - --- | Catch any Postgres exception that gets thrown, --- print the query that was run and the query parameters, --- then rethrow inside an 'Error'. -handlePGException :: - forall a params m. - ( ToRow params, - MonadUnliftIO m, - MonadLogger m - ) => - PrettyPrintDatabaseQueries -> - Text -> - Query -> - -- | Depending on whether we used `format` or `formatMany`. - Either params (NonEmpty params) -> - IO a -> - Transaction m a -handlePGException prettyQuery queryType query' params io = do - withRunInIO $ \unliftIO -> - io - `catches` [ Handler $ unliftIO . logQueryException @SqlError, - Handler $ unliftIO . logQueryException @QueryError, - Handler $ unliftIO . logQueryException @ResultError, - Handler $ unliftIO . logFormatException - ] - where - -- TODO: use throwInternalError here (after pulling it into the MonadPostgres class) - throwAsError = unwrapIOError . Left . newError - throwErr err = liftIO $ throwAsError $ prettyErrorTree $ nestedMultiError "A Postgres query failed" err - logQueryException :: (Exception e) => e -> Transaction m a - logQueryException exc = do - formattedQuery <- - case params of - Left one -> pgFormatQuery' prettyQuery query' one - Right many -> pgFormatQueryMany' prettyQuery query' many - throwErr - ( singleError [fmt|Query Type: {queryType}|] - :| [ nestedError "Exception" (exc & showPretty & newError & singleError), - nestedError "Query" (formattedQuery & bytesToTextUtf8Lenient & newError & singleError) - ] - ) - logFormatException :: FormatError -> Transaction m a - logFormatException fe = throwErr (fe & showPretty & newError & singleError & singleton) - --- | Perform a Postgres action within a transaction -withPGTransaction :: - -- | Postgres connection pool to be used for the action - (Pool Postgres.Connection) -> - -- | DB-action to be performed - (Postgres.Connection -> IO a) -> - -- | Result of the DB-action - IO a -withPGTransaction connPool f = - Pool.withResource - connPool - (\conn -> Postgres.withTransaction conn (f conn)) - --- | `pg_formatter` is a perl script that does not support any kind of streaming. --- Thus we initialize a pool with a bunch of these scripts running, waiting for input. This way we can have somewhat fast SQL formatting. --- --- Call `initPgFormatPool` to initialize, then use `runPgFormat` to format some sql. -data PgFormatPool = PgFormatPool - { pool :: Pool PgFormatProcess, - pgFormat :: Tool - } - -data PgFormatProcess = PgFormatProcess - { stdinHdl :: Handle, - stdoutHdl :: Handle, - stderrHdl :: Handle, - procHdl :: ProcessHandle, - startedAt :: Otel.Timestamp - } - -initPgFormatPool :: (HasField "pgFormat" tools Tool) => tools -> IO PgFormatPool -initPgFormatPool tools = do - pool <- - Pool.newPool - ( Pool.defaultPoolConfig - (pgFormatStartCommandWaitForInput tools) - ( \pgFmt -> do - Process.terminateProcess pgFmt.procHdl - -- make sure we don’t leave any zombies - _ <- forkIO $ do - _ <- Process.waitForProcess pgFmt.procHdl - pure () - pure () - ) - -- unused resource time - 100 - -- number of resources - 10 - ) - - -- fill the pool with resources - let go = - Pool.tryWithResource pool (\_ -> go) >>= \case - Nothing -> pure () - Just () -> pure () - _ <- go - pure (PgFormatPool {pool, pgFormat = tools.pgFormat}) - -destroyPgFormatPool :: PgFormatPool -> IO () -destroyPgFormatPool pool = Pool.destroyAllResources pool.pool - --- | Get the oldest resource from the pool, or stop if you find a resource that’s older than `cutoffPointMs`. -takeOldestResource :: PgFormatPool -> Arg "cutoffPointMs" Integer -> IO (PgFormatProcess, Pool.LocalPool PgFormatProcess) -takeOldestResource pool cutoffPointMs = do - now <- Otel.getTimestamp - mask_ $ do - a <- Pool.takeResource pool.pool - (putBack, res) <- go now [] a - -- make sure we don’t leak any resources we didn’t use in the end - for_ putBack $ \(x, xLocal) -> Pool.putResource xLocal x - pure res - where - mkMs ts = (ts & Otel.timestampNanoseconds & toInteger) `div` 1000_000 - go now putBack a@(a', _) = - if abs (mkMs now - mkMs a'.startedAt) > cutoffPointMs.unArg - then pure (putBack, a) - else - Pool.tryTakeResource pool.pool >>= \case - Nothing -> pure (putBack, a) - Just b@(b', _) -> do - if a'.startedAt < b'.startedAt - then go now (b : putBack) a - else go now (a : putBack) b - --- | Format the given SQL with pg_formatter. Will use the pool of already running formatters to speed up execution. -runPgFormat :: PgFormatPool -> ByteString -> IO (T3 "exitCode" ExitCode "formatted" ByteString "stderr" ByteString) -runPgFormat pool sqlStatement = do - bracket - (takeOldestResource pool 200) - ( \(a, localPool) -> do - -- we always destroy the resource, because the process exited - Pool.destroyResource pool.pool localPool a - -- create a new process to keep the pool “warm” - new <- pgFormatStartCommandWaitForInput pool - Pool.putResource localPool new - ) - ( \(pgFmt, _localPool) -> do - ByteString.hPut pgFmt.stdinHdl sqlStatement - -- close stdin to make pg_formatter format (it exits …) - -- issue: https://github.com/darold/pgFormatter/issues/333 - hClose pgFmt.stdinHdl - formatted <- ByteString.hGetContents pgFmt.stdoutHdl - errs <- ByteString.hGetContents pgFmt.stderrHdl - exitCode <- Process.waitForProcess pgFmt.procHdl - pure $ - T3 - (label @"exitCode" exitCode) - (label @"formatted" formatted) - (label @"stderr" errs) - ) - -runPGTransactionImpl :: - (MonadUnliftIO m) => - m (Pool Postgres.Connection) -> - Transaction m a -> - m a -{-# INLINE runPGTransactionImpl #-} -runPGTransactionImpl zoom (Transaction transaction) = do - pool <- zoom - withRunInIO $ \unliftIO -> - withPGTransaction pool $ \conn -> do - unliftIO $ runReaderT transaction conn - -executeImpl :: - (ToRow params, MonadUnliftIO m, MonadLogger m, Otel.MonadTracer m) => - m (DebugLogDatabaseQueries, PrettyPrintDatabaseQueries) -> - Query -> - params -> - Transaction m (Label "numberOfRowsAffected" Natural) -{-# INLINE executeImpl #-} -executeImpl zoomDbOptions qry params = - Otel.inSpan' "Postgres Query (execute)" Otel.defaultSpanArguments $ \span -> do - (logDatabaseQueries, prettyQuery) <- lift @Transaction zoomDbOptions - traceQueryIfEnabled span logDatabaseQueries prettyQuery qry (HasSingleParam params) - conn <- Transaction ask - PG.execute conn qry params - & handlePGException prettyQuery "execute" qry (Left params) - >>= toNumberOfRowsAffected "executeImpl" - -executeImpl_ :: - ( MonadUnliftIO m, - MonadLogger m, - Otel.MonadTracer m - ) => - m (DebugLogDatabaseQueries, PrettyPrintDatabaseQueries) -> - Query -> - Transaction m (Label "numberOfRowsAffected" Natural) -{-# INLINE executeImpl_ #-} -executeImpl_ zoomDbOptions qry = - Otel.inSpan' "Postgres Query (execute)" Otel.defaultSpanArguments $ \span -> do - (logDatabaseQueries, prettyQuery) <- lift @Transaction zoomDbOptions - traceQueryIfEnabled @() span logDatabaseQueries prettyQuery qry HasNoParams - conn <- Transaction ask - PG.execute_ conn qry - & handlePGException prettyQuery "execute_" qry (Left ()) - >>= toNumberOfRowsAffected "executeImpl_" - -executeManyImpl :: - (ToRow params, MonadUnliftIO m, MonadLogger m, Otel.MonadTracer m) => - m (DebugLogDatabaseQueries, PrettyPrintDatabaseQueries) -> - Query -> - NonEmpty params -> - Transaction m (Label "numberOfRowsAffected" Natural) -executeManyImpl zoomDbOptions qry params = - Otel.inSpan' "Postgres Query (executeMany)" Otel.defaultSpanArguments $ \span -> do - (logDatabaseQueries, prettyQuery) <- lift @Transaction zoomDbOptions - traceQueryIfEnabled span logDatabaseQueries prettyQuery qry (HasMultiParams params) - conn <- Transaction ask - PG.executeMany conn qry (params & toList) - & handlePGException prettyQuery "executeMany" qry (Right params) - >>= toNumberOfRowsAffected "executeManyImpl" - -toNumberOfRowsAffected :: (MonadIO m) => Text -> Int64 -> m (Label "numberOfRowsAffected" Natural) -toNumberOfRowsAffected functionName i64 = - i64 - & intToNatural - & annotate [fmt|{functionName}: postgres returned a negative number of rows affected: {i64}|] - -- we throw this directly in IO here, because we don’t want to e.g. have to propagate MonadThrow through user code (it’s an assertion) - & unwrapIOError - & liftIO - <&> label @"numberOfRowsAffected" - -executeManyReturningWithImpl :: - ( ToRow params, - MonadUnliftIO m, - MonadLogger m, - Otel.MonadTracer m - ) => - m (DebugLogDatabaseQueries, PrettyPrintDatabaseQueries) -> - Query -> - NonEmpty params -> - Decoder r -> - Transaction m [r] -{-# INLINE executeManyReturningWithImpl #-} -executeManyReturningWithImpl zoomDbOptions qry params (Decoder fromRow) = do - Otel.inSpan' "Postgres Query (executeManyReturning)" Otel.defaultSpanArguments $ \span -> do - (logDatabaseQueries, prettyQuery) <- lift @Transaction zoomDbOptions - traceQueryIfEnabled span logDatabaseQueries prettyQuery qry (HasMultiParams params) - conn <- Transaction ask - PG.returningWith fromRow conn qry (params & toList) - & handlePGException prettyQuery "executeManyReturning" qry (Right params) - -foldRowsWithAccImpl :: - ( ToRow params, - MonadUnliftIO m, - MonadLogger m, - Otel.MonadTracer m - ) => - m (DebugLogDatabaseQueries, PrettyPrintDatabaseQueries) -> - Query -> - params -> - Decoder row -> - a -> - (a -> row -> Transaction m a) -> - Transaction m a -{-# INLINE foldRowsWithAccImpl #-} -foldRowsWithAccImpl zoomDbOptions qry params (Decoder rowParser) accumulator f = do - Otel.inSpan' "Postgres Query (foldRowsWithAcc)" Otel.defaultSpanArguments $ \span -> do - (logDatabaseQueries, prettyQuery) <- lift @Transaction zoomDbOptions - traceQueryIfEnabled span logDatabaseQueries prettyQuery qry (HasSingleParam params) - conn <- Transaction ask - withRunInIO - ( \runInIO -> - do - PG.foldWithOptionsAndParser - PG.defaultFoldOptions - rowParser - conn - qry - params - accumulator - (\acc row -> runInIO $ f acc row) - & handlePGException prettyQuery "fold" qry (Left params) - & runInIO - ) - -pgFormatQueryNoParams' :: - (MonadIO m, MonadLogger m) => - PrettyPrintDatabaseQueries -> - Query -> - Transaction m ByteString -pgFormatQueryNoParams' prettyQuery q = case prettyQuery of - DontPrettyPrintDatabaseQueries -> pure q.fromQuery - PrettyPrintDatabaseQueries pool -> lift $ pgFormatQueryByteString pool q.fromQuery - -pgFormatQuery :: - (ToRow params, MonadIO m) => - Query -> - params -> - Transaction m ByteString -pgFormatQuery qry params = Transaction $ do - conn <- ask - liftIO $ PG.formatQuery conn qry params - -pgFormatQueryMany :: - (MonadIO m, ToRow params) => - Query -> - NonEmpty params -> - Transaction m ByteString -pgFormatQueryMany qry params = Transaction $ do - conn <- ask - liftIO $ - PG.formatMany - conn - qry - ( params - -- upstream is partial on empty list, see https://github.com/haskellari/postgresql-simple/issues/129 - & toList - ) - -queryWithImpl :: - ( ToRow params, - MonadUnliftIO m, - MonadLogger m, - Otel.MonadTracer m - ) => - m (DebugLogDatabaseQueries, PrettyPrintDatabaseQueries) -> - Query -> - params -> - Decoder r -> - Transaction m [r] -{-# INLINE queryWithImpl #-} -queryWithImpl zoomDbOptions qry params (Decoder fromRow) = do - Otel.inSpan' "Postgres Query (queryWith)" Otel.defaultSpanArguments $ \span -> do - (logDatabaseQueries, prettyQuery) <- lift @Transaction zoomDbOptions - traceQueryIfEnabled span logDatabaseQueries prettyQuery qry (HasSingleParam params) - conn <- Transaction ask - PG.queryWith fromRow conn qry params - & handlePGException prettyQuery "query" qry (Left params) - -queryWithImpl_ :: - ( MonadUnliftIO m, - MonadLogger m - ) => - m PrettyPrintDatabaseQueries -> - Query -> - Decoder r -> - Transaction m [r] -{-# INLINE queryWithImpl_ #-} -queryWithImpl_ zoomDbOptions qry (Decoder fromRow) = do - prettyQuery <- lift @Transaction zoomDbOptions - conn <- Transaction ask - liftIO (PG.queryWith_ fromRow conn qry) - & handlePGException prettyQuery "query" qry (Left ()) - -data SingleRowError = SingleRowError - { -- | How many columns were actually returned by the query - numberOfRowsReturned :: Int - } - deriving stock (Show) - -instance Exception SingleRowError where - displayException (SingleRowError {..}) = [fmt|Single row expected from SQL query result, {numberOfRowsReturned} rows were returned instead."|] - -pgFormatQuery' :: - ( MonadIO m, - ToRow params, - MonadLogger m - ) => - PrettyPrintDatabaseQueries -> - Query -> - params -> - Transaction m ByteString -pgFormatQuery' prettyQuery q p = case prettyQuery of - DontPrettyPrintDatabaseQueries -> pgFormatQuery q p - PrettyPrintDatabaseQueries pool -> - pgFormatQuery q p - >>= lift . pgFormatQueryByteString pool - -pgFormatQueryMany' :: - ( MonadIO m, - ToRow params, - MonadLogger m - ) => - PrettyPrintDatabaseQueries -> - Query -> - NonEmpty params -> - Transaction m ByteString -pgFormatQueryMany' prettyQuery q p = case prettyQuery of - DontPrettyPrintDatabaseQueries -> pgFormatQueryMany q p - PrettyPrintDatabaseQueries pool -> - pgFormatQueryMany q p - >>= lift . pgFormatQueryByteString pool - --- | Read the executable name "pg_format" -postgresToolsParser :: ToolParserT IO (Label "pgFormat" Tool) -postgresToolsParser = label @"pgFormat" <$> readTool "pg_format" - -pgFormatQueryByteString :: - ( MonadIO m, - MonadLogger m - ) => - PgFormatPool -> - ByteString -> - m ByteString -pgFormatQueryByteString pool queryBytes = do - res <- - liftIO $ - runPgFormat - pool - (queryBytes) - case res.exitCode of - ExitSuccess -> pure (res.formatted) - ExitFailure status -> do - logWarn [fmt|pg_format failed with status {status} while formatting the query, using original query string. Is there a syntax error?|] - logDebug - ( prettyErrorTree - ( nestedMultiError - "pg_format output" - ( nestedError "stdout" (singleError (res.formatted & bytesToTextUtf8Lenient & newError)) - :| [(nestedError "stderr" (singleError (res.stderr & bytesToTextUtf8Lenient & newError)))] - ) - ) - ) - logDebug [fmt|pg_format stdout: stderr|] - pure (queryBytes) - -pgFormatStartCommandWaitForInput :: - ( MonadIO m, - HasField "pgFormat" tools Tool, - MonadFail m - ) => - tools -> - m PgFormatProcess -pgFormatStartCommandWaitForInput tools = do - do - startedAt <- Otel.getTimestamp - (Just stdinHdl, Just stdoutHdl, Just stderrHdl, procHdl) <- - Process.createProcess - ( ( Process.proc - tools.pgFormat.toolPath - [ "--no-rcfile", - "-" - ] - ) - { Process.std_in = Process.CreatePipe, - Process.std_out = Process.CreatePipe, - Process.std_err = Process.CreatePipe - } - ) - - pure PgFormatProcess {..} - -data DebugLogDatabaseQueries - = -- | Do not log the database queries - DontLogDatabaseQueries - | -- | Log the database queries as debug output; - LogDatabaseQueries - | -- | Log the database queries as debug output and additionally the EXPLAIN output (from the query analyzer, not the actual values after execution cause that’s a bit harder to do) - LogDatabaseQueriesAndExplain - deriving stock (Show, Enum, Bounded) - --- | Whether to pipe database queries thru `pg_format` before logging them. This takes a long (long! 200ms+) time per query, so should only be used in debugging environments where speed is not an issue. -data PrettyPrintDatabaseQueries - = -- | Do not pretty-print database querios - DontPrettyPrintDatabaseQueries - | -- | Pretty-print database queries, slow - PrettyPrintDatabaseQueries PgFormatPool - -instance Show PrettyPrintDatabaseQueries where - show DontPrettyPrintDatabaseQueries = "DontPrettyPrintDatabaseQueries" - show (PrettyPrintDatabaseQueries _) = "PrettyPrintDatabaseQueries" - -data HasQueryParams param - = HasNoParams - | HasSingleParam param - | HasMultiParams (NonEmpty param) - --- | Log the postgres query depending on the given setting -traceQueryIfEnabled :: - ( ToRow params, - MonadUnliftIO m, - MonadLogger m, - Otel.MonadTracer m - ) => - Otel.Span -> - DebugLogDatabaseQueries -> - PrettyPrintDatabaseQueries -> - Query -> - HasQueryParams params -> - Transaction m () -traceQueryIfEnabled span logDatabaseQueries prettyQuery qry params = do - -- In case we have query logging enabled, we want to do that - let formattedQuery = - withEvent - span - "Query Format start" - "Query Format end" - $ case params of - HasNoParams -> pgFormatQueryNoParams' prettyQuery qry - HasSingleParam p -> pgFormatQuery' prettyQuery qry p - HasMultiParams ps -> pgFormatQueryMany' prettyQuery qry ps - - let doLog errs = do - Otel.addAttribute span "_.postgres.query" (errs.query & bytesToTextUtf8Lenient & Otel.toAttribute) - for_ errs.explain $ \ex -> - Otel.addAttribute span "_.postgres.explain" (Otel.toAttribute @Text ex) - let doExplain = do - q <- formattedQuery - Otel.inSpan "Postgres EXPLAIN Query" Otel.defaultSpanArguments $ do - queryWithImpl_ - (pure prettyQuery) - ( "EXPLAIN " - <> ( - -- TODO: this is not nice, but the only way to get the `executeMany` form to work with this - -- because we need the query with all elements already interpolated. - Query q - ) - ) - (Dec.fromField @Text) - <&> Text.intercalate "\n" - case logDatabaseQueries of - DontLogDatabaseQueries -> pure () - LogDatabaseQueries -> do - q <- formattedQuery - doLog (T2 (label @"query" q) (label @"explain" Nothing)) - LogDatabaseQueriesAndExplain -> do - q <- formattedQuery - -- XXX: stuff like `CREATE SCHEMA` cannot be EXPLAINed, so we should catch exceptions here - -- and just ignore anything that errors (if it errors because of a problem with the query, it would have been caught by the query itself. - ex <- doExplain - doLog (T2 (label @"query" q) (label @"explain" (Just ex))) - --- | Add a start and end event to the span, and figure out how long the difference was. --- --- This is more lightweight than starting an extra span for timing things. -withEvent :: (MonadIO f) => Otel.Span -> Text -> Text -> f b -> f b -withEvent span start end act = do - let mkMs ts = (ts & Otel.timestampNanoseconds & toInteger) `div` 1000_000 - s <- Otel.getTimestamp - Otel.addEvent - span - ( Otel.NewEvent - { newEventName = start, - newEventAttributes = mempty, - newEventTimestamp = Just s - } - ) - res <- act - e <- Otel.getTimestamp - let tookMs = - (mkMs e - mkMs s) - -- should be small enough - & fromInteger @Int - Otel.addEvent - span - ( Otel.NewEvent - { newEventName = end, - newEventAttributes = HashMap.fromList [("took ms", Otel.toAttribute tookMs)], - newEventTimestamp = Just e - } - ) - pure res - -unzipPGArray :: - forall l1 t1 l2 t2 r. - ( HasField l1 r t1, - HasField l2 r t2 - ) => - [r] -> - (PGArray t1, PGArray t2) -{-# INLINEABLE unzipPGArray #-} -unzipPGArray xs = - ( PGArray $ getField @l1 <$> xs, - PGArray $ getField @l2 <$> xs - ) - -unzip3PGArray :: - forall l1 t1 l2 t2 l3 t3 r. - ( HasField l1 r t1, - HasField l2 r t2, - HasField l3 r t3 - ) => - [r] -> - (PGArray t1, PGArray t2, PGArray t3) -{-# INLINEABLE unzip3PGArray #-} -unzip3PGArray xs = - ( PGArray $ getField @l1 <$> xs, - PGArray $ getField @l2 <$> xs, - PGArray $ getField @l3 <$> xs - ) - -unzip4PGArray :: - forall l1 t1 l2 t2 l3 t3 l4 t4 r. - ( HasField l1 r t1, - HasField l2 r t2, - HasField l3 r t3, - HasField l4 r t4 - ) => - [r] -> - (PGArray t1, PGArray t2, PGArray t3, PGArray t4) -{-# INLINEABLE unzip4PGArray #-} -unzip4PGArray xs = - ( PGArray $ getField @l1 <$> xs, - PGArray $ getField @l2 <$> xs, - PGArray $ getField @l3 <$> xs, - PGArray $ getField @l4 <$> xs - ) - -unzip5PGArray :: - forall l1 t1 l2 t2 l3 t3 l4 t4 l5 t5 r. - ( HasField l1 r t1, - HasField l2 r t2, - HasField l3 r t3, - HasField l4 r t4, - HasField l5 r t5 - ) => - [r] -> - (PGArray t1, PGArray t2, PGArray t3, PGArray t4, PGArray t5) -{-# INLINEABLE unzip5PGArray #-} -unzip5PGArray xs = - ( PGArray $ getField @l1 <$> xs, - PGArray $ getField @l2 <$> xs, - PGArray $ getField @l3 <$> xs, - PGArray $ getField @l4 <$> xs, - PGArray $ getField @l5 <$> xs - ) - -instance (ToField t1) => ToRow (Label l1 t1) where - toRow t2 = toRow $ PG.Only $ getField @l1 t2 - -instance (ToField t1, ToField t2) => ToRow (T2 l1 t1 l2 t2) where - toRow t2 = toRow (getField @l1 t2, getField @l2 t2) - -instance (ToField t1, ToField t2, ToField t3) => ToRow (T3 l1 t1 l2 t2 l3 t3) where - toRow t3 = toRow (getField @l1 t3, getField @l2 t3, getField @l3 t3) diff --git a/users/Profpatsch/my-prelude/src/Pretty.hs b/users/Profpatsch/my-prelude/src/Pretty.hs deleted file mode 100644 index 3022e1368..000000000 --- a/users/Profpatsch/my-prelude/src/Pretty.hs +++ /dev/null @@ -1,134 +0,0 @@ -module Pretty - ( -- * Pretty printing for error messages - Err, - showPretty, - showPrettyJson, - showPrettyJsonColored, - showedStringPretty, - printPretty, - printShowedStringPretty, - -- constructors hidden - prettyErrs, - prettyErrsNoColor, - message, - messageString, - pretty, - prettyString, - hscolour', - ) -where - -import Data.Aeson qualified as Json -import Data.Aeson.Encode.Pretty qualified as Aeson.Pretty -import Data.List qualified as List -import Data.String (IsString (fromString)) -import Data.Text.Lazy.Builder qualified as Text.Builder -import Language.Haskell.HsColour - ( Output (TTYg), - hscolour, - ) -import Language.Haskell.HsColour.ANSI (TerminalType (..)) -import Language.Haskell.HsColour.Colourise - ( defaultColourPrefs, - ) -import PossehlAnalyticsPrelude -import System.Console.ANSI (setSGRCode) -import System.Console.ANSI.Types - ( Color (Red), - ColorIntensity (Dull), - ConsoleLayer (Foreground), - SGR (Reset, SetColor), - ) -import Text.Nicify (nicify) - --- | Print any 'Show'able type to stderr, formatted nicely and in color. Very helpful for debugging. -printPretty :: (Show a) => a -> IO () -printPretty a = - a & showPretty & putStderrLn - -showPretty :: (Show a) => a -> Text -showPretty a = a & pretty & (: []) & prettyErrs & stringToText - --- | Pretty-print a string that was produced by `show` to stderr, formatted nicely and in color. -printShowedStringPretty :: String -> IO () -printShowedStringPretty s = s & showedStringPretty & putStderrLn - --- | Pretty-print a string that was produced by `show` -showedStringPretty :: String -> Text -showedStringPretty s = s & ErrPrettyString & (: []) & prettyErrs & stringToText - -showPrettyJson :: Json.Value -> Text -showPrettyJson val = - val - & Aeson.Pretty.encodePrettyToTextBuilder - & Text.Builder.toLazyText - & toStrict - --- | Shows a pretty json string with some color (very inefficient!) -showPrettyJsonColored :: Json.Value -> Text -showPrettyJsonColored val = - val - & Aeson.Pretty.encodePrettyToTextBuilder - & Text.Builder.toLazyText - & toStrict - & textToString - & hscolour' - & stringToText - --- | Display a list of 'Err's as a colored error message -prettyErrs :: [Err] -> String -prettyErrs errs = res - where - res = List.intercalate "\n" $ map one errs - one = \case - ErrMsg s -> color Red s - ErrPrettyString s -> prettyShowString s - - -- \| Pretty print a String that was produced by 'show' - prettyShowString :: String -> String - prettyShowString = hscolour' . nicify - --- | Display a list of 'Err's as a plain-colored error message -prettyErrsNoColor :: [Err] -> String -prettyErrsNoColor errs = res - where - res = List.intercalate "\n" $ map one errs - one = \case - ErrMsg s -> s - ErrPrettyString s -> nicify s - --- | Small DSL for pretty-printing errors -data Err - = -- | Message to display in the error - ErrMsg String - | -- | Pretty print a String that was produced by 'show' - ErrPrettyString String - -instance IsString Err where - fromString s = ErrMsg s - --- | Plain message to display, as 'Text' -message :: Text -> Err -message = ErrMsg . textToString - --- | Plain message to display, as 'String' -messageString :: String -> Err -messageString = ErrMsg - --- | Any 'Show'able to pretty print -pretty :: (Show a) => a -> Err -pretty x = ErrPrettyString $ show x - --- | Pretty print a String that was produced by 'show' -prettyString :: String -> Err -prettyString s = ErrPrettyString s - --- Prettifying Helpers, mostly stolen from --- https://hackage.haskell.org/package/hspec-expectations-pretty-diff-0.7.2.5/docs/src/Test.Hspec.Expectations.Pretty.html#prettyColor - -hscolour' :: String -> String -hscolour' = - hscolour (TTYg Ansi16Colour) defaultColourPrefs False False "" False - -color :: Color -> String -> String -color c s = setSGRCode [SetColor Foreground Dull c] ++ s ++ setSGRCode [Reset] diff --git a/users/Profpatsch/my-prelude/src/RevList.hs b/users/Profpatsch/my-prelude/src/RevList.hs deleted file mode 100644 index a79e1668f..000000000 --- a/users/Profpatsch/my-prelude/src/RevList.hs +++ /dev/null @@ -1,33 +0,0 @@ -module RevList where - -import Data.Semigroup qualified as Semigroup -import PossehlAnalyticsPrelude - --- | A reversed list; `:` adds to the end of the list, and '(<>)' is reversed (i.e. @longList <> [oneElement]@ will be O(1) instead of O(n)) --- --- Invariant: the inner list is already reversed. -newtype RevList a = RevList [a] - deriving stock (Eq) - deriving (Semigroup, Monoid) via (Semigroup.Dual [a]) - -empty :: RevList a -{-# INLINE empty #-} -empty = RevList [] - -singleton :: a -> RevList a -{-# INLINE singleton #-} -singleton a = RevList [a] - --- | (@O(n)@) Turn the list into a reversed list (by reversing) -revList :: [a] -> RevList a -{-# INLINE revList #-} -revList xs = RevList $ reverse xs - --- | (@O(n)@) Turn the reversed list into a list (by reversing) -revListToList :: RevList a -> [a] -{-# INLINE revListToList #-} -revListToList (RevList rev) = reverse rev - -instance (Show a) => Show (RevList a) where - {-# INLINE show #-} - show (RevList rev) = rev & show diff --git a/users/Profpatsch/my-prelude/src/Seconds.hs b/users/Profpatsch/my-prelude/src/Seconds.hs deleted file mode 100644 index 8d05f30be..000000000 --- a/users/Profpatsch/my-prelude/src/Seconds.hs +++ /dev/null @@ -1,55 +0,0 @@ -module Seconds where - -import Data.Aeson (FromJSON) -import Data.Aeson qualified as Json -import Data.Aeson.Types (FromJSON (parseJSON)) -import Data.Scientific -import Data.Time (NominalDiffTime) -import FieldParser -import FieldParser qualified as Field -import GHC.Natural (naturalToInteger) -import PossehlAnalyticsPrelude - --- | A natural number of seconds. -newtype Seconds = Seconds {unSeconds :: Natural} - deriving stock (Eq, Show) - --- | Parse a decimal number as a number of seconds -textToSeconds :: FieldParser Text Seconds -textToSeconds = Seconds <$> Field.decimalNatural - -scientificToSeconds :: FieldParser Scientific Seconds -scientificToSeconds = - ( Field.boundedScientificIntegral @Int "Number of seconds" - >>> Field.integralToNatural - ) - & rmap Seconds - --- Microseconds, represented internally with a 64 bit Int -newtype MicrosecondsInt = MicrosecondsInt {unMicrosecondsInt :: Int} - deriving stock (Eq, Show) - --- | Try to fit a number of seconds into a MicrosecondsInt -secondsToMicrosecondsInt :: FieldParser Seconds MicrosecondsInt -secondsToMicrosecondsInt = - lmap - (\sec -> naturalToInteger sec.unSeconds * 1_000_000) - (Field.bounded "Could not fit into an Int after multiplying with 1_000_000 (seconds to microseconds)") - & rmap MicrosecondsInt - -secondsToNominalDiffTime :: Seconds -> NominalDiffTime -secondsToNominalDiffTime sec = - sec.unSeconds - & naturalToInteger - & fromInteger @NominalDiffTime - -instance FromJSON Seconds where - parseJSON = Field.toParseJSON jsonNumberToSeconds - --- | Parse a json number as a number of seconds. -jsonNumberToSeconds :: FieldParser' Error Json.Value Seconds -jsonNumberToSeconds = Field.jsonNumber >>> scientificToSeconds - --- | Return the number of seconds in a week -secondsInAWeek :: Seconds -secondsInAWeek = Seconds (3600 * 24 * 7) diff --git a/users/Profpatsch/my-prelude/src/Test.hs b/users/Profpatsch/my-prelude/src/Test.hs deleted file mode 100644 index 862ee16c2..000000000 --- a/users/Profpatsch/my-prelude/src/Test.hs +++ /dev/null @@ -1,115 +0,0 @@ -{-# LANGUAGE LambdaCase #-} - -{- Generate Test suites. - -Restricted version of hspec, introduction: http://hspec.github.io/getting-started.html --} -module Test - ( Spec, - runTest, - testMain, - - -- * Structure - describe, - it, - - -- * Expectations - Expectation, - testOk, - testErr, - shouldBe, - shouldNotBe, - shouldSatisfy, - shouldNotSatisfy, - - -- * Setup & Teardown (hooks http://hspec.github.io/writing-specs.html#using-hooks) - before, - before_, - beforeWith, - beforeAll, - beforeAll_, - beforeAllWith, - after, - after_, - afterAll, - afterAll_, - around, - around_, - aroundWith, - aroundAll, - aroundAllWith, - - -- * Common helpful predicates (use with 'shouldSatisfy') - isRight, - isLeft, - - -- * Pretty printing of errors - errColored, - module Pretty, - ) -where - --- export more expectations if needed - -import Data.Either - ( isLeft, - isRight, - ) -import Pretty -import Test.Hspec - ( Expectation, - HasCallStack, - Spec, - after, - afterAll, - afterAll_, - after_, - around, - aroundAll, - aroundAllWith, - aroundWith, - around_, - before, - beforeAll, - beforeAllWith, - beforeAll_, - beforeWith, - before_, - describe, - hspec, - it, - ) -import Test.Hspec.Expectations.Pretty - ( expectationFailure, - shouldBe, - shouldNotBe, - shouldNotSatisfy, - shouldSatisfy, - ) - --- | Run a test directly (e.g. from the repl) -runTest :: Spec -> IO () -runTest = hspec - --- | Run a testsuite -testMain :: - -- | Name of the test suite - String -> - -- | The tests in this test module - Spec -> - IO () -testMain testSuiteName tests = hspec $ describe testSuiteName tests - --- | test successful -testOk :: Expectation -testOk = pure () - --- | Abort the test with an error message. --- If you want to display a Haskell type, use `errColored`. -testErr :: HasCallStack => String -> Expectation -testErr = expectationFailure - --- | Display a list of 'Err's as a colored error message --- and abort the test. -errColored :: [Pretty.Err] -> Expectation -errColored = testErr . Pretty.prettyErrs diff --git a/users/Profpatsch/my-prelude/src/Tool.hs b/users/Profpatsch/my-prelude/src/Tool.hs deleted file mode 100644 index b773f4444..000000000 --- a/users/Profpatsch/my-prelude/src/Tool.hs +++ /dev/null @@ -1,75 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module Tool where - -import Data.Error.Tree -import Label -import PossehlAnalyticsPrelude -import System.Environment qualified as Env -import System.Exit qualified as Exit -import System.FilePath (()) -import System.Posix qualified as Posix -import ValidationParseT - -data Tool = Tool - { -- | absolute path to the executable - toolPath :: FilePath - } - deriving stock (Show) - --- | Reads all tools from the @toolsEnvVar@ variable or aborts. -readTools :: - Label "toolsEnvVar" Text -> - -- | Parser for Tools we bring with us at build time. - -- - -- These are executables that we need available, and that we have to ship with the distribution of @pa-cli@. - ToolParserT IO tools -> - IO tools -readTools env toolParser = - Env.lookupEnv (env.toolsEnvVar & textToString) >>= \case - Nothing -> do - Exit.die [fmt|Please set {env.toolsEnvVar} to a directory with all tools we need (see `Tools` in the code).|] - Just toolsDir -> - (Posix.fileExist toolsDir & ifTrueOrErr () [fmt|{env.toolsEnvVar} directory does not exist: {toolsDir}|]) - & thenValidateM - ( \() -> - (Posix.getFileStatus toolsDir <&> Posix.isDirectory) - & ifTrueOrErr () [fmt|{env.toolsEnvVar} does not point to a directory: {toolsDir}|] - ) - & thenValidateM - (\() -> toolParser.unToolParser toolsDir) - <&> first (errorTree [fmt|Could not find all tools in {env.toolsEnvVar}|]) - >>= \case - Failure err -> Exit.die (err & prettyErrorTree & textToString) - Success t -> pure t - -newtype ToolParserT m a = ToolParserT - { unToolParser :: - FilePath -> - m (Validation (NonEmpty Error) a) - } - deriving - (Functor, Applicative) - via (ValidationParseT FilePath m) - --- | Given a file path and the name of the tool executable, see whether it is an executable and return its full path. -readTool :: Text -> ToolParserT IO Tool -readTool exeName = ToolParserT $ \toolDir -> do - let toolPath :: FilePath = toolDir (exeName & textToString) - let read' = True - let write = False - let exec = True - Posix.fileExist toolPath - & ifTrueOrErr () [fmt|Tool does not exist: {toolPath}|] - & thenValidateM - ( \() -> - Posix.fileAccess toolPath read' write exec - & ifTrueOrErr (Tool {..}) [fmt|Tool is not readable/executable: {toolPath}|] - ) - --- | helper -ifTrueOrErr :: (Functor f) => a -> Text -> f Bool -> f (Validation (NonEmpty Error) a) -ifTrueOrErr true err io = - io <&> \case - True -> Success true - False -> Failure $ singleton $ newError err diff --git a/users/Profpatsch/my-prelude/src/ValidationParseT.hs b/users/Profpatsch/my-prelude/src/ValidationParseT.hs deleted file mode 100644 index 593b7ebf3..000000000 --- a/users/Profpatsch/my-prelude/src/ValidationParseT.hs +++ /dev/null @@ -1,16 +0,0 @@ -module ValidationParseT where - -import Control.Selective (Selective) -import Data.Functor.Compose (Compose (..)) -import PossehlAnalyticsPrelude - --- | A simple way to create an Applicative parser that parses from some environment. --- --- Use with DerivingVia. Grep codebase for examples. -newtype ValidationParseT env m a = ValidationParseT {unValidationParseT :: env -> m (Validation (NonEmpty Error) a)} - deriving - (Functor, Applicative, Selective) - via ( Compose - ((->) env) - (Compose m (Validation (NonEmpty Error))) - ) diff --git a/users/Profpatsch/my-tools/default.nix b/users/Profpatsch/my-tools/default.nix deleted file mode 100644 index 75a32a21d..000000000 --- a/users/Profpatsch/my-tools/default.nix +++ /dev/null @@ -1,48 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - exes = [ "copy" ]; - - drv = pkgs.haskellPackages.mkDerivation { - pname = "my-tools"; - version = "0.0.1-unreleased"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./my-tools.cabal - ./src/MyTools.hs - ./exe/Copy.hs - ]; - - isLibrary = false; - - libraryHaskellDepends = [ - depot.users.Profpatsch.my-prelude - pkgs.haskellPackages.optparse-simple - ]; - - # I copied this from `__generateOptparseApplicativeCompletion` because I can’t be bothered - # to figure out how the haskellPackages override callPackage bs really works. - postInstall = lib.concatMapStringsSep "\n" - (exeName: '' - bashCompDir="''${!outputBin}/share/bash-completion/completions" - zshCompDir="''${!outputBin}/share/zsh/vendor-completions" - fishCompDir="''${!outputBin}/share/fish/vendor_completions.d" - mkdir -p "$bashCompDir" "$zshCompDir" "$fishCompDir" - "''${!outputBin}/bin/${exeName}" --bash-completion-script "''${!outputBin}/bin/${exeName}" >"$bashCompDir/${exeName}" - "''${!outputBin}/bin/${exeName}" --zsh-completion-script "''${!outputBin}/bin/${exeName}" >"$zshCompDir/_${exeName}" - "''${!outputBin}/bin/${exeName}" --fish-completion-script "''${!outputBin}/bin/${exeName}" >"$fishCompDir/${exeName}.fish" - - # Sanity check - grep -F ${exeName} <$bashCompDir/${exeName} >/dev/null || { - echo 'Could not find ${exeName} in completion script.' - exit 1 - } - '') - exes; - - license = lib.licenses.mit; - - }; - -in -drv diff --git a/users/Profpatsch/my-tools/exe/Copy.hs b/users/Profpatsch/my-tools/exe/Copy.hs deleted file mode 100644 index 7a8dbbf1c..000000000 --- a/users/Profpatsch/my-tools/exe/Copy.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import MyTools - -main :: IO () -main = copyMain diff --git a/users/Profpatsch/my-tools/my-tools.cabal b/users/Profpatsch/my-tools/my-tools.cabal deleted file mode 100644 index e9c70988a..000000000 --- a/users/Profpatsch/my-tools/my-tools.cabal +++ /dev/null @@ -1,85 +0,0 @@ -cabal-version: 3.0 -name: my-tools -version: 0.0.1.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- Make #labels available - OverloadedLabels - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Allow the same record field name to be declared twice per module. - -- This works, because we use `OverloadedRecordDot` everywhere (enforced by `NoFieldSelectors`). - DuplicateRecordFields - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - -- allows defining pattern synonyms, but also the `import Foo (pattern FooPattern)` import syntax - PatternSynonyms - default-language: GHC2021 - - -library - import: common-options - hs-source-dirs: src - exposed-modules: - MyTools - - build-depends: - base >=4.15 && <5 - , my-prelude - , filepath - , directory - , process - , optparse-simple - , optparse-applicative - - -executable copy - import: common-options - hs-source-dirs: exe - build-depends: - base, - my-tools - main-is: Copy.hs diff --git a/users/Profpatsch/my-tools/src/MyTools.hs b/users/Profpatsch/my-tools/src/MyTools.hs deleted file mode 100644 index bb224ff05..000000000 --- a/users/Profpatsch/my-tools/src/MyTools.hs +++ /dev/null @@ -1,88 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module MyTools where - -import Control.Exception (IOException) -import Control.Exception.Base (try) -import Data.List qualified as List -import MyLabel -import MyPrelude -import Options.Applicative.Builder.Completer (requote) -import Options.Applicative.Simple (simpleOptions) -import Options.Applicative.Simple qualified as Opts -import Options.Applicative.Types qualified as Opts.Types -import System.Directory qualified as Dir -import System.Environment qualified -import System.FilePath.Posix (()) -import System.FilePath.Posix qualified as File -import System.Process qualified as Proc - -copyMain :: IO () -copyMain = do - ((), run) <- - simpleOptions - "latest" - "copy" - "Various ways of copying files" - (Opts.flag () () (Opts.long "some-flag")) - ( do - Opts.addCommand - "template" - "Use the given file as a template and create new file with the given name in the same directory" - copyAsTemplate - ( do - Opts.strArgument (Opts.metavar "FILE" <> Opts.completer completeFile) - -- TODO: this is a hack to be able to use the file in the next argument (it leads to the argument not being in the usage message) - & thenParser - ( \file -> do - name <- - Opts.strArgument - ( Opts.metavar "NAME" - <> Opts.completer - ( Opts.listCompleter - [ File.takeFileName file, - File.takeFileName file <> ".bak", - File.takeFileName file <> "_copy" - ] - ) - ) - pure (t2 #file file #name name) - ) - ) - ) - run - -completeFile :: Opts.Completer -completeFile = Opts.mkCompleter $ \word -> do - isFish <- System.Environment.getEnv "SHELL" <&> ("fish" `List.isInfixOf`) - - if isFish - then do - let cmd = - unwords - [ "complete", - "-C", - -- loool (via the impl of __fish_complete_path), probably extremely buggy - "\"'' " <> requote word <> "\"" - ] - Proc.readProcess "fish" ["--private", "--no-config", "-c", cmd] "" <&> lines & try @IOException <&> hush <&> fromMaybe [] - else do - let cmd = unwords ["compgen", "-A", "file", "--", requote word] - Proc.readProcess "bash" ["-c", cmd] "" <&> lines & try @IOException <&> hush <&> fromMaybe [] - -thenParser :: (a -> Opts.Parser b) -> Opts.Parser a -> Opts.Parser b -thenParser f a = Opts.Types.BindP a f - -assertMsg :: Bool -> Text -> IO () -assertMsg b msg = unless b $ exitWithMessage msg - -copyAsTemplate :: (HasField "file" r FilePath, HasField "name" r FilePath) => r -> IO () -copyAsTemplate opts = do - canon <- Dir.canonicalizePath opts.file - isFile <- Dir.doesFileExist canon - assertMsg isFile $ [fmt|File does not exist or is a directory: {canon}|] - let dir = File.takeDirectory canon - let finalPath = dir opts.name - targetExists <- Dir.doesFileExist finalPath - assertMsg (not targetExists) $ [fmt|Target file already exists: {finalPath}|] - Dir.copyFile canon finalPath diff --git a/users/Profpatsch/my-webstuff/default.nix b/users/Profpatsch/my-webstuff/default.nix deleted file mode 100644 index 0067235be..000000000 --- a/users/Profpatsch/my-webstuff/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ depot, pkgs, lib, ... }: - -pkgs.haskellPackages.mkDerivation { - pname = "my-webstuff"; - version = "0.0.1-unreleased"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./my-webstuff.cabal - ./src/Multipart2.hs - ]; - - isLibrary = true; - - libraryHaskellDepends = [ - depot.users.Profpatsch.my-prelude - pkgs.haskellPackages.dlist - pkgs.haskellPackages.monad-logger - pkgs.haskellPackages.pa-error-tree - pkgs.haskellPackages.pa-field-parser - pkgs.haskellPackages.pa-prelude - pkgs.haskellPackages.selective - pkgs.haskellPackages.wai-extra - ]; - - license = lib.licenses.mit; - -} diff --git a/users/Profpatsch/my-webstuff/my-webstuff.cabal b/users/Profpatsch/my-webstuff/my-webstuff.cabal deleted file mode 100644 index fb42d9f6a..000000000 --- a/users/Profpatsch/my-webstuff/my-webstuff.cabal +++ /dev/null @@ -1,72 +0,0 @@ -cabal-version: 3.0 -name: my-webstuff -version: 0.0.1.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - default-language: GHC2021 - - -library - import: common-options - hs-source-dirs: src - exposed-modules: - Multipart2 - - build-depends: - base >=4.15 && <5 - , my-prelude - , pa-prelude - , pa-label - , pa-error-tree - , pa-field-parser - , bytestring - , monad-logger - , dlist - , selective - , wai - , wai-extra diff --git a/users/Profpatsch/my-webstuff/src/Multipart2.hs b/users/Profpatsch/my-webstuff/src/Multipart2.hs deleted file mode 100644 index 90718bb78..000000000 --- a/users/Profpatsch/my-webstuff/src/Multipart2.hs +++ /dev/null @@ -1,237 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module Multipart2 where - -import Control.Monad.Logger (MonadLogger) -import Control.Selective (Selective) -import Data.ByteString.Lazy qualified as Lazy -import Data.DList (DList) -import Data.DList qualified as DList -import Data.Error.Tree -import Data.Functor.Compose -import Data.List qualified as List -import FieldParser -import Label -import Network.Wai qualified as Wai -import Network.Wai.Parse qualified as Wai -import PossehlAnalyticsPrelude -import ValidationParseT - -data FormFields = FormFields - { inputs :: [Wai.Param], - files :: [MultipartFile Lazy.ByteString] - } - --- | A parser for a HTTP multipart form (a form sent by the browser) -newtype MultipartParseT m a = MultipartParseT - { unMultipartParseT :: - FormFields -> - m (Validation (NonEmpty Error) a) - } - deriving - (Functor, Applicative, Selective) - via (ValidationParseT FormFields m) - --- | After parsing a form, either we get the result or a list of form fields that failed. --- --- Using this via Applicative you get either a valid result (@Just a@), or a list of validation errors. -newtype FormValidation a - = FormValidation - (DList FormValidationResult, Maybe a) - deriving (Functor, Applicative, Selective) via (Compose ((,) (DList FormValidationResult)) Maybe) - deriving stock (Show) - -data FormValidationResult = FormValidationResult - { hasError :: Maybe Error, - formFieldName :: ByteString, - originalValue :: ByteString - } - deriving stock (Show) - -mkFormValidationResult :: - ( HasField "formFieldName" form ByteString, - HasField "originalValue" form ByteString - ) => - form -> - Maybe Error -> - FormValidationResult -mkFormValidationResult form err = - FormValidationResult - { hasError = err, - formFieldName = form.formFieldName, - originalValue = form.originalValue - } - -eitherToFormValidation :: - ( HasField "formFieldName" form ByteString, - HasField "originalValue" form ByteString - ) => - form -> - Either Error a -> - FormValidation a -eitherToFormValidation form = \case - Left err -> - FormValidation $ (DList.singleton $ mkFormValidationResult form (Just err), Nothing) - Right a -> - FormValidation $ ((DList.singleton $ mkFormValidationResult form Nothing), Just a) - -failFormValidation :: - ( HasField "formFieldName" form ByteString, - HasField "originalValue" form ByteString - ) => - form -> - Error -> - FormValidation a -failFormValidation form err = - FormValidation (DList.singleton $ mkFormValidationResult form (Just err), Nothing) - --- | Parse the multipart form or throw a user error with a descriptive error message. -parseMultipartOrThrow :: - (MonadLogger m, MonadIO m) => - (ErrorTree -> m a) -> - MultipartParseT m a -> - Wai.Request -> - m a -parseMultipartOrThrow throwF parser req = do - -- TODO: this throws all errors with `error`, so leads to 500 on bad input … - formFields <- - liftIO $ - Wai.parseRequestBodyEx - Wai.defaultParseRequestBodyOptions - Wai.lbsBackEnd - req - parser.unMultipartParseT - FormFields - { inputs = fst formFields, - files = map fileDataToMultipartFile $ snd formFields - } - >>= \case - Failure errs -> throwF (errorTree "Cannot parse the multipart form" errs) - Success a -> pure a - --- | Parse the field out of the multipart message -field :: (Applicative m) => ByteString -> FieldParser ByteString a -> MultipartParseT m a -field fieldName fieldParser = MultipartParseT $ \mp -> - mp.inputs - & findMaybe (\input -> if fst input == fieldName then Just (snd input) else Nothing) - & annotate [fmt|Field "{fieldName}" does not exist in the multipart form|] - >>= runFieldParser fieldParser - & eitherToListValidation - & pure - --- | Parse the field out of the multipart message -fieldMay :: (Applicative m) => ByteString -> FieldParser ByteString a -> MultipartParseT m (Maybe a) -fieldMay fieldName fieldParser = MultipartParseT $ \mp -> - mp.inputs - & findMaybe (\input -> if fst input == fieldName then Just (snd input) else Nothing) - & \case - Nothing -> pure $ Success Nothing - Just b -> - b - & runFieldParser fieldParser - & eitherToListValidation - <&> Just - & pure - --- | Parse the field out of the multipart message --- TODO: what is this for?? -field' :: (Applicative m) => ByteString -> FieldParser ByteString a -> MultipartParseT m (FormValidation a) -field' fieldName fieldParser = MultipartParseT $ \mp -> - mp.inputs - & findMaybe (\input -> if fst input == fieldName then Just $ snd input else Nothing) - & annotate [fmt|Field "{fieldName}" does not exist in the multipart form|] - <&> ( \originalValue -> - originalValue - & runFieldParser fieldParser - & eitherToFormValidation - ( T2 - (label @"formFieldName" fieldName) - (label @"originalValue" originalValue) - ) - ) - & eitherToListValidation - & pure - --- | Parse the field out of the multipart message, and into a 'Label' of the given name. -fieldLabel :: forall lbl m a. (Applicative m) => ByteString -> FieldParser ByteString a -> MultipartParseT m (Label lbl a) -fieldLabel fieldName fieldParser = label @lbl <$> field fieldName fieldParser - --- | Parse the field out of the multipart message, and into a 'Label' of the given name. -fieldLabel' :: forall lbl m a. (Applicative m) => ByteString -> FieldParser ByteString a -> MultipartParseT m (FormValidation (Label lbl a)) -fieldLabel' fieldName fieldParser = fmap (label @lbl) <$> field' fieldName fieldParser - --- | parse all fields out of the multipart message, with the same parser -allFields :: (Applicative m) => FieldParser (T2 "key" ByteString "value" ByteString) b -> MultipartParseT m [b] -allFields fieldParser = MultipartParseT $ \mp -> - mp.inputs - <&> tupToT2 @"key" @"value" - & traverseValidate (runFieldParser fieldParser) - & eitherToValidation - & pure - -tupToT2 :: forall l1 l2 t1 t2. (t1, t2) -> T2 l1 t1 l2 t2 -tupToT2 (a, b) = T2 (label a) (label b) - --- | Parse a file by name out of the multipart message -file :: - (Applicative m) => - ByteString -> - MultipartParseT m (MultipartFile Lazy.ByteString) -file fieldName = MultipartParseT $ \mp -> - mp.files - & List.find (\input -> input.multipartNameAttribute == fieldName) - & annotate [fmt|File "{fieldName}" does not exist in the multipart form|] - & ( \case - Left err -> Failure (singleton err) - Right filePath -> Success filePath - ) - & pure - --- | Return all files from the multipart message -allFiles :: - (Applicative m) => - MultipartParseT m [MultipartFile Lazy.ByteString] -allFiles = MultipartParseT $ \mp -> do - pure $ Success $ mp.files - --- | Ensure there is exactly one file and return it (ignoring the field name) -exactlyOneFile :: - (Applicative m) => - MultipartParseT m (MultipartFile Lazy.ByteString) -exactlyOneFile = MultipartParseT $ \mp -> - mp.files - & \case - [] -> pure $ failParse "Expected to receive a file, but the multipart form did not contain any files" - [file_] -> pure $ Success file_ - more -> pure $ failParse [fmt|Expected to receive exactly one file, but the multipart form contained {List.length more} files|] - where - -- \| Fail to parse the multipart form with the given error message. - failParse :: Text -> Validation (NonEmpty Error) a - failParse = Failure . singleton . newError - -newtype GetFileContent backend m content = GetFileContent - {unGetFileContent :: (Wai.Request -> m (Either Error content))} - --- | A file field in a multipart message. -data MultipartFile content = MultipartFile - { -- | @name@ attribute of the corresponding HTML @\@ - multipartNameAttribute :: ByteString, - -- | name of the file on the client's disk - fileNameOnDisk :: ByteString, - -- | MIME type for the file - fileMimeType :: ByteString, - -- | Content of the file - content :: content - } - --- | Convert the multipart library struct of a multipart file to our own. -fileDataToMultipartFile :: - Wai.File Lazy.ByteString -> - (MultipartFile Lazy.ByteString) -fileDataToMultipartFile (multipartNameAttribute, file_) = do - MultipartFile - { multipartNameAttribute, - fileNameOnDisk = file_.fileName, - fileMimeType = file_.fileContentType, - content = file_.fileContent - } diff --git a/users/Profpatsch/my-xmonad/Xmonad.hs b/users/Profpatsch/my-xmonad/Xmonad.hs deleted file mode 100644 index bb727ac2f..000000000 --- a/users/Profpatsch/my-xmonad/Xmonad.hs +++ /dev/null @@ -1,127 +0,0 @@ -module Main where - -import Data.Function ((&)) -import XMonad -import XMonad qualified as Xmonad -import XMonad.Hooks.EwmhDesktops (ewmh) -import XMonad.Layout.Decoration -import XMonad.Layout.MultiToggle -import XMonad.Layout.MultiToggle.Instances (StdTransformers (..)) -import XMonad.Layout.Tabbed (TabbedDecoration) -import XMonad.Layout.Tabbed qualified as Tabbed -import XMonad.StackSet qualified as StackSet -import XMonad.Util.Cursor (setDefaultCursor) -import XMonad.Util.EZConfig (additionalKeys, additionalKeysP, removeKeysP) - -data Mode = Normal | Presentation - -main :: IO () -main = do - let config = ewmh myConfig - dirs <- Xmonad.getDirectories - Xmonad.launch config dirs - -myConfig :: - XConfig - ( MultiToggle - ( HCons - StdTransformers - XMonad.Layout.MultiToggle.EOT - ) - ( ModifiedLayout - ( Decoration - TabbedDecoration - DefaultShrinker - ) - Tall - ) - ) -myConfig = - conf - { modMask = modKey, - terminal = term Normal, - focusedBorderColor = "#859900", - layoutHook = layout, - startupHook = setDefaultCursor xC_heart, - workspaces = workspaceNames - } - `additionalKeysP` ( [ - -- fullscreen - ("M-e", sendMessage $ Toggle NBFULL), - -- i3-like keybindings, because I’m spoiled - ("M-S-x", kill), - -- exchange M-Ret and M-S-Ret - ("M-", spawn $ term Normal), - ("C-M-", spawn $ term Presentation), - ("M-S-", windows StackSet.swapMaster) - -- open simple exec dmenu - ] - ++ - -- something something workspaces - [ (otherModMasks ++ "M-" ++ [key], action tag) - | (tag, key) <- zip workspaceNames "123456789", - (otherModMasks, action) <- - [ ("", windows . StackSet.greedyView), - ("S-", windows . StackSet.shift) - ] - ] - ++ - -- mod-{w,e,r} %! Switch to physical/Xinerama screens 1, 2, or 3 - -- mod-shift-{w,e,r} %! Move client to screen 1, 2, or 3 - [ ("M-v", focusToScreen 0), - -- , ("M-l", focusToScreen 1) - ("M-c", focusToScreen 2), - ("M-S-v", windowToScreen 0), - ("M-S-l", windowToScreen 1), - ("M-S-c", windowToScreen 2) - ] - -- ((m .|. modMask, key), screenWorkspace sc >>= flip whenJust (windows . f)) - -- | (key, sc) <- zip [xK_w, xK_e, xK_r] [0..] - -- , (f, m) <- [(W.view, 0), (W.shift, shiftMask)]] - ) - `additionalKeys` - -- arrow keys should move as well (hjkl blindness) - [ ((modKey, xK_Up), windows StackSet.focusUp), - ((modKey, xK_Down), windows StackSet.focusDown) - ] - `removeKeysP` [ - -- previous kill command - "M-S-c", - -- It is way to easy to kill everything by default - "M-S-q", - -- no idea, I want to use it for Mozc - "M-n" - ] - where - conf = def - workspaceNames = conf & workspaces - modKey = mod4Mask - -- TODO: meh - term :: Mode -> String - -- TODO: get terminal-emulator from the system config (currently alacritty) - term Normal = "terminal-emulator" - term Presentation = "notify-send TODO: currently not terminal presentation mode implemented" -- "terminal- -u ~/.config/lilyterm/pres.conf" - toScreen with _number = screenWorkspace 0 >>= \ws -> whenJust ws (windows . with) - focusToScreen = toScreen StackSet.view - windowToScreen = toScreen StackSet.shift - --- copied from Xmonad.Config -layout :: - MultiToggle - (HCons StdTransformers EOT) - (ModifiedLayout (Decoration TabbedDecoration DefaultShrinker) Tall) - Window -layout = - tiled - & Tabbed.addTabsBottom Tabbed.shrinkText def - & toggleFullscreen - where - -- default tiling algorithm partitions the screen into two panes - tiled = Tall nmaster delta ratio - -- The default number of windows in the master pane - nmaster = 1 - -- Default proportion of screen occupied by master pane - ratio = 1 / 2 - -- Percent of screen to increment by when resizing panes - delta = 3 / 100 - toggleFullscreen = mkToggle1 NBFULL diff --git a/users/Profpatsch/my-xmonad/default.nix b/users/Profpatsch/my-xmonad/default.nix deleted file mode 100644 index 708d50e96..000000000 --- a/users/Profpatsch/my-xmonad/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - # bins = depot.nix.getBins pkgs.sqlite ["sqlite3"]; - - my-xmonad = pkgs.haskellPackages.mkDerivation { - pname = "my-xmonad"; - version = "0.1.0"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./my-xmonad.cabal - ./Xmonad.hs - ]; - - libraryHaskellDepends = [ - pkgs.haskellPackages.xmonad-contrib - ]; - - isExecutable = true; - isLibrary = false; - license = lib.licenses.mit; - }; - -in -my-xmonad diff --git a/users/Profpatsch/my-xmonad/my-xmonad.cabal b/users/Profpatsch/my-xmonad/my-xmonad.cabal deleted file mode 100644 index 175c6c163..000000000 --- a/users/Profpatsch/my-xmonad/my-xmonad.cabal +++ /dev/null @@ -1,62 +0,0 @@ -cabal-version: 3.0 -name: my-xmonad -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - default-language: GHC2021 - - -executable xmonad - import: common-options - - main-is: Xmonad.hs - - build-depends: - base >=4.15 && <5, - xmonad, - xmonad-contrib diff --git a/users/Profpatsch/napalm.nix b/users/Profpatsch/napalm.nix deleted file mode 100644 index 44c5885bd..000000000 --- a/users/Profpatsch/napalm.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ pkgs, ... }: -import - (builtins.fetchGit { - url = "https://github.com/nix-community/napalm"; - rev = "e1babff744cd278b56abe8478008b4a9e23036cf"; - }) -{ - inherit pkgs; -} diff --git a/users/Profpatsch/netencode/Netencode.hs b/users/Profpatsch/netencode/Netencode.hs deleted file mode 100644 index ca93ab2fe..000000000 --- a/users/Profpatsch/netencode/Netencode.hs +++ /dev/null @@ -1,433 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE TemplateHaskell #-} - -module Netencode where - -import Control.Applicative (many) -import Data.Attoparsec.ByteString qualified as Atto -import Data.Attoparsec.ByteString.Char8 qualified as Atto.Char -import Data.ByteString qualified as ByteString -import Data.ByteString.Builder (Builder) -import Data.ByteString.Builder qualified as Builder -import Data.ByteString.Lazy qualified as ByteString.Lazy -import Data.Fix (Fix (Fix)) -import Data.Fix qualified as Fix -import Data.Functor.Classes (Eq1 (liftEq)) -import Data.Int (Int16, Int32, Int64, Int8) -import Data.Map.NonEmpty (NEMap) -import Data.Map.NonEmpty qualified as NEMap -import Data.Semigroup qualified as Semi -import Data.String (IsString) -import Data.Word (Word16, Word32, Word64) -import GHC.Exts (fromString) -import Hedgehog qualified as Hedge -import Hedgehog.Gen qualified as Gen -import Hedgehog.Range qualified as Range -import PossehlAnalyticsPrelude -import Text.Show.Deriving -import Prelude hiding (sum) - --- | Netencode type base functor. --- --- Recursive elements have a @rec@. -data TF rec - = -- | Unit value - Unit - | -- | Boolean (2^1) - N1 Bool - | -- | Byte (2^3) - N3 Word8 - | -- | 64-bit Natural (2^6) - N6 Word64 - | -- | 64-bit Integer (2^6) - I6 Int64 - | -- | Unicode Text - Text Text - | -- | Arbitrary Bytestring - Bytes ByteString - | -- | A constructor of a(n open) Sum - Sum (Tag Text rec) - | -- | Record - Record (NEMap Text rec) - | -- | List - List [rec] - deriving stock (Show, Eq, Functor) - -instance Eq1 TF where - liftEq _ Unit Unit = True - liftEq _ (N1 b) (N1 b') = b == b' - liftEq _ (N3 w8) (N3 w8') = w8 == w8' - liftEq _ (N6 w64) (N6 w64') = w64 == w64' - liftEq _ (I6 i64) (I6 i64') = i64 == i64' - liftEq _ (Text t) (Text t') = t == t' - liftEq _ (Bytes b) (Bytes b') = b == b' - liftEq eq (Sum t) (Sum t') = eq (t.tagVal) (t'.tagVal) - liftEq eq (Record m) (Record m') = liftEq eq m m' - liftEq eq (List xs) (List xs') = liftEq eq xs xs' - liftEq _ _ _ = False - --- | A tagged value -data Tag tag val = Tag - { tagTag :: tag, - tagVal :: val - } - deriving stock (Show, Eq, Functor) - -$(Text.Show.Deriving.deriveShow1 ''Tag) -$(Text.Show.Deriving.deriveShow1 ''TF) - --- | The Netencode type -newtype T = T {unT :: Fix TF} - deriving stock (Eq, Show) - --- | Create a unit -unit :: T -unit = T $ Fix Unit - --- | Create a boolean -n1 :: Bool -> T -n1 = T . Fix . N1 - --- | Create a byte -n3 :: Word8 -> T -n3 = T . Fix . N3 - --- | Create a 64-bit natural -n6 :: Word64 -> T -n6 = T . Fix . N6 - --- | Create a 64-bit integer -i6 :: Int64 -> T -i6 = T . Fix . I6 - --- | Create a UTF-8 unicode text -text :: Text -> T -text = T . Fix . Text - --- | Create an arbitrary bytestring -bytes :: ByteString -> T -bytes = T . Fix . Bytes - --- | Create a tagged value from a tag name and a value -tag :: Text -> T -> T -tag key val = T $ Fix $ Sum $ coerce @(Tag Text T) @(Tag Text (Fix TF)) $ Tag key val - --- | Create a record from a non-empty map -record :: NEMap Text T -> T -record = T . Fix . Record . coerce @(NEMap Text T) @(NEMap Text (Fix TF)) - --- | Create a list -list :: [T] -> T -list = T . Fix . List . coerce @[T] @([Fix TF]) - --- | Stable encoding of a netencode value. Record keys will be sorted lexicographically ascending. -netencodeEncodeStable :: T -> Builder -netencodeEncodeStable (T fix) = Fix.foldFix (netencodeEncodeStableF id) fix - --- | Stable encoding of a netencode functor value. Record keys will be sorted lexicographically ascending. --- --- The given function is used for encoding the recursive values. -netencodeEncodeStableF :: (rec -> Builder) -> TF rec -> Builder -netencodeEncodeStableF inner tf = builder go - where - -- TODO: directly pass in BL? - innerBL = fromBuilder . inner - go = case tf of - Unit -> "u," - N1 False -> "n1:0," - N1 True -> "n1:1," - N3 w8 -> "n3:" <> fromBuilder (Builder.word8Dec w8) <> "," - N6 w64 -> "n6:" <> fromBuilder (Builder.word64Dec w64) <> "," - I6 i64 -> "i6:" <> fromBuilder (Builder.int64Dec i64) <> "," - Text t -> - let b = fromText t - in "t" <> builderLenDec b <> ":" <> b <> "," - Bytes b -> "b" <> builderLenDec (fromByteString b) <> ":" <> fromByteString b <> "," - Sum (Tag key val) -> encTag key val - Record m -> - -- NEMap uses Map internally, and that folds in lexicographic ascending order over the key. - -- Since these are `Text` in our case, this is stable. - let mBuilder = m & NEMap.foldMapWithKey encTag - in "{" <> builderLenDec mBuilder <> ":" <> mBuilder <> "}" - List xs -> - let xsBuilder = xs <&> innerBL & mconcat - in "[" <> builderLenDec xsBuilder <> ":" <> xsBuilder <> "]" - where - encTag key val = - let bKey = fromText key - in "<" <> builderLenDec bKey <> ":" <> bKey <> "|" <> innerBL val - --- | A builder that knows its own size in bytes -newtype BL = BL (Builder, Semi.Sum Natural) - deriving newtype (Monoid, Semigroup) - -instance IsString BL where - fromString s = - BL - ( fromString @Builder s, - fromString @ByteString s - & ByteString.length - & intToNatural - & fromMaybe 0 - & Semi.Sum - ) - --- | Retrieve the builder -builder :: BL -> Builder -builder (BL (b, _)) = b - --- | Retrieve the bytestring length -builderLen :: BL -> Natural -builderLen (BL (_, len)) = Semi.getSum $ len - --- | Take a 'BL' and create a new 'BL' that represents the length as a decimal integer -builderLenDec :: BL -> BL -builderLenDec (BL (_, len)) = - let b = Builder.intDec $ (len & Semi.getSum & fromIntegral @Natural @Int) - in b & fromBuilder - --- | Create a 'BL' from a 'Builder'. --- --- Not efficient, goes back to a lazy bytestring to get the length -fromBuilder :: Builder -> BL -fromBuilder b = - BL - ( b, - b - & Builder.toLazyByteString - & ByteString.Lazy.length - & fromIntegral @Int64 @Natural - & Semi.Sum - ) - --- | Create a 'BL' from a 'ByteString'. -fromByteString :: ByteString -> BL -fromByteString b = - BL - ( Builder.byteString b, - b - & ByteString.length - & fromIntegral @Int @Natural - & Semi.Sum - ) - --- | Create a 'BL' from a 'Text'. -fromText :: Text -> BL -fromText t = t & textToBytesUtf8 & fromByteString - --- | Parser for a netencode value. -netencodeParser :: Atto.Parser T -netencodeParser = T <$> go - where - go = Fix <$> netencodeParserF go - --- | Parser for one level of a netencode value. Requires a parser for the recursion. -netencodeParserF :: Atto.Parser rec -> Atto.Parser (TF rec) -netencodeParserF inner = do - typeTag <- Atto.Char.anyChar - case typeTag of - 't' -> Text <$> textParser - 'b' -> Bytes <$> bytesParser - 'u' -> unitParser - '<' -> Sum <$> tagParser - '{' -> Record <$> recordParser - '[' -> List <$> listParser - 'n' -> naturalParser - 'i' -> I6 <$> intParser - c -> fail ([c] <> " is not a valid netencode tag") - where - bytesParser = do - len <- boundedDecimalFail Atto. "bytes is missing a digit specifying the length" - _ <- Atto.Char.char ':' Atto. "bytes did not have : after length" - bytes' <- Atto.take len - _ <- Atto.Char.char ',' Atto. "bytes did not end with ," - pure bytes' - - textParser = do - len <- boundedDecimalFail Atto. "text is missing a digit specifying the length" - _ <- Atto.Char.char ':' Atto. "text did not have : after length" - text' <- - Atto.take len <&> bytesToTextUtf8 >>= \case - Left err -> fail [fmt|cannot decode text as utf8: {err & prettyError}|] - Right t -> pure t - _ <- Atto.Char.char ',' Atto. "text did not end with ," - pure text' - - unitParser = do - _ <- Atto.Char.char ',' Atto. "unit did not end with ," - pure $ Unit - - tagParser = do - len <- boundedDecimalFail Atto. "tag is missing a digit specifying the length" - _ <- Atto.Char.char ':' Atto. "tag did not have : after length" - tagTag <- - Atto.take len <&> bytesToTextUtf8 >>= \case - Left err -> fail [fmt|cannot decode tag key as utf8: {err & prettyError}|] - Right t -> pure t - _ <- Atto.Char.char '|' Atto. "tag was missing the key/value separator (|)" - tagVal <- inner - pure $ Tag {..} - - recordParser = do - -- TODO: the record does not use its inner length because we are descending into the inner parsers. - -- This is a smell! In theory it can be used to skip parsing the whole inner keys. - _len <- boundedDecimalFail Atto. "record is missing a digit specifying the length" - _ <- Atto.Char.char ':' Atto. "record did not have : after length" - record' <- - many (Atto.Char.char '<' >> tagParser) <&> nonEmpty >>= \case - Nothing -> fail "record is not allowed to have 0 elements" - Just tags -> - pure $ - tags - <&> (\t -> (t.tagTag, t.tagVal)) - -- later keys are preferred if they are duplicates, according to the standard - & NEMap.fromList - _ <- Atto.Char.char '}' Atto. "record did not end with }" - pure record' - - listParser = do - -- TODO: the list does not use its inner length because we are descending into the inner parsers. - -- This is a smell! In theory it can be used to skip parsing the whole inner keys. - _len <- boundedDecimalFail Atto. "list is missing a digit specifying the length" - _ <- Atto.Char.char ':' Atto. "list did not have : after length" - -- TODO: allow empty lists? - list' <- many inner - _ <- Atto.Char.char ']' Atto. "list did not end with ]" - pure list' - - intParser = do - let p :: forall parseSize. (Bounded parseSize, Integral parseSize) => (Integer -> Atto.Parser Int64) - p n = do - _ <- Atto.Char.char ':' Atto. [fmt|i{n & show} did not have : after length|] - isNegative <- Atto.option False (Atto.Char.char '-' <&> \_c -> True) - int <- - boundedDecimal @parseSize >>= \case - Nothing -> fail [fmt|cannot parse into i{n & show}, the number is too big (would overflow)|] - Just i -> - pure $ - if isNegative - then -- TODO: this should alread be done in the decimal parser, @minBound@ cannot be parsed cause it’s one more than @(-maxBound)@! - (-i) - else i - _ <- Atto.Char.char ',' Atto. [fmt|i{n & show} did not end with ,|] - pure $ fromIntegral @parseSize @Int64 int - digit <- Atto.Char.digit - case digit of - -- TODO: separate parser for i1 and i2 that makes sure the boundaries are right! - '1' -> p @Int8 1 - '2' -> p @Int8 2 - '3' -> p @Int8 3 - '4' -> p @Int16 4 - '5' -> p @Int32 5 - '6' -> p @Int64 6 - '7' -> fail [fmt|i parser only supports numbers up to size 6, was 7|] - '8' -> fail [fmt|i parser only supports numbers up to size 6, was 8|] - '9' -> fail [fmt|i parser only supports numbers up to size 6, was 9|] - o -> fail [fmt|i number with length {o & show} not possible|] - - naturalParser = do - let p :: forall parseSize finalSize. (Bounded parseSize, Integral parseSize, Num finalSize) => (Integer -> Atto.Parser finalSize) - p n = do - _ <- Atto.Char.char ':' Atto. [fmt|n{n & show} did not have : after length|] - int <- - boundedDecimal @parseSize >>= \case - Nothing -> fail [fmt|cannot parse into n{n & show}, the number is too big (would overflow)|] - Just i -> pure i - - _ <- Atto.Char.char ',' Atto. [fmt|n{n & show} did not end with ,|] - pure $ fromIntegral @parseSize @finalSize int - let b n = do - _ <- Atto.Char.char ':' Atto. [fmt|n{n & show} did not have : after length|] - bool <- - (Atto.Char.char '0' >> pure False) - <|> (Atto.Char.char '1' >> pure True) - _ <- Atto.Char.char ',' Atto. [fmt|n{n & show} did not end with ,|] - pure bool - - digit <- Atto.Char.digit - case digit of - -- TODO: separate parser for n1 and n2 that makes sure the boundaries are right! - '1' -> N1 <$> b 1 - '2' -> N3 <$> p @Word8 @Word8 2 - '3' -> N3 <$> p @Word8 @Word8 3 - '4' -> N6 <$> p @Word16 @Word64 4 - '5' -> N6 <$> p @Word32 @Word64 5 - '6' -> N6 <$> p @Word64 @Word64 6 - '7' -> fail [fmt|n parser only supports numbers up to size 6, was 7|] - '8' -> fail [fmt|n parser only supports numbers up to size 6, was 8|] - '9' -> fail [fmt|n parser only supports numbers up to size 6, was 9|] - o -> fail [fmt|n number with length {o & show} not possible|] - --- | Parser for a bounded decimal that does not overflow the decimal. --- --- via https://www.extrema.is/blog/2021/10/20/parsing-bounded-integers -boundedDecimal :: forall a. (Bounded a, Integral a) => Atto.Parser (Maybe a) -boundedDecimal = do - i :: Integer <- decimal - pure $ - if (i :: Integer) > fromIntegral (maxBound :: a) - then Nothing - else Just $ fromIntegral i - where - -- Copied from @Attoparsec.Text@ and adjusted to bytestring - decimal :: (Integral a2) => Atto.Parser a2 - decimal = ByteString.foldl' step 0 <$> Atto.Char.takeWhile1 Atto.Char.isDigit - where - step a c = a * 10 + fromIntegral (c - 48) -{-# SPECIALIZE boundedDecimal :: Atto.Parser (Maybe Int) #-} -{-# SPECIALIZE boundedDecimal :: Atto.Parser (Maybe Int64) #-} -{-# SPECIALIZE boundedDecimal :: Atto.Parser (Maybe Word8) #-} -{-# SPECIALIZE boundedDecimal :: Atto.Parser (Maybe Word64) #-} - --- | 'boundedDecimal', but fail the parser if the decimal overflows. -boundedDecimalFail :: Atto.Parser Int -boundedDecimalFail = - boundedDecimal >>= \case - Nothing -> fail "decimal out of range" - Just a -> pure a - --- | Hedgehog generator for a netencode value. -genNetencode :: Hedge.MonadGen m => m T -genNetencode = - Gen.recursive - Gen.choice - [ -- these are bundled into one Gen, so that scalar elements get chosen less frequently, and the generator produces nicely nested examples - Gen.frequency - [ (1, pure unit), - (1, n1 <$> Gen.bool), - (1, n3 <$> Gen.element [0, 1, 5]), - (1, n6 <$> Gen.element [0, 1, 5]), - (1, i6 <$> Gen.element [-1, 1, 5]), - (2, text <$> Gen.text (Range.linear 1 10) Gen.lower), - (2, bytes <$> Gen.bytes (Range.linear 1 10)) - ] - ] - [ do - key <- Gen.text (Range.linear 3 10) Gen.lower - val <- genNetencode - pure $ tag key val, - record - <$> ( let k = Gen.text (Range.linear 3 10) Gen.lower - v = genNetencode - in NEMap.insertMap - <$> k - <*> v - <*> ( (Gen.map (Range.linear 0 3)) $ - (,) <$> k <*> v - ) - ) - ] - --- | Hedgehog property: encoding a netencode value and parsing it again returns the same result. -prop_netencodeRoundtrip :: Hedge.Property -prop_netencodeRoundtrip = Hedge.property $ do - enc <- Hedge.forAll genNetencode - ( Atto.parseOnly - netencodeParser - ( netencodeEncodeStable enc - & Builder.toLazyByteString - & toStrictBytes - ) - ) - Hedge.=== (Right enc) diff --git a/users/Profpatsch/netencode/Netencode/Parse.hs b/users/Profpatsch/netencode/Netencode/Parse.hs deleted file mode 100644 index 184fb5f91..000000000 --- a/users/Profpatsch/netencode/Netencode/Parse.hs +++ /dev/null @@ -1,102 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module Netencode.Parse where - -import Control.Category qualified -import Control.Selective (Selective) -import Data.Error.Tree -import Data.Fix (Fix (..)) -import Data.Functor.Compose -import Data.List qualified as List -import Data.Map.NonEmpty (NEMap) -import Data.Map.NonEmpty qualified as NEMap -import Data.Semigroupoid qualified as Semigroupiod -import Data.Semigroupoid qualified as Semigroupoid -import Data.Text qualified as Text -import Netencode qualified -import PossehlAnalyticsPrelude -import Prelude hiding (log) - -newtype Parse from to - = -- TODO: the way @Context = [Text]@ has to be forwarded to everything is kinda shitty. - -- This is essentially just a difference list, and can probably be treated as a function in the output? - Parse (([Text], from) -> Validation (NonEmpty ErrorTree) ([Text], to)) - deriving - (Functor, Applicative, Selective) - via ( Compose - ( Compose - ((->) ([Text], from)) - (Validation (NonEmpty ErrorTree)) - ) - ((,) [Text]) - ) - -instance Semigroupoid Parse where - o p2 p1 = Parse $ \from -> case runParse' p1 from of - Failure err -> Failure err - Success to1 -> runParse' p2 to1 - -instance Category Parse where - (.) = Semigroupoid.o - id = Parse $ \t -> Success t - -runParse :: Error -> Parse from to -> from -> Either ErrorTree to -runParse errMsg parser t = - (["$"], t) - & runParse' parser - <&> snd - & first (nestedMultiError errMsg) - & validationToEither - -runParse' :: Parse from to -> ([Text], from) -> Validation (NonEmpty ErrorTree) ([Text], to) -runParse' (Parse f) from = f from - -parseEither :: (([Text], from) -> Either ErrorTree ([Text], to)) -> Parse from to -parseEither f = Parse $ \from -> f from & eitherToListValidation - -tAs :: (Netencode.TF (Fix Netencode.TF) -> Either ([Text] -> ErrorTree) to) -> Parse Netencode.T to -tAs f = parseEither ((\(context, Netencode.T (Fix tf)) -> f tf & bimap ($ context) (context,))) - -key :: Text -> Parse (NEMap Text to) to -key name = parseEither $ \(context, rec) -> - rec - & NEMap.lookup name - & annotate (errorTreeContext (showContext context) [fmt|Key "{name}" does not exist|]) - <&> (addContext name context,) - -showContext :: [Text] -> Text -showContext context = context & List.reverse & Text.intercalate "." - -addContext :: a -> [a] -> [a] -addContext = (:) - -asText :: Parse Netencode.T Text -asText = tAs $ \case - Netencode.Text t -> pure t - other -> typeError "of text" other - -asBytes :: Parse Netencode.T ByteString -asBytes = tAs $ \case - Netencode.Bytes b -> pure b - other -> typeError "of bytes" other - -asRecord :: Parse Netencode.T (NEMap Text (Netencode.T)) -asRecord = tAs $ \case - Netencode.Record rec -> pure (rec <&> Netencode.T) - other -> typeError "a record" other - -typeError :: Text -> Netencode.TF ignored -> (Either ([Text] -> ErrorTree) b) -typeError should is = do - let otherS = is <&> (\_ -> ("…" :: String)) & show - Left $ \context -> errorTreeContext (showContext context) [fmt|Value is not {should}, but a {otherS}|] - -orThrowParseError :: - Parse (Either Error to) to -orThrowParseError = Parse $ \case - (context, Left err) -> - err - & singleError - & errorTreeContext (showContext context) - & singleton - & Failure - (context, Right to) -> Success (context, to) diff --git a/users/Profpatsch/netencode/README.md b/users/Profpatsch/netencode/README.md deleted file mode 100644 index 3538a110a..000000000 --- a/users/Profpatsch/netencode/README.md +++ /dev/null @@ -1,133 +0,0 @@ -# netencode 0.1-unreleased - -[bencode][] and [netstring][]-inspired pipe format that should be trivial to generate correctly in every context (only requires a `byte_length()` and a `printf()`), easy to parse (100 lines of code or less), mostly human-decipherable for easy debugging, and support nested record and sum types. - - -## scalars - -Scalars have the format `[type prefix][size]:[value],`. - -where size is a natural number without leading zeroes. - -### unit - -The unit (`u`) has only one value. - -* The unit is: `u,` - -### numbers - -Naturals (`n`) and Integers (`i`), with a maximum size in bits. - -Bit sizes are specified in 2^n increments, 1 to 9 (`n1`..`n9`, `i1`..`n9`). - -* Natural `1234` that fits in 32 bits (2^5): `n5:1234,` -* Integer `-42` that fits in 8 bits (2^3): `i3:-42,` -* Integer `23` that fits in 64 bits (2^6): `i6:23,` -* Integer `-1` that fits in 512 bits (2^9): `i9:-1,` -* Natural `0` that fits in 1 bit (2^1): `n1:0,` - -An implementation can define the biggest numbers it supports, and has to throw an error for anything bigger. It has to support everything smaller, so for example if you support up to i6/n6, you have to support 1–6 as well. An implementation could support up to the current architecture’s wordsize for example. - -Floats are not supported, you can implement fixed-size decimals or ratios using integers. - -### booleans - -A boolean is represented as `n1`. - -* `n1:0,`: false -* `n1:1,`: true - -TODO: should we add `f,` and `t,`? - -### text - -Text (`t`) that *must* be encoded as UTF-8, starting with its length in bytes: - -* The string `hello world` (11 bytes): `t11:hello world,` -* The string `今日は` (9 bytes): `t9:今日は,` -* The string `:,` (2 bytes): `t2::,,` -* The empty sting `` (0 bytes): `t0:,` - -### binary - -Arbitrary binary strings (`b`) that can contain any data, starting with its length in bytes. - -* The ASCII string `hello world` as binary data (11 bytes): `b11:hello world,` -* The empty binary string (0 bytes): `b0:,` -* The bytestring with `^D` (1 byte): `b1:,` - -Since the binary strings are length-prefixd, they can contain `\0` and no escaping is required. Care has to be taken in languages with `\0`-terminated bytestrings. - -Use text (`t`) if you have utf-8 encoded data. - -## tagged values - -### tags - -A tag (`<`) gives a value a name. The tag is UTF-8 encoded, starting with its length in bytes and proceeding with the value. - -* The tag `foo` (3 bytes) tagging the text `hello` (5 bytes): `<3:foo|t5:hello,` -* The tag `` (0 bytes) tagging the 8-bit integer 0: `<0:|i3:0,` - -### records (products/records), also maps - -A record (`{`) is a concatenation of tags (`<`). It needs to be closed with `}`. - -If tag names repeat the *earlier* ones should be ignored. -Using the last tag corresponds with the way most languages handle converting a list of tuples to Maps, by using a for-loop and Map.insert without checking the contents first. Otherwise you’d have to revert the list first or remember which keys you already inserted. - -Ordering of tags in a record does not matter. - -Similar to text, records start with the length of their *whole encoded content*, in bytes. This makes it possible to treat their contents as opaque bytestrings. - -* There is no empty record. (TODO: make the empty record the unit type, remove `u,`?) -* A record with one empty field, `foo`: `{9:<3:foo|u,}` -* A record with two fields, `foo` and `x`: `{21:<3:foo|u,<1:x|t3:baz,}` -* The same record: `{21:<1:x|t3:baz,<3:foo|u,}` -* The same record (earlier occurences of fields are ignored): `{<1:x|u,28:<1:x|t3:baz,<3:foo|u,}` - -### sums (tagged unions) - -Simply a tagged value. The tag marker `<` indicates it is a sum if it appears outside of a record. - -## lists - -A list (`[`) imposes an ordering on a sequence of values. It needs to be closed with `]`. Values in it are simply concatenated. - -Similar to records, lists start with the length of their whole encoded content. - -* The empty list: `[0:]` -* The list with one element, the string `foo`: `[7:t3:foo,]` -* The list with text `foo` followed by i3 `-42`: `[14:t3:foo,i3:-42,]` -* The list with `Some` and `None` tags: `[33:<4:Some|t3:foo,<4None|u,<4None|u,]` - -## parser security considerations - -The length field is a decimal number that is not length-restricted, -meaning an attacker could give an infinitely long length (or extremely long) -thus overflowing your parser if you are not careful. - -You should thus put a practical length limit to the length of length fields, -which implicitely enforces a length limit on how long the value itself can be. - -Start by defining a max value length in bytes. -Then count the number of decimals in that number. - -So if your max length is 1024 bytes, your length field can be a maximum `count_digits(1024) == 4` bytes long. - -Thus, if you restrict your parser to a length field of 4 bytes, -it should also never parse anything longer than 1024 bytes for the value -(plus 1 byte for the type tag, 4 bytes for the length, and 2 bytes for the separator & ending character). - -## motivation - -TODO - -## guarantees - -TODO: do I want unique representation (bijection like bencode?) This would put more restrictions on the generator, like sorting records in lexicographic order, but would make it possible to compare without decoding - - -[bencode]: https://en.wikipedia.org/wiki/Bencode -[netstring]: https://en.wikipedia.org/wiki/Netstring diff --git a/users/Profpatsch/netencode/default.nix b/users/Profpatsch/netencode/default.nix deleted file mode 100644 index 6e7dce489..000000000 --- a/users/Profpatsch/netencode/default.nix +++ /dev/null @@ -1,184 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - netencode-rs = depot.nix.writers.rustSimpleLib - { - name = "netencode"; - dependencies = [ - depot.third_party.rust-crates.nom - depot.users.Profpatsch.execline.exec-helpers - ]; - } - (builtins.readFile ./netencode.rs); - - netencode-hs = pkgs.haskellPackages.mkDerivation { - pname = "netencode"; - version = "0.1.0"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./netencode.cabal - ./Netencode.hs - ./Netencode/Parse.hs - ]; - - libraryHaskellDepends = [ - pkgs.haskellPackages.hedgehog - pkgs.haskellPackages.nonempty-containers - pkgs.haskellPackages.deriving-compat - pkgs.haskellPackages.data-fix - pkgs.haskellPackages.bytestring - pkgs.haskellPackages.attoparsec - pkgs.haskellPackages.pa-prelude - pkgs.haskellPackages.pa-label - pkgs.haskellPackages.pa-error-tree - ]; - - isLibrary = true; - license = lib.licenses.mit; - - - }; - - gen = import ./gen.nix { inherit lib; }; - - pretty-rs = depot.nix.writers.rustSimpleLib - { - name = "netencode-pretty"; - dependencies = [ - netencode-rs - ]; - } - (builtins.readFile ./pretty.rs); - - pretty = depot.nix.writers.rustSimple - { - name = "netencode-pretty"; - dependencies = [ - netencode-rs - pretty-rs - depot.users.Profpatsch.execline.exec-helpers - ]; - } '' - extern crate netencode; - extern crate netencode_pretty; - extern crate exec_helpers; - - fn main() { - let (_, prog) = exec_helpers::args_for_exec("netencode-pretty", 0); - let t = netencode::t_from_stdin_or_die_user_error("netencode-pretty"); - match netencode_pretty::Pretty::from_u(t.to_u()).print_multiline(&mut std::io::stdout()) { - Ok(()) => {}, - Err(err) => exec_helpers::die_temporary("netencode-pretty", format!("could not write to stdout: {}", err)) - } - } - ''; - - netencode-mustache = depot.nix.writers.rustSimple - { - name = "netencode_mustache"; - dependencies = [ - depot.users.Profpatsch.arglib.netencode.rust - netencode-rs - depot.third_party.rust-crates.mustache - ]; - } - (builtins.readFile ./netencode-mustache.rs); - - - record-get = depot.nix.writers.rustSimple - { - name = "record-get"; - dependencies = [ - netencode-rs - depot.users.Profpatsch.execline.exec-helpers - ]; - } '' - extern crate netencode; - extern crate exec_helpers; - use netencode::{encode, dec}; - use netencode::dec::{Decoder, DecodeError}; - - fn main() { - let args = exec_helpers::args("record-get", 1); - let field = match std::str::from_utf8(&args[0]) { - Ok(f) => f, - Err(_e) => exec_helpers::die_user_error("record-get", format!("The field name needs to be valid unicode")) - }; - let t = netencode::t_from_stdin_or_die_user_error("record-get"); - match (dec::RecordDot {field, inner: dec::AnyU }).dec(t.to_u()) { - Ok(u) => encode(&mut std::io::stdout(), &u).expect("encoding to stdout failed"), - Err(DecodeError(err)) => exec_helpers::die_user_error("record-get", err) - } - } - ''; - - record-splice-env = depot.nix.writers.rustSimple - { - name = "record-splice-env"; - dependencies = [ - netencode-rs - depot.users.Profpatsch.execline.exec-helpers - ]; - } '' - extern crate netencode; - extern crate exec_helpers; - use netencode::dec::{Record, Try, ScalarAsBytes, Decoder, DecodeError}; - - fn main() { - let t = netencode::t_from_stdin_or_die_user_error("record-splice-env"); - let (_, prog) = exec_helpers::args_for_exec("record-splice-env", 0); - match Record(Try(ScalarAsBytes)).dec(t.to_u()) { - Ok(map) => { - exec_helpers::exec_into_args( - "record-splice-env", - prog, - // some elements can’t be decoded as scalars, so just ignore them - map.into_iter().filter_map(|(k, v)| v.map(|v2| (k, v2))) - ); - }, - Err(DecodeError(err)) => exec_helpers::die_user_error("record-splice-env", err), - } - } - ''; - - env-splice-record = depot.nix.writers.rustSimple - { - name = "env-splice-record"; - dependencies = [ - netencode-rs - depot.users.Profpatsch.execline.exec-helpers - ]; - } '' - extern crate netencode; - extern crate exec_helpers; - use netencode::{T}; - use std::os::unix::ffi::OsStringExt; - - fn main() { - exec_helpers::no_args("env-splice-record"); - let mut res = std::collections::HashMap::new(); - for (key, val) in std::env::vars_os() { - match (String::from_utf8(key.into_vec()), String::from_utf8(val.into_vec())) { - (Ok(k), Ok(v)) => { let _ = res.insert(k, T::Text(v)); }, - // same as in record-splice-env, we ignore non-utf8 variables - (_, _) => {}, - } - } - netencode::encode(&mut std::io::stdout(), &T::Record(res).to_u()).unwrap() - } - ''; - -in -depot.nix.readTree.drvTargets { - inherit - netencode-rs - netencode-hs - pretty-rs - pretty - netencode-mustache - record-get - record-splice-env - env-splice-record - gen - ; -} diff --git a/users/Profpatsch/netencode/gen.nix b/users/Profpatsch/netencode/gen.nix deleted file mode 100644 index efc9629ca..000000000 --- a/users/Profpatsch/netencode/gen.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ lib }: -let - - netstring = tag: suffix: s: - "${tag}${toString (builtins.stringLength s)}:${s}${suffix}"; - - unit = "u,"; - - n1 = b: if b then "n1:1," else "n1:0,"; - - n = i: n: "n${toString i}:${toString n},"; - i = i: n: "i${toString i}:${toString n},"; - - n3 = n 3; - n6 = n 6; - n7 = n 7; - - i3 = i 3; - i6 = i 6; - i7 = i 7; - - text = netstring "t" ","; - binary = netstring "b" ","; - - tag = key: val: netstring "<" "|" key + val; - - concatStrings = builtins.concatStringsSep ""; - - record = lokv: netstring "{" "}" - (concatStrings (map ({ key, val }: tag key val) lokv)); - - list = l: netstring "[" "]" (concatStrings l); - - dwim = val: - let - match = { - "bool" = n1; - "int" = i6; - "string" = text; - "set" = attrs: - # it could be a derivation, then just return the path - if attrs.type or "" == "derivation" then text "${attrs}" - else - record (lib.mapAttrsToList - (k: v: { - key = k; - val = dwim v; - }) - attrs); - "list" = l: list (map dwim l); - }; - in - match.${builtins.typeOf val} val; - -in -{ - inherit - unit - n1 - n3 - n6 - n7 - i3 - i6 - i7 - text - binary - tag - record - list - dwim - ; -} diff --git a/users/Profpatsch/netencode/netencode-mustache.rs b/users/Profpatsch/netencode/netencode-mustache.rs deleted file mode 100644 index 73ed5be1d..000000000 --- a/users/Profpatsch/netencode/netencode-mustache.rs +++ /dev/null @@ -1,52 +0,0 @@ -extern crate arglib_netencode; -extern crate mustache; -extern crate netencode; - -use mustache::Data; -use netencode::T; -use std::collections::HashMap; -use std::io::Read; -use std::os::unix::ffi::OsStrExt; - -fn netencode_to_mustache_data_dwim(t: T) -> Data { - match t { - // TODO: good idea? - T::Unit => Data::Null, - T::N1(b) => Data::Bool(b), - T::N3(u) => Data::String(u.to_string()), - T::N6(u) => Data::String(u.to_string()), - T::N7(u) => Data::String(u.to_string()), - T::I3(i) => Data::String(i.to_string()), - T::I6(i) => Data::String(i.to_string()), - T::I7(i) => Data::String(i.to_string()), - T::Text(s) => Data::String(s), - T::Binary(b) => unimplemented!(), - T::Sum(tag) => unimplemented!(), - T::Record(xs) => Data::Map( - xs.into_iter() - .map(|(key, val)| (key, netencode_to_mustache_data_dwim(val))) - .collect::>(), - ), - T::List(xs) => Data::Vec( - xs.into_iter() - .map(|x| netencode_to_mustache_data_dwim(x)) - .collect::>(), - ), - } -} - -pub fn from_stdin() -> () { - let data = netencode_to_mustache_data_dwim(arglib_netencode::arglib_netencode( - "netencode-mustache", - Some(std::ffi::OsStr::new("TEMPLATE_DATA")), - )); - let mut stdin = String::new(); - std::io::stdin().read_to_string(&mut stdin).unwrap(); - mustache::compile_str(&stdin) - .and_then(|templ| templ.render_data(&mut std::io::stdout(), &data)) - .unwrap() -} - -pub fn main() { - from_stdin() -} diff --git a/users/Profpatsch/netencode/netencode.cabal b/users/Profpatsch/netencode/netencode.cabal deleted file mode 100644 index 7bff4487b..000000000 --- a/users/Profpatsch/netencode/netencode.cabal +++ /dev/null @@ -1,74 +0,0 @@ -cabal-version: 3.0 -name: netencode -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - default-language: GHC2021 - - -library - import: common-options - exposed-modules: - Netencode, - Netencode.Parse - - build-depends: - base >=4.15 && <5, - pa-prelude, - pa-label, - pa-error-tree, - hedgehog, - nonempty-containers, - deriving-compat, - data-fix, - bytestring, - attoparsec, - text, - semigroupoids, - selective diff --git a/users/Profpatsch/netencode/netencode.rs b/users/Profpatsch/netencode/netencode.rs deleted file mode 100644 index 34a8fcef0..000000000 --- a/users/Profpatsch/netencode/netencode.rs +++ /dev/null @@ -1,969 +0,0 @@ -extern crate exec_helpers; -extern crate nom; - -use std::collections::HashMap; -use std::fmt::{Debug, Display}; -use std::io::{Read, Write}; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum T { - // Unit - Unit, - // Boolean - N1(bool), - // Naturals - N3(u8), - N6(u64), - N7(u128), - // Integers - I3(i8), - I6(i64), - I7(i128), - // Text - // TODO: make into &str - Text(String), - // TODO: rename to Bytes - Binary(Vec), - // Tags - // TODO: make into &str - // TODO: rename to Tag - Sum(Tag), - // TODO: make into &str - Record(HashMap), - List(Vec), -} - -impl T { - pub fn to_u<'a>(&'a self) -> U<'a> { - match self { - T::Unit => U::Unit, - T::N1(b) => U::N1(*b), - T::N3(u) => U::N3(*u), - T::N6(u) => U::N6(*u), - T::N7(u) => U::N7(*u), - T::I3(i) => U::I3(*i), - T::I6(i) => U::I6(*i), - T::I7(i) => U::I7(*i), - T::Text(t) => U::Text(t.as_str()), - T::Binary(v) => U::Binary(v), - T::Sum(Tag { tag, val }) => U::Sum(Tag { - tag: tag.as_str(), - val: Box::new(val.to_u()), - }), - T::Record(map) => U::Record(map.iter().map(|(k, v)| (k.as_str(), v.to_u())).collect()), - T::List(l) => U::List(l.iter().map(|v| v.to_u()).collect::>>()), - } - } - - pub fn encode<'a>(&'a self) -> Vec { - match self { - // TODO: don’t go via U, inefficient - o => o.to_u().encode(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum U<'a> { - Unit, - // Boolean - N1(bool), - // Naturals - N3(u8), - N6(u64), - N7(u128), - // Integers - I3(i8), - I6(i64), - I7(i128), - // Text - Text(&'a str), - Binary(&'a [u8]), - // TODO: the U-recursion we do here means we can’t be breadth-lazy anymore - // like we originally planned; maybe we want to go `U<'a>` → `&'a [u8]` again? - // Tags - // TODO: rename to Tag - Sum(Tag<&'a str, U<'a>>), - Record(HashMap<&'a str, U<'a>>), - List(Vec>), -} - -impl<'a> U<'a> { - pub fn encode(&self) -> Vec { - let mut c = std::io::Cursor::new(vec![]); - encode(&mut c, self); - c.into_inner() - } - - pub fn to_t(&self) -> T { - match self { - U::Unit => T::Unit, - U::N1(b) => T::N1(*b), - U::N3(u) => T::N3(*u), - U::N6(u) => T::N6(*u), - U::N7(u) => T::N7(*u), - U::I3(i) => T::I3(*i), - U::I6(i) => T::I6(*i), - U::I7(i) => T::I7(*i), - U::Text(t) => T::Text((*t).to_owned()), - U::Binary(v) => T::Binary((*v).to_owned()), - U::Sum(Tag { tag, val }) => T::Sum(Tag { - tag: (*tag).to_owned(), - val: Box::new(val.to_t()), - }), - U::Record(map) => T::Record( - map.iter() - .map(|(k, v)| ((*k).to_owned(), v.to_t())) - .collect::>(), - ), - U::List(l) => T::List(l.iter().map(|v| v.to_t()).collect::>()), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Tag { - // TODO: make into &str - pub tag: S, - pub val: Box, -} - -impl Tag { - fn map(self, f: F) -> Tag - where - F: Fn(A) -> B, - { - Tag { - tag: self.tag, - val: Box::new(f(*self.val)), - } - } -} - -fn encode_tag(w: &mut W, tag: &str, val: &U) -> std::io::Result<()> { - write!(w, "<{}:{}|", tag.len(), tag)?; - encode(w, val)?; - Ok(()) -} - -pub fn encode(w: &mut W, u: &U) -> std::io::Result<()> { - match u { - U::Unit => write!(w, "u,"), - U::N1(b) => { - if *b { - write!(w, "n1:1,") - } else { - write!(w, "n1:0,") - } - } - U::N3(n) => write!(w, "n3:{},", n), - U::N6(n) => write!(w, "n6:{},", n), - U::N7(n) => write!(w, "n7:{},", n), - U::I3(i) => write!(w, "i3:{},", i), - U::I6(i) => write!(w, "i6:{},", i), - U::I7(i) => write!(w, "i7:{},", i), - U::Text(s) => { - write!(w, "t{}:", s.len()); - w.write_all(s.as_bytes()); - write!(w, ",") - } - U::Binary(s) => { - write!(w, "b{}:", s.len()); - w.write_all(&s); - write!(w, ",") - } - U::Sum(Tag { tag, val }) => encode_tag(w, tag, val), - U::Record(m) => { - let mut c = std::io::Cursor::new(vec![]); - for (k, v) in m { - encode_tag(&mut c, k, v)?; - } - write!(w, "{{{}:", c.get_ref().len())?; - w.write_all(c.get_ref())?; - write!(w, "}}") - } - U::List(l) => { - let mut c = std::io::Cursor::new(vec![]); - for u in l { - encode(&mut c, u)?; - } - write!(w, "[{}:", c.get_ref().len())?; - w.write_all(c.get_ref())?; - write!(w, "]") - } - } -} - -pub fn text(s: String) -> T { - T::Text(s) -} - -pub fn t_from_stdin_or_die_user_error<'a>(prog_name: &'_ str) -> T { - match t_from_stdin_or_die_user_error_with_rest(prog_name, &vec![]) { - None => exec_helpers::die_user_error(prog_name, "stdin was empty"), - Some((rest, t)) => { - if rest.is_empty() { - t - } else { - exec_helpers::die_user_error( - prog_name, - format!( - "stdin contained some soup after netencode value: {:?}", - String::from_utf8_lossy(&rest) - ), - ) - } - } - } -} - -/// Read a netencode value from stdin incrementally, return bytes that could not be read. -/// Nothing if there was nothing to read from stdin & no initial_bytes were provided. -/// These can be passed back as `initial_bytes` if more values should be read. -pub fn t_from_stdin_or_die_user_error_with_rest<'a>( - prog_name: &'_ str, - initial_bytes: &[u8], -) -> Option<(Vec, T)> { - let mut chonker = Chunkyboi::new(std::io::stdin().lock(), 4096); - // The vec to pass to the parser on each step - let mut parser_vec: Vec = initial_bytes.to_vec(); - // whether stdin was already empty - let mut was_empty: bool = false; - loop { - match chonker.next() { - None => { - if parser_vec.is_empty() { - return None; - } else { - was_empty = true - } - } - Some(Err(err)) => exec_helpers::die_temporary( - prog_name, - &format!("could not read from stdin: {:?}", err), - ), - Some(Ok(mut new_bytes)) => parser_vec.append(&mut new_bytes), - } - - match parse::t_t(&parser_vec) { - Ok((rest, t)) => return Some((rest.to_owned(), t)), - Err(nom::Err::Incomplete(Needed)) => { - if was_empty { - exec_helpers::die_user_error( - prog_name, - &format!( - "unable to parse netencode from stdin, input incomplete: {:?}", - parser_vec - ), - ); - } - // read more from stdin and try parsing again - continue; - } - Err(err) => exec_helpers::die_user_error( - prog_name, - &format!("unable to parse netencode from stdin: {:?}", err), - ), - } - } -} - -// iter helper -// TODO: put into its own module -struct Chunkyboi { - inner: T, - buf: Vec, -} - -impl Chunkyboi { - fn new(inner: R, chunksize: usize) -> Self { - let buf = vec![0; chunksize]; - Chunkyboi { inner, buf } - } -} - -impl Iterator for Chunkyboi { - type Item = std::io::Result>; - - fn next(&mut self) -> Option>> { - match self.inner.read(&mut self.buf) { - Ok(0) => None, - Ok(read) => { - // clone a new buffer so we can reuse the internal one - Some(Ok(self.buf[..read].to_owned())) - } - Err(err) => Some(Err(err)), - } - } -} - -pub mod parse { - use super::{Tag, T, U}; - - use std::collections::HashMap; - use std::ops::Neg; - use std::str::FromStr; - - use nom::branch::alt; - use nom::bytes::streaming::{tag, take}; - use nom::character::streaming::{char, digit1}; - use nom::combinator::{flat_map, map, map_parser, map_res, opt}; - use nom::error::{context, ErrorKind, ParseError}; - use nom::sequence::tuple; - use nom::IResult; - - fn unit_t(s: &[u8]) -> IResult<&[u8], ()> { - let (s, _) = context("unit", tag("u,"))(s)?; - Ok((s, ())) - } - - fn usize_t(s: &[u8]) -> IResult<&[u8], usize> { - context( - "usize", - map_res(map_res(digit1, |n| std::str::from_utf8(n)), |s| { - s.parse::() - }), - )(s) - } - - fn sized(begin: char, end: char) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> { - move |s: &[u8]| { - // This is the point where we check the descriminator; - // if the beginning char does not match, we can immediately return. - let (s, _) = char(begin)(s)?; - let (s, (len, _)) = tuple((usize_t, char(':')))(s)?; - let (s, (res, _)) = tuple((take(len), char(end)))(s)?; - Ok((s, res)) - } - } - - fn uint_t<'a, I: FromStr + 'a>(t: &'static str) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], I> { - move |s: &'a [u8]| { - let (s, (_, _, int, _)) = tuple(( - tag(t.as_bytes()), - char(':'), - map_res(map_res(digit1, |n: &[u8]| std::str::from_utf8(n)), |s| { - s.parse::() - }), - char(','), - ))(s)?; - Ok((s, int)) - } - } - - fn bool_t<'a>() -> impl Fn(&'a [u8]) -> IResult<&'a [u8], bool> { - context( - "bool", - alt((map(tag("n1:0,"), |_| false), map(tag("n1:1,"), |_| true))), - ) - } - - fn int_t<'a, I: FromStr + Neg>( - t: &'static str, - ) -> impl Fn(&'a [u8]) -> IResult<&[u8], I> { - context(t, move |s: &'a [u8]| { - let (s, (_, _, neg, int, _)) = tuple(( - tag(t.as_bytes()), - char(':'), - opt(char('-')), - map_res(map_res(digit1, |n: &[u8]| std::str::from_utf8(n)), |s| { - s.parse::() - }), - char(','), - ))(s)?; - let res = match neg { - Some(_) => -int, - None => int, - }; - Ok((s, res)) - }) - } - - fn tag_t(s: &[u8]) -> IResult<&[u8], Tag> { - // recurses into the main parser - map(tag_g(t_t), |Tag { tag, val }| Tag { - tag: tag.to_string(), - val, - })(s) - } - - fn tag_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Tag<&'a str, O>> - where - P: Fn(&'a [u8]) -> IResult<&'a [u8], O>, - { - move |s: &[u8]| { - let (s, tag) = sized('<', '|')(s)?; - let (s, val) = inner(s)?; - Ok(( - s, - Tag { - tag: std::str::from_utf8(tag) - .map_err(|_| nom::Err::Failure((s, ErrorKind::Char)))?, - val: Box::new(val), - }, - )) - } - } - - /// parse text scalar (`t5:hello,`) - fn text(s: &[u8]) -> IResult<&[u8], T> { - let (s, res) = text_g(s)?; - Ok((s, T::Text(res.to_string()))) - } - - fn text_g(s: &[u8]) -> IResult<&[u8], &str> { - let (s, res) = sized('t', ',')(s)?; - Ok(( - s, - std::str::from_utf8(res).map_err(|_| nom::Err::Failure((s, ErrorKind::Char)))?, - )) - } - - fn binary<'a>() -> impl Fn(&'a [u8]) -> IResult<&'a [u8], T> { - map(binary_g(), |b| T::Binary(b.to_owned())) - } - - fn binary_g() -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> { - sized('b', ',') - } - - fn list_t(s: &[u8]) -> IResult<&[u8], Vec> { - list_g(t_t)(s) - } - - /// Wrap the inner parser of an `many0`/`fold_many0`, so that the parser - /// is not called when the `s` is empty already, preventing it from - /// returning `Incomplete` on streaming parsing. - fn inner_no_empty_string<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], O> - where - O: Clone, - P: Fn(&'a [u8]) -> IResult<&'a [u8], O>, - { - move |s: &'a [u8]| { - if s.is_empty() { - // This is a bit hacky, `many0` considers the inside done - // when a parser returns `Err::Error`, ignoring the actual error content - Err(nom::Err::Error((s, nom::error::ErrorKind::Many0))) - } else { - inner(s) - } - } - } - - fn list_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], Vec> - where - O: Clone, - P: Fn(&'a [u8]) -> IResult<&'a [u8], O>, - { - map_parser( - sized('[', ']'), - nom::multi::many0(inner_no_empty_string(inner)), - ) - } - - fn record_t<'a>(s: &'a [u8]) -> IResult<&'a [u8], HashMap> { - let (s, r) = record_g(t_t)(s)?; - Ok(( - s, - r.into_iter() - .map(|(k, v)| (k.to_string(), v)) - .collect::>(), - )) - } - - fn record_g<'a, P, O>(inner: P) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], HashMap<&'a str, O>> - where - O: Clone, - P: Fn(&'a [u8]) -> IResult<&'a [u8], O>, - { - move |s: &'a [u8]| { - let (s, map) = map_parser( - sized('{', '}'), - nom::multi::fold_many0( - inner_no_empty_string(tag_g(&inner)), - HashMap::new(), - |mut acc: HashMap<_, _>, Tag { tag, mut val }| { - // ignore earlier tags with the same name - // according to netencode spec - let _ = acc.insert(tag, *val); - acc - }, - ), - )(s)?; - if map.is_empty() { - // records must not be empty, according to the spec - Err(nom::Err::Failure((s, nom::error::ErrorKind::Many1))) - } else { - Ok((s, map)) - } - } - } - - pub fn u_u(s: &[u8]) -> IResult<&[u8], U> { - alt(( - map(text_g, U::Text), - map(binary_g(), U::Binary), - map(unit_t, |()| U::Unit), - map(tag_g(u_u), |t| U::Sum(t)), - map(list_g(u_u), U::List), - map(record_g(u_u), U::Record), - map(bool_t(), |u| U::N1(u)), - map(uint_t("n3"), |u| U::N3(u)), - map(uint_t("n6"), |u| U::N6(u)), - map(uint_t("n7"), |u| U::N7(u)), - map(int_t("i3"), |u| U::I3(u)), - map(int_t("i6"), |u| U::I6(u)), - map(int_t("i7"), |u| U::I7(u)), - // less common - map(uint_t("n2"), |u| U::N3(u)), - map(uint_t("n4"), |u| U::N6(u)), - map(uint_t("n5"), |u| U::N6(u)), - map(int_t("i1"), |u| U::I3(u)), - map(int_t("i2"), |u| U::I3(u)), - map(int_t("i4"), |u| U::I6(u)), - map(int_t("i5"), |u| U::I6(u)), - // TODO: 8, 9 not supported - ))(s) - } - - pub fn t_t(s: &[u8]) -> IResult<&[u8], T> { - alt(( - text, - binary(), - map(unit_t, |_| T::Unit), - map(tag_t, |t| T::Sum(t)), - map(list_t, |l| T::List(l)), - map(record_t, |p| T::Record(p)), - map(bool_t(), |u| T::N1(u)), - // 8, 64 and 128 bit - map(uint_t("n3"), |u| T::N3(u)), - map(uint_t("n6"), |u| T::N6(u)), - map(uint_t("n7"), |u| T::N7(u)), - map(int_t("i3"), |u| T::I3(u)), - map(int_t("i6"), |u| T::I6(u)), - map(int_t("i7"), |u| T::I7(u)), - // less common - map(uint_t("n2"), |u| T::N3(u)), - map(uint_t("n4"), |u| T::N6(u)), - map(uint_t("n5"), |u| T::N6(u)), - map(int_t("i1"), |u| T::I3(u)), - map(int_t("i2"), |u| T::I3(u)), - map(int_t("i4"), |u| T::I6(u)), - map(int_t("i5"), |u| T::I6(u)), - // TODO: 8, 9 not supported - ))(s) - } - - #[cfg(test)] - mod tests { - use super::*; - - #[test] - fn test_parse_unit_t() { - assert_eq!(unit_t("u,".as_bytes()), Ok(("".as_bytes(), ()))); - } - - #[test] - fn test_parse_bool_t() { - assert_eq!(bool_t()("n1:0,".as_bytes()), Ok(("".as_bytes(), false))); - assert_eq!(bool_t()("n1:1,".as_bytes()), Ok(("".as_bytes(), true))); - } - - #[test] - fn test_parse_usize_t() { - assert_eq!(usize_t("32foo".as_bytes()), Ok(("foo".as_bytes(), 32))); - } - - #[test] - fn test_parse_int_t() { - assert_eq!( - uint_t::("n3")("n3:42,abc".as_bytes()), - Ok(("abc".as_bytes(), 42)) - ); - assert_eq!( - uint_t::("n3")("n3:1024,abc".as_bytes()), - Err(nom::Err::Error(( - "1024,abc".as_bytes(), - nom::error::ErrorKind::MapRes - ))) - ); - assert_eq!( - int_t::("i6")("i6:-23,abc".as_bytes()), - Ok(("abc".as_bytes(), -23)) - ); - assert_eq!( - int_t::("i3")("i3:0,:abc".as_bytes()), - Ok((":abc".as_bytes(), 0)) - ); - assert_eq!( - uint_t::("n7")("n7:09,".as_bytes()), - Ok(("".as_bytes(), 9)) - ); - // assert_eq!( - // length("c"), - // Err(nom::Err::Error(("c", nom::error::ErrorKind::Digit))) - // ); - // assert_eq!( - // length(":"), - // Err(nom::Err::Error((":", nom::error::ErrorKind::Digit))) - // ); - } - - #[test] - fn test_parse_text() { - assert_eq!( - text("t5:hello,".as_bytes()), - Ok(("".as_bytes(), T::Text("hello".to_owned()))), - "{}", - r"t5:hello," - ); - assert_eq!( - text("t4:fo".as_bytes()), - // The content of the text should be 4 long - Err(nom::Err::Incomplete(nom::Needed::Size(4))), - "{}", - r"t4:fo," - ); - assert_eq!( - text("t9:今日は,".as_bytes()), - Ok(("".as_bytes(), T::Text("今日は".to_owned()))), - "{}", - r"t9:今日は," - ); - } - - #[test] - fn test_parse_binary() { - assert_eq!( - binary()("b5:hello,".as_bytes()), - Ok(("".as_bytes(), T::Binary(Vec::from("hello".to_owned())))), - "{}", - r"b5:hello," - ); - assert_eq!( - binary()("b4:fo".as_bytes()), - // The content of the byte should be 4 long - Err(nom::Err::Incomplete(nom::Needed::Size(4))), - "{}", - r"b4:fo," - ); - assert_eq!( - binary()("b4:foob".as_bytes()), - // The content is 4 bytes now, but the finishing , is missing - Err(nom::Err::Incomplete(nom::Needed::Size(1))), - "{}", - r"b4:fo," - ); - assert_eq!( - binary()("b9:今日は,".as_bytes()), - Ok(("".as_bytes(), T::Binary(Vec::from("今日は".as_bytes())))), - "{}", - r"b9:今日は," - ); - } - - #[test] - fn test_list() { - assert_eq!( - list_t("[0:]".as_bytes()), - Ok(("".as_bytes(), vec![])), - "{}", - r"[0:]" - ); - assert_eq!( - list_t("[6:u,u,u,]".as_bytes()), - Ok(("".as_bytes(), vec![T::Unit, T::Unit, T::Unit,])), - "{}", - r"[6:u,u,u,]" - ); - assert_eq!( - list_t("[15:u,[7:t3:foo,]u,]".as_bytes()), - Ok(( - "".as_bytes(), - vec![T::Unit, T::List(vec![T::Text("foo".to_owned())]), T::Unit,] - )), - "{}", - r"[15:u,[7:t3:foo,]u,]" - ); - } - - #[test] - fn test_record() { - assert_eq!( - record_t("{21:<1:a|u,<1:b|u,<1:c|u,}".as_bytes()), - Ok(( - "".as_bytes(), - vec![ - ("a".to_owned(), T::Unit), - ("b".to_owned(), T::Unit), - ("c".to_owned(), T::Unit), - ] - .into_iter() - .collect::>() - )), - "{}", - r"{21:<1:a|u,<1:b|u,<1:c|u,}" - ); - // duplicated keys are ignored (first is taken) - assert_eq!( - record_t("{25:<1:a|u,<1:b|u,<1:a|i1:-1,}".as_bytes()), - Ok(( - "".as_bytes(), - vec![("a".to_owned(), T::I3(-1)), ("b".to_owned(), T::Unit),] - .into_iter() - .collect::>() - )), - "{}", - r"{25:<1:a|u,<1:b|u,<1:a|i1:-1,}" - ); - // empty records are not allowed - assert_eq!( - record_t("{0:}".as_bytes()), - Err(nom::Err::Failure(( - "".as_bytes(), - nom::error::ErrorKind::Many1 - ))), - "{}", - r"{0:}" - ); - } - - #[test] - fn test_parse() { - assert_eq!( - t_t("n3:255,".as_bytes()), - Ok(("".as_bytes(), T::N3(255))), - "{}", - r"n3:255," - ); - assert_eq!( - t_t("t6:halloo,".as_bytes()), - Ok(("".as_bytes(), T::Text("halloo".to_owned()))), - "{}", - r"t6:halloo," - ); - assert_eq!( - t_t("<3:foo|t6:halloo,".as_bytes()), - Ok(( - "".as_bytes(), - T::Sum(Tag { - tag: "foo".to_owned(), - val: Box::new(T::Text("halloo".to_owned())) - }) - )), - "{}", - r"<3:foo|t6:halloo," - ); - // { a: Unit - // , foo: List } - assert_eq!( - t_t("{52:<1:a|u,<3:foo|[33:<1:A|u,<1:A|n1:1,<1:B|[7:i3:127,]]}".as_bytes()), - Ok(( - "".as_bytes(), - T::Record( - vec![ - ("a".to_owned(), T::Unit), - ( - "foo".to_owned(), - T::List(vec![ - T::Sum(Tag { - tag: "A".to_owned(), - val: Box::new(T::Unit) - }), - T::Sum(Tag { - tag: "A".to_owned(), - val: Box::new(T::N1(true)) - }), - T::Sum(Tag { - tag: "B".to_owned(), - val: Box::new(T::List(vec![T::I3(127)])) - }), - ]) - ) - ] - .into_iter() - .collect::>() - ) - )), - "{}", - r"{52:<1:a|u,<3:foo|[33:<1:A|u,<1:A|n1:1,<1:B|[7:i3:127,]]}" - ); - } - } -} - -pub mod dec { - use super::*; - use std::collections::HashMap; - - pub struct DecodeError(pub String); - - pub trait Decoder<'a> { - type A; - fn dec(&self, u: U<'a>) -> Result; - } - - /// Any netencode, as `T`. - #[derive(Clone, Copy)] - pub struct AnyT; - /// Any netencode, as `U`. - #[derive(Clone, Copy)] - pub struct AnyU; - - impl<'a> Decoder<'a> for AnyT { - type A = T; - fn dec(&self, u: U<'a>) -> Result { - Ok(u.to_t()) - } - } - - impl<'a> Decoder<'a> for AnyU { - type A = U<'a>; - fn dec(&self, u: U<'a>) -> Result { - Ok(u) - } - } - - /// A text - #[derive(Clone, Copy)] - pub struct Text; - - /// A bytestring - // TODO: rename to Bytes - #[derive(Clone, Copy)] - pub struct Binary; - - impl<'a> Decoder<'a> for Text { - type A = &'a str; - fn dec(&self, u: U<'a>) -> Result { - match u { - U::Text(t) => Ok(t), - other => Err(DecodeError(format!("Cannot decode {:?} into Text", other))), - } - } - } - - impl<'a> Decoder<'a> for Binary { - type A = &'a [u8]; - fn dec(&self, u: U<'a>) -> Result { - match u { - U::Binary(b) => Ok(b), - other => Err(DecodeError(format!( - "Cannot decode {:?} into Binary", - other - ))), - } - } - } - - /// Any scalar, converted to bytes. - #[derive(Clone, Copy)] - pub struct ScalarAsBytes; - - impl<'a> Decoder<'a> for ScalarAsBytes { - type A = Vec; - fn dec(&self, u: U<'a>) -> Result { - match u { - U::N3(u) => Ok(format!("{}", u).into_bytes()), - U::N6(u) => Ok(format!("{}", u).into_bytes()), - U::N7(u) => Ok(format!("{}", u).into_bytes()), - U::I3(i) => Ok(format!("{}", i).into_bytes()), - U::I6(i) => Ok(format!("{}", i).into_bytes()), - U::I7(i) => Ok(format!("{}", i).into_bytes()), - U::Text(t) => Ok(t.as_bytes().to_owned()), - U::Binary(b) => Ok(b.to_owned()), - o => Err(DecodeError(format!("Cannot decode {:?} into scalar", o))), - } - } - } - - /// A map of Ts (TODO: rename to map) - #[derive(Clone, Copy)] - pub struct Record(pub T); - - impl<'a, Inner> Decoder<'a> for Record - where - Inner: Decoder<'a>, - { - type A = HashMap<&'a str, Inner::A>; - fn dec(&self, u: U<'a>) -> Result { - match u { - U::Record(map) => map - .into_iter() - .map(|(k, v)| self.0.dec(v).map(|v2| (k, v2))) - .collect::>(), - o => Err(DecodeError(format!("Cannot decode {:?} into record", o))), - } - } - } - - /// Assume a record and project out the field with the given name and type. - #[derive(Clone, Copy)] - pub struct RecordDot<'a, T> { - pub field: &'a str, - pub inner: T, - } - - impl<'a, Inner> Decoder<'a> for RecordDot<'_, Inner> - where - Inner: Decoder<'a> + Clone, - { - type A = Inner::A; - fn dec(&self, u: U<'a>) -> Result { - match Record(self.inner.clone()).dec(u) { - Ok(mut map) => match map.remove(self.field) { - Some(inner) => Ok(inner), - None => Err(DecodeError(format!( - "Cannot find `{}` in record map", - self.field - ))), - }, - Err(err) => Err(err), - } - } - } - - /// Equals one of the listed `A`s exactly, after decoding. - #[derive(Clone)] - pub struct OneOf { - pub inner: T, - pub list: Vec, - } - - impl<'a, Inner> Decoder<'a> for OneOf - where - Inner: Decoder<'a>, - Inner::A: Display + Debug + PartialEq, - { - type A = Inner::A; - fn dec(&self, u: U<'a>) -> Result { - match self.inner.dec(u) { - Ok(inner) => match self.list.iter().any(|x| x.eq(&inner)) { - true => Ok(inner), - false => Err(DecodeError(format!( - "{} is not one of {:?}", - inner, self.list - ))), - }, - Err(err) => Err(err), - } - } - } - - /// Try decoding as `T`. - #[derive(Clone)] - pub struct Try(pub T); - - impl<'a, Inner> Decoder<'a> for Try - where - Inner: Decoder<'a>, - { - type A = Option; - fn dec(&self, u: U<'a>) -> Result { - match self.0.dec(u) { - Ok(inner) => Ok(Some(inner)), - Err(err) => Ok(None), - } - } - } -} diff --git a/users/Profpatsch/netencode/pretty.rs b/users/Profpatsch/netencode/pretty.rs deleted file mode 100644 index 935c3d4a8..000000000 --- a/users/Profpatsch/netencode/pretty.rs +++ /dev/null @@ -1,163 +0,0 @@ -extern crate netencode; - -use netencode::{Tag, T, U}; - -pub enum Pretty { - Single { - r#type: char, - length: String, - val: String, - trailer: char, - }, - Tag { - r#type: char, - length: String, - key: String, - inner: char, - val: Box, - }, - Multi { - r#type: char, - length: String, - vals: Vec, - trailer: char, - }, -} - -impl Pretty { - pub fn from_u<'a>(u: U<'a>) -> Pretty { - match u { - U::Unit => Self::scalar('u', "", ""), - U::N1(b) => Self::scalar('n', "1:", if b { "1" } else { "0" }), - U::N3(n) => Self::scalar('n', "3:", n), - U::N6(n) => Self::scalar('n', "6:", n), - U::N7(n) => Self::scalar('n', "7:", n), - U::I3(i) => Self::scalar('i', "3:", i), - U::I6(i) => Self::scalar('i', "6:", i), - U::I7(i) => Self::scalar('i', "7:", i), - U::Text(s) => Pretty::Single { - r#type: 't', - length: format!("{}:", s.len()), - val: s.to_string(), - trailer: ',', - }, - U::Binary(s) => Pretty::Single { - r#type: 'b', - length: format!("{}:", s.len()), - // For pretty printing we want the string to be visible obviously. - // Instead of not supporting binary, let’s use lossy conversion. - val: String::from_utf8_lossy(s).into_owned(), - trailer: ',', - }, - U::Sum(Tag { tag, val }) => Self::pretty_tag(tag, Self::from_u(*val)), - U::Record(m) => Pretty::Multi { - r#type: '{', - // TODO: we are losing the size here, should we recompute it? Keep it? - length: String::from(""), - vals: m - .into_iter() - .map(|(k, v)| Self::pretty_tag(k, Self::from_u(v))) - .collect(), - trailer: '}', - }, - U::List(l) => Pretty::Multi { - r#type: '[', - // TODO: we are losing the size here, should we recompute it? Keep it? - length: String::from(""), - vals: l.into_iter().map(|v| Self::from_u(v)).collect(), - trailer: ']', - }, - } - } - - fn scalar(r#type: char, length: &str, d: D) -> Pretty - where - D: std::fmt::Display, - { - Pretty::Single { - r#type, - length: length.to_string(), - val: format!("{}", d), - trailer: ',', - } - } - - fn pretty_tag(tag: &str, val: Pretty) -> Pretty { - Pretty::Tag { - r#type: '<', - length: format!("{}:", tag.len()), - key: tag.to_string(), - inner: '|', - val: Box::new(val), - } - } - - pub fn print_multiline(&self, mut w: &mut W) -> std::io::Result<()> - where - W: std::io::Write, - { - Self::go(&mut w, self, 0, true); - write!(w, "\n") - } - - fn go(mut w: &mut W, p: &Pretty, depth: usize, is_newline: bool) -> std::io::Result<()> - where - W: std::io::Write, - { - const full: usize = 4; - const half: usize = 2; - let i = &vec![b' '; depth * full]; - let iandhalf = &vec![b' '; depth * full + half]; - let (i, iandhalf) = unsafe { - ( - std::str::from_utf8_unchecked(i), - std::str::from_utf8_unchecked(iandhalf), - ) - }; - if is_newline { - write!(&mut w, "{}", i); - } - match p { - Pretty::Single { - r#type, - length, - val, - trailer, - } => write!(&mut w, "{} {}{}", r#type, val, trailer), - Pretty::Tag { - r#type, - length, - key, - inner, - val, - } => { - write!(&mut w, "{} {} {}", r#type, key, inner)?; - Self::go::(&mut w, val, depth, false) - } - // if the length is 0 or 1, we print on one line, - // only if there’s more than one element we split the resulting value. - // we never break lines on arbitrary column sizes, since that is just silly. - Pretty::Multi { - r#type, - length, - vals, - trailer, - } => match vals.len() { - 0 => write!(&mut w, "{} {}", r#type, trailer), - 1 => { - write!(&mut w, "{} ", r#type); - Self::go::(&mut w, &vals[0], depth, false)?; - write!(&mut w, "{}", trailer) - } - more => { - write!(&mut w, "\n{}{} \n", iandhalf, r#type)?; - for v in vals { - Self::go::(&mut w, v, depth + 1, true)?; - write!(&mut w, "\n")?; - } - write!(&mut w, "{}{}", iandhalf, trailer) - } - }, - } - } -} diff --git a/users/Profpatsch/netstring/README.md b/users/Profpatsch/netstring/README.md deleted file mode 100644 index b8daea11d..000000000 --- a/users/Profpatsch/netstring/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Netstring - -Netstrings are a djb invention. They are intended as a serialization format. Instead of inline control characters like `\n` or `\0` to signal the end of a string, they use a run-length encoding given as the number of bytes, encoded in ASCII, at the beginning of the string. - -``` -hello -> 5:hello, -foo! -> 4:foo!, -こんにちは -> 15:こんにちは, -``` - -They can be used to encode e.g. lists by simply concatenating and reading them in one-by-one. - -If you need a more complex encoding, you could start encoding e.g. tuples as netstrings-in-netstrings, or you could use [`netencode`](../netencode/README.md) instead, which is what-if-json-but-netstrings, and takes the idea of netstrings to their logical conclusion. - -Resources: - -Spec: http://cr.yp.to/proto/netstrings.txt -Wiki: https://en.wikipedia.org/wiki/Netstring diff --git a/users/Profpatsch/netstring/default.nix b/users/Profpatsch/netstring/default.nix deleted file mode 100644 index 047fe6bae..000000000 --- a/users/Profpatsch/netstring/default.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ lib, pkgs, depot, ... }: -let - toNetstring = depot.nix.netstring.fromString; - - toNetstringList = xs: - lib.concatStrings (map toNetstring xs); - - toNetstringKeyVal = depot.nix.netstring.attrsToKeyValList; - - python-netstring = depot.users.Profpatsch.writers.python3Lib - { - name = "netstring"; - } '' - def read_netstring(bytes): - (int_length, rest) = bytes.split(sep=b':', maxsplit=1) - val = rest[:int(int_length)] - # has to end on a , - assert(rest[len(val)] == ord(',')) - return (val, rest[len(val) + 1:]) - - def read_netstring_key_val(bytes): - (keyvalnet, rest) = read_netstring(bytes) - (key, valnet) = read_netstring(keyvalnet) - (val, nothing) = read_netstring(valnet) - assert(nothing == b"") - return (key, val, rest) - - def read_netstring_key_val_list(bytes): - rest = bytes - res = {} - while rest != b"": - (key, val, r) = read_netstring_key_val(rest) - rest = r - res[key] = val - return res - ''; - - rust-netstring = depot.nix.writers.rustSimpleLib - { - name = "netstring"; - } '' - pub fn to_netstring(s: &[u8]) -> Vec { - let len = s.len(); - // length of the integer as ascii - let i_len = ((len as f64).log10() as usize) + 1; - let ns_len = i_len + 1 + len + 1; - let mut res = Vec::with_capacity(ns_len); - res.extend_from_slice(format!("{}:", len).as_bytes()); - res.extend_from_slice(s); - res.push(b','); - res - } - ''; - -in -depot.nix.readTree.drvTargets { - inherit - toNetstring - toNetstringList - toNetstringKeyVal - python-netstring - rust-netstring - ; -} diff --git a/users/Profpatsch/netstring/tests/default.nix b/users/Profpatsch/netstring/tests/default.nix deleted file mode 100644 index 6a1062988..000000000 --- a/users/Profpatsch/netstring/tests/default.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - - python-netstring-test = depot.users.Profpatsch.writers.python3 - { - name = "python-netstring-test"; - libraries = p: [ - depot.users.Profpatsch.netstring.python-netstring - ]; - } '' - import netstring - - def assEq(left, right): - assert left == right, "{} /= {}".format(str(left), str(right)) - - assEq( - netstring.read_netstring(b"""${depot.nix.netstring.fromString "hi!"}"""), - (b"hi!", b"") - ) - - assEq( - netstring.read_netstring_key_val( - b"""${depot.nix.netstring.attrsToKeyValList { foo = "42"; }}""" - ), - (b'foo', b'42', b"") - ) - - assEq( - netstring.read_netstring_key_val_list( - b"""${depot.nix.netstring.attrsToKeyValList { foo = "42"; bar = "hi"; }}""" - ), - { b'foo': b'42', b'bar': b'hi' } - ) - ''; - - rust-netstring-test = depot.nix.writers.rustSimple - { - name = "rust-netstring-test"; - dependencies = [ - depot.users.Profpatsch.netstring.rust-netstring - ]; - } '' - extern crate netstring; - - fn main() { - assert_eq!( - std::str::from_utf8(&netstring::to_netstring(b"hello")).unwrap(), - r##"${depot.nix.netstring.fromString "hello"}"## - ); - assert_eq!( - std::str::from_utf8(&netstring::to_netstring("こんにちは".as_bytes())).unwrap(), - r##"${depot.nix.netstring.fromString "こんにちは"}"## - ); - } - ''; - -in -depot.nix.readTree.drvTargets { - inherit - python-netstring-test - rust-netstring-test - ; -} diff --git a/users/Profpatsch/nix-home/README.md b/users/Profpatsch/nix-home/README.md deleted file mode 100644 index 222978bc8..000000000 --- a/users/Profpatsch/nix-home/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# nix-home - -My very much simplified version of [home-manager](https://github.com/nix-community/home-manager/). - -Only takes care about installing symlinks into `$HOME`, and uses [`GNU stow`](https://www.gnu.org/software/stow/) for doing the actual mutating. - -No support for services (yet). diff --git a/users/Profpatsch/nix-home/default.nix b/users/Profpatsch/nix-home/default.nix deleted file mode 100644 index 8c8d82eb7..000000000 --- a/users/Profpatsch/nix-home/default.nix +++ /dev/null @@ -1,211 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - bins = depot.nix.getBins pkgs.stow [ "stow" ] - // depot.nix.getBins pkgs.coreutils [ "mkdir" "ln" "printenv" "rm" ] - // depot.nix.getBins pkgs.xe [ "xe" ] - // depot.nix.getBins pkgs.lr [ "lr" ] - // depot.nix.getBins pkgs.nix [ "nix-store" ] - ; - - # run stow to populate the target directory with the given stow package, read from stowDir. - # Bear in mind that `stowDirOriginPath` should always be semantically bound to the given `stowDir`, otherwise stow might become rather confused. - runStow = - { - # “stow package” to stow (see manpage) - # TODO: allow this function to un-stow multiple packages! - stowPackage - , # “target directory” to stow in (see manpage) - targetDir - , # The “stow directory” (see manpage), containing “stow packages” (see manpage) - stowDir - , # representative directory for the stowDir in the file system, against which stow will create relative links. - # ATTN: this is always overwritten with the contents of `stowDir`! You shouldn’t re-use the same `stowDirOriginPath` for different `stowDir`s, otherwise there might be surprises. - stowDirOriginPath - , - }: depot.nix.writeExecline "stow-${stowPackage}" { } [ - # first, create a temporary stow directory to use as source - # (stow will use it to determine the origin of files) - "if" - [ bins.mkdir "-p" stowDirOriginPath ] - # remove old symlinks - "if" - [ - "pipeline" - [ - bins.lr - "-0" - "-t" - "depth == 1 && type == l" - stowDirOriginPath - ] - bins.xe - "-0" - bins.rm - ] - # create an indirect gc root so our config is not cleaned under our asses by a garbage collect - "if" - [ - bins.nix-store - "--realise" - "--indirect" - "--add-root" - "${stowDirOriginPath}/.nix-stowdir-gc-root" - stowDir - ] - # populate with new stow targets - "if" - [ - "elglob" - "-w0" - "stowPackages" - "${stowDir}/*" - bins.ln - "--force" - "-st" - stowDirOriginPath - "$stowPackages" - ] - # stow always looks for $HOME/.stowrc to read more arguments - "export" - "HOME" - "/homeless-shelter" - bins.stow - # always run restow for now; this does more stat but will remove stale links - "--restow" - "--dir" - stowDirOriginPath - "--target" - targetDir - stowPackage - ]; - - # create a stow dir from a list of drv paths and a stow package name. - makeStowDir = - (with depot.nix.yants; - defun - [ - (list (struct { - originalDir = drv; - stowPackage = string; - })) - drv - ]) - (dirs: - depot.nix.runExecline "make-stow-dir" - { - stdin = lib.pipe dirs [ - (map depot.users.Profpatsch.netencode.gen.dwim) - depot.users.Profpatsch.netstring.toNetstringList - ]; - } [ - "importas" - "out" - "out" - "if" - [ bins.mkdir "-p" "$out" ] - "forstdin" - "-d" - "" - "-o" - "0" - "line" - "pipeline" - [ - depot.users.Profpatsch.execline.print-one-env - "line" - ] - depot.users.Profpatsch.netencode.record-splice-env - "importas" - "-ui" - "originalDir" - "originalDir" - "importas" - "-ui" - "stowPackage" - "stowPackage" - bins.ln - "-sT" - "$originalDir" - "\${out}/\${stowPackage}" - ]); - - # this is a dumb way of generating a pure list of packages from a depot namespace. - readTreeNamespaceDrvs = namespace: - lib.pipe namespace [ - (lib.filterAttrs (_: v: lib.isDerivation v)) - (lib.mapAttrsToList (k: v: { - name = k; - drv = v; - })) - ]; - - scriptsStow = - lib.pipe { } [ - (_: makeStowDir [{ - stowPackage = "scripts"; - originalDir = pkgs.linkFarm "scripts-farm" - ([ - { - name = "scripts/ytextr"; - path = depot.users.Profpatsch.ytextr; - } - { - name = "scripts/lorri-wait-for-eval"; - path = depot.users.Profpatsch.lorri-wait-for-eval; - } - { - name = "scripts/lw"; - path = depot.users.Profpatsch.lorri-wait-for-eval; - } - ] - ++ - (lib.pipe depot.users.Profpatsch.aliases [ - readTreeNamespaceDrvs - (map ({ name, drv }: { - name = "scripts/${name}"; - path = drv; - })) - ])); - }]) - (d: runStow { - stowDir = d; - stowPackage = "scripts"; - targetDir = "/home/philip"; - stowDirOriginPath = "/home/philip/.local/share/nix-home/stow-origin"; - }) - ]; - - - - terminalEmulatorStow = - lib.pipe { } [ - (_: makeStowDir [{ - stowPackage = "terminal-emulator"; - originalDir = pkgs.linkFarm "terminal-emulator-farm" - ([ - { - name = "bin/terminal-emulator"; - path = depot.users.Profpatsch.alacritty.alacritty; - } - ]); - - }]) - (d: runStow { - stowDir = d; - stowPackage = "terminal-emulator"; - targetDir = "/home/philip"; - # TODO: this should only be done once, in a single runStow instead of multiple - stowDirOriginPath = "/home/philip/.local/share/nix-home/stow-origin-terminal-emulator"; - }) - ]; - -in - -# TODO: run multiple stows with runStow? - # TODO: temp setup -depot.nix.writeExecline "nix-home" { } [ - "if" - [ scriptsStow ] - terminalEmulatorStow -] diff --git a/users/Profpatsch/nix-tools.nix b/users/Profpatsch/nix-tools.nix deleted file mode 100644 index 4f2927457..000000000 --- a/users/Profpatsch/nix-tools.nix +++ /dev/null @@ -1,159 +0,0 @@ -{ depot, pkgs, ... }: - -let - bins = depot.nix.getBins pkgs.nix [ "nix-build" "nix-instantiate" ]; - - # TODO: both of these don’t prevent `result` from being created. good? bad? - - # Usage (execline syntax): - # nix-run { -A foo } args... - # - # Takes an execline block of `nix-build` arguments, which should produce an executable store path. - # Then runs the store path with `prog...`. - nix-run = depot.nix.writeExecline "nix-run" { argMode = "env"; } [ - "backtick" - "-iE" - "storepath" - [ - runblock - "1" - bins.nix-build - ] - runblock - "-r" - "2" - "$storepath" - ]; - - # Usage (execline syntax): - # nix-run-bin { -A foo } args... - # - # Takes an execline block of `nix-build` arguments, which should produce a store path with a bin/ directory in it. - # Then runs the given command line with the given arguments. All executables in the built storepath’s bin directory are prepended to `PATH`. - nix-run-bin = depot.nix.writeExecline "nix-run-bin" { argMode = "env"; } [ - "backtick" - "-iE" - "storepath" - [ - runblock - "1" - bins.nix-build - ] - "importas" - "-ui" - "PATH" - "PATH" - "export" - "PATH" - "\${storepath}/bin:\${PATH}" - runblock - "-r" - "2" - ]; - - nix-eval = depot.nix.writeExecline "nix-eval" { } [ - bins.nix-instantiate - "--read-write-mode" - "--eval" - "--strict" - "$@" - ]; - - # This is a rewrite of execline’s runblock. - # It adds the feature that instead of just - # executing the block it reads, it can also - # pass it as argv to given commands. - # - # This is going to be added to a future version - # of execline by skarnet, but for now it’s easier - # to just dirtily reimplement it in Python. - # - # TODO: this was added to recent execline versions, - # but it doesn’t seem to be a drop-in replacement, - # if I use execline’s runblock in nix-run-bin above, - # I get errors like - # > export: fatal: unable to exec runblock: Success - runblock = pkgs.writers.writePython3 "runblock" - { - flakeIgnore = [ "E501" "E226" ]; - } '' - import sys - import os - from pathlib import Path - - skip = False - one = sys.argv[1] - if one == "-r": - skip = True - block_number = int(sys.argv[2]) - block_start = 3 - elif one.startswith("-"): - print("runblock-python: only -r supported", file=sys.stderr) - sys.exit(100) - else: - block_number = int(one) - block_start = 2 - - execline_argv_no = int(os.getenvb(b"#")) - runblock_argv = [os.getenv(str(no)) for no in range(1, execline_argv_no + 1)] - - - def parse_block(args): - new_args = [] - if args == []: - print( - "runblock-python: empty block", - file=sys.stderr - ) - sys.exit(100) - for arg in args: - if arg == "": - break - elif arg.startswith(" "): - new_args.append(arg[1:]) - else: - print( - "runblock-python: unterminated block: {}".format(args), - file=sys.stderr - ) - sys.exit(100) - args_rest = args[len(new_args)+1:] - return (new_args, args_rest) - - - if skip: - rest = runblock_argv - for _ in range(0, block_number-1): - (_, rest) = parse_block(rest) - new_argv = rest - else: - new_argv = [] - rest = runblock_argv - for _ in range(0, block_number): - (new_argv, rest) = parse_block(rest) - - given_argv = sys.argv[block_start:] - run = given_argv + new_argv - if os.path.isabs(run[0]): - # TODO: ideally I’d check if it’s an executable here, but it was too hard to figure out and I couldn’t be bothered tbh - if not Path(run[0]).is_file(): - print( - "runblock-python: Executable {} does not exist or is not a file.".format(run[0]), - file=sys.stderr - ) - sys.exit(100) - os.execvp( - file=run[0], - args=run - ) - ''; - - -in -{ - inherit - nix-run - nix-run-bin - nix-eval - ; -} diff --git a/users/Profpatsch/omega.nix b/users/Profpatsch/omega.nix deleted file mode 100644 index 39d27628c..000000000 --- a/users/Profpatsch/omega.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ depot, pkgs, lib, ... }: -let - - # fix: https://github.com/NixOS/nixpkgs/pull/352144 - omega-templates = pkgs.stdenv.mkDerivation { - name = "omega-templates"; - phases = [ "unpackPhase" "installPhase" ]; - src = pkgs.xapian-omega.src; - installPhase = '' - mkdir -p $out/share/omega - mv templates $out/share/omega - ''; - }; - - omega-test = pkgs.stdenv.mkDerivation { - name = "omega-test"; - phases = [ "installPhase" ]; - installPhase = '' - mkdir localhost - ln -sT localhost localhost:8080 - mkdir ./default - cp -r ${lib.getOutput "doc" pkgs.tipidee}/share/doc/tipidee ./default/tipidee - cp -r ${lib.getOutput "doc" pkgs.tipidee}/share/doc/tipidee ./localhost/tipidee - - ln -sT ${pkgs.writers.writeText "omega.conf" '' - database_dir ./omega.db - log_dir /tmp/omega.log - template_dir ${omega-templates}/share/omega/templates - ''} omega.conf - - ${pkgs.tipidee}/bin/tipidee-config -o tipidee.cdb -i ${pkgs.writers.writeText "tipidee.conf" '' - domain localhost - cgi /omega - ''} - - cp ${pkgs.xapian-omega}/lib/xapian-omega/bin/omega ./localhost - - mkdir omega.db - ${pkgs.xapian-omega}/bin/omindex --db ./omega.db/default --url / ./default - - mkdir -p $out - cp -r ./* $out - ''; - }; - - run-omega = pkgs.writers.writeBash "run-omega" '' - cd ${omega-test} - emptyenv -p \ - ${pkgs.s6-networking}/bin/s6-tcpserver 127.0.0.1 8080 \ - ${pkgs.s6-networking}/bin/s6-tcpserver-access \ - ${pkgs.tipidee}/bin/tipideed -f tipidee.cdb - ''; - - -in -{ - inherit - run-omega - omega-test - ; -} - diff --git a/users/Profpatsch/openlab-tools/Main.hs b/users/Profpatsch/openlab-tools/Main.hs deleted file mode 100644 index d5f958a38..000000000 --- a/users/Profpatsch/openlab-tools/Main.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import OpenlabTools qualified - -main :: IO () -main = OpenlabTools.main diff --git a/users/Profpatsch/openlab-tools/default.nix b/users/Profpatsch/openlab-tools/default.nix deleted file mode 100644 index 0c5a70a9a..000000000 --- a/users/Profpatsch/openlab-tools/default.nix +++ /dev/null @@ -1,68 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - # bins = depot.nix.getBins pkgs.sqlite ["sqlite3"]; - - openlab-tools = pkgs.haskellPackages.mkDerivation { - pname = "openlab-tools"; - version = "0.1.0"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./openlab-tools.cabal - ./Main.hs - ./src/OpenlabTools.hs - ]; - - libraryHaskellDepends = [ - depot.users.Profpatsch.my-prelude - depot.users.Profpatsch.my-webstuff - pkgs.haskellPackages.pa-prelude - pkgs.haskellPackages.pa-label - pkgs.haskellPackages.pa-error-tree - pkgs.haskellPackages.pa-field-parser - pkgs.haskellPackages.pa-run-command - pkgs.haskellPackages.aeson-better-errors - pkgs.haskellPackages.blaze-html - pkgs.haskellPackages.deepseq - pkgs.haskellPackages.case-insensitive - pkgs.haskellPackages.hs-opentelemetry-sdk - pkgs.haskellPackages.http-conduit - pkgs.haskellPackages.http-types - pkgs.haskellPackages.ihp-hsx - pkgs.haskellPackages.monad-logger - pkgs.haskellPackages.selective - pkgs.haskellPackages.unliftio - pkgs.haskellPackages.wai-extra - pkgs.haskellPackages.warp - pkgs.haskellPackages.tagsoup - pkgs.haskellPackages.time - ]; - - isExecutable = true; - isLibrary = false; - license = lib.licenses.mit; - }; - - bins = depot.nix.getBins openlab-tools [ "openlab-tools" ]; - -in - -depot.nix.writeExecline "openlab-tools-wrapped" { } [ - "importas" - "-i" - "PATH" - "PATH" - "export" - "PATH" - "${pkgs.postgresql}/bin:$${PATH}" - "export" - "OPENLAB_TOOLS_TOOLS" - (pkgs.linkFarm "openlab-tools-tools" [ - { - name = "pg_format"; - path = "${pkgs.pgformatter}/bin/pg_format"; - } - ]) - bins.openlab-tools -] - diff --git a/users/Profpatsch/openlab-tools/openlab-tools.cabal b/users/Profpatsch/openlab-tools/openlab-tools.cabal deleted file mode 100644 index e8f7e8bc1..000000000 --- a/users/Profpatsch/openlab-tools/openlab-tools.cabal +++ /dev/null @@ -1,110 +0,0 @@ -cabal-version: 3.0 -name: openlab-tools -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - default-language: GHC2021 - - -library - import: common-options - - hs-source-dirs: src - - exposed-modules: - OpenlabTools - - build-depends: - base >=4.15 && <5, - text, - my-prelude, - my-webstuff, - pa-prelude, - pa-error-tree, - pa-label, - pa-field-parser, - pa-run-command, - aeson-better-errors, - aeson, - blaze-html, - bytestring, - containers, - deepseq, - unordered-containers, - exceptions, - filepath, - hs-opentelemetry-sdk, - hs-opentelemetry-api, - http-conduit, - http-types, - ihp-hsx, - monad-logger, - mtl, - network-uri, - scientific, - selective, - unliftio, - wai-extra, - wai, - warp, - tagsoup, - time, - stm, - case-insensitive - -executable openlab-tools - import: common-options - - main-is: Main.hs - - ghc-options: - -threaded - - build-depends: - base >=4.15 && <5, - openlab-tools diff --git a/users/Profpatsch/openlab-tools/src/OpenlabTools.hs b/users/Profpatsch/openlab-tools/src/OpenlabTools.hs deleted file mode 100644 index 7ba52c302..000000000 --- a/users/Profpatsch/openlab-tools/src/OpenlabTools.hs +++ /dev/null @@ -1,551 +0,0 @@ -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE ScopedTypeVariables #-} - -module OpenlabTools where - -import Control.Concurrent.STM hiding (atomically, readTVarIO) -import Control.DeepSeq (NFData, deepseq) -import Control.Monad.Logger qualified as Logger -import Control.Monad.Logger.CallStack -import Control.Monad.Reader -import Data.Aeson.BetterErrors qualified as Json -import Data.CaseInsensitive qualified as CaseInsensitive -import Data.Error.Tree -import Data.HashMap.Strict qualified as HashMap -import Data.List qualified as List -import Data.Maybe (listToMaybe) -import Data.Text qualified as Text -import Data.Time (NominalDiffTime, UTCTime (utctDayTime), diffUTCTime, getCurrentTime) -import Data.Time qualified as Time -import Data.Time.Clock (addUTCTime) -import Data.Time.Format qualified as Time.Format -import Debug.Trace -import FieldParser (FieldParser' (..)) -import FieldParser qualified as Field -import GHC.Records (HasField (..)) -import GHC.Stack qualified -import IHP.HSX.QQ (hsx) -import Json qualified -import Label -import Network.HTTP.Client.Conduit qualified as Http -import Network.HTTP.Simple qualified as Http -import Network.HTTP.Types -import Network.HTTP.Types qualified as Http -import Network.Wai qualified as Wai -import Network.Wai.Handler.Warp qualified as Warp -import Network.Wai.Parse qualified as Wai -import OpenTelemetry.Trace qualified as Otel hiding (getTracer, inSpan, inSpan') -import OpenTelemetry.Trace.Core qualified as Otel hiding (inSpan, inSpan') -import OpenTelemetry.Trace.Monad qualified as Otel -import Parse (Parse) -import Parse qualified -import PossehlAnalyticsPrelude -import Pretty -import System.Environment qualified as Env -import System.IO qualified as IO -import Text.Blaze.Html.Renderer.Pretty qualified as Html.Pretty -import Text.Blaze.Html.Renderer.Utf8 qualified as Html -import Text.Blaze.Html5 qualified as Html -import Text.HTML.TagSoup qualified as Soup -import UnliftIO hiding (Handler, newTVarIO) -import Prelude hiding (span, until) - -mapallSpaceOla :: Text -mapallSpaceOla = "https://mapall.space/heatmap/show.php?id=OpenLab+Augsburg" - -mainPage :: Html.Html -mainPage = - Html.docTypeHtml - [hsx| - - Openlab Augsburg Tools - - - - - -

    Welcome to the OpenLab Augsburg tools thingy. The idea is to provide some services that can be embedded into our other pages.

    - -

    What’s there

    -
    - - -

    Show me the code/how to contribute

    - -

    The source code can be found in my user dir in the tvl repo.

    - -

    To build the server, clone the repository from https://code.tvl.fyi/depot.git. - Then cd into users/Profpatsch, run nix-shell. -

    - -

    You can now run the server with cabal repl openlab-tools/` by executing the main function inside the GHC repl. It starts on port 9099. -
    - To try out changes to the code, stop the server with Ctrl+z and type :reload, then main again. -
    - Finally, from within users/Profpatsch you can start a working development environment by installing vscode or vscodium and the Haskell extension. Then run code . from within the directory. -

    - -

    Once you have a patch, contact me on Matrix or DM me at irc/libera, nick Profpatsch. -

    - - |] - -debug :: Bool -debug = False - -runApp :: IO () -runApp = withTracer $ \tracer -> do - let renderHtml = - if debug - then Html.Pretty.renderHtml >>> stringToText >>> textToBytesUtf8 >>> toLazyBytes - else Html.renderHtml - - let runApplication :: - (MonadUnliftIO m, MonadLogger m) => - ( Wai.Request -> - (Wai.Response -> m Wai.ResponseReceived) -> - m Wai.ResponseReceived - ) -> - m () - runApplication app = do - withRunInIO $ \runInIO -> Warp.run 9099 $ \req respond -> do - let catchAppException act = - try act >>= \case - Right a -> pure a - Left (AppException err) -> do - runInIO (logError err) - respond (Wai.responseLBS Http.status500 [] "") - liftIO $ catchAppException (runInIO $ app req (\resp -> liftIO $ respond resp)) - - let appT :: AppT IO () = do - let h extra res = Wai.responseLBS Http.ok200 (("Content-Type", "text/html") : extra) res - runHandlers - runApplication - [ Handler - { path = "", - body = - Body - (pure ()) - (\((), _) -> pure $ h [] (renderHtml mainPage)) - }, - Handler - { path = "snips/table-opening-hours-last-week", - body = - Body - ((label @"ifModifiedSince" <$> parseIfModifiedSince)) - ( \(req', cache) -> do - now <- liftIO getCurrentTime <&> mkSecondTime - new <- updateCacheIfNewer now cache heatmap - let cacheToHeaders = - [ ("Last-Modified", new.lastModified & formatHeaderTime), - ("Expires", new.until & formatHeaderTime), - ( "Cache-Control", - let maxAge = new.until `diffSecondTime` now - in [fmt|max-age={maxAge & floor @NominalDiffTime @Int & show}, immutable|] - ) - ] - if - -- If the last cache update is newer or equal to the requested version, we can tell the browser it’s fine - | Just modifiedSince <- req'.ifModifiedSince, - modifiedSince >= new.lastModified -> - pure $ Wai.responseLBS Http.status304 cacheToHeaders "" - | otherwise -> - pure $ h cacheToHeaders (new.result & toLazyBytes) - ) - } - ] - - runReaderT (appT :: AppT IO ()).unAppT Context {..} - where - -- "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified#syntax" - headerFormat = "%a, %d %b %0Y %T GMT" - formatHeaderTime (SecondTime t) = - t - & Time.Format.formatTime - @UTCTime - Time.Format.defaultTimeLocale - headerFormat - & stringToText - & textToBytesUtf8 - parseHeaderTime = - Field.utf8 - >>> ( FieldParser $ \t -> - t - & textToString - & Time.Format.parseTimeM - @Maybe - @UTCTime - {-no leading whitespace -} False - Time.Format.defaultTimeLocale - headerFormat - & annotate [fmt|Cannot parse header timestamp "{t}"|] - ) - parseIfModifiedSince :: Parse Wai.Request (Maybe SecondTime) - parseIfModifiedSince = - lmap - ( (.requestHeaders) - >>> findMaybe - ( \(h, v) -> - if "If-Modified-Since" == CaseInsensitive.mk h then Just v else Nothing - ) - ) - (Parse.maybe $ Parse.fieldParser parseHeaderTime) - & rmap (fmap mkSecondTime) - -parseRequest :: (MonadThrow f) => Otel.Span -> Parse from a -> from -> f a -parseRequest span parser req = - Parse.runParse "Unable to parse the HTTP request" parser req - & assertM span id - -heatmap :: AppT IO ByteString -heatmap = do - Http.httpBS [fmt|GET {mapallSpaceOla}|] - <&> (.responseBody) - <&> Soup.parseTags - <&> Soup.canonicalizeTags - <&> findHeatmap - <&> fromMaybe (htmlToTags [hsx|

    Uh oh! could not fetch the table from {mapallSpaceOla}

    |]) - <&> Soup.renderTags - where - firstSection f t = t & Soup.sections f & listToMaybe - match :: Soup.Tag ByteString -> Soup.Tag ByteString -> Bool - match x (t :: Soup.Tag ByteString) = (Soup.~==) @ByteString t x - findHeatmap t = - t - & firstSection (match (Soup.TagOpen ("") [("class", "heatmap")])) - >>= firstSection (match (Soup.TagOpen "table" [])) - <&> getTable - <&> (<> htmlToTags [hsx|
    source: mapall.space
    |]) - <&> wrapTagStream (T2 (label @"el" "figure") (label @"attrs" [])) - - -- get the table from opening tag to closing tag (allowing nested tables) - getTable = go 0 - where - go _ [] = [] - go d (el : els) - | match (Soup.TagOpen "table" []) el = el : go (d + 1) els - | match (Soup.TagClose "table") el = if d <= 1 then [el] else el : go (traceShowId $ d - 1) els - | otherwise = el : go d els - - htmlToTags :: Html.Html -> [Soup.Tag ByteString] - htmlToTags h = h & Html.renderHtml & toStrictBytes & Soup.parseTags - - -- TODO: this is dog-slow because of the whole list recreation! - wrapTagStream :: - T2 "el" ByteString "attrs" [Soup.Attribute ByteString] -> - [Soup.Tag ByteString] -> - [Soup.Tag ByteString] - wrapTagStream tag inner = (Soup.TagOpen (tag.el) tag.attrs : inner) <> [Soup.TagClose tag.el] - -main :: IO () -main = - runApp - --- ( do --- -- todo: trace that to the init functions as well --- Otel.inSpan "whatcd-resolver main function" Otel.defaultSpanArguments $ do --- _ <- runTransaction migrate --- htmlUi --- ) - -data Handler m = Handler - { path :: Text, - body :: Body m - } - -data Body m - = forall a. - Body - (Parse Wai.Request a) - ((a, TVar (Cache ByteString)) -> m Wai.Response) - -runHandlers :: - (Otel.MonadTracer m, MonadUnliftIO m, MonadThrow m) => - -- ( (Wai.Request -> (Wai.Response -> m Wai.ResponseReceived) -> m Wai.ResponseReceived) -> - -- m () - -- ) -> - ( (Wai.Request -> (Wai.Response -> m a) -> m a) -> - m () - ) -> - [Handler m] -> - m () -runHandlers runApplication handlers = do - withCaches :: - [ T2 - "handler" - (Handler m) - "cache" - (TVar (Cache ByteString)) - ] <- - handlers - & traverse - ( \h -> do - cache <- liftIO $ newCache h.path "nothing yet" - pure $ T2 (label @"handler" h) (label @"cache" cache) - ) - runApplication $ \req respond -> do - let mHandler = - withCaches - & List.find - ( \h -> - (h.handler.path) - == (req & Wai.pathInfo & Text.intercalate "/") - ) - case mHandler of - Nothing -> respond $ Wai.responseLBS Http.status404 [] "nothing here (yet)" - Just handler -> do - inSpan' "TODO" $ \span -> do - case handler.handler.body of - Body parse runHandler -> do - req' <- req & parseRequest span parse - resp <- runHandler (req', handler.cache) - respond resp - -inSpan :: (MonadUnliftIO m, Otel.MonadTracer m) => Text -> m a -> m a -inSpan name = Otel.inSpan name Otel.defaultSpanArguments - -inSpan' :: Text -> (Otel.Span -> m a) -> m a --- inSpan' name = Otel.inSpan' name Otel.defaultSpanArguments -inSpan' _name act = act (error "todo telemetry disabled") - -zipT2 :: - forall l1 l2 t1 t2. - ( HasField l1 (T2 l1 [t1] l2 [t2]) [t1], - HasField l2 (T2 l1 [t1] l2 [t2]) [t2] - ) => - T2 l1 [t1] l2 [t2] -> - [T2 l1 t1 l2 t2] -zipT2 xs = - zipWith - (\t1 t2 -> T2 (label @l1 t1) (label @l2 t2)) - (getField @l1 xs) - (getField @l2 xs) - -unzipT2 :: forall l1 t1 l2 t2. [T2 l1 t1 l2 t2] -> T2 l1 [t1] l2 [t2] -unzipT2 xs = xs <&> toTup & unzip & fromTup - where - toTup :: forall a b. T2 a t1 b t2 -> (t1, t2) - toTup (T2 a b) = (getField @a a, getField @b b) - fromTup :: (a, b) -> T2 l1 a l2 b - fromTup (t1, t2) = T2 (label @l1 t1) (label @l2 t2) - -unzipT3 :: forall l1 t1 l2 t2 l3 t3. [T3 l1 t1 l2 t2 l3 t3] -> T3 l1 [t1] l2 [t2] l3 [t3] -unzipT3 xs = xs <&> toTup & unzip3 & fromTup - where - toTup :: forall a b c. T3 a t1 b t2 c t3 -> (t1, t2, t3) - toTup (T3 a b c) = (getField @a a, getField @b b, getField @c c) - fromTup :: (a, b, c) -> T3 l1 a l2 b l3 c - fromTup (t1, t2, t3) = T3 (label @l1 t1) (label @l2 t2) (label @l3 t3) - -newtype Optional a = OptionalInternal (Maybe a) - -mkOptional :: a -> Optional a -mkOptional defaultValue = OptionalInternal $ Just defaultValue - -defaults :: Optional a -defaults = OptionalInternal Nothing - -instance HasField "withDefault" (Optional a) (a -> a) where - getField (OptionalInternal m) defaultValue = case m of - Nothing -> defaultValue - Just a -> a - -httpJson :: - ( MonadIO m, - MonadThrow m - ) => - (Optional (Label "contentType" ByteString)) -> - Otel.Span -> - Json.Parse ErrorTree b -> - Http.Request -> - m b -httpJson opts span parser req = do - let opts' = opts.withDefault (label @"contentType" "application/json") - Http.httpBS req - >>= assertM - span - ( \resp -> do - let statusCode = resp & Http.responseStatus & (.statusCode) - contentType = - resp - & Http.responseHeaders - & List.lookup "content-type" - <&> Wai.parseContentType - <&> (\(ct, _mimeAttributes) -> ct) - if - | statusCode == 200, - Just ct <- contentType, - ct == opts'.contentType -> - Right $ (resp & Http.responseBody) - | statusCode == 200, - Just otherType <- contentType -> - Left [fmt|Server returned a non-json body, with content-type "{otherType}"|] - | statusCode == 200, - Nothing <- contentType -> - Left [fmt|Server returned a body with unspecified content type|] - | code <- statusCode -> Left $ singleError [fmt|Server returned an non-200 error code, code {code}: {[pretty resp] & prettyErrsNoColor}|] - ) - >>= assertM - span - ( \body -> - Json.parseStrict parser body - & first (Json.parseErrorTree "could not parse redacted response") - ) - -assertM :: (MonadThrow f) => Otel.Span -> (t -> Either ErrorTree a) -> t -> f a -assertM span f v = case f v of - Right a -> pure a - Left err -> appThrowTree span err - --- | UTC time that is only specific to the second -newtype SecondTime = SecondTime {unSecondTime :: UTCTime} - deriving newtype (Show, Eq, Ord) - -mkSecondTime :: UTCTime -> SecondTime -mkSecondTime utcTime = SecondTime utcTime {utctDayTime = Time.secondsToDiffTime $ floor utcTime.utctDayTime} - -diffSecondTime :: SecondTime -> SecondTime -> NominalDiffTime -diffSecondTime (SecondTime a) (SecondTime b) = diffUTCTime a b - -data Cache a = Cache - { name :: !Text, - until :: !SecondTime, - lastModified :: !SecondTime, - result :: !a - } - deriving stock (Show) - -newCache :: Text -> a -> IO (TVar (Cache a)) -newCache name result = do - let until = mkSecondTime $ Time.UTCTime {utctDay = Time.ModifiedJulianDay 1, utctDayTime = 1} - let lastModified = until - newTVarIO $ Cache {..} - -updateCache :: (NFData a, Eq a) => SecondTime -> TVar (Cache a) -> a -> STM (Cache a) -updateCache now cache result' = do - -- make sure we don’t hold onto the world by deepseq-ing and evaluating to WHNF - let !result = deepseq result' result' - let until = mkSecondTime $ (5 * 60) `addUTCTime` now.unSecondTime - !toWrite <- do - old <- readTVar cache - let name = old.name - -- only update the lastModified time iff the content changed (this is helpful for HTTP caching with If-Modified-Since) - if old.result == result - then do - let lastModified = old.lastModified - pure $ Cache {..} - else do - let lastModified = now - pure $ Cache {..} - _ <- writeTVar cache $! toWrite - pure toWrite - --- | Run the given action iff the cache is stale, otherwise just return the item from the cache. -updateCacheIfNewer :: (MonadUnliftIO m, NFData b, Eq b) => SecondTime -> TVar (Cache b) -> m b -> m (Cache b) -updateCacheIfNewer now cache act = withRunInIO $ \runInIO -> do - old <- readTVarIO cache - if old.until < now - then do - res <- runInIO act - atomically $ updateCache now cache res - else pure old - --- pgFormat <- readTools (label @"toolsEnvVar" "OPENLAB_TOOLS_TOOLS") (readTool "pg_format") --- let config = label @"logDatabaseQueries" LogDatabaseQueries --- pgConnPool <- --- Pool.newPool $ --- Pool.defaultPoolConfig --- {- resource init action -} (Postgres.connectPostgreSQL (db & TmpPg.toConnectionString)) --- {- resource destruction -} Postgres.close --- {- unusedResourceOpenTime -} 10 --- {- max resources across all stripes -} 20 --- transmissionSessionId <- newEmptyMVar --- let newAppT = do --- logInfo [fmt|Running with config: {showPretty config}|] --- logInfo [fmt|Connected to database at {db & TmpPg.toDataDirectory} on socket {db & TmpPg.toConnectionString}|] --- appT --- runReaderT newAppT.unAppT Context {..} - -withTracer :: (Otel.Tracer -> IO c) -> IO c -withTracer f = do - setDefaultEnv "OTEL_SERVICE_NAME" "whatcd-resolver" - bracket - -- Install the SDK, pulling configuration from the environment - Otel.initializeGlobalTracerProvider - -- Ensure that any spans that haven't been exported yet are flushed - Otel.shutdownTracerProvider - -- Get a tracer so you can create spans - (\tracerProvider -> f $ Otel.makeTracer tracerProvider "whatcd-resolver" Otel.tracerOptions) - -setDefaultEnv :: String -> String -> IO () -setDefaultEnv envName defaultValue = do - Env.lookupEnv envName >>= \case - Just _env -> pure () - Nothing -> Env.setEnv envName defaultValue - -data Context = Context - { tracer :: Otel.Tracer - } - -newtype AppT m a = AppT {unAppT :: ReaderT Context m a} - deriving newtype (Functor, Applicative, Monad, MonadIO, MonadUnliftIO, MonadThrow) - -data AppException = AppException Text - deriving stock (Show) - deriving anyclass (Exception) - --- | A specialized variant of @addEvent@ that records attributes conforming to --- the OpenTelemetry specification's --- --- --- @since 0.0.1.0 -recordException :: - ( MonadIO m, - HasField "message" r Text, - HasField "type_" r Text - ) => - Otel.Span -> - r -> - m () -recordException span dat = liftIO $ do - callStack <- GHC.Stack.whoCreated dat.message - newEventTimestamp <- Just <$> Otel.getTimestamp - Otel.addEvent span $ - Otel.NewEvent - { newEventName = "exception", - newEventAttributes = - HashMap.fromList - [ ("exception.type", Otel.toAttribute @Text dat.type_), - ("exception.message", Otel.toAttribute @Text dat.message), - ("exception.stacktrace", Otel.toAttribute @Text $ Text.unlines $ map stringToText callStack) - ], - .. - } - -appThrowTree :: (MonadThrow m) => Otel.Span -> ErrorTree -> m a -appThrowTree _span exc = do - let msg = prettyErrorTree exc - -- recordException - -- span - -- ( T2 - -- (label @"type_" "AppException") - -- (label @"message" msg) - -- ) - throwM $ AppException msg - -orAppThrowTree :: (MonadThrow m) => Otel.Span -> Either ErrorTree a -> m a -orAppThrowTree span = \case - Left err -> appThrowTree span err - Right a -> pure a - -instance (MonadIO m) => MonadLogger (AppT m) where - monadLoggerLog loc src lvl msg = liftIO $ Logger.defaultOutput IO.stderr loc src lvl (Logger.toLogStr msg) - -instance (Monad m) => Otel.MonadTracer (AppT m) where - getTracer = AppT $ asks (.tracer) diff --git a/users/Profpatsch/package.json b/users/Profpatsch/package.json deleted file mode 100644 index 42bbc52eb..000000000 --- a/users/Profpatsch/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "profpatsch", - "version": "1.0.0", - "description": "Welcome, Welcome.", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "MIT", - "devDependencies": { - "@eslint/js": "^9.11.1", - "@types/eslint__js": "^8.42.3", - "@typescript-eslint/parser": "^8.8.0", - "eslint": "^9.11.1", - "typescript-eslint": "^8.8.0" - } -} diff --git a/users/Profpatsch/parked/ical-smolify/IcalSmolify.hs b/users/Profpatsch/parked/ical-smolify/IcalSmolify.hs deleted file mode 100644 index 77264d169..000000000 --- a/users/Profpatsch/parked/ical-smolify/IcalSmolify.hs +++ /dev/null @@ -1,124 +0,0 @@ -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE QuasiQuotes #-} -{-# OPTIONS_GHC -Wall #-} - -module Main where - -import qualified Data.ByteString.Lazy as Bytes.Lazy -import qualified Data.CaseInsensitive as CaseInsensitive -import qualified Data.Default as Default -import qualified Data.Map.Strict as Map -import qualified Data.Set as Set -import ExecHelpers (dieUserError, CurrentProgramName) -import MyPrelude -import qualified System.Environment as Env -import Text.ICalendar -import Prelude hiding (log) - -main :: IO () -main = do - Env.getArgs >>= \case - [] -> dieUserError progName "First argument must be the ics file name" - (file : _) -> - do - parse file - >>= traverse_ - ( \vcal -> - vcal - & stripSingleTimezone - & minify - & printICalendar Default.def - & Bytes.Lazy.putStr - ) - -progName :: CurrentProgramName -progName = "ical-smolify" - -log :: Error -> IO () -log err = do - putStderrLn (errorContext "ical-smolify" err & prettyError) - -parse :: FilePath -> IO [VCalendar] -parse file = do - parseICalendarFile Default.def file >>= \case - Left err -> do - dieUserError progName [fmt|Cannot parse ical file: {err}|] - Right (cals, warnings) -> do - for_ warnings (\warn -> log [fmt|Warning: {warn}|]) - pure cals - --- | Converts a single timezone definition to the corresponding X-WR-Timezone field. -stripSingleTimezone :: VCalendar -> VCalendar -stripSingleTimezone vcal = - case vcal & vcTimeZones & Map.toList of - [] -> vcal - [(_, tz)] -> do - let xtz = - OtherProperty - { otherName = CaseInsensitive.mk "X-WR-TIMEZONE", - otherValue = tz & vtzId & tzidValue & textToBytesUtf8Lazy, - otherParams = OtherParams Set.empty - } - vcal - { vcOther = - vcal & vcOther - -- remove any existing x-wr-timezone fields - & Set.filter (\prop -> (prop & otherName) /= (xtz & otherName)) - & Set.insert xtz, - vcTimeZones = Map.empty - } - _more -> vcal - --- | Minify the vcalendar event by throwing away everything that’s not an event. -minify :: VCalendar -> VCalendar -minify vcal = - vcal - { vcProdId = ProdId "" (OtherParams Set.empty), - -- , vcVersion :: ICalVersion - -- , vcScale :: Scale - -- , vcMethod :: Maybe Method - -- , vcOther :: … - -- , vcTimeZones :: Map Text VTimeZone - vcEvents = Map.map minifyEvent (vcal & vcEvents), - vcTodos = Map.empty, - vcJournals = Map.empty, - vcFreeBusys = Map.empty, - vcOtherComps = Set.empty - } - -minifyEvent :: VEvent -> VEvent -minifyEvent vev = - vev --- { veDTStamp :: DTStamp --- , veUID :: UID --- , veClass :: Class -- ^ 'def' = 'Public' --- , veDTStart :: Maybe DTStart --- , veCreated :: Maybe Created --- , veDescription :: Maybe Description --- , veGeo :: Maybe Geo --- , veLastMod :: Maybe LastModified --- , veLocation :: Maybe Location --- , veOrganizer :: Maybe Organizer --- , vePriority :: Priority -- ^ 'def' = 0 --- , veSeq :: Sequence -- ^ 'def' = 0 --- , veStatus :: Maybe EventStatus --- , veSummary :: Maybe Summary --- , veTransp :: TimeTransparency -- ^ 'def' = 'Opaque' --- , veUrl :: Maybe URL --- , veRecurId :: Maybe RecurrenceId --- , veRRule :: Set RRule --- , veDTEndDuration :: Maybe (Either DTEnd DurationProp) --- , veAttach :: Set Attachment --- , veAttendee :: Set Attendee --- , veCategories :: Set Categories --- , veComment :: Set Comment --- , veContact :: Set Contact --- , veExDate :: Set ExDate --- , veRStatus :: Set RequestStatus --- , veRelated :: Set RelatedTo --- , veResources :: Set Resources --- , veRDate :: Set RDate --- , veAlarms :: Set VAlarm --- , veOther :: Set OtherProperty --- } diff --git a/users/Profpatsch/parked/ical-smolify/README.md b/users/Profpatsch/parked/ical-smolify/README.md deleted file mode 100644 index 86c166d3c..000000000 --- a/users/Profpatsch/parked/ical-smolify/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# ical-smolify - -Ensmallen an `ical` by stripping out redundant information like timezone definitions. - -The idea here was that after running through this preprocessor, it fits into a QR code (~2000bits) that can be scanned with your phone (for automatically adding to mobile calendar). diff --git a/users/Profpatsch/parked/ical-smolify/default.nix.inactive b/users/Profpatsch/parked/ical-smolify/default.nix.inactive deleted file mode 100644 index bf766db0e..000000000 --- a/users/Profpatsch/parked/ical-smolify/default.nix.inactive +++ /dev/null @@ -1,23 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - ical-smolify = pkgs.writers.writeHaskell "ical-smolify" - { - libraries = [ - pkgs.haskellPackages.iCalendar - depot.users.Profpatsch.my-prelude - depot.users.Profpatsch.execline.exec-helpers-hs - - ]; - ghcArgs = [ "-threaded" ]; - } ./IcalSmolify.hs; - -in - -ical-smolify.overrideAttrs (old: { - meta = lib.recursiveUpdate old.meta or { } { - # Dependency iCalendar no longer builds in nixpkgs due to a lack of maintenance upstream - # https://github.com/nixos/nixpkgs/commit/13d10cc6e302e7d5800c6a08c1728b14c3801e26 - ci.skip = true; - }; -}) diff --git a/users/Profpatsch/parked/ical-smolify/ical-smolify.cabal b/users/Profpatsch/parked/ical-smolify/ical-smolify.cabal deleted file mode 100644 index d7a46c581..000000000 --- a/users/Profpatsch/parked/ical-smolify/ical-smolify.cabal +++ /dev/null @@ -1,18 +0,0 @@ -cabal-version: 3.0 -name: ical-smolify -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -executable ical-smolify - main-is: IcalSmolify.hs - - build-depends: - base >=4.15 && <5, - my-prelude, - exec-helpers - data-default - case-insensitive - iCalendar - - default-language: Haskell2010 diff --git a/users/Profpatsch/parked/mailbox-org/MailboxOrg.hs b/users/Profpatsch/parked/mailbox-org/MailboxOrg.hs deleted file mode 100644 index 6c5820080..000000000 --- a/users/Profpatsch/parked/mailbox-org/MailboxOrg.hs +++ /dev/null @@ -1,523 +0,0 @@ -{-# LANGUAGE ApplicativeDo #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE DerivingVia #-} -{-# LANGUAGE GHC2021 #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedRecordDot #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE PackageImports #-} -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE NoFieldSelectors #-} -{-# OPTIONS_GHC -Wall #-} - -module Main where - -import Aeson (parseErrorTree) -import AesonQQ (aesonQQ) -import ArglibNetencode -import Control.Exception (try) -import Control.Monad (replicateM) -import Data.Aeson qualified as Json -import Data.Aeson.BetterErrors qualified as Json -import Data.Aeson.KeyMap qualified as KeyMap -import Data.ByteString qualified as ByteString -import Data.ByteString.Lazy qualified as Lazy -import Data.Char qualified as Char -import "pa-error-tree" Data.Error.Tree -import Data.Functor.Compose -import Data.List qualified as List -import Data.Map.Strict qualified as Map -import Data.Text qualified as Text -import ExecHelpers -import Label -import Netencode qualified -import Netencode.Parse qualified as NetParse -import Network.HTTP.Conduit qualified as Client -import Network.HTTP.Simple qualified as Client -import PossehlAnalyticsPrelude -import Pretty -import System.Directory qualified as File -import System.Environment qualified as Env -import System.Exit (ExitCode (ExitFailure, ExitSuccess)) -import System.Exit qualified as Exit -import System.FilePath (()) -import System.Process.Typed qualified as Process -import System.Random qualified as Random -import System.Random.Stateful qualified as Random -import Prelude hiding (log) - -secret :: Tools -> IO (T2 "email" ByteString "password" ByteString) -secret tools = do - T2 - (label @"email" "mail@profpatsch.de") - <$> (label @"password" <$> fromPass "email/mailbox.org") - where - fromPass name = - tools.pass & runToolExpect0 [name] - -progName :: CurrentProgramName -progName = "mailbox-org" - -log :: Error -> IO () -log err = do - putStderrLn (errorContext progName.unCurrentProgramName err & prettyError) - -data Tools = Tools - { pass :: Tool - } - deriving stock (Show) - -newtype Tool = Tool {unTool :: FilePath} - deriving stock (Show) - -parseTools :: Applicative m => (Text -> m (Either Error Tool)) -> m (Either ErrorTree Tools) -parseTools getTool = do - let parser = - ( do - pass <- get "pass" - pure Tools {..} - ) - parser & finalize - where - get name = name & getTool <&> eitherToListValidation & Compose - finalize p = - p.getCompose - <&> first (errorTree "Error reading tools") - <&> validationToEither - -main :: IO () -main = - arglibNetencode progName Nothing - >>= parseToolsArglib - >>= secret - >>= run applyFilters - -run :: - ( HasField "email" dat ByteString, - HasField "password" dat ByteString - ) => - (Session -> IO ()) -> - dat -> - IO () -run act loginData = do - session <- login loginData - act session - -listFilterConfig :: Session -> IO () -listFilterConfig session = do - mailfilter - session - "config" - mempty - (Json.key "data" Json.asObject) - () - >>= printPretty - -applyFilterRule :: - (HasField "folderId" dat Text) => - dat -> - Session -> - IO () -applyFilterRule dat session = do - mailfilter - session - "apply" - ( T2 - (label @"extraQueryParams" [("folderId", Just (dat.folderId & textToBytesUtf8))]) - mempty - ) - (Json.key "data" Json.asArray >> pure ()) - (Json.Object mempty) - -data FilterRule = FilterRule - { actioncmds :: NonEmpty Json.Object, - test :: NonEmpty Json.Object - } - -data MailfilterList = MailfilterList - { id_ :: Json.Value, - rulename :: Text - } - deriving stock (Show, Eq) - -simpleRule :: - ( HasField "rulename" r Text, - HasField "id" r Natural, - HasField "emailContains" r Text, - HasField "subjectStartsWith" r Text - ) => - r -> - Json.Value -simpleRule dat = do - [aesonQQ|{ - "id": |dat.id & enc @Natural|, - "position": 3, - "rulename": |dat.rulename & enc @Text|, - "active": true, - "flags": [], - "test": { - "id": "allof", - "tests": [ - { - "id": "from", - "comparison": "contains", - "values": [ - |dat.emailContains & enc @Text| - ] - }, - { - "id": "subject", - "comparison": "startswith", - "values": [ - |dat.subjectStartsWith & enc @Text| - ] - } - ] - }, - "actioncmds": [ - { - "id": "move", - "into": "default0/Archive" - }, - { - "id": "stop" - } - ] - }|] - where - enc :: forall a. Json.ToJSON a => a -> Lazy.ByteString - enc val = val & Json.toJSON & Json.encode - -applyFilters :: Session -> IO () -applyFilters session = do - filters <- - mailfilter - session - "list" - mempty - ( Json.key "data" $ do - ( Json.eachInArray $ asDat @"mailfilter" $ do - id_ <- Json.key "id" Json.asValue - rulename <- Json.key "rulename" Json.asText - pure MailfilterList {..} - ) - <&> mapFromListOn (\dat -> getLabel @"rulename" dat.parsed) - ) - ([] :: [()]) - let goal = Map.fromList [(label @"rulename" "another", 32 :: Integer), (label @"rulename" "xyz", 23)] - let actions = declarativeUpdate goal filters - log [fmt|To * create: {actions.toCreate & Map.keys & show}, * update: {actions.toUpdate & Map.keys & show}, * delete: {actions.toDelete & Map.keys & show}|] - --- where --- filters --- & Map.elems --- & traverse_ --- ( updateIfDifferent --- session --- ( \el -> --- pure $ --- el.original.mailfilter --- & KeyMap.insert "active" (Json.Bool False) --- ) --- (pure ()) --- ) - --- updateIfDifferent :: --- forall label parsed. --- ( HasField "id_" parsed Json.Value, --- HasField "rulename" parsed Text --- ) => --- Session -> --- (Dat label Json.Object parsed -> IO Json.Object) -> --- Json.Parse Error () -> --- Dat label Json.Object parsed -> --- IO () --- updateIfDifferent session switcheroo parser dat = do --- new <- switcheroo dat --- if new /= getField @label dat.original --- then do --- log [fmt|Updating filter "{dat.parsed.rulename}" (id {dat.parsed.id_ & show @Json.Value})|] --- mailfilter --- session --- "update" --- mempty --- parser --- new --- else do --- log [fmt|Skipping updating filter "{dat.parsed.rulename}" (id {dat.parsed.id_ & show @Json.Value}) because nothing changed.|] - --- | https://oxpedia.org/wiki/index.php?title=HTTP_API_MailFilter -mailfilter :: - ( Json.ToJSON a, - Show b - ) => - Session -> - ByteString -> - T2 - "extraQueryParams" - Client.Query - "httpMethod" - (Maybe ByteString) -> - Json.Parse Error b -> - a -> - IO b -mailfilter session action opts parser body = do - req <- - Client.parseRequest "https://office.mailbox.org/appsuite/api/mailfilter/v2" - <&> Client.setQueryString - ( [ ("action", Just action), - ("colums", Just "1") - ] - <> opts.extraQueryParams - ) - <&> Client.setRequestMethod (opts.httpMethod & fromMaybe "PUT") - <&> Client.setRequestBodyJSON body - <&> addSession session - req - & httpJSON [fmt|Cannot parse result for {req & prettyRequestShort}|] parser - >>= okOrDie - -- >>= (\resp -> printPretty resp >> pure resp) - <&> Client.responseBody - where - prettyRequestShort :: Client.Request -> Text - prettyRequestShort req = [fmt|request {req & Client.method}: {req & Client.host}{req & Client.path}{req & Client.queryString}|] - --- | Given a goal and the actual state, return which elements to delete, update and create. -declarativeUpdate :: - Ord k => - -- | goal map - Map k a -> - -- | actual map - Map k b -> - T3 - "toCreate" - (Map k a) - "toDelete" - (Map k b) - "toUpdate" - (Map k a) -declarativeUpdate goal actual = - T3 - (label @"toCreate" $ goal `Map.difference` actual) - (label @"toDelete" $ actual `Map.difference` goal) - (label @"toUpdate" $ goal `Map.intersection` actual) - -newtype Session = Session Client.CookieJar - -httpJSON :: - Error -> - Json.Parse Error b -> - Client.Request -> - IO (Client.Response b) -httpJSON errMsg parser req = do - req - & Client.httpJSON @_ @Json.Value - >>= traverse - ( \val -> do - case val of - Json.Object obj - | "error" `KeyMap.member` obj - && "error_desc" `KeyMap.member` obj -> do - printPretty obj - diePanic' "Server returned above inline error" - _ -> pure () - val & Json.parseValue parser & \case - Left errs -> - errs - & parseErrorTree errMsg - & diePanic' - Right a -> pure a - ) - -data Dat label orig parsed = Dat - { original :: Label label orig, - parsed :: parsed - } - deriving stock (Show, Eq) - -asDat :: - forall label err m a. - Monad m => - Json.ParseT err m a -> - Json.ParseT err m (Dat label Json.Object a) -asDat parser = do - original <- label @label <$> Json.asObject - parsed <- parser - pure Dat {..} - -addSession :: Session -> Client.Request -> Client.Request -addSession (Session jar) req = do - let sessionId = - jar - & Client.destroyCookieJar - & List.find (\c -> "open-xchange-session-" `ByteString.isPrefixOf` c.cookie_name) - & annotate "The cookie jar did not contain an open-exchange-session-*" - & unwrapError - & (.cookie_value) - - let req' = req & Client.addToRequestQueryString [("session", Just sessionId)] - req' {Client.cookieJar = Just jar} - --- | Log into the mailbox.org service, and return the session secret cookies. -login :: (HasField "email" dat ByteString, HasField "password" dat ByteString) => dat -> IO Session -login dat = do - rnd <- randomString - req <- - Client.parseRequest "https://office.mailbox.org/ajax/login" - <&> Client.setQueryString - [ ("action", Just "formlogin"), - ("authId", Just $ ("mbo-" <> rnd) & stringToText & textToBytesUtf8) - ] - <&> Client.urlEncodedBody - [ ("version", "Form+Login"), - ("autologin", "true"), - ("client", "open-xchange-appsuite"), - ("uiWebPath", "/appsuite/"), - ("login", dat.email), - ("password", dat.password) - ] - Client.httpNoBody req - >>= okOrDie - <&> Client.responseCookieJar - <&> Session - where - -- For some reason they want the client to pass a random string - -- which is used for the session?‽!? - randomString = do - gen <- Random.newIOGenM =<< Random.newStdGen - let chars = ['a' .. 'z'] <> ['A' .. 'Z'] <> ['0' .. '9'] - let len = 11 - Random.uniformRM (0, List.length chars - 1) gen - & replicateM len - <&> map (\index -> chars !! index) - -okOrDie :: Show a => Client.Response a -> IO (Client.Response a) -okOrDie resp = - case resp & Client.getResponseStatusCode of - 200 -> pure resp - _ -> do - printPretty resp - diePanic' "non-200 result" - -diePanic' :: ErrorTree -> IO a -diePanic' errs = errs & prettyErrorTree & diePanic progName - --- | Parse the tools from the given arglib input, and check that the executables exist -parseToolsArglib :: Netencode.T -> IO Tools -parseToolsArglib t = do - let oneTool name = - NetParse.asText - <&> textToString - <&> ( \path -> - path - & File.getPermissions - <&> File.executable - <&> ( \case - False -> Left $ [fmt|Tool "{name}" is not an executable|] - True -> Right (Tool path) - ) - ) - let allTools = - parseTools (\name -> Compose $ NetParse.key name >>> oneTool name) - & getCompose - t - & NetParse.runParse - "test" - -- TODO: a proper ParseT for netencode values - ( NetParse.asRecord - >>> NetParse.key "BINS" - >>> NetParse.asRecord - >>> allTools - ) - & orDo diePanic' - & join @IO - >>= orDo (\errs -> errs & diePanic') - --- | Just assume the tools exist by name in the environment. -parseToolsToolname :: IO Tools -parseToolsToolname = - parseTools - ( \name -> - checkInPath name <&> \case - False -> Left [fmt|"Cannot find "{name}" in PATH|] - True -> Right $ Tool (name & textToString) - ) - >>= orDo diePanic' - -checkInPath :: Text -> IO Bool -checkInPath name = do - Env.lookupEnv "PATH" - <&> annotate "No PATH set" - >>= orDo diePanic' - <&> stringToText - <&> Text.split (== ':') - <&> filter (/= "") - >>= traverse - ( \p -> - File.getPermissions ((textToString p) (textToString name)) - <&> File.executable - & try @IOError - >>= \case - Left _ioError -> pure False - Right isExe -> pure isExe - ) - <&> or - -orDo :: Applicative f => (t -> f a) -> Either t a -> f a -orDo f = \case - Left e -> f e - Right a -> pure a - -runTool :: [Text] -> Tool -> IO (Exit.ExitCode, ByteString) -runTool args tool = do - let bashArgs = prettyArgsForBash ((tool.unTool & stringToText) : args) - log [fmt|Running: $ {bashArgs}|] - Process.proc - tool.unTool - (args <&> textToString) - & Process.readProcessStdout - <&> second toStrictBytes - <&> second stripWhitespaceFromEnd - --- | Like `runCommandExpect0`, run the given tool, given a tool accessor. -runToolExpect0 :: [Text] -> Tool -> IO ByteString -runToolExpect0 args tool = - tool & runTool args >>= \(ex, stdout) -> do - checkStatus0 tool.unTool ex - pure stdout - --- | Check whether a command exited 0 or crash. -checkStatus0 :: FilePath -> ExitCode -> IO () -checkStatus0 executable = \case - ExitSuccess -> pure () - ExitFailure status -> do - diePanic' [fmt|Command `{executable}` did not exit with status 0 (success), but status {status}|] - -stripWhitespaceFromEnd :: ByteString -> ByteString -stripWhitespaceFromEnd = ByteString.reverse . ByteString.dropWhile (\w -> w == charToWordUnsafe '\n') . ByteString.reverse - --- | Pretty print a command line in a way that can be copied to bash. -prettyArgsForBash :: [Text] -> Text -prettyArgsForBash = Text.intercalate " " . map simpleBashEscape - --- | Simple escaping for bash words. If they contain anything that’s not ascii chars --- and a bunch of often-used special characters, put the word in single quotes. -simpleBashEscape :: Text -> Text -simpleBashEscape t = do - case Text.find (not . isSimple) t of - Just _ -> escapeSingleQuote t - Nothing -> t - where - -- any word that is just ascii characters is simple (no spaces or control characters) - -- or contains a few often-used characters like - or . - isSimple c = - Char.isAsciiLower c - || Char.isAsciiUpper c - || Char.isDigit c - -- These are benign, bash will not interpret them as special characters. - || List.elem c ['-', '.', ':', '/'] - -- Put the word in single quotes - -- If there is a single quote in the word, - -- close the single quoted word, add a single quote, open the word again - escapeSingleQuote t' = "'" <> Text.replace "'" "'\\''" t' <> "'" diff --git a/users/Profpatsch/parked/mailbox-org/README.md b/users/Profpatsch/parked/mailbox-org/README.md deleted file mode 100644 index b84e7b59c..000000000 --- a/users/Profpatsch/parked/mailbox-org/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# mailbox-org - -Interfacing with the API of [https://mailbox.org/](). - -They use [open-xchange](https://www.open-xchange.com/resources/oxpedia) as their App Suite, so we have to work with/reverse engineer their weird API. - -Intended so I have a way of uploading Sieve rules into their system semi-automatically. diff --git a/users/Profpatsch/parked/mailbox-org/default.nix.inactive b/users/Profpatsch/parked/mailbox-org/default.nix.inactive deleted file mode 100644 index 73bd28292..000000000 --- a/users/Profpatsch/parked/mailbox-org/default.nix.inactive +++ /dev/null @@ -1,38 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - mailbox-org = pkgs.haskellPackages.mkDerivation { - pname = "mailbox-org"; - version = "0.1.0"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./mailbox-org.cabal - ./src/AesonQQ.hs - ./MailboxOrg.hs - ]; - - libraryHaskellDepends = [ - depot.users.Profpatsch.my-prelude - depot.users.Profpatsch.execline.exec-helpers-hs - depot.users.Profpatsch.arglib.netencode.haskell - pkgs.haskellPackages.pa-prelude - pkgs.haskellPackages.pa-label - pkgs.haskellPackages.pa-error-tree - pkgs.haskellPackages.aeson - pkgs.haskellPackages.http-conduit - pkgs.haskellPackages.aeson-better-errors - ]; - - isLibrary = false; - isExecutable = true; - license = lib.licenses.mit; - }; - - -in -lib.pipe mailbox-org [ - (x: (depot.nix.getBins x [ "mailbox-org" ]).mailbox-org) - (depot.users.Profpatsch.arglib.netencode.with-args "mailbox-org" { - BINS = depot.nix.getBins pkgs.dovecot_pigeonhole [ "sieve-test" ]; - }) -] diff --git a/users/Profpatsch/parked/mailbox-org/mailbox-org.cabal b/users/Profpatsch/parked/mailbox-org/mailbox-org.cabal deleted file mode 100644 index a1b041447..000000000 --- a/users/Profpatsch/parked/mailbox-org/mailbox-org.cabal +++ /dev/null @@ -1,95 +0,0 @@ -cabal-version: 3.0 -name: mailbox-org -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - default-language: GHC2021 - - -library - import: common-options - - hs-source-dirs: src - - exposed-modules: - AesonQQ - - build-depends: - base >=4.15 && <5, - pa-prelude, - aeson, - PyF, - template-haskell - - - -executable mailbox-org - import: common-options - main-is: MailboxOrg.hs - - build-depends: - base >=4.15 && <5, - mailbox-org, - my-prelude, - pa-prelude, - pa-label, - pa-error-tree, - exec-helpers, - netencode, - text, - directory, - filepath, - arglib-netencode, - random, - http-conduit, - aeson, - aeson-better-errors, - bytestring, - typed-process, - containers, diff --git a/users/Profpatsch/parked/mailbox-org/src/AesonQQ.hs b/users/Profpatsch/parked/mailbox-org/src/AesonQQ.hs deleted file mode 100644 index 2ac3d533a..000000000 --- a/users/Profpatsch/parked/mailbox-org/src/AesonQQ.hs +++ /dev/null @@ -1,24 +0,0 @@ -{-# LANGUAGE TemplateHaskellQuotes #-} - -module AesonQQ where - -import Data.Aeson qualified as Json -import Language.Haskell.TH.Quote (QuasiQuoter) -import PossehlAnalyticsPrelude -import PyF qualified -import PyF.Internal.QQ qualified as PyFConf - -aesonQQ :: QuasiQuoter -aesonQQ = - PyF.mkFormatter - "aesonQQ" - PyF.defaultConfig - { PyFConf.delimiters = Just ('|', '|'), - PyFConf.postProcess = \exp_ -> do - -- TODO: this does not throw an error at compilation time if the json does not parse - [| - case Json.eitherDecodeStrict' @Json.Value $ textToBytesUtf8 $ stringToText $(exp_) of - Left err -> error err - Right a -> a - |] - } diff --git a/users/Profpatsch/parked/reverse-haskell-deps/README.md b/users/Profpatsch/parked/reverse-haskell-deps/README.md deleted file mode 100644 index efc288cae..000000000 --- a/users/Profpatsch/parked/reverse-haskell-deps/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# reverse-haskell-deps - -Parse the HTML at `https://packdeps.haskellers.com/reverse` to get the data about Haskell package reverse dependencies in a structured way (they should just expose that as a json tbh). diff --git a/users/Profpatsch/parked/reverse-haskell-deps/ReverseHaskellDeps.hs b/users/Profpatsch/parked/reverse-haskell-deps/ReverseHaskellDeps.hs deleted file mode 100644 index 0e18ce8a6..000000000 --- a/users/Profpatsch/parked/reverse-haskell-deps/ReverseHaskellDeps.hs +++ /dev/null @@ -1,76 +0,0 @@ -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE MultiWayIf #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} - -module Main where - -import Data.ByteString qualified as ByteString -import Data.Either -import Data.List qualified as List -import Data.Maybe -import Data.Text (Text) -import Data.Text qualified as Text -import Data.Text.Encoding qualified -import MyPrelude -import Numeric.Natural -import Text.HTML.TagSoup qualified as Tag -import Text.Nicify -import Text.Read qualified as Read - -parseNat :: Text -> Maybe Natural -parseNat = Read.readMaybe . textToString - -printNice :: Show a => a -> IO () -printNice = putStrLn . nicify . show - -type Tag = Tag.Tag Text - -main = do - reverseHtml <- readStdinUtf8 - printNice $ List.sortOn snd $ packagesAndReverseDeps reverseHtml - where - readStdinUtf8 = bytesToTextUtf8Lenient <$> ByteString.getContents - --- | reads the table provided by https://packdeps.haskellers.com/reverse --- figuring out all sections (starting with the link to the package name), --- then figuring out the name of the package and the first column, --- which is the number of reverse dependencies of the package -packagesAndReverseDeps :: Text -> [(Text, Natural)] -packagesAndReverseDeps reverseHtml = do - let tags = Tag.parseTags reverseHtml - let sections = Tag.partitions (isJust . reverseLink) tags - let sectionName [] = "" - sectionName (sect : _) = sect & reverseLink & fromMaybe "" - let sectionNames = map sectionName sections - mapMaybe - ( \(name :: Text, sect) -> do - reverseDeps <- firstNaturalNumber sect - pure (sectionPackageName name sect, reverseDeps) :: Maybe (Text, Natural) - ) - $ zip sectionNames sections - where - reverseLink = \case - Tag.TagOpen "a" attrs -> findMaybe attrReverseLink attrs - _ -> Nothing - - attrReverseLink = \case - ("href", lnk) -> - if - | "packdeps.haskellers.com/reverse/" `Text.isInfixOf` lnk -> Just lnk - | otherwise -> Nothing - _ -> Nothing - - sectionPackageName :: Text -> [Tag] -> Text - sectionPackageName sectionName = \case - (_ : Tag.TagText name : _) -> name - (_ : el : _) -> sectionName - xs -> sectionName - - firstNaturalNumber :: [Tag] -> Maybe Natural - firstNaturalNumber = - findMaybe - ( \case - Tag.TagText t -> parseNat t - _ -> Nothing - ) diff --git a/users/Profpatsch/parked/reverse-haskell-deps/default.nix.inactive b/users/Profpatsch/parked/reverse-haskell-deps/default.nix.inactive deleted file mode 100644 index b0a44420d..000000000 --- a/users/Profpatsch/parked/reverse-haskell-deps/default.nix.inactive +++ /dev/null @@ -1,32 +0,0 @@ -{ depot, pkgs, ... }: - -# Parses https://packdeps.haskellers.com/reverse -# and outputs the amount of reverse dependencies of each hackage package. - -let - - rev = depot.nix.writeExecline "reverse-haskell-deps" { } [ - "pipeline" - [ - "${pkgs.curl}/bin/curl" - "-L" - "https://packdeps.haskellers.com/reverse" - ] - rev-hs - - ]; - - rev-hs = pkgs.writers.writeHaskell "revers-haskell-deps-hs" - { - libraries = [ - depot.users.Profpatsch.my-prelude - pkgs.haskellPackages.nicify-lib - pkgs.haskellPackages.tagsoup - ]; - ghcArgs = [ "-threaded" ]; - } - ./ReverseHaskellDeps.hs; - - -in -rev diff --git a/users/Profpatsch/parked/reverse-haskell-deps/reverse-haskell-deps.cabal b/users/Profpatsch/parked/reverse-haskell-deps/reverse-haskell-deps.cabal deleted file mode 100644 index 4792f52ad..000000000 --- a/users/Profpatsch/parked/reverse-haskell-deps/reverse-haskell-deps.cabal +++ /dev/null @@ -1,16 +0,0 @@ -cabal-version: 3.0 -name: reverse-haskell-deps -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -library - exposed-modules: ReverseHaskellDeps.hs - - build-depends: - base >=4.15 && <5, - my-prelude, - tagsoup, - nicify-lib - - default-language: Haskell2010 diff --git a/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/README.md b/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/README.md deleted file mode 100644 index e0a6aa2fb..000000000 --- a/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# sync-abfall-ics-aichach-friedberg - -A small tool to sync the ICS files for the local trash collection times at https://abfallwirtschaft.lra-aic-fdb.de/ diff --git a/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/default.nix.inactive b/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/default.nix.inactive deleted file mode 100644 index 739274cb6..000000000 --- a/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/default.nix.inactive +++ /dev/null @@ -1,31 +0,0 @@ -{ depot, pkgs, ... }: - -let - sync-to-dir = depot.users.Profpatsch.writers.python3 - { - name = "sync-ics-to-dir"; - libraries = (py: [ - py.httpx - py.icalendar - ]); - } ./sync-ics-to-dir.py; - - config = - depot.users.Profpatsch.importDhall.importDhall - { - root = ./..; - files = [ - "sync-abfall-ics-aichach-friedberg/ics-to-caldav.dhall" - "dhall/lib.dhall" - "ini/ini.dhall" - ]; - main = "sync-abfall-ics-aichach-friedberg/ics-to-caldav.dhall"; - deps = [ - ]; - } - depot.users.Profpatsch.ini.externs; - - - -in -{ inherit config; } diff --git a/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/ics-to-caldav.dhall b/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/ics-to-caldav.dhall deleted file mode 100644 index 2a7ac8497..000000000 --- a/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/ics-to-caldav.dhall +++ /dev/null @@ -1,139 +0,0 @@ -let Ini = ../ini/ini.dhall - -let Lib = ../dhall/lib.dhall - -in \(Ini/externs : Ini.Externs) -> - let Vdirsyncer = - let StorageType = - < FileSystem : { path : Text, fileext : < ICS > } - | Http : { url : Text } - > - - let Collection = < FromA | FromB | Collection : Text > - - let Collections = - < Unspecified | TheseCollections : List Collection > - - let Storage = { storageName : Text, storage : StorageType } - - in { Storage - , StorageType - , Collection - , Collections - , Pair = - { pairName : Text - , a : Storage - , b : Storage - , collections : Collections - } - } - - let toIniSections - : Vdirsyncer.Pair -> Ini.Sections - = \(pair : Vdirsyncer.Pair) -> - let - -- we assume the names are [a-zA-Z_] - renderList = - \(l : List Text) -> - "[" - ++ Lib.Text/concatMapSep - ", " - Text - (\(t : Text) -> "\"${t}\"") - l - ++ "]" - - in let nv = \(name : Text) -> \(value : Text) -> { name, value } - - let mkStorage = - \(storage : Vdirsyncer.Storage) -> - { name = "storage ${storage.storageName}" - , value = - merge - { FileSystem = - \ ( fs - : { path : Text, fileext : < ICS > } - ) -> - [ nv "type" "filesystem" - , nv - "fileext" - (merge { ICS = ".ics" } fs.fileext) - , nv "path" fs.path - ] - , Http = - \(http : { url : Text }) -> - [ nv "type" "http", nv "url" http.url ] - } - storage.storage - } - - in [ { name = "pair ${pair.pairName}" - , value = - [ nv "a" pair.a.storageName - , nv "b" pair.b.storageName - , nv - "collections" - ( merge - { Unspecified = "none" - , TheseCollections = - \(colls : List Vdirsyncer.Collection) -> - renderList - ( Lib.List/map - Vdirsyncer.Collection - Text - ( \ ( coll - : Vdirsyncer.Collection - ) -> - merge - { FromA = "from a" - , FromB = "from b" - , Collection = - \(t : Text) -> t - } - coll - ) - colls - ) - } - pair.collections - ) - ] - } - , mkStorage pair.a - , mkStorage pair.b - ] - - in { example = - Ini/externs.renderIni - ( Ini.appendInis - ( Lib.List/map - Vdirsyncer.Pair - Ini.Ini - ( \(pair : Vdirsyncer.Pair) -> - { globalSection = [] : Ini.Section - , sections = toIniSections pair - } - ) - ( [ { pairName = "testPair" - , a = - { storageName = "mystor" - , storage = - Vdirsyncer.StorageType.FileSystem - { path = "./test-ics" - , fileext = < ICS >.ICS - } - } - , b = - { storageName = "mystor" - , storage = - Vdirsyncer.StorageType.Http - { url = "https://profpatsch.de" } - } - , collections = Vdirsyncer.Collections.Unspecified - } - ] - : List Vdirsyncer.Pair - ) - ) - ) - } diff --git a/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/sync-ics-to-dir.py b/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/sync-ics-to-dir.py deleted file mode 100644 index 4af3b9fb8..000000000 --- a/users/Profpatsch/parked/sync-abfall-ics-aichach-friedberg/sync-ics-to-dir.py +++ /dev/null @@ -1,133 +0,0 @@ -# horrible little module that fetches ICS files for the local trash public service. -# -# It tries its best to not overwrite existing ICS files in case the upstream goes down -# or returns empty ICS files. -import sys -import httpx -import asyncio -import icalendar -from datetime import datetime -import syslog -import os.path - -# Internal id for the street (extracted from the ics download url) -ortsteil_id = "e9c32ab3-df25-4660-b88e-abda91897d7a" - -# They are using a numeric encoding to refer to different kinds of trash -fraktionen = { - "restmüll": "1", - "bio": "5", - "papier": "7", - "gelbe_tonne": "13", - "problemmüllsammlung": "20" -} - -def ics_url(year): - frakt = ','.join(fraktionen.values()) - return f'https://awido.cubefour.de/Customer/aic-fdb/KalenderICS.aspx?oid={ortsteil_id}&jahr={year}&fraktionen={frakt}&reminder=1.12:00' - -def fetchers_for_years(start_year, no_of_years_in_future): - """given a starting year, and a number of years in the future, - return the years for which to fetch ics files""" - current_year = datetime.now().year - max_year = current_year + no_of_years_in_future - return { - "passed_years": range(start_year, current_year), - "this_and_future_years": range(current_year, 1 + max_year) - } - -async def fetch_ics(c, url): - """fetch an ICS file from an URL""" - try: - resp = await c.get(url) - except Exception as e: - return { "ics_does_not_exist_exc": e } - - if resp.is_error: - return { "ics_does_not_exist": resp } - else: - try: - ics = icalendar.Calendar.from_ical(resp.content) - return { "ics": { "ics_parsed": ics, "ics_bytes": resp.content } } - except ValueError as e: - return { "ics_cannot_be_parsed": e } - -def ics_has_events(ics): - """Determine if there is any event in the ICS, otherwise we can assume it’s an empty file""" - for item in ics.walk(): - if isinstance(item, icalendar.Event): - return True - return False - -async def write_nonempty_ics(directory, year, ics): - # only overwrite if the new ics has any events - if ics_has_events(ics['ics_parsed']): - path = os.path.join(directory, f"{year}.ics") - with open(path, "wb") as f: - f.write(ics['ics_bytes']) - info(f"wrote ics for year {year} to file {path}") - else: - info(f"ics for year {year} was empty, skipping") - - -def main(): - ics_directory = os.getenv("ICS_DIRECTORY", None) - if not ics_directory: - critical("please set ICS_DIRECTORY") - start_year = int(os.getenv("ICS_START_YEAR", 2022)) - future_years = int(os.getenv("ICS_FUTURE_YEARS", 2)) - - years = fetchers_for_years(start_year, no_of_years_in_future=future_years) - - - async def go(): - async with httpx.AsyncClient(follow_redirects=True) as c: - info(f"fetching ics for passed years: {years['passed_years']}") - for year in years["passed_years"]: - match await fetch_ics(c, ics_url(year)): - case { "ics_does_not_exist_exc": error }: - warn(f"The ics for the year {year} is gone, error when requesting: {error} for url {ics_url(year)}") - case { "ics_does_not_exist": resp }: - warn(f"The ics for the year {year} is gone, server returned status {resp.status} for url {ics_url(year)}") - case { "ics_cannot_be_parsed": error }: - warn(f"The returned ICS could not be parsed: {error} for url {ics_url(year)}") - case { "ics": ics }: - info(f"fetched ics from {ics_url(year)}") - await write_nonempty_ics(ics_directory, year, ics) - case _: - critical("unknown case for ics result") - - - info(f"fetching ics for current and upcoming years: {years['this_and_future_years']}") - for year in years["this_and_future_years"]: - match await fetch_ics(c, ics_url(year)): - case { "ics_does_not_exist_exc": error }: - critical(f"The ics for the year {year} is not available, error when requesting: {error} for url {ics_url(year)}") - case { "ics_does_not_exist": resp }: - critical(f"The ics for the year {year} is not available, server returned status {resp.status} for url {ics_url(year)}") - case { "ics_cannot_be_parsed": error }: - critical(f"The returned ICS could not be parsed: {error} for url {ics_url(year)}") - case { "ics": ics }: - info(f"fetched ics from {ics_url(year)}") - await write_nonempty_ics(ics_directory, year, ics) - case _: - critical("unknown case for ics result") - - asyncio.run(go()) - -def info(msg): - syslog.syslog(syslog.LOG_INFO, msg) - -def critical(msg): - syslog.syslog(syslog.LOG_CRIT, msg) - sys.exit(1) - -def warn(msg): - syslog.syslog(syslog.LOG_WARNING, msg) - -def debug(msg): - syslog.syslog(syslog.LOG_DEBUG, msg) - - -if __name__ == "__main__": - main() diff --git a/users/Profpatsch/read-http.nix b/users/Profpatsch/read-http.nix deleted file mode 100644 index d9ad6fc30..000000000 --- a/users/Profpatsch/read-http.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ depot, pkgs, ... }: - -let - - read-http = depot.nix.writers.rustSimple - { - name = "read-http"; - dependencies = [ - depot.third_party.rust-crates.ascii - depot.third_party.rust-crates.httparse - depot.users.Profpatsch.netencode.netencode-rs - depot.users.Profpatsch.arglib.netencode.rust - depot.users.Profpatsch.execline.exec-helpers - ]; - } - (builtins.readFile ./read-http.rs); - -in -read-http diff --git a/users/Profpatsch/read-http.rs b/users/Profpatsch/read-http.rs deleted file mode 100644 index 2b24e6beb..000000000 --- a/users/Profpatsch/read-http.rs +++ /dev/null @@ -1,249 +0,0 @@ -extern crate arglib_netencode; -extern crate ascii; -extern crate exec_helpers; -extern crate httparse; -extern crate netencode; - -use exec_helpers::{die_expected_error, die_temporary, die_user_error}; -use std::collections::HashMap; -use std::io::{Read, Write}; -use std::os::unix::io::FromRawFd; - -use netencode::dec::Decoder; -use netencode::{dec, T, U}; - -enum What { - Request, - Response, -} - -// reads a http request (stdin), and writes all headers to stdout, as netencoded record. -// The keys are text, but can be lists of text iff headers appear multiple times, so beware. -fn main() -> std::io::Result<()> { - exec_helpers::no_args("read-http"); - - let args = dec::RecordDot { - field: "what", - inner: dec::OneOf { - list: vec!["request", "response"], - inner: dec::Text, - }, - }; - let what: What = match args.dec(arglib_netencode::arglib_netencode("read-http", None).to_u()) { - Ok("request") => What::Request, - Ok("response") => What::Response, - Ok(v) => panic!("shouldn’t happen!, value was: {}", v), - Err(dec::DecodeError(err)) => die_user_error("read-http", err), - }; - - fn read_stdin_to_complete(mut parse: F) -> () - where - F: FnMut(&[u8]) -> httparse::Result, - { - let mut res = httparse::Status::Partial; - loop { - if let httparse::Status::Complete(_) = res { - return; - } - let mut buf = [0; 2048]; - match std::io::stdin().read(&mut buf[..]) { - Ok(size) => { - if size == 0 { - break; - } - } - Err(err) => { - die_temporary("read-http", format!("could not read from stdin, {:?}", err)) - } - } - match parse(&buf) { - Ok(status) => { - res = status; - } - Err(err) => { - die_temporary("read-http", format!("httparse parsing failed: {:#?}", err)) - } - } - } - } - - fn normalize_headers<'a>(headers: &'a [httparse::Header]) -> HashMap> { - let mut res = HashMap::new(); - for httparse::Header { name, value } in headers { - let val = ascii::AsciiStr::from_ascii(*value) - .expect(&format!( - "read-http: we require header values to be ASCII, but the header {} was {:?}", - name, value - )) - .as_str(); - // lowercase the header names, since the standard doesn’t care - // and we want unique strings to match against - let name_lower = name.to_lowercase(); - match res.insert(name_lower, U::Text(val)) { - None => (), - Some(U::Text(t)) => { - let name_lower = name.to_lowercase(); - let _ = res.insert(name_lower, U::List(vec![U::Text(t), U::Text(val)])); - () - } - Some(U::List(mut l)) => { - let name_lower = name.to_lowercase(); - l.push(U::Text(val)); - let _ = res.insert(name_lower, U::List(l)); - () - } - Some(o) => panic!("read-http: header not text nor list: {:?}", o), - } - } - res - } - - // tries to read until the end of the http header (deliniated by two newlines "\r\n\r\n") - fn read_till_end_of_header(buf: &mut Vec, reader: R) -> Option<()> { - let mut chonker = Chunkyboi::new(reader, 4096); - loop { - // TODO: attacker can send looooong input, set upper maximum - match chonker.next() { - Some(Ok(chunk)) => { - buf.extend_from_slice(&chunk); - if chunk.windows(4).any(|c| c == b"\r\n\r\n") { - return Some(()); - } - } - Some(Err(err)) => { - die_temporary("read-http", format!("error reading from stdin: {:?}", err)) - } - None => return None, - } - } - } - - // max header size chosen arbitrarily - let mut headers = [httparse::EMPTY_HEADER; 128]; - let stdin = std::io::stdin(); - - match what { - Request => { - let mut req = httparse::Request::new(&mut headers); - let mut buf: Vec = vec![]; - match read_till_end_of_header(&mut buf, stdin.lock()) { - Some(()) => match req.parse(&buf) { - Ok(httparse::Status::Complete(_body_start)) => {} - Ok(httparse::Status::Partial) => { - die_expected_error("read-http", "httparse should have gotten a full header") - } - Err(err) => die_expected_error( - "read-http", - format!("httparse response parsing failed: {:#?}", err), - ), - }, - None => die_expected_error( - "read-http", - format!("httparse end of stdin reached before able to parse request headers"), - ), - } - let method = req.method.expect("method must be filled on complete parse"); - let path = req.path.expect("path must be filled on complete parse"); - write_dict_req(method, path, &normalize_headers(req.headers)) - } - Response => { - let mut resp = httparse::Response::new(&mut headers); - let mut buf: Vec = vec![]; - match read_till_end_of_header(&mut buf, stdin.lock()) { - Some(()) => match resp.parse(&buf) { - Ok(httparse::Status::Complete(_body_start)) => {} - Ok(httparse::Status::Partial) => { - die_expected_error("read-http", "httparse should have gotten a full header") - } - Err(err) => die_expected_error( - "read-http", - format!("httparse response parsing failed: {:#?}", err), - ), - }, - None => die_expected_error( - "read-http", - format!("httparse end of stdin reached before able to parse response headers"), - ), - } - let code = resp.code.expect("code must be filled on complete parse"); - let reason = resp - .reason - .expect("reason must be filled on complete parse"); - write_dict_resp(code, reason, &normalize_headers(resp.headers)) - } - } -} - -fn write_dict_req<'a, 'buf>( - method: &'buf str, - path: &'buf str, - headers: &'a HashMap>, -) -> std::io::Result<()> { - let mut http = vec![("method", U::Text(method)), ("path", U::Text(path))] - .into_iter() - .collect(); - write_dict(http, headers) -} - -fn write_dict_resp<'a, 'buf>( - code: u16, - reason: &'buf str, - headers: &'a HashMap>, -) -> std::io::Result<()> { - let mut http = vec![ - ("status", U::N6(code as u64)), - ("status-text", U::Text(reason)), - ] - .into_iter() - .collect(); - write_dict(http, headers) -} - -fn write_dict<'buf, 'a>( - mut http: HashMap<&str, U<'a>>, - headers: &'a HashMap>, -) -> std::io::Result<()> { - match http.insert( - "headers", - U::Record( - headers - .iter() - .map(|(k, v)| (k.as_str(), v.clone())) - .collect(), - ), - ) { - None => (), - Some(_) => panic!("read-http: headers already in dict"), - }; - netencode::encode(&mut std::io::stdout(), &U::Record(http))?; - Ok(()) -} - -// iter helper -// TODO: put into its own module -struct Chunkyboi { - inner: T, - buf: Vec, -} - -impl Chunkyboi { - fn new(inner: R, chunksize: usize) -> Self { - let buf = vec![0; chunksize]; - Chunkyboi { inner, buf } - } -} - -impl Iterator for Chunkyboi { - type Item = std::io::Result>; - - fn next(&mut self) -> Option>> { - match self.inner.read(&mut self.buf) { - Ok(0) => None, - Ok(read) => { - // clone a new buffer so we can reuse the internal one - Some(Ok(self.buf[..read].to_owned())) - } - Err(err) => Some(Err(err)), - } - } -} diff --git a/users/Profpatsch/shell.nix b/users/Profpatsch/shell.nix deleted file mode 100644 index b7442a758..000000000 --- a/users/Profpatsch/shell.nix +++ /dev/null @@ -1,113 +0,0 @@ -# generic shell.nix that can be used for most of my projects here, -# until I figure out a way to have composable shells. -let root = (import ../../. { }); in -{ pkgs ? root.third_party.nixpkgs, depot ? root, ... }: - -pkgs.mkShell { - - buildInputs = [ - pkgs.sqlite-interactive - pkgs.sqlite-utils - pkgs.haskell-language-server - pkgs.cabal-install - (pkgs.haskellPackages.ghcWithHoogle (h: [ - h.async - h.aeson-better-errors - h.blaze-html - h.bencode - h.conduit-extra - h.error - h.monad-logger - h.pa-field-parser - h.pa-label - h.pa-json - h.pa-pretty - h.pa-run-command - h.ihp-hsx - h.optparse-simple - h.PyF - h.foldl - h.unliftio - h.xml-conduit - h.wai - h.wai-extra - h.warp - h.profunctors - h.semigroupoids - h.validation-selective - h.free - h.cryptonite-conduit - h.sqlite-simple - h.hedgehog - h.http-conduit - h.http-conduit - h.wai-conduit - h.nonempty-containers - h.deriving-compat - h.unix - h.tagsoup - h.attoparsec - # h.iCalendar - h.case-insensitive - h.hscolour - h.nicify-lib - h.hspec - h.hspec-expectations-pretty-diff - h.tmp-postgres - h.postgresql-simple - h.resource-pool - h.xmonad-contrib - h.hs-opentelemetry-sdk - h.punycode - ])) - - pkgs.rustup - pkgs.pkg-config - pkgs.fuse - pkgs.postgresql_14 - pkgs.nodejs - pkgs.ninja - pkgs.s6 - pkgs.caddy - - (depot.nix.binify { - name = "nix-run"; - exe = depot.users.Profpatsch.nix-tools.nix-run; - }) - ]; - - DEPOT_ROOT = toString ./../..; - PROFPATSCH_ROOT = toString ./.; - - WHATCD_RESOLVER_TOOLS = pkgs.linkFarm "whatcd-resolver-tools" [ - { - name = "pg_format"; - path = "${pkgs.pgformatter}/bin/pg_format"; - } - ]; - WHATCD_RESOLVER_TRANSMISSION_DOWNLOAD_DIRECTORY = "/home/philip/tmp/a/seeding"; - - # DECLIB_MASTODON_ACCESS_TOKEN read from `pass` in .envrc. - - RUSTC_WRAPPER = - let - wrapperArgFile = libs: pkgs.writeText "rustc-wrapper-args" - (pkgs.lib.concatStringsSep - "\n" - (pkgs.lib.concatLists - (map - (lib: [ - "-L" - "${pkgs.lib.getLib lib}/lib" - ]) - libs))); - in - depot.nix.writeExecline "rustc-wrapper" { readNArgs = 1; } [ - "$1" - "$@" - "@${wrapperArgFile [ - depot.third_party.rust-crates.nom - ]}" - ]; - -} diff --git a/users/Profpatsch/shortcuttable/default.nix b/users/Profpatsch/shortcuttable/default.nix deleted file mode 100644 index 13ba22040..000000000 --- a/users/Profpatsch/shortcuttable/default.nix +++ /dev/null @@ -1,172 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - # run prog... and restart whenever SIGHUP is received - # - # this is useful for binding to a shortcut. - # - # Unfortunately, this requires a bunch of workarounds around the semantics of `trap`, - # but the general idea of bundling subprocesses with `setsid` is somewhat sound. - runShortcuttable = - depot.nix.writeExecline "run-shortcuttable" { } [ - "importas" - "-i" - "run" - "XDG_RUNTIME_DIR" - "if" - [ "mkdir" "-p" "\${run}/shortcuttable/test" ] - "getpid" - "-E" - "controlpid" - savePid - "\${run}/shortcuttable/test/control" - "$controlpid" - - # start the program - "background" - [ - startSaveSID - "\${run}/shortcuttable/test/running-sid" - "$@" - ] - - "trap" - [ - "SIGHUP" - [ - "if" - [ "echo" "got hup" ] - "if" - [ - "if" - [ "echo" "killing our child processes" ] - "envfile" - "\${run}/shortcuttable/test/running-sid" - "importas" - "-ui" - "child_sid" - "pid" - "foreground" - [ "ps" "-f" "--sid" "$child_sid" ] - ctrlCCtrlDSid - "$child_sid" - ] - "if" - [ "echo" "restarting into" "$@" ] - "background" - [ - startSaveSID - "\${run}/shortcuttable/test/running-sid" - "$@" - ] - ] - "SIGTERM" - [ - (killShortcuttable { signal = "TERM"; }) - "\${run}/shortcuttable/test/running-sid" - "\${run}/shortcuttable/test/exit" - ] - "SIGINT" - [ - (killShortcuttable { signal = "INT"; }) - "\${run}/shortcuttable/test/running-sid" - "\${run}/shortcuttable/test/exit" - ] - ] - depot.users.Profpatsch.execline.setsid - "child_sid" - "getpid" - "-E" - "exitpid" - savePid - "\${run}/shortcuttable/test/exit" - "$exitpid" - "sleep" - "infinity" - ]; - - killShortcuttable = { signal }: depot.nix.writeExecline "kill-shortcuttable" { readNArgs = 2; } [ - "if" - [ "echo" "got SIG${signal}, quitting" ] - "if" - [ - "envfile" - "$1" - "importas" - "-ui" - "child_sid" - "pid" - "foreground" - [ "ps" "-f" "--sid" "$child_sid" ] - ctrlCCtrlDSid - "$child_sid" - ] - "if" - [ "echo" "killing shortcuttable loop" ] - "envfile" - "$2" - "importas" - "-ui" - "trap_pid" - "pid" - "foreground" - [ "ps" "-fp" "$trap_pid" ] - "kill" - "--signal" - signal - "$trap_pid" - ]; - - savePid = depot.nix.writeExecline "save-pid" { readNArgs = 2; } [ - "if" - [ "echo" "saving process:" ] - "if" - [ "ps" "-fp" "$2" ] - "if" - [ - "redirfd" - "-w" - "1" - "$1" - "printf" - "pid = %s\n" - "$2" - ] - "$@" - ]; - - # try to kill process, first with SIGTERM then SIGQUIT (in case it’s a repl) - ctrlCCtrlDSid = depot.nix.writeExecline "ctrl-c-ctrl-d" { readNArgs = 1; } [ - "ifelse" - "-n" - [ "kill" "--signal" "TERM" "--" "-\${1}" ] - [ - "if" - [ "echo" "could not kill via SIGTERM, trying SIGQUIT …" ] - "ifelse" - "-n" - [ "kill" "--signal" "QUIT" "--" "-\${1}" ] - [ "echo" "SIGQUIT failed as well, keeping it running" ] - "$@" - ] - "$@" - ]; - - startSaveSID = depot.nix.writeExecline "start-save-sid" { readNArgs = 1; } [ - depot.users.Profpatsch.execline.setsid - "child_sid" - "importas" - "-ui" - "child_sid" - "child_sid" - "if" - [ "echo" "children sid:" "$child_sid" ] - savePid - "$1" - "$child_sid" - "$@" - ]; - - -in -runShortcuttable diff --git a/users/Profpatsch/tagtime/README.md b/users/Profpatsch/tagtime/README.md deleted file mode 100644 index ab2c7d14e..000000000 --- a/users/Profpatsch/tagtime/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# tagtime reimplementation - -What’s great about original perl tagtime? - -* timestamps are deterministic from the beginning (keep) -* the tagging system should just work (tm) - -What’s the problem with the original perl tagtime? - -* it uses a bad, arbitrary file format -> sqlite3 -* the query window does not time out, so it’s easy to miss that it’s open (often hidden behind another window), and then the following pings might never appear) -* There’s a bug with tags containing a `.` -> sqlite3 - -What would be cool to have? - -* multi-entry mode (ping on phone and laptop and merge the replies eventually since they will apply to single timestamps) -* simplifying reporting based on fuzzy matching & history -* auto-generate nice time reports with hours for work items diff --git a/users/Profpatsch/toINI.nix b/users/Profpatsch/toINI.nix deleted file mode 100644 index 537505d30..000000000 --- a/users/Profpatsch/toINI.nix +++ /dev/null @@ -1,79 +0,0 @@ -{ lib, ... }: -let - /* Generate an INI-style config file from an attrset - * specifying the global section (no header), and a - * list of sections which contain name/value pairs. - * - * generators.toINI {} { - * globalSection = [ - * { name = "someGlobalKey"; value = "hi"; } - * ]; - * sections = [ - * { name = "foo"; value = [ - * { name = "hi"; value = "${pkgs.hello}"; } - * { name = "ciao"; value = "bar"; } - * ]; - * } - * { name = "baz"; - * value = [ { name = "also, integers"; value = 42; } ]; - * } - * ]; - * } - * - *> someGlobalKey=hi - *> - *> [foo] - *> hi=/nix/store/y93qql1p5ggfnaqjjqhxcw0vqw95rlz0-hello-2.10 - *> ciao=bar - *> - *> [baz] - *> also, integers=42 - *> - * - * The mk* configuration attributes can generically change - * the way sections and key-value strings are generated. - * - * Order of the sections and of keys is preserved, - * duplicate keys are allowed. - */ - toINI = - { - # apply transformations (e.g. escapes) to section names - mkSectionName ? (name: lib.strings.escape [ "[" "]" ] name) - , # format a setting line from key and value - mkKeyValue ? lib.generators.mkKeyValueDefault { } "=" - , - }: { globalSection, sections }: - let - mkSection = sectName: sectValues: '' - [${mkSectionName sectName}] - '' + toKeyValue { inherit mkKeyValue; } sectValues; - # map input to ini sections - mkSections = lib.strings.concatMapStringsSep "\n" - ({ name, value }: mkSection name value) - sections; - mkGlobalSection = - if globalSection == [ ] - then "" - else toKeyValue { inherit mkKeyValue; } globalSection - + "\n"; - in - mkGlobalSection - + mkSections; - - /* Generate a name-value-style config file from a list. - * - * mkKeyValue is the same as in toINI. - */ - toKeyValue = - { mkKeyValue ? lib.generators.mkKeyValueDefault { } "=" - , - }: - let - mkLine = k: v: mkKeyValue k v + "\n"; - mkLines = k: v: [ (mkLine k v) ]; - in - nameValues: lib.strings.concatStrings (lib.concatLists (map ({ name, value }: mkLines name value) nameValues)); - -in -toINI diff --git a/users/Profpatsch/tree-sitter.nix b/users/Profpatsch/tree-sitter.nix deleted file mode 100644 index 2224da2a3..000000000 --- a/users/Profpatsch/tree-sitter.nix +++ /dev/null @@ -1,209 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - bins = depot.nix.getBins pkgs.coreutils [ "head" "printf" "cat" ] - // depot.nix.getBins pkgs.ncurses [ "tput" ] - // depot.nix.getBins pkgs.bc [ "bc" ] - // depot.nix.getBins pkgs.ocamlPackages.sexp [ "sexp" ]; - - print-ast = depot.nix.writers.rustSimple - { - name = "print-ast"; - dependencies = with depot.third_party.rust-crates; [ - libloading - tree-sitter - ]; - } '' - extern crate libloading; - extern crate tree_sitter; - use std::mem; - use std::io::{Read}; - use libloading::{Library, Symbol}; - use tree_sitter::{Language, Parser}; - - /// Load the shared lib FILE and return the language under SYMBOL-NAME. - /// Inspired by the rust source of emacs-tree-sitter. - fn _load_language(file: String, symbol_name: String) -> Result { - let lib = Library::new(file)?; - let tree_sitter_lang: Symbol<'_, unsafe extern "C" fn() -> _> = - unsafe { lib.get(symbol_name.as_bytes())? }; - let language: Language = unsafe { tree_sitter_lang() }; - // Avoid segmentation fault by not unloading the lib, as language is a static piece of data. - // TODO: Attach an Rc to Language instead. - mem::forget(lib); - Ok(language) - } - - fn main() { - let mut args = std::env::args(); - let so = args.nth(1).unwrap(); - let symbol_name = args.nth(0).unwrap(); - let file = args.nth(0).unwrap(); - let mut parser = Parser::new(); - let lang = _load_language(so, symbol_name).unwrap(); - parser.set_language(lang).unwrap(); - let bytes = std::fs::read(&file).unwrap(); - print!("{}", parser.parse(&bytes, None).unwrap().root_node().to_sexp()); - } - - - ''; - - tree-sitter-nix = buildTreeSitterGrammar { - language = "tree-sitter-nix"; - source = pkgs.fetchFromGitHub { - owner = "cstrahan"; - repo = "tree-sitter-nix"; - rev = "791b5ff0e4f0da358cbb941788b78d436a2ca621"; - sha256 = "1y5b3wh3fcmbgq8r2i97likzfp1zp02m58zacw5a1cjqs5raqz66"; - }; - }; - - watch-file-modified = depot.nix.writers.rustSimple - { - name = "watch-file-modified"; - dependencies = [ - depot.third_party.rust-crates.inotify - depot.users.Profpatsch.netstring.rust-netstring - ]; - } '' - extern crate inotify; - extern crate netstring; - use inotify::{EventMask, WatchMask, Inotify}; - use std::io::Write; - - fn main() { - let mut inotify = Inotify::init() - .expect("Failed to initialize inotify"); - - let file = std::env::args().nth(1).unwrap(); - - let file_watch = inotify - .add_watch( - &file, - WatchMask::MODIFY - ) - .expect("Failed to add inotify watch"); - - let mut buffer = [0u8; 4096]; - loop { - let events = inotify - .read_events_blocking(&mut buffer) - .expect("Failed to read inotify events"); - - for event in events { - if event.wd == file_watch { - std::io::stdout().write(&netstring::to_netstring(file.as_bytes())); - std::io::stdout().flush(); - } - } - } - } - - ''; - - # clear screen and set LINES and COLUMNS to terminal height & width - clear-screen = depot.nix.writeExecline "clear-screen" { } [ - "if" - [ bins.tput "clear" ] - "backtick" - "-in" - "LINES" - [ bins.tput "lines" ] - "backtick" - "-in" - "COLUMNS" - [ bins.tput "cols" ] - "$@" - ]; - - print-nix-file = depot.nix.writeExecline "print-nix-file" { readNArgs = 1; } [ - "pipeline" - [ print-ast "${tree-sitter-nix}/parser" "tree_sitter_nix" "$1" ] - "pipeline" - [ bins.sexp "print" ] - clear-screen - "importas" - "-ui" - "lines" - "LINES" - "backtick" - "-in" - "ls" - [ - "pipeline" - # when you pull out bc to decrement an integer it’s time to switch to python lol - [ bins.printf "x=%s; --x\n" "$lines" ] - bins.bc - ] - "importas" - "-ui" - "l" - "ls" - bins.head - "-n\${l}" - ]; - - print-nix-file-on-update = depot.nix.writeExecline "print-nix-file-on-update" { readNArgs = 1; } [ - "if" - [ print-nix-file "$1" ] - "pipeline" - [ watch-file-modified "$1" ] - "forstdin" - "-d" - "" - "file" - "importas" - "file" - "file" - print-nix-file - "$file" - ]; - - # copied from nixpkgs - buildTreeSitterGrammar = - { - # language name - language - # source for the language grammar - , source - }: - - pkgs.stdenv.mkDerivation { - - pname = "${language}-grammar"; - inherit (pkgs.tree-sitter) version; - - src = source; - - buildInputs = [ pkgs.tree-sitter ]; - - dontUnpack = true; - configurePhase = ":"; - buildPhase = '' - runHook preBuild - scanner_cc="$src/src/scanner.cc" - if [ ! -f "$scanner_cc" ]; then - scanner_cc="" - fi - $CXX -I$src/src/ -c $scanner_cc - $CC -I$src/src/ -shared -o parser -Os scanner.o $src/src/parser.c -lstdc++ - runHook postBuild - ''; - installPhase = '' - runHook preInstall - mkdir $out - mv parser $out/ - runHook postInstall - ''; - }; - -in -depot.nix.readTree.drvTargets { - inherit - print-ast - tree-sitter-nix - print-nix-file-on-update - watch-file-modified - ; -} diff --git a/users/Profpatsch/whatcd-resolver/.gitignore b/users/Profpatsch/whatcd-resolver/.gitignore deleted file mode 100644 index f9c4bdf8b..000000000 --- a/users/Profpatsch/whatcd-resolver/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/.ninja/ diff --git a/users/Profpatsch/whatcd-resolver/Main.hs b/users/Profpatsch/whatcd-resolver/Main.hs deleted file mode 100644 index 21cd80cbf..000000000 --- a/users/Profpatsch/whatcd-resolver/Main.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import WhatcdResolver qualified - -main :: IO () -main = WhatcdResolver.main diff --git a/users/Profpatsch/whatcd-resolver/README.md b/users/Profpatsch/whatcd-resolver/README.md deleted file mode 100644 index d1902e546..000000000 --- a/users/Profpatsch/whatcd-resolver/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# whatcd-resolver - -To run: - -``` -ninja run-services -``` - -in one terminal (starts the background tasks) - -``` -ninja run -``` - -to start the server. It runs on `9092`. - -You need to be in the `nix-shell` in `./..`. - -You need to set the `pass` key `internet/redacted/api-keys/whatcd-resolver` to an API key for RED. - -You need to have a transmission-rpc-daemon listening on port `9091` (no auth, try ssh port forwarding lol). diff --git a/users/Profpatsch/whatcd-resolver/build.ninja b/users/Profpatsch/whatcd-resolver/build.ninja deleted file mode 100644 index ff6ba8df0..000000000 --- a/users/Profpatsch/whatcd-resolver/build.ninja +++ /dev/null @@ -1,20 +0,0 @@ - -builddir = .ninja - -outdir = ./output - -rule run-services - command = s6-svscan ./services - -rule run - command = execlineb -c '$ - importas -i DEPOT_ROOT DEPOT_ROOT $ - importas -i PROFPATSCH_ROOT PROFPATSCH_ROOT cd $$PROFPATSCH_ROOT $ - nix-run { $$DEPOT_ROOT -A users.Profpatsch.shortcuttable } cabal repl whatcd-resolver/ --repl-options "-e main" $ - ' - -build run-services: run-services - pool = console - -build run: run - pool = console diff --git a/users/Profpatsch/whatcd-resolver/default.nix b/users/Profpatsch/whatcd-resolver/default.nix deleted file mode 100644 index ab52c3225..000000000 --- a/users/Profpatsch/whatcd-resolver/default.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - # bins = depot.nix.getBins pkgs.sqlite ["sqlite3"]; - - whatcd-resolver = pkgs.haskellPackages.mkDerivation { - pname = "whatcd-resolver"; - version = "0.1.0"; - - src = depot.users.Profpatsch.exactSource ./. [ - ./whatcd-resolver.cabal - ./Main.hs - ./src/WhatcdResolver.hs - ./src/AppT.hs - ./src/Bencode.hs - ./src/JsonLd.hs - ./src/Optional.hs - ./src/Html.hs - ./src/Http.hs - ./src/Transmission.hs - ./src/Redacted.hs - ]; - - libraryHaskellDepends = [ - depot.users.Profpatsch.my-prelude - depot.users.Profpatsch.my-webstuff - pkgs.haskellPackages.pa-prelude - pkgs.haskellPackages.pa-label - pkgs.haskellPackages.pa-error-tree - pkgs.haskellPackages.pa-field-parser - pkgs.haskellPackages.pa-run-command - pkgs.haskellPackages.aeson-better-errors - pkgs.haskellPackages.bencode - pkgs.haskellPackages.blaze-html - pkgs.haskellPackages.hs-opentelemetry-sdk - pkgs.haskellPackages.http-conduit - pkgs.haskellPackages.http-types - pkgs.haskellPackages.ihp-hsx - pkgs.haskellPackages.monad-logger - pkgs.haskellPackages.resource-pool - pkgs.haskellPackages.postgresql-simple - pkgs.haskellPackages.tmp-postgres - pkgs.haskellPackages.unliftio - pkgs.haskellPackages.wai-extra - pkgs.haskellPackages.warp - pkgs.haskellPackages.punycode - ]; - - isExecutable = true; - isLibrary = false; - license = lib.licenses.mit; - }; - - bins = depot.nix.getBins whatcd-resolver [ "whatcd-resolver" ]; - -in - -depot.nix.writeExecline "whatcd-resolver-wrapped" { } [ - "importas" - "-i" - "PATH" - "PATH" - "export" - "PATH" - # TODO: figure out how to automatically migrate to a new postgres version with tmp_postgres (dump?) - "${pkgs.postgresql_14}/bin:$${PATH}" - "export" - "WHATCD_RESOLVER_TOOLS" - (pkgs.linkFarm "whatcd-resolver-tools" [ - { - name = "pg_format"; - path = "${pkgs.pgformatter}/bin/pg_format"; - } - ]) - bins.whatcd-resolver -] - diff --git a/users/Profpatsch/whatcd-resolver/notes.org b/users/Profpatsch/whatcd-resolver/notes.org deleted file mode 100644 index 24662c0f3..000000000 --- a/users/Profpatsch/whatcd-resolver/notes.org +++ /dev/null @@ -1,48 +0,0 @@ -* The Glorious what.cd¹ Resolver - - ¹: At the time of writing, what.cd didn’t even exist anymore - -** Idea - - Stream your music (or media) from a private tracker transparently. - “Spotify for torrents” - -** Technical - - You need to have a seedbox, which runs a server program. - The server manages queries, downloads torrents and requested files, and - provides http streams to the downloaded files (while caching them for - seeding). - - Clients then use the API to search for music (e.g. query for artists or - tracks) and get back the promise of a stream to the resolved file (a bit how - resolvers in the Tomahawk Player work) - -*** The Server - -**** Resolving queries - - ~resolve :: Query -> IO Identifiers~ - - A query is a search input for content (could be an artist or a movie name - or something) - - There have to be multiple providers, depending on the site used - (e.g. one for Gazelle trackers, one for Piratebay) and some intermediate - structure (e.g. for going through Musicbrainz first). - - Output is a unique identifier for a fetchable resource; this could be a - link to a torrent combined with a file/directory in said torrent. - -**** Fetching Identifiers - - ~fetch :: Identifier -> IO (Promise Stream)~ - - Takes an Identifier (which should provide all information on how to grab - the media file and returns a stream to the media file once it’s ready. - - For torrents, this probably consists of telling the torrent - library/application to fetch a certain torrent and start downloading the - required files in it. The torrent fetcher would also need to do seeding and - space management, since one usually has to keep a ratio and hard drive - space is not unlimited. diff --git a/users/Profpatsch/whatcd-resolver/server-notes.org b/users/Profpatsch/whatcd-resolver/server-notes.org deleted file mode 100644 index cb990aba3..000000000 --- a/users/Profpatsch/whatcd-resolver/server-notes.org +++ /dev/null @@ -1,2 +0,0 @@ -* whatcd-resolver-server - diff --git a/users/Profpatsch/whatcd-resolver/services/.gitignore b/users/Profpatsch/whatcd-resolver/services/.gitignore deleted file mode 100644 index 5cdb254e8..000000000 --- a/users/Profpatsch/whatcd-resolver/services/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/.s6-svscan/ -/**/event/ -/**/supervise/ diff --git a/users/Profpatsch/whatcd-resolver/services/jaeger/run b/users/Profpatsch/whatcd-resolver/services/jaeger/run deleted file mode 100755 index 7800d8828..000000000 --- a/users/Profpatsch/whatcd-resolver/services/jaeger/run +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env execlineb -importas -i DEPOT_ROOT DEPOT_ROOT -nix-run { $DEPOT_ROOT -A users.Profpatsch.jaeger -kK } diff --git a/users/Profpatsch/whatcd-resolver/services/reverse-proxy/caddyfile b/users/Profpatsch/whatcd-resolver/services/reverse-proxy/caddyfile deleted file mode 100644 index a0c0813b4..000000000 --- a/users/Profpatsch/whatcd-resolver/services/reverse-proxy/caddyfile +++ /dev/null @@ -1,17 +0,0 @@ -{ - # Global options block - auto_https off -} - -:9092 { - # Serve files from the directory specified by WHATCD_RESOLVER_TRANSMISSION_DOWNLOAD_DIRECTORY - handle_path /files/* { - root * {env.WHATCD_RESOLVER_TRANSMISSION_DOWNLOAD_DIRECTORY} - file_server { - browse off - } - } - - # Reverse proxy from localhost:9092 to localhost:9093 - reverse_proxy * localhost:9093 -} diff --git a/users/Profpatsch/whatcd-resolver/services/reverse-proxy/run b/users/Profpatsch/whatcd-resolver/services/reverse-proxy/run deleted file mode 100755 index 71522832a..000000000 --- a/users/Profpatsch/whatcd-resolver/services/reverse-proxy/run +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env execlineb -caddy run --config ./caddyfile diff --git a/users/Profpatsch/whatcd-resolver/src/AppT.hs b/users/Profpatsch/whatcd-resolver/src/AppT.hs deleted file mode 100644 index 5397f74d3..000000000 --- a/users/Profpatsch/whatcd-resolver/src/AppT.hs +++ /dev/null @@ -1,365 +0,0 @@ -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -Wno-orphans #-} - -module AppT where - -import Builder -import Control.Monad.Logger qualified as Logger -import Control.Monad.Logger.CallStack -import Control.Monad.Reader -import Data.Error.Tree -import Data.HashMap.Strict (HashMap) -import Data.HashMap.Strict qualified as HashMap -import Data.Pool (Pool) -import Data.String (IsString (fromString)) -import Data.Text qualified as Text -import Database.PostgreSQL.Simple qualified as Postgres -import FieldParser (FieldParser) -import FieldParser qualified as Field -import GHC.Generics qualified as G -import GHC.Records (getField) -import GHC.Stack qualified -import GHC.TypeLits -import Json.Enc -import Json.Enc qualified as Enc -import Label -import MyPrelude -import OpenTelemetry.Context.ThreadLocal qualified as Otel -import OpenTelemetry.Trace qualified as Otel hiding (getTracer, inSpan, inSpan') -import OpenTelemetry.Trace.Core qualified as Otel hiding (inSpan, inSpan') -import OpenTelemetry.Trace.Monad qualified as Otel -import Postgres.MonadPostgres -import Pretty qualified -import System.IO qualified as IO -import UnliftIO -import Prelude hiding (span) - -data Context = Context - { pgConfig :: - T2 - "logDatabaseQueries" - DebugLogDatabaseQueries - "prettyPrintDatabaseQueries" - PrettyPrintDatabaseQueries, - pgConnPool :: (Pool Postgres.Connection), - tracer :: Otel.Tracer, - transmissionSessionId :: IORef (Maybe ByteString), - redactedApiKey :: ByteString - } - -newtype AppT m a = AppT {unAppT :: ReaderT Context m a} - deriving newtype (Functor, Applicative, Monad, MonadIO, MonadUnliftIO, MonadThrow) - -data AppException - = AppExceptionTree ErrorTree - | AppExceptionPretty [Pretty.Err] - | AppExceptionEnc Enc - deriving anyclass (Exception) - -instance IsString AppException where - fromString s = AppExceptionTree (fromString s) - -instance Show AppException where - showsPrec _ (AppExceptionTree t) = ("AppException: " ++) . ((textToString $ prettyErrorTree t) ++) - showsPrec _ (AppExceptionPretty t) = ("AppException: " ++) . ((Pretty.prettyErrsNoColor t) ++) - showsPrec _ (AppExceptionEnc e) = ((textToString $ Enc.encToTextPretty e) ++) - -instance (MonadIO m) => MonadLogger (AppT m) where - monadLoggerLog loc src lvl msg = liftIO $ Logger.defaultOutput IO.stderr loc src lvl (Logger.toLogStr msg) - -instance (Monad m) => Otel.MonadTracer (AppT m) where - getTracer = AppT $ asks (.tracer) - -class (MonadUnliftIO m, Otel.MonadTracer m) => MonadOtel m - -instance (MonadUnliftIO m) => MonadOtel (AppT m) - -instance (MonadOtel m) => MonadOtel (Transaction m) - -inSpan :: (MonadOtel m) => Text -> m a -> m a -inSpan name = Otel.inSpan name Otel.defaultSpanArguments - -inSpan' :: (MonadOtel m) => Text -> (Otel.Span -> m a) -> m a -inSpan' name = Otel.inSpan' name Otel.defaultSpanArguments - --- | Add the attribute to the span, prefixing it with the `_` namespace (to easier distinguish our application’s tags from standard tags) -addAttribute :: (MonadIO m, Otel.ToAttribute a) => Otel.Span -> Text -> a -> m () -addAttribute span key a = Otel.addAttribute span ("_." <> key) a - --- | Add the attributes to the span, prefixing each key with the `_` namespace (to easier distinguish our application’s tags from standard tags) -addAttributes :: (MonadIO m) => Otel.Span -> HashMap Text Otel.Attribute -> m () -addAttributes span attrs = Otel.addAttributes span $ attrs & HashMap.mapKeys ("_." <>) - -addEventSimple :: (MonadIO m) => Otel.Span -> Text -> m () -addEventSimple span name = - Otel.addEvent - span - Otel.NewEvent - { Otel.newEventName = name, - Otel.newEventTimestamp = Nothing, - Otel.newEventAttributes = mempty - } - --- | Create an otel attribute from a json encoder -jsonAttribute :: Enc -> Otel.Attribute -jsonAttribute e = e & Enc.encToTextPretty & Otel.toAttribute - -instance Otel.ToAttribute (a, TextBuilder a) where - toAttribute (a, b) = buildText b a & Otel.toAttribute - -parseOrThrow :: (MonadThrow m, MonadIO m) => Otel.Span -> FieldParser from to -> from -> m to -parseOrThrow span fp f = - f & Field.runFieldParser fp & \case - Left err -> appThrow span (AppExceptionTree $ singleError err) - Right a -> pure a - -orThrowAppErrorNewSpan :: (MonadThrow m, MonadOtel m) => Text -> Either AppException a -> m a -orThrowAppErrorNewSpan msg = \case - Left err -> appThrowNewSpan msg err - Right a -> pure a - -appThrowNewSpan :: (MonadThrow m, MonadOtel m) => Text -> AppException -> m a -appThrowNewSpan spanName exc = inSpan' spanName $ \span -> do - let msg = case exc of - AppExceptionTree e -> prettyErrorTree e - AppExceptionPretty p -> Pretty.prettyErrsNoColor p & stringToText - AppExceptionEnc e -> Enc.encToTextPretty e - recordException - span - ( T2 - (label @"type_" "AppException") - (label @"message" msg) - ) - throwM $ exc - -appThrow :: (MonadThrow m, MonadIO m) => Otel.Span -> AppException -> m a -appThrow span exc = do - let msg = case exc of - AppExceptionTree e -> prettyErrorTree e - AppExceptionPretty p -> Pretty.prettyErrsNoColor p & stringToText - AppExceptionEnc e -> Enc.encToTextPretty e - recordException - span - ( T2 - (label @"type_" "AppException") - (label @"message" msg) - ) - throwM $ exc - -orAppThrow :: (MonadThrow m, MonadIO m) => Otel.Span -> Either AppException a -> m a -orAppThrow span = \case - Left err -> appThrow span err - Right a -> pure a - --- | If action returns a Left, throw an AppException -assertM :: (MonadThrow f, MonadIO f) => Otel.Span -> (t -> Either AppException a) -> t -> f a -assertM span f v = case f v of - Right a -> pure a - Left err -> appThrow span err - -assertMNewSpan :: (MonadThrow f, MonadOtel f) => Text -> (t -> Either AppException a) -> t -> f a -assertMNewSpan spanName f v = case f v of - Right a -> pure a - Left err -> appThrowNewSpan spanName err - --- | A specialized variant of @addEvent@ that records attributes conforming to --- the OpenTelemetry specification's --- --- --- @since 0.0.1.0 -recordException :: - ( MonadIO m, - HasField "message" r Text, - HasField "type_" r Text - ) => - Otel.Span -> - r -> - m () -recordException span dat = liftIO $ do - callStack <- GHC.Stack.whoCreated dat.message - newEventTimestamp <- Just <$> Otel.getTimestamp - Otel.addEvent span $ - Otel.NewEvent - { newEventName = "exception", - newEventAttributes = - HashMap.fromList - [ ("exception.type", Otel.toAttribute @Text dat.type_), - ("exception.message", Otel.toAttribute @Text dat.message), - ("exception.stacktrace", Otel.toAttribute @Text $ Text.unlines $ Prelude.map stringToText callStack) - ], - .. - } - --- * Async wrappers with Otel tracing - -withAsyncTraced :: (MonadUnliftIO m) => m a -> (Async a -> m b) -> m b -withAsyncTraced act f = do - ctx <- Otel.getContext - withAsync - ( do - _old <- Otel.attachContext ctx - act - ) - f - --- | Run two actions concurrently, and add them to the current Otel trace -concurrentlyTraced :: (MonadUnliftIO m) => m a -> m b -> m (a, b) -concurrentlyTraced act1 act2 = do - ctx <- Otel.getContext - concurrently - ( do - _old <- Otel.attachContext ctx - act1 - ) - ( do - _old <- Otel.attachContext ctx - act2 - ) - -mapConcurrentlyTraced :: (MonadUnliftIO m, Traversable t) => (a -> m b) -> t a -> m (t b) -mapConcurrentlyTraced f t = do - ctx <- Otel.getContext - mapConcurrently - ( \a -> do - _old <- Otel.attachContext ctx - f a - ) - t - --- * Postgres - -instance (MonadThrow m, MonadUnliftIO m) => MonadPostgres (AppT m) where - execute = executeImpl dbConfig - executeMany = executeManyImpl dbConfig - executeManyReturningWith = executeManyReturningWithImpl dbConfig - queryWith = queryWithImpl dbConfig - queryWith_ = queryWithImpl_ (dbConfig <&> snd) - - foldRowsWithAcc = foldRowsWithAccImpl dbConfig - runTransaction = runPGTransaction - -dbConfig :: (Monad m) => AppT m (DebugLogDatabaseQueries, PrettyPrintDatabaseQueries) -dbConfig = - AppT $ - asks - ( \c -> - ( c.pgConfig.logDatabaseQueries, - c.pgConfig.prettyPrintDatabaseQueries - ) - ) - -runPGTransaction :: (MonadUnliftIO m) => Transaction (AppT m) a -> AppT m a -runPGTransaction (Transaction transaction) = do - pool <- AppT ask <&> (.pgConnPool) - withRunInIO $ \unliftIO -> - withPGTransaction pool $ \conn -> do - unliftIO $ runReaderT transaction conn - --- | Best effort to convert a value to a JSON string that can be put in an Otel attribute. -toOtelJsonAttr :: (ToOtelJsonAttr a) => a -> Otel.Attribute -toOtelJsonAttr = toOtelJsonAttrImpl >>> Enc.encToTextPretty >>> Otel.toAttribute - --- | Best effort to convert a value to a JSON string that can be put in an Otel attribute. -class ToOtelJsonAttr a where - toOtelJsonAttrImpl :: a -> Enc - -instance ToOtelJsonAttr Enc where - toOtelJsonAttrImpl = id - --- | Bytes are leniently converted to Text, because they are often used as UTF-8 encoded strings. -instance ToOtelJsonAttr ByteString where - toOtelJsonAttrImpl = Enc.text . bytesToTextUtf8Lenient - -instance ToOtelJsonAttr Text where - toOtelJsonAttrImpl = Enc.text - -instance ToOtelJsonAttr Int where - toOtelJsonAttrImpl = Enc.int - -instance ToOtelJsonAttr Natural where - toOtelJsonAttrImpl = Enc.natural - -instance ToOtelJsonAttr Bool where - toOtelJsonAttrImpl = Enc.bool - -instance (ToOtelJsonAttr a) => ToOtelJsonAttr (Maybe a) where - toOtelJsonAttrImpl = \case - Nothing -> Enc.null - Just a -> toOtelJsonAttrImpl a - -instance (ToOtelJsonAttr a) => ToOtelJsonAttr [a] where - toOtelJsonAttrImpl = Enc.list toOtelJsonAttrImpl - -instance (ToOtelJsonAttr t1, ToOtelJsonAttr t2, KnownSymbol l1, KnownSymbol l2) => ToOtelJsonAttr (T2 l1 t1 l2 t2) where - toOtelJsonAttrImpl (T2 a b) = - Enc.object - [ (symbolText @l1, a & getField @l1 & toOtelJsonAttrImpl), - (symbolText @l2, b & getField @l2 & toOtelJsonAttrImpl) - ] - -instance (ToOtelJsonAttr t1, ToOtelJsonAttr t2, ToOtelJsonAttr t3, KnownSymbol l1, KnownSymbol l2, KnownSymbol l3) => ToOtelJsonAttr (T3 l1 t1 l2 t2 l3 t3) where - toOtelJsonAttrImpl (T3 a b c) = - Enc.object - [ (symbolText @l1, a & getField @l1 & toOtelJsonAttrImpl), - (symbolText @l2, b & getField @l2 & toOtelJsonAttrImpl), - (symbolText @l3, c & getField @l3 & toOtelJsonAttrImpl) - ] - -instance (ToOtelJsonAttr t1, ToOtelJsonAttr t2) => ToOtelJsonAttr (t1, t2) where - toOtelJsonAttrImpl t = Enc.tuple2 toOtelJsonAttrImpl toOtelJsonAttrImpl t - -instance (ToOtelJsonAttr t1, ToOtelJsonAttr t2, ToOtelJsonAttr t3) => ToOtelJsonAttr (t1, t2, t3) where - toOtelJsonAttrImpl t = Enc.tuple3 toOtelJsonAttrImpl toOtelJsonAttrImpl toOtelJsonAttrImpl t - --- | Pretty-print the given value to a string -toOtelAttrGenericStruct :: (Generic a, GenericStructSimple (G.Rep a)) => a -> Otel.Attribute -toOtelAttrGenericStruct a = toOtelJsonAttr @Enc $ encodeSimpleValue $ G.from a - -class GenericStruct f where - encodeStructAsObject :: f a -> [(Text, Enc)] - --- :*: (product) --- Object fields (get field name and put into a list of key-value pair) -instance - (KnownSymbol l, ToOtelJsonAttr val) => - GenericStruct (G.M1 G.S (G.MetaSel (Just l) u s f) (G.K1 i val)) - where - encodeStructAsObject (G.M1 (G.K1 x)) = [(symbolText @l, toOtelJsonAttrImpl x)] - --- Concatenate two fields in a struct -instance (GenericStruct f, GenericStruct g) => GenericStruct (f G.:*: g) where - encodeStructAsObject (f G.:*: g) = encodeStructAsObject f <> encodeStructAsObject g - -class GenericStructSimple f where - encodeSimpleValue :: f a -> Enc - -instance - (ToOtelJsonAttr val, KnownSymbol l) => - GenericStructSimple (G.M1 G.S (G.MetaSel (Just l) u s f) (G.K1 i val)) - where - encodeSimpleValue (G.M1 x) = Enc.object $ [(symbolText @l, encodeSimpleValue x)] - --- pass through other M1 -instance (GenericStructSimple f) => GenericStructSimple (G.M1 G.D u f) where - encodeSimpleValue (G.M1 x) = encodeSimpleValue x - --- pass through other M1 -instance (GenericStructSimple f) => GenericStructSimple (G.M1 G.C u f) where - encodeSimpleValue (G.M1 x) = encodeSimpleValue x - --- | Encode a generic representation as an object with :*: -instance (GenericStruct f, GenericStruct g) => GenericStructSimple (f G.:*: g) where - encodeSimpleValue (a G.:*: b) = Enc.object $ encodeStructAsObject a <> encodeStructAsObject b - --- Void -instance GenericStructSimple G.V1 where - encodeSimpleValue x = case x of {} - --- Empty type is the empty object -instance GenericStructSimple G.U1 where - encodeSimpleValue _ = emptyObject - --- K1 -instance (ToOtelJsonAttr val) => GenericStructSimple (G.K1 i val) where - encodeSimpleValue (G.K1 x) = toOtelJsonAttrImpl x diff --git a/users/Profpatsch/whatcd-resolver/src/Bencode.hs b/users/Profpatsch/whatcd-resolver/src/Bencode.hs deleted file mode 100644 index f6dd8a5c3..000000000 --- a/users/Profpatsch/whatcd-resolver/src/Bencode.hs +++ /dev/null @@ -1,109 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module Bencode where - -import Aeson (jsonArray) -import Data.Aeson qualified as Json -import Data.Aeson.Key qualified as Key -import Data.Aeson.KeyMap qualified as KeyMap -import Data.BEncode (BEncode) -import Data.BEncode qualified as Bencode -import Data.ByteString.Lazy (LazyByteString) -import Data.ByteString.Lazy.Char8 qualified as Char8.Lazy -import Data.Char qualified as Char -import Data.List qualified as List -import Data.Map.Strict qualified as Map -import FieldParser qualified as Field -import Json (RestrictJsonOpts (RestrictJsonOpts), mkJsonArray) -import Json qualified -import MyPrelude -import Parse (Parse, fieldParser, mkParseNoContext, showContext) -import Pretty -import Text.Printf (printf) -import Prelude hiding (span) - -bencodeBytes :: Parse BEncode ByteString -bencodeBytes = Parse.mkParseNoContext $ \(ctx, bencode) -> case bencode of - Bencode.BString bs -> Right (toStrictBytes bs) - _ -> Left $ [fmt|Expected a bencode byte-string, but got {bencode & prettyBencodeRestricted}, at {showContext ctx}|] - -bencodeInteger :: Parse BEncode Integer -bencodeInteger = Parse.mkParseNoContext $ \(ctx, bencode) -> case bencode of - Bencode.BInt i -> Right i - _ -> Left $ [fmt|Expected a bencode integer, but got {bencode & prettyBencodeRestricted}, at {showContext ctx}|] - -bencodeNatural :: Parse BEncode Natural -bencodeNatural = bencodeInteger >>> Parse.fieldParser Field.integralToNatural - -bencodeDict :: Parse BEncode (Map Text BEncode) -bencodeDict = Parse.mkParseNoContext $ \(ctx, bencode) -> case bencode of - Bencode.BDict d -> Right $ Map.mapKeys stringToText d - _ -> Left $ [fmt|Expected a bencode dict, but got {bencode & prettyBencodeRestricted}, at {showContext ctx}|] - -bencodeList :: Parse BEncode [BEncode] -bencodeList = Parse.mkParseNoContext $ \(ctx, bencode) -> case bencode of - Bencode.BList l -> Right $ l - _ -> Left $ [fmt|Expected a bencode list, but got {bencode & prettyBencodeRestricted}, at {showContext ctx}|] - -parseBencode :: Parse ByteString BEncode -parseBencode = Parse.mkParseNoContext $ \(ctx, bs) -> do - let lazy = toLazyBytes bs - case Bencode.bRead lazy of - Nothing -> Left $ [fmt|Failed to parse bencode: {Bencode.BString lazy & prettyBencodeRestricted}, at {showContext ctx}|] - Just a -> Right a - -bencodeTextLenient :: Parse BEncode Text -bencodeTextLenient = Parse.mkParseNoContext $ \(ctx, bencode) -> do - case bencode of - Bencode.BString bs -> Right (bs & toStrictBytes & bytesToTextUtf8Lenient) - _ -> Left $ [fmt|Expected a bencode string, but got {bencode & prettyBencodeRestricted}, at {showContext ctx}|] - -prettyBencodeRestricted :: BEncode -> Text -prettyBencodeRestricted = - showPrettyJson . Json.restrictJson restriction . bencodeToJsonValue - where - restriction = - RestrictJsonOpts - { maxDepth = 3, - maxSizeObject = 10, - maxSizeArray = 10, - maxStringLength = 100 - } - -bencodeToJsonValue :: BEncode -> Json.Value -bencodeToJsonValue = \case - Bencode.BString bs -> case bs & bytesToTextUtf8Lazy of - -- If it’s not valid utf-8, let’s at least display a hexdump - Left _ -> mkJsonArray $ "hexdump of bytes:" : (hexdump 0 bs <&> Json.String) - Right a -> Json.String $ a & toStrict - Bencode.BInt i -> Json.Number (fromIntegral @Integer @Scientific i) - Bencode.BDict m -> Json.Object $ m & Map.toList <&> bimap Key.fromString bencodeToJsonValue & KeyMap.fromList - Bencode.BList l -> jsonArray $ l <&> bencodeToJsonValue - --- | Unfold using f until the predicate becomes true. -unfoldUntil :: (b -> Bool) -> (b -> (a, b)) -> b -> [a] -unfoldUntil p f = List.unfoldr (\x -> guard (not (p x)) >> pure (f x)) - --- | Return hex characters for the byte value. -bytehex :: Int -> String -bytehex n = printf "%02x" n - --- | Return a printable character, or a dot. -prChar :: Char -> Char -prChar ch - | Char.ord ch >= 32 && Char.ord ch < 128 = ch - | otherwise = '.' - --- | Return a string containing a pretty hexdump of xs using addresses --- starting at n. -hexdump :: Int -> LazyByteString -> [Text] -hexdump n xs = zipWith hexLine addrs dlines - where - addrs = [n, n + 16 ..] - dlines = unfoldUntil null (splitAt 16) (Char8.Lazy.unpack xs) - hexLine :: Int -> String -> Text - hexLine addr xs' = stringToText $ printf "%08x |%-23s %-23s| %s" addr h1 h2 s - where - h1 = unwords $ map (bytehex . Char.ord) $ take 8 xs' - h2 = unwords $ map (bytehex . Char.ord) $ drop 8 xs' - s = map prChar xs' diff --git a/users/Profpatsch/whatcd-resolver/src/Html.hs b/users/Profpatsch/whatcd-resolver/src/Html.hs deleted file mode 100644 index dc5202738..000000000 --- a/users/Profpatsch/whatcd-resolver/src/Html.hs +++ /dev/null @@ -1,70 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module Html where - -import Builder -import Data.Aeson qualified as Json -import Data.Aeson.KeyMap qualified as KeyMap -import Data.List.NonEmpty qualified as NonEmpty -import Data.Map.Strict qualified as Map -import IHP.HSX.QQ (hsx) -import PossehlAnalyticsPrelude -import Text.Blaze.Html (Html) -import Text.Blaze.Html5 qualified as Html -import Prelude hiding (span) - --- | Render an arbitrary json value to HTML in a more-or-less reasonable fashion. -mkVal :: Json.Value -> Html -mkVal = \case - Json.Number n -> Html.lazyText $ buildTextLazy scientificDecimalT n - Json.String s -> Html.toHtml @Text s - Json.Bool True -> [hsx|true|] - Json.Bool False -> [hsx|false|] - Json.Null -> [hsx|null|] - Json.Array arr -> toOrderedList mkVal arr - Json.Object obj -> - obj - & KeyMap.toMapText - & toDefinitionList (Html.toHtml @Text) mkVal - -toOrderedList :: (Foldable t1) => (t2 -> Html) -> t1 t2 -> Html -toOrderedList mkValFn arr = - arr - & foldMap (\el -> Html.li $ mkValFn el) - & Html.ol - -toUnorderedList :: (Foldable t1) => (t2 -> Html) -> t1 t2 -> Html -toUnorderedList mkValFn arr = - arr - & foldMap (\el -> Html.li $ mkValFn el) - & Html.ul - --- | Render a definition list from a Map -toDefinitionList :: (Text -> Html) -> (t -> Html) -> Map Text t -> Html -toDefinitionList mkKeyFn mkValFn obj = - obj - & Map.toList - & foldMap (\(k, v) -> Html.dt (mkKeyFn k) <> Html.dd (mkValFn v)) - & Html.dl - --- | Render a table-like structure of json values as an HTML table. -toTable :: [[(Text, Json.Value)]] -> Html -toTable xs = - case xs & nonEmpty of - Nothing -> - [hsx|

    No results.

    |] - Just xs' -> do - let headers = xs' & NonEmpty.head <&> fst <&> (\h -> [hsx|{h}|]) & mconcat - let vals = xs' & foldMap (Html.tr . foldMap (Html.td . mkVal . snd)) - [hsx| - - - - {headers} - - - - {vals} - -
    - |] diff --git a/users/Profpatsch/whatcd-resolver/src/Http.hs b/users/Profpatsch/whatcd-resolver/src/Http.hs deleted file mode 100644 index 4b1721f20..000000000 --- a/users/Profpatsch/whatcd-resolver/src/Http.hs +++ /dev/null @@ -1,268 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} -{-# OPTIONS_GHC -Wno-orphans #-} - -module Http - ( textToURI, - uriToHttpClientRequest, - doRequestJson, - RequestOptions (..), - mkRequestOptions, - httpJson, - Http.httpBS, - Http.Request, - Http.setRequestMethod, - Http.setQueryString, - Http.setRequestBodyLBS, - Http.setRequestHeader, - Http.getResponseStatus, - Http.getResponseHeader, - Http.getResponseHeaders, - Http.getResponseBody, - ) -where - -import AppT -import Control.Exception (Exception (..), SomeException) -import Control.Monad.Catch.Pure (runCatch) -import Data.Aeson qualified as Json -import Data.Aeson.BetterErrors qualified as Json -import Data.CaseInsensitive (CI (original)) -import Data.Char qualified as Char -import Data.Error.Tree -import Data.List qualified as List -import Data.List.NonEmpty qualified as NonEmpty -import Data.Ord (clamp) -import Data.Text qualified as Text -import Data.Text.Punycode qualified as Punycode -import FieldParser (FieldParser' (..)) -import FieldParser qualified as Field -import Json qualified -import Json.Enc qualified as Enc -import Label -import MyPrelude -import Network.HTTP.Client -import Network.HTTP.Client qualified as Http -import Network.HTTP.Simple qualified as Http -import Network.HTTP.Types.Status (Status (..)) -import Network.URI (URI, parseURI) -import Network.Wai.Parse qualified as Wai -import Optional -import Parse (Parse) -import Parse qualified -import Pretty -import UnliftIO.Concurrent (threadDelay) -import Prelude hiding (span) - --- | Make sure we can parse the given Text into an URI. -textToURI :: Parse Text URI -textToURI = - Parse.fieldParser - ( FieldParser $ \text -> - text - & textToString - & Network.URI.parseURI - & annotate [fmt|Cannot parse this as a URL: "{text}"|] - ) - --- | Make sure we can parse the given URI into a Request. --- --- This tries to work around the horrible, horrible interface in Http.Client. -uriToHttpClientRequest :: Parse URI Http.Request -uriToHttpClientRequest = - Parse.mkParseNoContext - ( \(ctx, url) -> - (url & Http.requestFromURI) - & runCatch - & first (checkException @Http.HttpException) - & \case - Left (Right (Http.InvalidUrlException urlText reason)) -> - Left [fmt|Unable to set the url "{urlText}" as request URL, reason: {reason}, at {Parse.showContext ctx}|] - Left (Right exc@(Http.HttpExceptionRequest _ _)) -> - Left [fmt|Weird! Should not get a HttpExceptionRequest when parsing an URL (bad library design), was {exc & displayException}, at {Parse.showContext ctx}|] - Left (Left someExc) -> - Left [fmt|Weird! Should not get anyhting but a HttpException when parsing an URL (bad library design), was {someExc & displayException}, at {Parse.showContext ctx}|] - Right req -> pure req - ) - where - checkException :: (Exception b) => SomeException -> Either SomeException b - checkException some = case fromException some of - Nothing -> Left some - Just e -> Right e - -data RequestOptions = RequestOptions - { method :: ByteString, - host :: Text, - port :: Optional Int, - path :: Optional [Text], - headers :: Optional [Http.Header], - usePlainHttp :: Optional Bool - } - -mkRequestOptions :: (HasField "method" r ByteString, HasField "host" r Text) => r -> RequestOptions -mkRequestOptions opts = - RequestOptions - { method = opts.method, - port = defaults, - host = opts.host, - path = defaults, - headers = defaults, - usePlainHttp = defaults - } - -httpJson :: - ( MonadThrow m, - MonadOtel m - ) => - (Optional (Label "contentType" ByteString)) -> - Json.Parse ErrorTree b -> - Http.Request -> - m b -httpJson opts parser req = inSpan' "HTTP Request (JSON)" $ \span -> do - let opts' = opts.withDefault (label @"contentType" "application/json") - let go = - Http.httpBS req - >>= ( \resp -> do - let statusCode = resp & Http.responseStatus & (.statusCode) - contentType = - resp - & Http.responseHeaders - & List.lookup "content-type" - <&> Wai.parseContentType - <&> (\(ct, _mimeAttributes) -> ct) - if - | statusCode == 200, - Just ct <- contentType, - ct == opts'.contentType -> - pure $ Right $ (resp & Http.responseBody) - | statusCode == 200, - Just otherType <- contentType -> - pure $ Left [fmt|Server returned a non-json body, with content-type "{otherType}"|] - | statusCode == 200, - Nothing <- contentType -> - pure $ Left [fmt|Server returned a body with unspecified content type|] - | statusCode == 429 -> do - let retryAfter = - resp - & Http.getResponseHeader "Retry-After" - & nonEmpty - >>= ( NonEmpty.head - >>> Field.runFieldParser - ( Field.utf8 - >>> (Field.decimalNatural <&> toInteger) - >>> (Field.bounded @Int "Int" <&> clamp @Int (0, 10)) - ) - >>> hush - ) - & fromMaybe 2 - inSpan' "HTTP Request (JSON) - Rate Limited" $ \span' -> do - addAttribute span' "request.response.status" statusCode - addAttribute span' "request.response.retry-after" retryAfter - threadDelay (retryAfter * 1_000_000) - go - | code <- statusCode -> pure $ Left $ AppExceptionPretty [[fmt|Server returned an non-200 error code, code {code}:|], pretty resp] - ) - go - >>= orAppThrow span - >>= \body -> do - val <- - Json.eitherDecodeStrict body - & first (\err -> AppExceptionTree $ nestedError "HTTP response was not valid JSON" (err & stringToText & newError & singleError)) - & orAppThrow span - - let res = Json.parseValue parser val - case res of - Left e -> do - let err = Json.parseErrorTreeValCtx val e - appThrow - span - ( AppExceptionEnc $ - Enc.tuple3 - Enc.text - Enc.enc - (Enc.nullOr Enc.value) - ("Could not parse HTTP response", err.errorMessage, err.valueAtErrorPath) - ) - Right a -> pure a - -doRequestJson :: - (MonadOtel m) => - RequestOptions -> - Enc.Enc -> - m (Response ByteString) -doRequestJson opts val = inSpan' "HTTP Request (JSON)" $ \span -> do - addAttribute span "request.xh" (requestToXhCommandLine opts val) - resp <- - defaultRequest {secure = not (opts & optsUsePlainHttp)} - & Http.setRequestHost (opts & optsHost) - & Http.setRequestPort (opts & optsPort) - -- TODO: is this automatically escaped by the library? - & Http.setRequestPath (opts & optsPath) - & Http.setRequestHeaders (opts & optsHeaders) - & Http.setRequestMethod opts.method - & Http.setRequestBodyLBS (Enc.encToBytesUtf8Lazy val) - & Http.httpBS - let code = resp & Http.getResponseStatus & (.statusCode) - let msg = resp & Http.getResponseStatus & (.statusMessage) & bytesToTextUtf8Lenient - addAttribute - span - "request.response.status" - ([fmt|{code} {msg}|] :: Text) - pure resp - -optsHost :: RequestOptions -> ByteString -optsHost opts = - if opts.host & Text.isAscii - then opts.host & textToBytesUtf8 - else opts.host & Punycode.encode - -optsUsePlainHttp :: RequestOptions -> Bool -optsUsePlainHttp opts = opts.usePlainHttp.withDefault False - -optsPort :: RequestOptions -> Int -optsPort opts = opts.port.withDefault (if opts & optsUsePlainHttp then 80 else 443) - -optsPath :: RequestOptions -> ByteString -optsPath opts = opts.path.withDefault [] & Text.intercalate "/" & ("/" <>) & textToBytesUtf8 - -optsHeaders :: RequestOptions -> [Http.Header] -optsHeaders opts = opts.headers.withDefault [] - --- | Create a string that can be pasted on the command line to invoke the same HTTP request via the `xh` tool (curl but nicer syntax) -requestToXhCommandLine :: RequestOptions -> Enc.Enc -> Text -requestToXhCommandLine opts val = do - let protocol = if opts & optsUsePlainHttp then "http" :: Text else "https" - let url = [fmt|{protocol}://{opts & optsHost}:{opts & optsPort}{opts & optsPath}|] - let headers = opts & optsHeaders <&> \(hdr, v) -> hdr.original <> ":" <> v - - prettyArgsForBash $ - mconcat - [ ["xh", url], - headers <&> bytesToTextUtf8Lenient, - ["--raw"], - [val & Enc.encToBytesUtf8 & bytesToTextUtf8Lenient] - ] - --- | Pretty print a command line in a way that can be copied to bash. -prettyArgsForBash :: [Text] -> Text -prettyArgsForBash = Text.intercalate " " . map simpleBashEscape - --- | Simple escaping for bash words. If they contain anything that’s not ascii chars --- and a bunch of often-used special characters, put the word in single quotes. -simpleBashEscape :: Text -> Text -simpleBashEscape t = do - case Text.find (not . isSimple) t of - Just _ -> escapeSingleQuote t - Nothing -> t - where - -- any word that is just ascii characters is simple (no spaces or control characters) - -- or contains a few often-used characters like - or . - isSimple c = - Char.isAsciiLower c - || Char.isAsciiUpper c - || Char.isDigit c - -- These are benign, bash will not interpret them as special characters. - || List.elem c ['-', '.', ':', '/'] - -- Put the word in single quotes - -- If there is a single quote in the word, - -- close the single quoted word, add a single quote, open the word again - escapeSingleQuote t' = "'" <> Text.replace "'" "'\\''" t' <> "'" diff --git a/users/Profpatsch/whatcd-resolver/src/JsonLd.hs b/users/Profpatsch/whatcd-resolver/src/JsonLd.hs deleted file mode 100644 index db2fb9434..000000000 --- a/users/Profpatsch/whatcd-resolver/src/JsonLd.hs +++ /dev/null @@ -1,135 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module JsonLd where - -import AppT -import Data.Aeson qualified as Json -import Data.Aeson.BetterErrors qualified as Json -import Data.ByteString.Builder qualified as Builder -import Data.List qualified as List -import Data.Map.Strict qualified as Map -import Data.Set (Set) -import Data.Set qualified as Set -import Html qualified -import Http -import IHP.HSX.QQ (hsx) -import Json qualified -import Label -import MyPrelude -import Network.HTTP.Types.URI qualified as Url -import Network.URI (URI) -import Optional -import Text.Blaze.Html (Html) -import Prelude hiding (span) - --- | A recursive `json+ld` structure. -data Jsonld - = JsonldObject JsonldObject - | JsonldAnonymousObject JsonldAnonymousObject - | JsonldArray [Jsonld] - | JsonldField Json.Value - deriving stock (Show, Eq) - --- | A json+ld object, that is something which can be further expanded by following the URL in its `id_` field. -data JsonldObject = JsonldObject' - { -- | `@type` field; currently just the plain value without taking into account the json+ld context - type_ :: Set Text, - -- | `@id` field, usually a link to follow for expanding the object to its full glory - id_ :: Text, - -- | any fields of this object that remote deemed important enough to already pre-emptively include in the object; to get all fields resolve the URL in `id_`. - previewFields :: Map Text Jsonld - } - deriving stock (Show, Eq) - --- | A json+ld object that cannot be inspected further by resolving its ID -data JsonldAnonymousObject = JsonldAnonymousObject' - { -- | `@type` field; currently just the plain value without taking into account the json+ld context - type_ :: Set Text, - -- | fields of this anonymous object - fields :: Map Text Jsonld - } - deriving stock (Show, Eq) - -jsonldParser :: (Monad m) => Json.ParseT err m Jsonld -jsonldParser = - Json.asValue >>= \cur -> do - if - | Json.Object _ <- cur -> do - type_ <- - Json.keyMay "@type" (Json.asArraySet Json.asText Json.<|> (Set.singleton <$> Json.asText)) - <&> fromMaybe Set.empty - idMay <- Json.keyMay "@id" $ Json.asText - fields <- - Json.asObjectMap jsonldParser - <&> Map.delete "@type" - <&> Map.delete "@id" - - if - | Just id_ <- idMay -> do - pure $ JsonldObject $ JsonldObject' {previewFields = fields, ..} - | otherwise -> pure $ JsonldAnonymousObject $ JsonldAnonymousObject' {..} - | Json.Array _ <- cur -> do - JsonldArray <$> Json.eachInArray jsonldParser - | otherwise -> pure $ JsonldField cur - -renderJsonld :: Jsonld -> Html -renderJsonld = \case - JsonldObject obj -> renderObject obj (Just obj.id_) obj.previewFields - JsonldAnonymousObject obj -> renderObject obj Nothing obj.fields - JsonldArray arr -> - Html.toOrderedList renderJsonld arr - JsonldField f -> Html.mkVal f - where - renderObject obj mId_ fields = do - let id_ = - mId_ <&> \i -> - [hsx| -
    Url
    -
    {i}
    - |] - getMoreButton = - mId_ <&> \i -> - [hsx| -
    - -
    - |] - [hsx| -
    -
    Type
    -
    {obj.type_ & toList & schemaTypes}
    - {id_} -
    Fields
    -
    - {fields & Html.toDefinitionList schemaType renderJsonld} - {getMoreButton} -
    -
    - |] - snippetHref target = - Builder.toLazyByteString $ - "/snips/jsonld/render" - <> Url.renderQueryBuilder True [("target", Just (textToBytesUtf8 target))] - - schemaTypes xs = - xs - <&> schemaType - & List.intersperse ", " - & mconcat - schemaType t = - let href :: Text = [fmt|https://schema.org/{t}|] in [hsx|{t}|] - -httpGetJsonLd :: (MonadThrow m, MonadOtel m) => (URI, Http.Request) -> m Jsonld -httpGetJsonLd (uri, req) = inSpan' "Fetch json+ld" $ \span -> do - addAttribute span "json+ld.targetUrl" (uri & showToText) - httpJson - (mkOptional (label @"contentType" "application/ld+json")) - jsonldParser - ( req - & Http.setRequestMethod "GET" - & Http.setRequestHeader "Accept" ["application/ld+json"] - ) diff --git a/users/Profpatsch/whatcd-resolver/src/Optional.hs b/users/Profpatsch/whatcd-resolver/src/Optional.hs deleted file mode 100644 index 9791c8497..000000000 --- a/users/Profpatsch/whatcd-resolver/src/Optional.hs +++ /dev/null @@ -1,18 +0,0 @@ -module Optional where - -import GHC.Records (getField) -import MyPrelude - -newtype Optional a = OptionalInternal (Maybe a) - deriving newtype (Functor) - -mkOptional :: a -> Optional a -mkOptional defaultValue = OptionalInternal $ Just defaultValue - -defaults :: Optional a -defaults = OptionalInternal Nothing - -instance HasField "withDefault" (Optional a) (a -> a) where - getField (OptionalInternal m) defaultValue = case m of - Nothing -> defaultValue - Just a -> a diff --git a/users/Profpatsch/whatcd-resolver/src/Redacted.hs b/users/Profpatsch/whatcd-resolver/src/Redacted.hs deleted file mode 100644 index ab71636e3..000000000 --- a/users/Profpatsch/whatcd-resolver/src/Redacted.hs +++ /dev/null @@ -1,1168 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module Redacted where - -import AppT -import Arg -import Bencode -import Builder -import Comparison -import Conduit (ConduitT) -import Conduit qualified as Cond -import Control.Monad.Logger.CallStack -import Control.Monad.Reader -import Control.Monad.Trans.Resource (resourceForkWith) -import Data.Aeson qualified as Json -import Data.Aeson.BetterErrors qualified as Json -import Data.Aeson.Key qualified as Key -import Data.Aeson.KeyMap qualified as KeyMap -import Data.BEncode (BEncode) -import Data.Conduit ((.|)) -import Data.Error.Tree -import Data.List qualified as List -import Data.List.NonEmpty qualified as NonEmpty -import Data.Maybe (catMaybes) -import Data.Text.IO qualified as Text.IO -import Data.Time (NominalDiffTime, UTCTime) -import Data.Time.Clock.POSIX (posixSecondsToUTCTime) -import Database.PostgreSQL.Simple (Binary (Binary), Only (..)) -import Database.PostgreSQL.Simple qualified as Postgres -import Database.PostgreSQL.Simple.Types (PGArray (PGArray)) -import FieldParser (FieldParser) -import FieldParser qualified as Field -import Http qualified -import Json qualified -import Label -import MyLabel -import MyPrelude -import Network.HTTP.Types -import Network.Wai.Parse qualified as Wai -import OpenTelemetry.Context.ThreadLocal qualified as Otel -import OpenTelemetry.Trace qualified as Otel hiding (getTracer, inSpan, inSpan') -import Optional -import Parse (Parse, mapLookup, mapLookupMay, runParse) -import Parse qualified -import Postgres.Decoder qualified as Dec -import Postgres.MonadPostgres -import Pretty -import RevList (RevList) -import RevList qualified -import System.FilePath (()) -import UnliftIO (MonadUnliftIO, askRunInIO, async, newQSem, withQSem) -import UnliftIO.Async (Async) -import UnliftIO.Async qualified as Async -import UnliftIO.Concurrent (threadDelay) -import Prelude hiding (length, span) - -class MonadRedacted m where - getRedactedApiKey :: m ByteString - -instance (MonadIO m) => MonadRedacted (AppT m) where - getRedactedApiKey = AppT (asks (.redactedApiKey)) - -redactedSearch :: - ( MonadThrow m, - MonadOtel m, - MonadRedacted m, - HasField "actionArgs" extraArguments [(ByteString, ByteString)], - HasField "page" dat (Maybe Natural) - ) => - extraArguments -> - dat -> - Json.Parse ErrorTree a -> - m a -redactedSearch extraArguments dat parser = - inSpan' "Redacted API Search" $ \span -> - redactedPagedRequest - span - ( t3 - #action - "browse" - #actionArgs - extraArguments.actionArgs - #page - dat.page - ) - parser - -redactedGetArtist :: - ( MonadOtel m, - MonadThrow m, - MonadRedacted m, - HasField "artistId" r Int, - HasField "page" r (Maybe Natural) - ) => - r -> - Json.Parse ErrorTree a -> - m a -redactedGetArtist dat parser = - inSpan' "Redacted Get Artist" $ \span -> do - redactedPagedRequest - span - ( t3 - #action - "artist" - #actionArgs - [("id", buildBytes intDecimalB dat.artistId)] - #page - (dat.page) - ) - parser - -redactedPagedRequest :: - ( MonadThrow m, - MonadOtel m, - MonadRedacted m, - HasField "action" dat ByteString, - HasField "actionArgs" dat [(ByteString, ByteString)], - HasField "page" dat (Maybe Natural) - ) => - Otel.Span -> - dat -> - Json.Parse ErrorTree a -> - m a -redactedPagedRequest span dat parser = - redactedApiRequestJson - span - ( t2 - #action - dat.action - #actionArgs - ( (dat.actionArgs <&> second Just) - <> ( dat.page - & ifExists - (\page -> ("page", Just $ buildBytes naturalDecimalB page)) - ) - ) - ) - parser - -redactedGetTorrentFile :: - ( MonadLogger m, - MonadThrow m, - HasField "torrentId" dat Int, - HasField "useFreeleechTokens" dat Bool, - MonadOtel m, - MonadRedacted m - ) => - dat -> - m ByteString -redactedGetTorrentFile dat = inSpan' "Redacted Get Torrent File" $ \span -> do - let actionArgs = - [ ("id", Just (buildBytes intDecimalB dat.torrentId)) - ] - -- try using tokens as long as we have them (TODO: what if there’s no tokens left? - -- ANSWER: it breaks: - -- responseBody = "{\"status\":\"failure\",\"error\":\"You do not have any freeleech tokens left. Please use the regular DL link.\"}", - <> (if dat.useFreeleechTokens then [("usetoken", Just "1")] else []) - let reqDat = - ( T2 - (label @"action" "download") - ( label @"actionArgs" $ actionArgs - ) - ) - addAttribute span "redacted.request" (toOtelJsonAttr reqDat) - req <- mkRedactedApiRequest reqDat - - httpTorrent span req - -mkRedactedTorrentLink :: Arg "torrentGroupId" Int -> Text -mkRedactedTorrentLink torrentId = [fmt|https://redacted.sh/torrents.php?id={torrentId.unArg}|] - -exampleSearch :: (MonadThrow m, MonadLogger m, MonadPostgres m, MonadOtel m, MonadRedacted m) => Transaction m () -exampleSearch = do - _x1 <- - redactedSearchAndInsert - [ ("searchstr", "cherish"), - ("artistname", "kirinji"), - -- ("year", "1982"), - -- ("format", "MP3"), - -- ("releasetype", "album"), - ("order_by", "year") - ] - _x3 <- - redactedSearchAndInsert - [ ("searchstr", "mouss et hakim"), - ("artistname", "mouss et hakim"), - -- ("year", "1982"), - -- ("format", "MP3"), - -- ("releasetype", "album"), - ("order_by", "year") - ] - _x2 <- - redactedSearchAndInsert - [ ("searchstr", "thriller"), - ("artistname", "michael jackson"), - -- ("year", "1982"), - -- ("format", "MP3"), - -- ("releasetype", "album"), - ("order_by", "year") - ] - pure () - -redactedRefreshArtist :: - ( MonadLogger m, - MonadPostgres m, - MonadThrow m, - MonadOtel m, - MonadRedacted m, - HasField "artistId" dat Int - ) => - dat -> - Transaction m (Label "newTorrents" [Label "torrentId" Int]) -redactedRefreshArtist dat = do - redactedPagedSearchAndInsert - ( Json.key "torrentgroup" $ - parseTourGroups - ( t2 - #torrentFieldName - "torrent" - #torrentIdName - "id" - ) - ) - ( \page -> - redactedGetArtist - ( T2 - (getLabel @"artistId" dat) - page - ) - ) - --- | Do the search, return a transaction that inserts all results from all pages of the search. -redactedSearchAndInsert :: - (MonadLogger m, MonadPostgres m, MonadThrow m, MonadOtel m, MonadRedacted m) => - [(ByteString, ByteString)] -> - Transaction m (Label "newTorrents" [Label "torrentId" Int]) -redactedSearchAndInsert extraArguments = - redactedPagedSearchAndInsert - (Json.key "results" $ parseTourGroups (T2 (label @"torrentFieldName" "torrents") (label @"torrentIdName" "torrentId"))) - ( redactedSearch - (label @"actionArgs" extraArguments) - ) - --- | Parse the standard Redacted reply object, @{ status: "success", response: ... }@ or throw an error. --- --- The response might contain a `pages` field, if not we’ll return 1. -parseRedactedReplyStatus :: - (Monad m) => - Json.ParseT ErrorTree m b -> - Json.ParseT ErrorTree m (T2 "pages" Natural "response" b) -parseRedactedReplyStatus inner = do - status <- Json.key "status" Json.asText - when (status /= "success") $ do - Json.throwCustomError ([fmt|Status was not "success", but {status}|] :: ErrorTree) - Json.key "response" $ do - pages <- - Json.keyMay - "pages" - ( Field.toJsonParser - ( Field.mapError singleError $ - Field.jsonNumber >>> Field.boundedScientificIntegral @Int "not an Integer" >>> Field.integralToNatural - ) - ) - -- in case the field is missing, let’s assume there is only one page - <&> fromMaybe 1 - res <- inner - pure $ - T2 - (label @"pages" pages) - (label @"response" res) - -type TourGroups = - ( Label - "tourGroups" - [ T2 - "tourGroup" - TourGroup - "torrents" - [T2 "torrentId" Int "fullJsonResult" Json.Value] - ] - ) - -data TourGroup = TourGroup - { groupId :: Int, - groupName :: Text, - fullJsonResult :: Json.Value, - -- | Needed for sm0rt request recursion - groupArtists :: [Label "artistId" Int] - } - -parseTourGroups :: - ( Monad m, - HasField "torrentFieldName" opts Text, - HasField "torrentIdName" opts Text - ) => - opts -> - Json.ParseT err m TourGroups -parseTourGroups opts = - do - label @"tourGroups" - <$> ( catMaybes - <$> ( Json.eachInArray $ do - Json.keyMay opts.torrentFieldName (pure ()) >>= \case - -- not a torrent group, maybe some files or something (e.g. guitar tabs see Dream Theater Systematic Chaos) - Nothing -> pure Nothing - Just () -> do - groupId <- Json.key "groupId" (Json.asIntegral @_ @Int) - groupName <- Json.key "groupName" Json.asText - groupArtists <- - Json.keyMayMempty "artists" $ - Json.eachInArray $ - lbl #artistId <$> Json.key "id" (Json.asIntegral @_ @Int) - fullJsonResult <- - Json.asObject - -- remove torrents cause they are inserted separately below - <&> KeyMap.filterWithKey (\k _ -> k /= (opts.torrentFieldName & Key.fromText)) - <&> Json.Object - let tourGroup = TourGroup {..} - torrents <- Json.keyLabel @"torrents" opts.torrentFieldName $ - Json.eachInArray $ do - torrentId <- Json.keyLabel @"torrentId" opts.torrentIdName (Json.asIntegral @_ @Int) - fullJsonResultT <- - label @"fullJsonResult" - <$> ( Json.asObject - <&> KeyMap.mapKeyVal - ( \k -> - if - -- some torrent objects use “snatched” instead of “snatches” - | k == "snatched" -> "snatches" - -- normalize the torrent id field - | k == (opts.torrentIdName & Key.fromText) -> "torrentId" - | otherwise -> k - ) - id - <&> Json.Object - ) - pure $ T2 torrentId fullJsonResultT - pure $ Just (T2 (label @"tourGroup" tourGroup) torrents) - ) - ) - -testChunkBetween :: IO [NonEmpty Integer] -testChunkBetween = do - Cond.runConduit $ - ( do - Cond.yield [0] - Cond.yield [1, 2] - Cond.yield [3, 4] - Cond.yield [] - Cond.yield [5, 6] - Cond.yield [7] - ) - .| filterEmpty - .| chunkBetween (t2 #low 2 #high 4) - .| Cond.sinkList - -filterEmpty :: (Monad m) => ConduitT [a] (NonEmpty a) m () -filterEmpty = Cond.awaitForever yieldIfNonEmpty - --- | Chunk the given stream of lists into chunks that are between @low@ and @high@ (both incl). --- The last chunk might be shorter than low. -chunkBetween :: - ( HasField "low" p Natural, - HasField "high" p Natural, - Monad m - ) => - p -> - ConduitT (NonEmpty a) (NonEmpty a) m () -chunkBetween opts = do - go mempty - where - low = min opts.low opts.high - high = max opts.low opts.high - high' = assertField (boundedNatural @Int) high - l = lengthNatural - go !acc = do - if l acc >= low - then do - let (c, rest) = List.splitAt high' acc - yieldIfNonEmpty c - go rest - else do - xs <- Cond.await - case xs of - Nothing -> yieldIfNonEmpty acc - Just xs' -> go (acc <> NonEmpty.toList xs') - -yieldIfNonEmpty :: (Monad m) => [a] -> ConduitT i (NonEmpty a) m () -yieldIfNonEmpty = \case - IsNonEmpty xs -> Cond.yield xs - IsEmpty -> pure () - -redactedPagedSearchAndInsert :: - forall m. - ( MonadLogger m, - MonadPostgres m, - MonadOtel m - ) => - Json.Parse ErrorTree TourGroups -> - -- | A redacted request that returns a paged result - ( forall a. - Label "page" (Maybe Natural) -> - Json.Parse ErrorTree a -> - m a - ) -> - Transaction m (Label "newTorrents" [Label "torrentId" Int]) -redactedPagedSearchAndInsert innerParser pagedRequest = do - -- The first search returns the amount of pages, so we use that to query all results piece by piece. - firstPage <- go Nothing - let remainingPages = firstPage.pages - 1 - logInfo [fmt|Got the first page, found {remainingPages} more pages|] - let otherPagesNum = [(2 :: Natural) .. remainingPages] - - Cond.runConduit @(Transaction m) $ - ( do - Cond.yield (singleton firstPage) - case otherPagesNum of - IsNonEmpty o -> runConcurrentlyBunched' (lbl #batchSize 5) (go . Just <$> o) - IsEmpty -> pure () - ) - .| chunkBetween (t2 #low 5 #high 10) - .| Cond.mapMC - ( \block -> - block - & concatMap (.response.tourGroups) - & \case - IsNonEmpty tgs -> do - tgs & insertTourGroupsAndTorrents - pure $ tgs & concatMap (\tg -> tg.torrents <&> getLabel @"torrentId") - IsEmpty -> pure [] - ) - .| Cond.concatC - .| Cond.sinkList - <&> label @"newTorrents" - where - go mpage = - lift @Transaction $ - pagedRequest - (label @"page" mpage) - ( parseRedactedReplyStatus $ innerParser - ) - insertTourGroupsAndTorrents :: - NonEmpty - ( T2 - "tourGroup" - TourGroup - "torrents" - [T2 "torrentId" Int "fullJsonResult" Json.Value] - ) -> - Transaction m () - insertTourGroupsAndTorrents dat = inSpan' "Insert Tour Groups & Torrents" $ \span -> do - addAttribute span "tour_group.length" (dat & lengthNatural, naturalDecimalT) - let tourGroups = dat <&> (.tourGroup) - let torrents = dat <&> (.torrents) - insertTourGroups tourGroups - >>= ( \res -> - insertTorrents $ - zipT2 $ - T2 - (label @"torrentGroupIdPg" $ res <&> (.tourGroupIdPg)) - (label @"torrents" (torrents & toList)) - ) - insertTourGroups :: - NonEmpty TourGroup -> - Transaction m [Label "tourGroupIdPg" Int] - insertTourGroups dats = do - let groupNames = - dats <&> \dat -> [fmt|{dat.groupId}: {dat.groupName}|] - logInfo [fmt|Inserting tour groups for {showPretty groupNames}|] - _ <- - execute - [fmt| - DELETE FROM redacted.torrent_groups - WHERE group_id = ANY (?::integer[]) - |] - (Only $ (dats <&> (.groupId) & toList & PGArray :: PGArray Int)) - executeManyReturningWith - [fmt| - INSERT INTO redacted.torrent_groups ( - group_id, group_name, full_json_result - ) VALUES - ( ?, ? , ? ) - ON CONFLICT (group_id) DO UPDATE SET - group_id = excluded.group_id, - group_name = excluded.group_name, - full_json_result = excluded.full_json_result - RETURNING (id) - |] - ( dats - -- make sure we don’t have the same conflict target twice - & NonEmpty.nubBy (\a b -> a.groupId == b.groupId) - <&> ( \dat -> - ( dat.groupId, - dat.groupName, - dat.fullJsonResult - ) - ) - ) - (label @"tourGroupIdPg" <$> Dec.fromField @Int) - - insertTorrents :: - [ T2 - "torrentGroupIdPg" - Int - "torrents" - [T2 "torrentId" Int "fullJsonResult" Json.Value] - ] -> - Transaction m () - insertTorrents dats = do - _ <- - execute - [sql| - DELETE FROM redacted.torrents_json - WHERE torrent_id = ANY (?::integer[]) - |] - ( Only $ - PGArray - [ torrent.torrentId - | dat <- dats, - torrent <- dat.torrents - ] - ) - - execute - [sql| - INSERT INTO redacted.torrents_json - ( torrent_group - , torrent_id - , full_json_result) - SELECT * - FROM UNNEST( - ?::integer[] - , ?::integer[] - , ?::jsonb[] - ) AS inputs( - torrent_group - , torrent_id - , full_json_result) - |] - ( [ T3 - (getLabel @"torrentGroupIdPg" dat) - (getLabel @"torrentId" group) - (getLabel @"fullJsonResult" group) - | dat <- dats, - group <- dat.torrents - ] - & List.nubBy (\a b -> a.torrentId == b.torrentId) - & unzip3PGArray - @"torrentGroupIdPg" - @Int - @"torrentId" - @Int - @"fullJsonResult" - @Json.Value - ) - pure () - --- | Traverse over the given function in parallel, but only allow a certain amount of concurrent requests. --- Will start new threads as soon as a resource becomes available, but always return results in input ordering. -runConcurrentlyBunched' :: - forall m opts a. - ( MonadUnliftIO m, - HasField "batchSize" opts Natural - ) => - opts -> - -- | list of actions to run - NonEmpty (m a) -> - ConduitT () (NonEmpty a) m () -runConcurrentlyBunched' opts acts = do - let batchSize = assertField (boundedNatural @Int) opts.batchSize - runInIO <- lift askRunInIO - -- NB: make sure none of the asyncs escape from here - Cond.transPipe (Cond.runResourceT @m) $ do - -- This use of resourceForkWith looks a little off, but it’s the only way to return an `Async a`, I hope it brackets correctly lol - ctx <- Otel.getContext - let spawn :: m a -> Cond.ResourceT m (Async a) - spawn f = resourceForkWith (\io -> async (io >> Otel.attachContext ctx >> runInIO f)) (pure ()) - qsem <- newQSem batchSize - - -- spawn all asyncs here, but limit how many get run consecutively by threading through a semaphore - spawned <- for acts $ \act -> - lift $ spawn $ withQSem qsem $ act - - Cond.yieldMany (spawned & NonEmpty.toList) - .| awaitAllReadyAsyncs - --- | Consume as many asyncs as are ready and return their results. --- --- Make sure they are already running (if you use 'Cond.yieldM' they are only started when awaited by the conduit). --- --- If any async throws an exception, the exception will be thrown in the conduit. --- Already running asyncs will not be cancelled. (TODO: can we somehow make that a thing?) -awaitAllReadyAsyncs :: forall m a. (MonadIO m) => ConduitT (Async a) (NonEmpty a) m () -awaitAllReadyAsyncs = go - where - -- wait for the next async and then consume as many as are already done - go :: ConduitT (Async a) (NonEmpty a) m () - go = do - Cond.await >>= \case - Nothing -> pure () - Just nextAsync -> do - res <- Async.wait nextAsync - -- consume as many asyncs as are already done - goAllReady (RevList.singleton res) - - goAllReady :: RevList a -> ConduitT (Async a) (NonEmpty a) m () - goAllReady !acc = do - next <- Cond.await - case next of - Nothing -> yieldIfNonEmptyRev acc - Just a -> do - thereAlready <- Async.poll a - case thereAlready of - Nothing -> do - -- consumed everything that was available, yield and wait for the next block - yieldIfNonEmptyRev acc - Cond.leftover a - go - Just _ -> do - -- will not block - res <- Async.wait a - goAllReady (acc <> RevList.singleton res) - - yieldIfNonEmptyRev :: RevList a -> ConduitT (Async a) (NonEmpty a) m () - yieldIfNonEmptyRev r = do - case r & RevList.revListToList of - IsNonEmpty e -> Cond.yield e - IsEmpty -> pure () - -testAwaitAllReadyAsyncs :: IO [[Char]] -testAwaitAllReadyAsyncs = - Cond.runConduit $ - ( do - running <- - lift $ - sequence - [ async (print "foo" >> pure 'a'), - async (pure 'b'), - async (threadDelay 5000 >> pure 'c'), - async (print "bar" >> pure '5'), - async (threadDelay 1_000_000 >> print "lol" >> pure 'd'), - async (error "no"), - async (print "baz" >> pure 'f') - ] - Cond.yieldMany running - ) - .| awaitAllReadyAsyncs - .| Cond.mapC toList - .| Cond.sinkList - --- | Run the field parser and throw an uncatchable assertion error if it fails. -assertField :: (HasCallStack) => FieldParser from to -> from -> to -assertField parser from = Field.runFieldParser parser from & unwrapError - -boundedNatural :: forall i. (Integral i, Bounded i) => FieldParser Natural i -boundedNatural = lmap naturalToInteger (Field.bounded @i "boundedNatural") - -redactedGetTorrentFileAndInsert :: - ( HasField "torrentId" r Int, - HasField "useFreeleechTokens" r Bool, - MonadPostgres m, - MonadThrow m, - MonadLogger m, - MonadOtel m, - MonadRedacted m - ) => - r -> - Transaction m (Label "torrentFile" ByteString) -redactedGetTorrentFileAndInsert dat = inSpan' "Redacted Get Torrent File and Insert" $ \span -> do - bytes <- lift $ redactedGetTorrentFile dat - execute - [sql| - UPDATE redacted.torrents_json - SET torrent_file = ?::bytea - WHERE torrent_id = ?::integer - |] - ( (Binary bytes :: Binary ByteString), - dat.torrentId - ) - >>= assertOneUpdated span "redactedGetTorrentFileAndInsert" - >>= \() -> pure (label @"torrentFile" bytes) - -getTorrentFileById :: - ( MonadPostgres m, - HasField "torrentId" r Int, - MonadThrow m - ) => - r -> - Transaction m (Maybe (Label "torrentFile" ByteString)) -getTorrentFileById dat = do - queryWith - [sql| - SELECT torrent_file - FROM redacted.torrents - WHERE torrent_id = ?::integer - |] - (Only $ (dat.torrentId :: Int)) - (fmap @Maybe (label @"torrentFile") <$> Dec.byteaMay) - >>= ensureSingleRow - -updateTransmissionTorrentHashById :: - ( MonadPostgres m, - HasField "torrentId" r Int, - HasField "torrentHash" r Text - ) => - r -> - Transaction m (Label "numberOfRowsAffected" Natural) -updateTransmissionTorrentHashById dat = do - execute - [sql| - UPDATE redacted.torrents_json - SET transmission_torrent_hash = ?::text - WHERE torrent_id = ?::integer - |] - ( dat.torrentHash :: Text, - dat.torrentId :: Int - ) - -assertOneUpdated :: - (HasField "numberOfRowsAffected" r Natural, MonadThrow m, MonadIO m) => - Otel.Span -> - Text -> - r -> - m () -assertOneUpdated span name x = case x.numberOfRowsAffected of - 1 -> pure () - n -> appThrow span ([fmt|{name :: Text}: Expected to update exactly one row, but updated {n :: Natural} row(s)|]) - -data TorrentData transmissionInfo = TorrentData - { groupId :: Int, - torrentId :: Int, - releaseType :: ReleaseType, - seedingWeight :: Int, - artists :: [T2 "artistId" Int "artistName" Text], - torrentGroupJson :: TorrentGroupJson, - torrentStatus :: TorrentStatus transmissionInfo, - torrentFormat :: Text - } - --- | https://redacted.sh/wiki.php?action=article&id=455#_1804298149 -data ReleaseType = ReleaseType {intKey :: Int, stringKey :: Text} - deriving stock (Eq, Show) - -releaseTypeFromTextOrIntKey :: Text -> ReleaseType -releaseTypeFromTextOrIntKey t = - allReleaseTypesSorted - & List.find - ( \rt -> do - rt.stringKey == t || buildText intDecimalT rt.intKey == t - ) - & fromMaybe (ReleaseType {intKey = (-1), stringKey = t}) - -releaseTypeComparison :: Comparison ReleaseType -releaseTypeComparison = listIndexComparison allReleaseTypesSorted - -allReleaseTypesSorted :: [ReleaseType] -allReleaseTypesSorted = - [ releaseTypeAlbum, - releaseTypeLiveAlbum, - releaseTypeAnthology, - releaseTypeSoundtrack, - releaseTypeEP, - releaseTypeCompilation, - releaseTypeSingle, - releaseTypeRemix, - releaseTypeBootleg, - releaseTypeInterview, - releaseTypeMixtape, - releaseTypeDemo, - releaseTypeConcertRecording, - releaseTypeDJMix, - releaseTypeUnknown, - releaseTypeProducedBy, - releaseTypeComposition, - releaseTypeRemixedBy, - releaseTypeGuestAppearance - ] - -releaseTypeAlbum, releaseTypeSoundtrack, releaseTypeEP, releaseTypeAnthology, releaseTypeCompilation, releaseTypeSingle, releaseTypeLiveAlbum, releaseTypeRemix, releaseTypeBootleg, releaseTypeInterview, releaseTypeMixtape, releaseTypeDemo, releaseTypeConcertRecording, releaseTypeDJMix, releaseTypeUnknown, releaseTypeProducedBy, releaseTypeComposition, releaseTypeRemixedBy, releaseTypeGuestAppearance :: ReleaseType -releaseTypeAlbum = ReleaseType 1 "Album" -releaseTypeSoundtrack = ReleaseType 3 "Soundtrack" -releaseTypeEP = ReleaseType 5 "EP" -releaseTypeAnthology = ReleaseType 6 "Anthology" -releaseTypeCompilation = ReleaseType 7 "Compilation" -releaseTypeSingle = ReleaseType 9 "Single" -releaseTypeLiveAlbum = ReleaseType 11 "Live album" -releaseTypeRemix = ReleaseType 13 "Remix" -releaseTypeBootleg = ReleaseType 14 "Bootleg" -releaseTypeInterview = ReleaseType 15 "Interview" -releaseTypeMixtape = ReleaseType 16 "Mixtape" -releaseTypeDemo = ReleaseType 17 "Demo" -releaseTypeConcertRecording = ReleaseType 18 "Concert Recording" -releaseTypeDJMix = ReleaseType 19 "DJ Mix" -releaseTypeUnknown = ReleaseType 21 "Unknown" -releaseTypeProducedBy = ReleaseType 1021 "Produced By" -releaseTypeComposition = ReleaseType 1022 "Composition" -releaseTypeRemixedBy = ReleaseType 1023 "Remixed By" -releaseTypeGuestAppearance = ReleaseType 1024 "Guest Appearance" - -data TorrentGroupJson = TorrentGroupJson - { groupName :: Text, - groupYear :: Natural - } - -data TorrentStatus transmissionInfo - = NoTorrentFileYet - | NotInTransmissionYet - | InTransmission (T2 "torrentHash" Text "transmissionInfo" transmissionInfo) - -getTorrentById :: (MonadPostgres m, HasField "torrentId" r Int, MonadThrow m) => r -> Transaction m Json.Value -getTorrentById dat = do - queryWith - [sql| - SELECT full_json_result FROM redacted.torrents - WHERE torrent_id = ?::integer - |] - (getLabel @"torrentId" dat) - (Dec.json Json.asValue) - >>= ensureSingleRow - -data GetBestTorrentsFilter = GetBestTorrentsFilter - { onlyArtist :: Maybe (Label "artistRedactedId" Int), - onlyTheseTorrents :: Maybe ([Label "torrentId" Int]), - disallowedReleaseTypes :: [ReleaseType], - limitResults :: Maybe Natural, - ordering :: BestTorrentsOrdering, - onlyFavourites :: Bool - } - -data BestTorrentsOrdering = BySeedingWeight | ByLastReleases - --- | Find the best torrent for each torrent group (based on the seeding_weight) -getBestTorrents :: - (MonadPostgres m) => - GetBestTorrentsFilter -> - Transaction m [TorrentData ()] -getBestTorrents opts = do - queryWith - ( [sql| - WITH - artist_has_been_snatched AS ( - SELECT DISTINCT artist_id - FROM ( - SELECT - UNNEST(artist_ids) as artist_id, - t.torrent_file IS NOT NULL as has_torrent_file - FROM redacted.torrents t) as _ - WHERE has_torrent_file - ), - filtered_torrents AS ( - SELECT DISTINCT ON (torrent_group) - id - FROM - redacted.torrents - JOIN LATERAL - -- filter everything that’s not a favourite if requested - (SELECT ( - artist_ids && ARRAY(SELECT artist_id FROM redacted.artist_favourites) - OR artist_ids && ARRAY(SELECT artist_id FROM artist_has_been_snatched) - ) as is_favourite) as _ - ON (NOT ?::bool OR is_favourite) - WHERE - -- filter by artist id - (?::bool OR (?::int = any (artist_ids))) - -- filter by torrent ids - AND - (?::bool OR torrent_id = ANY (?::int[])) - ORDER BY - torrent_group, - -- prefer torrents which we already downloaded - torrent_file, - seeding_weight DESC - ), - prepare1 AS ( - SELECT - tg.group_id, - t.torrent_id, - t.seeding_weight, - tg.full_json_result->>'releaseType' AS release_type, - -- TODO: different endpoints handle this differently (e.g. action=search and action=artist), we should unify this while parsing - COALESCE( - t.full_json_result->'artists', - tg.full_json_result->'artists', - '[]'::jsonb - ) as artists, - t.artist_ids || tg.artist_ids as artist_ids, - tg.full_json_result->>'groupName' AS group_name, - tg.full_json_result->>'groupYear' AS group_year, - t.torrent_file IS NOT NULL AS has_torrent_file, - t.transmission_torrent_hash, - t.full_json_result->>'encoding' AS torrent_format - FROM filtered_torrents f - JOIN redacted.torrents t ON t.id = f.id - JOIN redacted.torrent_groups tg ON tg.id = t.torrent_group - WHERE - tg.full_json_result->>'releaseType' <> ALL (?::text[]) - ) - SELECT - group_id, - torrent_id, - seeding_weight, - release_type, - artists, - group_name, - group_year, - has_torrent_file, - transmission_torrent_hash, - torrent_format - FROM prepare1 - |] - <> case opts.ordering of - BySeedingWeight -> [fmt|ORDER BY seeding_weight DESC|] <> "\n" - ByLastReleases -> [fmt|ORDER BY group_id DESC|] <> "\n" - <> [sql| - LIMIT ?::int - |] - ) - ( do - let (onlyArtistB, onlyArtistId) = case opts.onlyArtist of - Nothing -> (True, 0) - Just a -> (False, a.artistRedactedId) - let (onlyTheseTorrentsB, onlyTheseTorrents) = case opts.onlyTheseTorrents of - Nothing -> (True, PGArray []) - Just a -> (False, a <&> (.torrentId) & PGArray) - ( opts.onlyFavourites :: Bool, - onlyArtistB :: Bool, - onlyArtistId :: Int, - onlyTheseTorrentsB :: Bool, - onlyTheseTorrents, - (opts.disallowedReleaseTypes & concatMap (\rt -> [rt.stringKey, rt.intKey & buildText intDecimalT]) & PGArray :: PGArray Text), - opts.limitResults <&> naturalToInteger :: Maybe Integer - ) - ) - ( do - groupId <- Dec.fromField @Int - torrentId <- Dec.fromField @Int - seedingWeight <- Dec.fromField @Int - releaseType <- releaseTypeFromTextOrIntKey <$> Dec.text - artists <- Dec.json $ - Json.eachInArray $ do - id_ <- Json.keyLabel @"artistId" "id" (Json.asIntegral @_ @Int) - name <- Json.keyLabel @"artistName" "name" Json.asText - pure $ T2 id_ name - torrentGroupJson <- do - groupName <- Dec.text - groupYear <- Dec.textParse Field.decimalNatural - pure $ TorrentGroupJson {..} - hasTorrentFile <- Dec.fromField @Bool - transmissionTorrentHash <- Dec.fromField @(Maybe Text) - torrentFormat <- Dec.text - pure $ - TorrentData - { torrentStatus = - if - | not hasTorrentFile -> NoTorrentFileYet - | Nothing <- transmissionTorrentHash -> NotInTransmissionYet - | Just hash <- transmissionTorrentHash -> - InTransmission $ - T2 (label @"torrentHash" hash) (label @"transmissionInfo" ()), - torrentFormat = case torrentFormat of - "Lossless" -> "flac" - "V0 (VBR)" -> "V0" - "V2 (VBR)" -> "V2" - "320" -> "320" - "256" -> "256" - o -> o, - .. - } - ) - -getArtistNameById :: (MonadPostgres m, HasField "artistId" r Int) => r -> Transaction m (Maybe Text) -getArtistNameById dat = do - queryFirstRowWithMaybe - [sql| - SELECT artist_name FROM redacted.artist_names - WHERE artist_id = ?::int - LIMIT 1 - |] - (getLabel @"artistId" dat) - (Dec.fromField @Text) - --- | Do a request to the redacted API. If you know what that is, you know how to find the API docs. -mkRedactedApiRequest :: - ( MonadThrow m, - HasField "action" p ByteString, - HasField "actionArgs" p [(ByteString, Maybe ByteString)], - MonadRedacted m - ) => - p -> - m Http.Request -mkRedactedApiRequest dat = do - authKey <- getRedactedApiKey - pure $ - [fmt|https://redacted.sh/ajax.php|] - & Http.setRequestMethod "GET" - & Http.setQueryString (("action", Just dat.action) : dat.actionArgs) - & Http.setRequestHeader "Authorization" [authKey] - -httpTorrent :: - ( MonadIO m, - MonadThrow m - ) => - Otel.Span -> - Http.Request -> - m ByteString -httpTorrent span req = - Http.httpBS req - >>= assertM - span - ( \resp -> do - let statusCode = resp & Http.getResponseStatus & (.statusCode) - contentType = - resp - & Http.getResponseHeaders - & List.lookup "content-type" - <&> Wai.parseContentType - <&> (\(ct, _mimeAttributes) -> ct) - if - | statusCode == 200, - Just "application/x-bittorrent" <- contentType -> - Right $ (resp & Http.getResponseBody) - | statusCode == 200, - Just otherType <- contentType -> - Left [fmt|Redacted returned a non-torrent body, with content-type "{otherType}"|] - | statusCode == 200, - Nothing <- contentType -> - Left [fmt|Redacted returned a body with unspecified content type|] - | code <- statusCode -> Left $ AppExceptionPretty [[fmt|Redacted returned an non-200 error code, code {code}|], pretty resp] - ) - -redactedApiRequestJson :: - ( MonadThrow m, - HasField "action" p ByteString, - HasField "actionArgs" p [(ByteString, Maybe ByteString)], - MonadOtel m, - MonadRedacted m - ) => - Otel.Span -> - p -> - Json.Parse ErrorTree a -> - m a -redactedApiRequestJson span dat parser = do - addAttribute span "redacted.request" (toOtelJsonAttr (T2 (getLabel @"action" dat) (getLabel @"actionArgs" dat))) - mkRedactedApiRequest dat - >>= Http.httpJson defaults parser - -test :: (MonadThrow m, MonadRedacted m, MonadOtel m) => m () -test = - inSpan' "test" $ \span -> do - redactedApiRequestJson - span - (T2 (label @"action" "artist") (label @"actionArgs" [("id", Just "2785")])) - (Json.asValue) - <&> Pretty.showPrettyJsonColored - >>= liftIO . putStderrLn - -readTorrentFile :: (MonadIO m, MonadPostgres m) => m () -readTorrentFile = runTransaction $ do - torrentBytes <- - queryWith - [sql| - SELECT torrent_file from redacted.torrents where torrent_file is not null limit 10 |] - () - Dec.bytea - liftIO $ for_ torrentBytes $ \b -> case testBencode b of - Left e -> do - Text.IO.putStrLn $ prettyErrorTree e - Right a -> printPretty a - liftIO $ print $ lengthNatural torrentBytes - -testBencode :: ByteString -> (Either ErrorTree TorrentFile) -testBencode bs = Parse.runParse "cannot parse bencode" (parseBencode >>> bencodeTorrentParser) bs - --- | A torrent file --- --- from wikipedia: --- --- * announce—the URL of the high tracker --- * info—this maps to a dictionary whose keys are very dependent on whether one or more files are being shared: --- - files—a list of dictionaries each corresponding to a file (only when multiple files are being shared). Each dictionary has the following keys: --- * length—size of the file in bytes. --- * path—a list of strings corresponding to subdirectory names, the last of which is the actual file name --- - length—size of the file in bytes (only when one file is being shared though) --- - name—suggested filename where the file is to be saved (if one file)/suggested directory name where the files are to be saved (if multiple files) --- - piece length—number of bytes per piece. This is commonly 28 KiB = 256 KiB = 262,144 B. --- - pieces—a hash list, i.e., a concatenation of each piece's SHA-1 hash. As SHA-1 returns a 160-bit hash, pieces will be a string whose length is a multiple of 20 bytes. If the torrent contains multiple files, the pieces are formed by concatenating the files in the order they appear in the files dictionary (i.e., all pieces in the torrent are the full piece length except for the last piece, which may be shorter). -data TorrentFile = TorrentFile - { announce :: Text, - comment :: Maybe Text, - createdBy :: Maybe Text, - creationDate :: Maybe UTCTime, - encoding :: Maybe Text, - info :: Info - } - deriving stock (Eq, Show) - -data Info = Info - { name :: Text, - files :: [File], - pieceLength :: Natural, - pieces :: ByteString, - private :: Maybe Bool, - source :: Maybe Text - } - deriving stock (Eq, Show) - -data File = File - { length_ :: Natural, - path :: [Text] - } - deriving stock (Eq, Show) - -bencodeTorrentParser :: Parse BEncode TorrentFile -bencodeTorrentParser = - bencodeDict >>> do - announce <- mapLookup "announce" bencodeTextLenient - comment <- mapLookupMay "comment" bencodeTextLenient - createdBy <- mapLookupMay "created by" bencodeTextLenient - creationDate <- mapLookupMay "creation date" (bencodeInteger <&> posixSecondsToUTCTime . fromInteger @NominalDiffTime) - encoding <- mapLookupMay "encoding" bencodeTextLenient - info <- - mapLookup "info" $ - bencodeDict >>> do - name <- mapLookup "name" bencodeTextLenient - files <- - mapLookup "files" $ - bencodeList - >>> ( Parse.multiple $ - bencodeDict >>> do - length_ <- mapLookup "length" bencodeNatural - path <- mapLookup "path" $ bencodeList >>> Parse.multiple bencodeTextLenient - pure $ File {..} - ) - pieceLength <- mapLookup "piece length" bencodeNatural - pieces <- mapLookup "pieces" bencodeBytes - private <- - mapLookupMay "private" bencodeInteger - <&> fmap - ( \case - 0 -> False - _ -> True - ) - source <- mapLookupMay "source" bencodeTextLenient - pure Info {..} - pure TorrentFile {..} - -getTorrentFilePath :: (MonadPostgres m, HasField "torrentId" dat Int, HasField "fileId" dat Natural) => dat -> m (Maybe FilePath) -getTorrentFilePath dat = do - mTorrent <- - runTransaction $ - queryFirstRowWithMaybe - [fmt| - SELECT torrent_file FROM redacted.torrents - WHERE torrent_file IS NOT NULL - AND torrent_id = ?::int - |] - ( Only $ (dat.torrentId :: Int) - ) - ( Dec.parse @(Postgres.Binary ByteString) - (lmap (Postgres.fromBinary) parseBencode >>> bencodeTorrentParser) - ) - if - | Just torrent <- mTorrent -> - pure $ - torrent.info.files - & atMay dat.fileId - <&> (\f -> (torrent.info.name & textToString) (f.path <&> textToString & foldl' () "")) - | otherwise -> pure Nothing diff --git a/users/Profpatsch/whatcd-resolver/src/Transmission.hs b/users/Profpatsch/whatcd-resolver/src/Transmission.hs deleted file mode 100644 index 11a0d565f..000000000 --- a/users/Profpatsch/whatcd-resolver/src/Transmission.hs +++ /dev/null @@ -1,337 +0,0 @@ -{-# LANGUAGE QuasiQuotes #-} - -module Transmission where - -import AppT -import Builder -import Control.Monad.Logger.CallStack -import Control.Monad.Reader -import Data.Aeson qualified as Json -import Data.Aeson.BetterErrors qualified as Json -import Data.Aeson.KeyMap qualified as KeyMap -import Data.Error.Tree -import Data.HashMap.Strict qualified as HashMap -import Data.List qualified as List -import Data.List.NonEmpty qualified as NonEmpty -import Data.Map.Strict qualified as Map -import Database.PostgreSQL.Simple (Only (..)) -import Database.PostgreSQL.Simple.Types (PGArray (PGArray)) -import FieldParser (FieldParser' (..)) -import FieldParser qualified as Field -import Html qualified -import Http qualified -import Json qualified -import Json.Enc (Enc) -import Json.Enc qualified as Enc -import Label -import MyPrelude -import Network.HTTP.Types -import OpenTelemetry.Trace qualified as Otel hiding (getTracer, inSpan, inSpan') -import Optional -import Postgres.MonadPostgres -import Pretty -import Text.Blaze.Html (Html) -import UnliftIO -import Prelude hiding (span) - --- | A value between (inclusive) 0% and (inclusive) 100%. Precise to 1% steps. -newtype Percentage = Percentage {unPercentage :: Int} - deriving stock (Show) - --- | Parse a scientific into a Percentage -scientificPercentage :: FieldParser' Error Scientific Percentage -scientificPercentage = - Field.boundedScientificRealFloat @Float - >>> ( FieldParser $ \f -> - if - | f < 0 -> Left "percentage cannot be negative" - | f > 1 -> Left "percentage cannot be over 100%" - | otherwise -> Right $ Percentage $ ceiling (f * 100) - ) - --- | Fetch the current status from transmission, --- and remove the transmission hash and torrent file from our database iff it does not exist in transmission anymore -getAndUpdateTransmissionTorrentsStatus :: - ( MonadTransmission m, - MonadThrow m, - MonadLogger m, - MonadPostgres m, - MonadOtel m, - HasField "groupId" info Int, - HasField "torrentId" info Int - ) => - Map (Label "torrentHash" Text) info -> - (Transaction m (Label "knownTorrentsStale" Bool, (Map (Label "torrentHash" Text) (Label "percentDone" Percentage)))) -getAndUpdateTransmissionTorrentsStatus knownTorrents = inSpan' "getAndUpdateTransmissionTorrentsStatus" $ \span -> do - let fields = ["hashString", "percentDone"] - actualTorrents <- - lift @Transaction $ - doTransmissionRequest' - ( transmissionRequestListOnlyTorrents - ( T2 - (label @"fields" fields) - (label @"ids" (Map.keys knownTorrents)) - ) - $ do - torrentHash <- Json.keyLabel @"torrentHash" "hashString" Json.asText - percentDone <- Json.keyLabel @"percentDone" "percentDone" (Field.toJsonParser $ Field.jsonNumber >>> scientificPercentage) - pure (torrentHash, percentDone) - ) - <&> Map.fromList - let toDelete = Map.difference knownTorrents actualTorrents - if - | Map.null toDelete -> do - addEventSimple span "We know about all transmission hashes." - pure (label @"knownTorrentsStale" False, actualTorrents) - | otherwise -> inSpan' "Delete outdated transmission hashes" $ \span' -> do - addAttribute - span' - "db.delete-transmission-hashes" - ( toDelete - & Map.toList - & Enc.list - ( \(k, v) -> - Enc.object - [ ("torrentHash", Enc.text k.torrentHash), - ("groupId", Enc.int v.groupId), - ("torrentId", Enc.int v.torrentId) - ] - ) - & jsonAttribute - ) - _ <- - execute - [fmt| - UPDATE redacted.torrents_json - SET transmission_torrent_hash = NULL, - torrent_file = NULL - WHERE transmission_torrent_hash = ANY (?::text[]) - |] - $ Only (toDelete & Map.keys <&> (.torrentHash) & PGArray :: PGArray Text) - pure (label @"knownTorrentsStale" True, actualTorrents) - -getTransmissionTorrentsTable :: - (MonadTransmission m, MonadThrow m, MonadLogger m, MonadOtel m) => m Html -getTransmissionTorrentsTable = do - let fields = - [ "hashString", - "name", - "percentDone", - "percentComplete", - "downloadDir", - "files" - ] - doTransmissionRequest' - ( transmissionRequestListAllTorrents fields $ do - Json.asObject <&> KeyMap.toMapText - ) - <&> \resp -> - Html.toTable - ( resp - & List.sortOn (\m -> m & Map.lookup "percentDone" & fromMaybe (Json.Number 0)) - <&> Map.toList - -- TODO - & List.take 100 - ) - -data TransmissionRequest = TransmissionRequest - { method :: Text, - arguments :: Map Text Enc, - tag :: Maybe Int - } - deriving stock (Show) - -transmissionConnectionConfig :: T3 "host" Text "port" Int "usePlainHttp" Bool -transmissionConnectionConfig = (T3 (label @"host" "localhost") (label @"port" 9091) (label @"usePlainHttp" True)) - -transmissionRequestListAllTorrents :: (Monad m) => [Text] -> Json.ParseT e m out -> (TransmissionRequest, Json.ParseT e m [out]) -transmissionRequestListAllTorrents fields parseTorrent = - ( TransmissionRequest - { method = "torrent-get", - arguments = - Map.fromList - [ ("fields", Enc.list Enc.text fields) - ], - tag = Nothing - }, - Json.key "torrents" $ Json.eachInArray parseTorrent - ) - -transmissionRequestListOnlyTorrents :: - ( HasField "ids" r1 [(Label "torrentHash" Text)], - HasField "fields" r1 [Text], - Monad m - ) => - r1 -> - Json.ParseT e m out -> - (TransmissionRequest, Json.ParseT e m [out]) -transmissionRequestListOnlyTorrents dat parseTorrent = - ( TransmissionRequest - { method = "torrent-get", - arguments = - Map.fromList - [ ("ids", Enc.list (\i -> Enc.text i.torrentHash) dat.ids), - ("fields", Enc.list Enc.text dat.fields) - ], - tag = Nothing - }, - Json.key "torrents" $ Json.eachInArray parseTorrent - ) - -transmissionRequestAddTorrent :: - (HasField "torrentFile" r ByteString, Monad m) => - r -> - ( TransmissionRequest, - Json.ParseT err m (T2 "torrentHash" Text "torrentName" Text) - ) -transmissionRequestAddTorrent dat = - ( TransmissionRequest - { method = "torrent-add", - arguments = - Map.fromList - [ ("metainfo", Enc.base64Bytes dat.torrentFile), - ("paused", Enc.bool False) - ], - tag = Nothing - }, - do - let p method = Json.key method $ do - hash <- Json.keyLabel @"torrentHash" "hashString" Json.asText - name <- Json.keyLabel @"torrentName" "name" Json.asText - pure $ T2 hash name - p "torrent-duplicate" Json.<|> p "torrent-added" - ) - -data TransmissionResponse output = TransmissionResponse - { result :: TransmissionResponseStatus, - arguments :: Maybe output, - tag :: Maybe Int - } - deriving stock (Show) - -data TransmissionResponseStatus - = TransmissionResponseSuccess - | TransmissionResponseFailure Text - deriving stock (Show) - -doTransmissionRequest' :: - ( MonadTransmission m, - MonadThrow m, - MonadLogger m, - MonadOtel m - ) => - (TransmissionRequest, Json.Parse Error output) -> - m output -doTransmissionRequest' req = inSpan' "Transmission Request" $ \span -> do - resp <- - doTransmissionRequest - span - transmissionConnectionConfig - req - case resp.result of - TransmissionResponseFailure err -> appThrow span (AppExceptionTree $ nestedError "Transmission RPC error" $ singleError $ newError err) - TransmissionResponseSuccess -> case resp.arguments of - Nothing -> appThrow span "Transmission RPC error: No `arguments` field in response" - Just out -> pure out - --- | Contact the transmission RPC, and do the CSRF protection dance. --- --- Spec: https://github.com/transmission/transmission/blob/main/docs/rpc-spec.md -doTransmissionRequest :: - ( MonadTransmission m, - HasField "host" t1 Text, - HasField "port" t1 Int, - HasField "usePlainHttp" t1 Bool, - MonadThrow m, - MonadLogger m, - MonadOtel m - ) => - Otel.Span -> - t1 -> - (TransmissionRequest, Json.Parse Error output) -> - m (TransmissionResponse output) -doTransmissionRequest span dat (req, parser) = do - sessionId <- getCurrentTransmissionSessionId - let textArg t = (Enc.text t, Otel.toAttribute @Text t) - let encArg enc = (enc, enc & toOtelJsonAttr) - let intArg i = (Enc.int i, Otel.toAttribute @Int i) - - let body :: [(Text, (Enc, Otel.Attribute))] = - ( [ ("method", req.method & textArg), - ("arguments", encArg $ Enc.map id req.arguments) - ] - <> (req.tag & foldMap (\t -> [("tag", t & intArg)])) - ) - addAttributes - span - ( HashMap.fromList $ - body - <&> bimap - (\k -> [fmt|transmission.{k}|]) - (\(_, attr) -> attr) - ) - resp <- - Http.doRequestJson - ( (Http.mkRequestOptions (T2 (label @"method" "POST") (label @"host" dat.host))) - { Http.path = mkOptional ["transmission", "rpc"], - Http.port = mkOptional dat.port, - Http.headers = mkOptional $ (sessionId & ifExists ("X-Transmission-Session-Id",)), - Http.usePlainHttp = mkOptional dat.usePlainHttp - } - ) - (body <&> second fst & Enc.object) - -- Implement the CSRF protection thingy - case resp & Http.getResponseStatus & (.statusCode) of - 409 -> inSpan' "New Transmission Session ID" $ \span' -> do - tid <- - resp - & Http.getResponseHeader "X-Transmission-Session-Id" - & nonEmpty - & annotate [fmt|Missing "X-Transmission-Session-Id" header in 409 response: {showPretty resp}|] - & unwrapIOError - & liftIO - <&> NonEmpty.head - - addAttribute span' "transmission.new_session_id" (tid, utf8LenientT) - addAttribute span' "transmission.old_session_id" (sessionId, utf8LenientT >&< fromMaybe "") - - updateTransmissionSessionId tid - - doTransmissionRequest span dat (req, parser) - 200 -> do - addAttribute span "transmission.valid_session_id" (sessionId, utf8LenientT >&< fromMaybe "") - resp - & Http.getResponseBody - & Json.parseStrict - ( Json.mapError singleError $ do - result <- - Json.key "result" Json.asText <&> \case - "success" -> TransmissionResponseSuccess - err -> TransmissionResponseFailure err - arguments <- - Json.keyMay "arguments" parser - tag <- - Json.keyMay - "tag" - (Field.toJsonParser (Field.jsonNumber >>> Field.boundedScientificIntegral "tag too long")) - pure TransmissionResponse {..} - ) - & first (Json.parseErrorTree "Cannot parse transmission RPC response") - & \case - Right a -> pure a - Left err -> do - case Json.eitherDecodeStrict' @Json.Value (resp & Http.getResponseBody) of - Left _err -> pure () - Right val -> logInfo [fmt|failing transmission response: {showPrettyJson val}|] - appThrow span (AppExceptionTree err) - _ -> appThrow span $ AppExceptionPretty [[fmt|Non-200 response:|], pretty resp] - -class MonadTransmission m where - getCurrentTransmissionSessionId :: m (Maybe ByteString) - updateTransmissionSessionId :: ByteString -> m () - -instance (MonadIO m) => MonadTransmission (AppT m) where - getCurrentTransmissionSessionId = AppT (asks (.transmissionSessionId)) >>= readIORef - updateTransmissionSessionId t = do - var <- AppT $ asks (.transmissionSessionId) - writeIORef var (Just t) diff --git a/users/Profpatsch/whatcd-resolver/src/WhatcdResolver.hs b/users/Profpatsch/whatcd-resolver/src/WhatcdResolver.hs deleted file mode 100644 index c838f51c6..000000000 --- a/users/Profpatsch/whatcd-resolver/src/WhatcdResolver.hs +++ /dev/null @@ -1,1566 +0,0 @@ -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE QuasiQuotes #-} - -module WhatcdResolver where - -import AppT -import Arg -import Builder -import Comparison -import Conduit (ConduitT) -import Conduit qualified -import Control.Category qualified as Cat -import Control.Monad.Logger.CallStack -import Control.Monad.Reader -import Data.Aeson qualified as Json -import Data.Aeson.BetterErrors qualified as Json -import Data.Aeson.KeyMap qualified as KeyMap -import Data.ByteString qualified as ByteString -import Data.CaseInsensitive (CI) -import Data.Conduit ((.|)) -import Data.Error.Tree -import Data.HashMap.Strict qualified as HashMap -import Data.List qualified as List -import Data.List.NonEmpty qualified as NonEmpty -import Data.Map.Strict qualified as Map -import Data.Pool qualified as Pool -import Data.Text qualified as Text -import Database.PostgreSQL.Simple qualified as Postgres -import Database.PostgreSQL.Simple.Types (Only (..), PGArray (PGArray)) -import Database.Postgres.Temp qualified as TmpPg -import FieldParser (FieldParser) -import FieldParser qualified as Field -import GHC.Records (HasField (..)) -import Html qualified -import Http -import IHP.HSX.QQ (hsx) -import IHP.HSX.ToHtml (ToHtml) -import Json qualified -import Json.Enc (Enc) -import Json.Enc qualified as Enc -import JsonLd -import Label -import Multipart2 (MultipartParseT) -import Multipart2 qualified as Multipart -import MyLabel -import MyPrelude -import Network.HTTP.Client.Conduit qualified as Http -import Network.HTTP.Simple qualified as Http -import Network.HTTP.Types -import Network.HTTP.Types qualified as Http -import Network.Wai (ResponseReceived) -import Network.Wai qualified as Wai -import Network.Wai.Handler.Warp qualified as Warp -import Network.Wai.Parse (parseContentType) -import OpenTelemetry.Attributes qualified as Otel -import OpenTelemetry.Trace qualified as Otel hiding (getTracer, inSpan, inSpan') -import OpenTelemetry.Trace.Monad qualified as Otel -import Parse (Parse, showContext) -import Parse qualified -import Postgres.Decoder qualified as Dec -import Postgres.MonadPostgres -import Pretty -import Redacted -import RunCommand (runCommandExpect0) -import System.Directory qualified as Dir -import System.Directory qualified as Xdg -import System.Environment qualified as Env -import System.FilePath (()) -import Text.Blaze.Html (Html) -import Text.Blaze.Html.Renderer.Utf8 qualified as Html -import Text.Blaze.Html5 qualified as Html -import Tool (readTool, readTools) -import Transmission -import UnliftIO hiding (Handler) -import UnliftIO.Async qualified as Async -import UnliftIO.Concurrent (threadDelay) -import Prelude hiding (span) - -main :: IO () -main = - runAppWith - ( do - -- todo: trace that to the init functions as well - Otel.inSpan "whatcd-resolver main function" Otel.defaultSpanArguments $ do - _ <- runTransaction migrate - htmlUi - ) - <&> first showToError - >>= expectIOError "could not start whatcd-resolver" - -htmlUi :: AppT IO () -htmlUi = do - uniqueRunId <- - runTransaction $ - querySingleRowWith - [sql| - SELECT gen_random_uuid()::text - |] - () - (Dec.fromField @Text) - - ourHtmlIntegrities <- prefetchHtmlIntegrities - - (counterHtmlM, counterHandler, _counterAsync) <- testCounter (label @"endpoint" "counter") - - withRunInIO $ \runInIO -> Warp.run 9093 $ \req respondOrig -> do - let catchAppException act = - try act >>= \case - Right a -> pure a - Left (AppExceptionTree err) -> do - runInIO (logError (prettyErrorTree err)) - respondOrig (Wai.responseLBS Http.status500 [] "") - Left (AppExceptionPretty err) -> do - runInIO (logError (err & Pretty.prettyErrsNoColor & stringToText)) - respondOrig (Wai.responseLBS Http.status500 [] "") - Left (AppExceptionEnc err) -> do - runInIO (logError (Enc.encToTextPrettyColored err)) - respondOrig (Wai.responseLBS Http.status500 [] "") - - catchAppException $ do - let torrentIdMp span = - parseMultipartOrThrow - span - req - ( do - label @"torrentId" <$> Multipart.field "torrent-id" ((Field.utf8 >>> Field.signedDecimal >>> Field.bounded @Int "int")) - ) - - let parseQueryArgsNewSpan spanName parser = - Parse.runParse "Unable to find the right request query arguments" (lmap Wai.queryString parser) req - & assertMNewSpan spanName (first AppExceptionTree) - - let handlers :: Handlers (AppT IO) - handlers = - Map.fromList $ - ourHtmlIntegrities.handlers - <> [ ( "", - HtmlStream (pure ()) $ \_dat span -> - ( pure $ htmlPageChrome ourHtmlIntegrities "whatcd-resolver", - do - counterHtml <- counterHtmlM - mainHtml counterHtml uniqueRunId span - ) - ), - ( "redacted-search", - HtmlStream (label @"searchstr" <$> singleQueryArgument "searchstr" Cat.id) $ - \dat _span -> - ( pure $ htmlPageChrome ourHtmlIntegrities [fmt|whatcd-resolver – Search – {dat.queryArgs.searchstr & bytesToTextUtf8Lenient}|], - do - runTransaction $ do - res <- redactedSearchAndInsert [("searchstr", dat.queryArgs.searchstr)] - (table, settings) <- - concurrentlyTraced - ( do - d <- - getBestTorrentsData - bestTorrentsDataDefault - ( Just - ( E21 - (label @"onlyTheseTorrents" res.newTorrents) - ) :: - Maybe - ( E2 - "onlyTheseTorrents" - [Label "torrentId" Int] - "artistRedactedId" - Int - ) - ) - pure $ mkBestTorrentsTableByReleaseType d - ) - (getSettings) - pure $ - mainHtml' - ( MainHtml - { returnUrl = dat.returnUrl, - counterHtml = "", - mainContent = - [hsx|

    Search results for
    {dat.queryArgs.searchstr}

    {table}|], - uniqueRunId, - searchFieldContent = dat.queryArgs.searchstr & bytesToTextUtf8Lenient, - settings - } - ) - ) - ), - ( "snips/redacted/torrentDataJson", - Html $ \span -> do - dat <- torrentIdMp span - Html.mkVal <$> (runTransaction $ getTorrentById dat) - ), - ( "snips/redacted/getTorrentFile", - HtmlOrReferer $ \span -> do - dat <- torrentIdMp span - runTransaction $ do - settings <- getSettings - inserted <- redactedGetTorrentFileAndInsert (T2 dat (getLabel @"useFreeleechTokens" settings)) - running <- - lift @Transaction $ - doTransmissionRequest' (transmissionRequestAddTorrent inserted) - updateTransmissionTorrentHashById - ( T2 - (getLabel @"torrentHash" running) - (getLabel @"torrentId" dat) - ) - pure $ - everySecond - "snips/transmission/getTorrentState" - (Enc.object [("torrent-hash", Enc.text running.torrentHash)]) - "Starting" - ), - -- TODO: this is bad duplication?? - ( "snips/redacted/startTorrentFile", - Html $ \span -> do - dat <- torrentIdMp span - runTransaction $ do - file <- - getTorrentFileById dat - <&> annotate [fmt|No torrent file for torrentId "{dat.torrentId}"|] - >>= orAppThrow span - - running <- - lift @Transaction $ - doTransmissionRequest' (transmissionRequestAddTorrent file) - updateTransmissionTorrentHashById - ( T2 - (getLabel @"torrentHash" running) - (getLabel @"torrentId" dat) - ) - pure $ - everySecond - "snips/transmission/getTorrentState" - (Enc.object [("torrent-hash", Enc.text running.torrentHash)]) - "Starting" - ), - ( "snips/transmission/getTorrentState", - Html $ \span -> do - dat <- parseMultipartOrThrow span req $ label @"torrentHash" <$> Multipart.field "torrent-hash" Field.utf8 - status <- - doTransmissionRequest' - ( transmissionRequestListOnlyTorrents - ( T2 - (label @"ids" [label @"torrentHash" dat.torrentHash]) - (label @"fields" ["hashString"]) - ) - (Json.keyLabel @"torrentHash" "hashString" Json.asText) - ) - <&> List.find (\torrent -> torrent.torrentHash == dat.torrentHash) - - pure $ - case status of - Nothing -> [hsx|ERROR unknown|] - Just _torrent -> [hsx|Running|] - ), - ( "snips/jsonld/render", - do - HtmlWithQueryArgs - ( label @"target" - <$> ( (singleQueryArgument "target" Field.utf8 >>> textToURI) - & Parse.andParse uriToHttpClientRequest - ) - ) - ( \dat _span -> do - jsonld <- httpGetJsonLd (dat.queryArgs.target) - pure $ renderJsonld jsonld - ) - ), - ("counter", counterHandler), - ( "settings", - PostAndRedirect - ( do - settings <- runTransaction getSettings - pure $ do - returnTo <- Multipart.fieldLabel @"returnTo" "returnTo" Field.utf8 - parsed <- label @"settings" <$> settingsMultipartParser settings - pure $ T2 returnTo parsed - ) - $ \_span (s :: T2 "returnTo" Text "settings" Settings) -> do - let Settings {useFreeleechTokens} = s.settings - runTransaction $ do - _ <- - writeSettings - [ T2 - (label @"key" "useFreeleechTokens") - (label @"val" $ Json.Bool useFreeleechTokens) - ] - pure $ label @"redirectTo" (s.returnTo & textToBytesUtf8) - ), - ( "artist", - do - HtmlStream - ( label @"artistRedactedId" - <$> ( singleQueryArgument - "redacted_id" - parseRedactedId - ) - ) - $ \dat _span -> - ( do - runTransaction $ do - (artistName, _) <- - concurrentlyTraced - ( inSpan' "finding artist name" $ \span -> do - addAttribute span "artist-redacted-id" (dat.queryArgs.artistRedactedId, intDecimalT) - mArtistName <- getArtistNameById (lbl #artistId dat.queryArgs.artistRedactedId) - let pageTitle = case mArtistName of - Nothing -> "whatcd-resolver" - Just a -> [fmt|{a} - Artist Page - whatcd-resolver|] - pure $ htmlPageChrome ourHtmlIntegrities pageTitle - ) - ( do - execute [sql|INSERT INTO redacted.artist_favourites (artist_id) VALUES (?) ON CONFLICT DO NOTHING|] (Only (dat.queryArgs.artistRedactedId :: Int)) - ) - pure artistName, - do - artistPage (T2 dat.queryArgs (label @"uniqueRunId" uniqueRunId)) - ) - ), - ( "artist/refresh", - HtmlOrRedirect $ - \span -> do - dat <- - parseMultipartOrThrow - span - req - ( label @"artistId" - <$> Multipart.field - "artist-id" - parseRedactedId - ) - runTransaction $ redactedRefreshArtist dat - pure $ E22 (label @"redirectTo" $ textToBytesUtf8 $ mkArtistLink dat) - ), - ( "serve/torrent", - HtmlWithQueryArgsRedirect - ( do - torrentId <- singleQueryArgument "torrent-id" parseRedactedId - fileId <- singleQueryArgument "file-id" (Field.utf8 >>> Field.decimalNatural) - pure $ t2 #torrentId torrentId #fileId fileId - ) - ( \dat _span -> do - let transmissionTorrentEndpoint :: Text - transmissionTorrentEndpoint = "/files" - - mFilePath <- getTorrentFilePath dat.queryArgs - case mFilePath of - Nothing -> do - pure $ e21 #err "Torrent file not found" - Just filePath -> do - let redirectPath = transmissionTorrentEndpoint <> "/" <> (filePath & stringToText) - pure $ e22 #redirectTo (textToBytesUtf8 redirectPath) - ) - ), - ( "autorefresh", - Plain $ do - qry <- - parseQueryArgsNewSpan - "Autorefresh Query Parse" - ( label @"hasItBeenRestarted" - <$> singleQueryArgument "hasItBeenRestarted" Field.utf8 - ) - pure $ - Wai.responseLBS - Http.ok200 - ( [("Content-Type", "text/html")] - <> if uniqueRunId /= qry.hasItBeenRestarted - then -- cause the client side to refresh - [("HX-Refresh", "true")] - else [] - ) - "" - ) - ] - runInIO $ - runHandlers - ( Html $ \span -> do - counterHtml <- counterHtmlM - mainHtml counterHtml uniqueRunId span - ) - handlers - req - respondOrig - where - everySecond :: Text -> Enc -> Html -> Html - everySecond call extraData innerHtml = [hsx|
    {innerHtml}
    |] - - mainHtml :: Html -> Text -> Otel.Span -> AppT IO Html - mainHtml counterHtml uniqueRunId _span = runTransaction $ do - -- jsonld <- - -- httpGetJsonLd - -- ( URI.parseURI "https://musicbrainz.org/work/92000fd4-d304-406d-aeb4-6bdbeed318ec" & annotate "not an URI" & unwrapError, - -- "https://musicbrainz.org/work/92000fd4-d304-406d-aeb4-6bdbeed318ec" - -- ) - -- <&> renderJsonld - (bestTorrentsTable, settings) <- - concurrentlyTraced - ( do - d <- - getBestTorrentsData - ( BestTorrentsData - { limitResults = Just 100, - ordering = ByLastReleases, - onlyFavourites = True, - disallowedReleaseTypes = - [ releaseTypeBootleg, - releaseTypeGuestAppearance, - releaseTypeRemix - ], - .. - } - ) - Nothing - pure $ case d & nonEmpty of - Nothing -> [hsx|

    Latest Releases

    No torrents found

    |] - Just d' -> mkBestTorrentsTableSection (lbl #sectionName "Last Releases") d' - ) - (getSettings) - -- transmissionTorrentsTable <- lift @Transaction getTransmissionTorrentsTable - pure $ - mainHtml' - ( MainHtml - { returnUrl = "/", - counterHtml, - mainContent = bestTorrentsTable, - uniqueRunId, - settings, - searchFieldContent = "" - } - ) - -parseRedactedId :: Field.FieldParser' Error ByteString Int -parseRedactedId = - ( Field.utf8 - >>> (Field.decimalNatural <&> toInteger) - >>> (Field.bounded @Int "Int") - ) - -data MainHtml = MainHtml - { returnUrl :: ByteString, - counterHtml :: Html, - mainContent :: Html, - searchFieldContent :: Text, - uniqueRunId :: Text, - settings :: Settings - } - -mainHtml' :: MainHtml -> Html -mainHtml' dat = do - [hsx| - {dat.counterHtml} - {settingButtons dat} - -
    - - - -
    Search running!
    -
    -
    - {dat.mainContent} -
    - - - |] - -parseMultipartOrThrow :: (MonadLogger m, MonadIO m, MonadThrow m) => Otel.Span -> Wai.Request -> Multipart.MultipartParseT m a -> m a -parseMultipartOrThrow span req parser = - Multipart.parseMultipartOrThrow - (appThrow span . AppExceptionTree) - parser - req - --- | Reload the current page (via the Referer header) if the browser has Javascript disabled (and thus htmx does not work). This should make post requests work out of the box. -htmxOrReferer :: Wai.Request -> Wai.Response -> Wai.Response -htmxOrReferer req resp = do - let fnd h = req & Wai.requestHeaders & List.find (\(hdr, _) -> hdr == h) - let referer = fnd "Referer" - if - | Just _ <- fnd "Hx-Request" -> resp - | Nothing <- referer -> resp - | Just (_, rfr) <- referer -> do - Wai.responseLBS seeOther303 [("Location", rfr)] "" - --- | Redirect to the given page, if the browser has Javascript enabled use HTMX client side redirect, otherwise use a normal HTTP redirect. -redirectOrFallback :: ByteString -> (Status -> (CI ByteString, ByteString) -> Wai.Response) -> Wai.Request -> Wai.Response -redirectOrFallback target responseFn req = do - let fnd h = req & Wai.requestHeaders & List.find (\(hdr, _) -> hdr == h) - case fnd "Hx-Request" of - Just _ -> responseFn Http.ok200 ("Hx-Redirect", target) - Nothing -> responseFn Http.seeOther303 ("Location", target) - -htmlPageChrome :: OurHtmlIntegrities m -> Text -> HtmlHead -htmlPageChrome integrities title = - HtmlHead - { title, - headContent = - [hsx| - - - - - {integrities.html} - - |] - } - -data OurHtmlIntegrities m = OurHtmlIntegrities - { html :: Html, - handlers :: [(Text, HandlerResponse m)] - } - -prefetchHtmlIntegrities :: (MonadOtel m, MonadThrow m) => m (OurHtmlIntegrities m) -prefetchHtmlIntegrities = do - let resources = - [ HtmlIntegrity - { integrityName = "Stylize CSS", - integrityUrl = "https://raw.githubusercontent.com/vasanthv/stylize.css/master/stylize.css", - integrityHash = "sha384-EsaVGfq7QMIquv7LCLomD9pQFZbPh2fOY3gcgN9MW/AlV2aQk/miZ1/EbrcwMr67", - localPath = "resources/stylize.css", - provideSourceMap = False, - isTag = e21 #link (), - ignoreUpstreamContentType = True - }, - HtmlIntegrity - { integrityName = "htmx", - integrityUrl = "https://unpkg.com/htmx.org@1.9.2", - integrityHash = "sha384-L6OqL9pRWyyFU3+/bjdSri+iIphTN/bvYyM37tICVyOJkWZLpP2vGn6VUEXgzg6h", - localPath = "resources/htmx.js", - provideSourceMap = False, - isTag = e22 #script (), - ignoreUpstreamContentType = False - } - ] - resources - & mapConcurrentlyTraced - ( \r -> - prefetchResourceIntegrity r <&> \(html, handler) -> - ( html, - [(r.localPath, handler (Arg @"giveSourceMap" False))] - -- a little hacky, we provide an extra handler if there is a source map - <> ifTrue - (r.provideSourceMap) - [(r.localPath <> ".map", handler (Arg @"giveSourceMap" True))] - ) - ) - <&> fold - <&> \(html, handlers) -> OurHtmlIntegrities {..} - -artistPage :: - ( HasField "artistRedactedId" dat Int, - HasField "uniqueRunId" dat Text, - MonadPostgres m, - MonadOtel m, - MonadLogger m, - MonadThrow m, - MonadTransmission m - ) => - dat -> - m Html -artistPage dat = runTransaction $ do - (fresh, settings) <- - concurrentlyTraced - ( getBestTorrentsData - bestTorrentsDataDefault - (Just $ E22 (getLabel @"artistRedactedId" dat)) - ) - (getSettings) - let torrents = mkBestTorrentsTableByReleaseType fresh - - let returnUrl = - textToBytesUtf8 $ - mkArtistLink (label @"artistId" (dat.artistRedactedId)) - - let mainContent = - [hsx| -
    - {torrents} -
    - -
    - - -
    Refreshing!
    -
    - |] - pure $ - mainHtml' - ( MainHtml - { -- pageTitle, - returnUrl, - counterHtml = "", - mainContent, - uniqueRunId = dat.uniqueRunId, - searchFieldContent = "", - settings - } - ) - -type Handlers m = Map Text (HandlerResponse m) - -data QueryArgsDat a = QueryArgsDat - { queryArgs :: a, - returnUrl :: ByteString - } - -data HtmlHead = HtmlHead - { title :: Text, - headContent :: Html - } - -data HandlerResponse m where - -- | render html - Html :: (Otel.Span -> m Html) -> HandlerResponse m - -- | either render html or redirect to another page - HtmlOrRedirect :: (Otel.Span -> m (E2 "respond" Html "redirectTo" ByteString)) -> HandlerResponse m - -- | render html after parsing some query arguments - HtmlWithQueryArgs :: Parse Query a -> (QueryArgsDat a -> Otel.Span -> m Html) -> HandlerResponse m - -- | Redirect (HTTP 302) to the given path or show 404 with error message - HtmlWithQueryArgsRedirect :: Parse Query a -> (QueryArgsDat a -> Otel.Span -> m (E2 "err" Error "redirectTo" ByteString)) -> HandlerResponse m - -- | render html or reload the page via the Referer header if no htmx - HtmlOrReferer :: (Otel.Span -> m Html) -> HandlerResponse m - -- | render html and stream the head before even doing any work in the handler - HtmlStream :: Parse Query a -> (QueryArgsDat a -> Otel.Span -> (m HtmlHead, m Html)) -> HandlerResponse m - -- | parse the request as POST submission, then redirect to the given endpoint - PostAndRedirect :: - m (MultipartParseT m dat) -> - (Otel.Span -> dat -> m (Label "redirectTo" ByteString)) -> - HandlerResponse m - -- | render a plain wai response - Plain :: m Wai.Response -> HandlerResponse m - -runHandlers :: - forall m. - (MonadOtel m, MonadLogger m, MonadThrow m) => - (HandlerResponse m) -> - (Map Text (HandlerResponse m)) -> - Wai.Request -> - (Wai.Response -> IO ResponseReceived) -> - m ResponseReceived -runHandlers defaultHandler handlers req respond = withRunInIO $ \runInIO -> do - let path = req & Wai.pathInfo & Text.intercalate "/" - let inRouteSpan = - Otel.inSpan' - [fmt|Route /{path}|] - ( Otel.defaultSpanArguments - { Otel.attributes = - HashMap.fromList - [ ("_.server.path", Otel.toAttribute @Text path), - ("_.server.query_args", Otel.toAttribute @Text (req.rawQueryString & bytesToTextUtf8Lenient)) - ] - } - ) - let html' resp act = - inRouteSpan - ( \span -> do - res <- act span <&> (\h -> label @"html" h) - addEventSimple span "Got Html result, rendering…" - liftIO $ respond (resp res) - ) - let htmlResp res = Wai.responseLBS Http.ok200 ([("Content-Type", "text/html")]) . Html.renderHtml $ res.html - let html = html' htmlResp - let htmlOrReferer = html' $ \res -> htmxOrReferer req (htmlResp res) - let htmlOrRedirect :: (Otel.Span -> m (E2 "respond" Html "redirectTo" ByteString)) -> m ResponseReceived - htmlOrRedirect = html' $ \res -> case res.html of - E21 h -> htmlResp (label @"html" h.respond) - E22 r -> - redirectOrFallback - r.redirectTo - (\status header -> Wai.responseLBS status [header] "") - req - let redirectOr404 :: (Otel.Span -> m (E2 "err" Error "redirectTo" ByteString)) -> m ResponseReceived - redirectOr404 = html' $ \res -> case res.html of - E21 h -> - Wai.responseLBS - Http.notFound404 - [("Content-Type", "text/plain")] - (h.err & prettyError & textToBytesUtf8 & toLazyBytes) - E22 r -> Wai.responseLBS Http.seeOther303 [("Location", r.redirectTo)] "" - let postAndRedirect :: - MultipartParseT m dat -> - (Otel.Span -> dat -> m (Label "redirectTo" ByteString)) -> - m ResponseReceived - postAndRedirect parser act = inRouteSpan $ \span -> do - if (req & Wai.requestMethod) == "POST" - then do - dat <- parseMultipartOrThrow span req parser - res <- act span dat - liftIO $ respond (Wai.responseLBS Http.seeOther303 [("Location", res.redirectTo)] "") - else do - liftIO $ respond (Wai.responseLBS Http.methodNotAllowed405 [] "") - let htmlWithQueryArgs' parser = - case req & Parse.runParse "Unable to find the right request query arguments" (lmap Wai.queryString parser) of - Right queryArgs -> Right $ QueryArgsDat {queryArgs, returnUrl = (req & Wai.rawPathInfo) <> (req & Wai.rawQueryString)} - Left err -> - Left - ( \span -> do - recordException - span - ( T2 - (label @"type_" "Query Parse Exception") - (label @"message" (prettyErrorTree err)) - ) - - pure - [hsx| -

    Error:

    -
    {err & prettyErrorTree}
    - |] - ) - let htmlWithQueryArgs parser act = case htmlWithQueryArgs' parser of - Right dat -> html (act dat) - Left act' -> html act' - - let htmlWithQueryArgsRedirect parser act = case htmlWithQueryArgs' parser of - Right dat -> redirectOr404 (act dat) - Left act' -> html act' - - let htmlStream :: Parse Query a -> (QueryArgsDat a -> Otel.Span -> (m HtmlHead, m Html)) -> m ResponseReceived - htmlStream parser act = inRouteSpan $ \span -> do - case htmlWithQueryArgs' parser of - Left act' -> html act' - Right dat -> do - let (mkHead, mkBody) = act dat span - -- start the body work (heh) immediately, but stream the head first - withAsyncTraced mkBody $ \bodyAsync -> do - withRunInIO $ \runInIO' -> respond $ Wai.responseStream Http.ok200 [("Content-Type", "text/html")] $ \send flush -> do - runInIO' $ inSpan "sending " $ do - htmlHead <- mkHead - liftIO $ do - send "\n" - send "\n" - send $ - Html.renderHtmlBuilder $ - [hsx| - - {htmlHead.title} - {htmlHead.headContent} - - |] - flush - htmlBody <- liftIO $ wait bodyAsync - send "\n" - send $ Html.renderHtmlBuilder htmlBody - send "\n" - send "\n" - flush - - let handler = - handlers - & Map.lookup path - & fromMaybe defaultHandler - & \case - Html act -> html act - HtmlOrRedirect act -> htmlOrRedirect act - HtmlWithQueryArgs parser act -> htmlWithQueryArgs parser act - HtmlWithQueryArgsRedirect parser act -> htmlWithQueryArgsRedirect parser act - HtmlOrReferer act -> htmlOrReferer act - HtmlStream parser act -> htmlStream parser act - PostAndRedirect mParser act -> mParser >>= \parser -> postAndRedirect parser act - Plain act -> liftIO $ runInIO act >>= respond - runInIO handler - -singleQueryArgument :: Text -> FieldParser ByteString to -> Parse Http.Query to -singleQueryArgument field inner = - Parse.mkParsePushContext - field - ( \(ctx, qry) -> case qry - & mapMaybe - ( \(k, v) -> - if k == (field & textToBytesUtf8) - then Just v - else Nothing - ) of - [] -> Left [fmt|No such query argument "{field}", at {ctx & Parse.showContext}|] - [Nothing] -> Left [fmt|Expected one query argument with a value, but "{field}" was a query flag|] - [Just one] -> Right one - more -> Left [fmt|More than one value for query argument "{field}": {show more}, at {ctx & Parse.showContext}|] - ) - >>> Parse.fieldParser inner - -singleQueryArgumentMay :: Text -> FieldParser ByteString to -> Parse Http.Query (Maybe to) -singleQueryArgumentMay field inner = - Parse.mkParsePushContext - field - ( \(ctx, qry) -> case qry - & mapMaybe - ( \(k, v) -> - if k == (field & textToBytesUtf8) - then Just v - else Nothing - ) of - [] -> Right Nothing - [Nothing] -> Left [fmt|Expected one query argument with a value, but "{field}" was a query flag|] - [Just one] -> Right (Just one) - more -> Left [fmt|More than one value for query argument "{field}": {show more}, at {ctx & Parse.showContext}|] - ) - >>> Parse.maybe (Parse.fieldParser inner) - -data ArtistFilter = ArtistFilter - { onlyArtist :: Maybe (Label "artistId" Text) - } - -doIfJust :: (Applicative f) => (a -> f ()) -> Maybe a -> f () -doIfJust = traverse_ - -data BestTorrentsData = BestTorrentsData - { limitResults :: Maybe Natural, - ordering :: BestTorrentsOrdering, - disallowedReleaseTypes :: [ReleaseType], - onlyFavourites :: Bool - } - -bestTorrentsDataDefault :: BestTorrentsData -bestTorrentsDataDefault = - BestTorrentsData - { limitResults = Nothing, - ordering = BySeedingWeight, - disallowedReleaseTypes = [], - onlyFavourites = False - } - -getBestTorrentsData :: - ( MonadTransmission m, - MonadThrow m, - MonadLogger m, - MonadPostgres m, - MonadOtel m - ) => - BestTorrentsData -> - Maybe (E2 "onlyTheseTorrents" [Label "torrentId" Int] "artistRedactedId" Int) -> - Transaction m [TorrentData (Label "percentDone" Percentage)] -getBestTorrentsData opts filters = inSpan' "get torrents table data" $ \span -> do - let onlyArtist = label @"artistRedactedId" <$> (filters >>= getE22 @"artistRedactedId") - onlyArtist & doIfJust (\a -> addAttribute span "artist-filter.redacted-id" (a.artistRedactedId, intDecimalT)) - let onlyTheseTorrents = filters >>= getE21 @"onlyTheseTorrents" - onlyTheseTorrents & doIfJust (\a -> addAttribute span "torrent-filter.ids" (a <&> (getLabel @"torrentId") & showToText & Otel.toAttribute)) - let limitResults = getField @"limitResults" opts - - let ordering = opts.ordering - let disallowedReleaseTypes = opts.disallowedReleaseTypes - let onlyFavourites = opts.onlyFavourites - let getBest = getBestTorrents GetBestTorrentsFilter {..} - - bestStale :: [TorrentData ()] <- getBest - (statusInfo, transmissionStatus) <- - getAndUpdateTransmissionTorrentsStatus - ( bestStale - & mapMaybe - ( \td -> case td.torrentStatus of - InTransmission h -> Just (getLabel @"torrentHash" h, td) - _ -> Nothing - ) - & Map.fromList - ) - bestBest <- - -- Instead of serving a stale table when a torrent gets deleted, fetch - -- the whole view again. This is a little wasteful, but torrents - -- shouldn’t get deleted very often, so it’s fine. - -- Re-evaluate invariant if this happens too often. - if statusInfo.knownTorrentsStale - then inSpan' "Fetch torrents table data again" $ - \span' -> do - addEventSimple span' "The transmission torrent list was out of date, refetching torrent list." - getBest - else pure bestStale - pure $ - bestBest - -- filter out some kinds we don’t really care about - & filter - ( \td -> - td.releaseType - `List.notElem` [ releaseTypeCompilation, - releaseTypeDJMix, - releaseTypeMixtape, - releaseTypeRemix - ] - ) - -- we have to update the status of every torrent that’s not in tranmission anymore - -- TODO I feel like it’s easier (& more correct?) to just do the database request again … - <&> ( \td -> case td.torrentStatus of - InTransmission info -> - case transmissionStatus & Map.lookup (getLabel @"torrentHash" info) of - -- TODO this is also pretty dumb, cause it assumes that we have the torrent file if it was in transmission before, - -- which is an internal factum that is established in getBestTorrents (and might change later) - Nothing -> td {torrentStatus = NotInTransmissionYet} - Just transmissionInfo -> td {torrentStatus = InTransmission (T2 (getLabel @"torrentHash" info) (label @"transmissionInfo" transmissionInfo))} - NotInTransmissionYet -> td {torrentStatus = NotInTransmissionYet} - NoTorrentFileYet -> td {torrentStatus = NoTorrentFileYet} - ) - -mkBestTorrentsTableByReleaseType :: - [TorrentData (Label "percentDone" Percentage)] -> - Html -mkBestTorrentsTableByReleaseType fresh = - fresh - & toList - & groupAllWithComparison ((.releaseType) >$< releaseTypeComparison) - & foldMap - ( \ts -> do - let releaseType = ts & NonEmpty.head & (.releaseType.stringKey) - mkBestTorrentsTableSection (lbl #sectionName [fmt|{releaseType}s|]) ts - ) - -mkBestTorrentsTableSection :: - (HasField "sectionName" opts Text) => - opts -> - NonEmpty (TorrentData (Label "percentDone" Percentage)) -> - Html -mkBestTorrentsTableSection opts torrents = do - let localTorrent b = case b.torrentStatus of - NoTorrentFileYet -> - [hsx| -
    - - -
    - |] - InTransmission info -> [hsx|{info.transmissionInfo.percentDone.unPercentage}% done|] - NotInTransmissionYet -> [hsx||] - let bestRows :: NonEmpty (TorrentData (Label "percentDone" Percentage)) -> Html - bestRows rowData = - rowData - & foldMap - ( \b -> do - let torrentPosition :: Text = [fmt|torrent-{b.torrentId}|] - let artists = - b.artists - <&> ( \a -> - T2 - (label @"url" $ mkArtistLink a) - (label @"content" $ Html.toHtml @Text a.artistName) - ) - & mkLinkList - let releaseTypeTooltip rt = [fmt|{rt.stringKey} (Release type ID: {rt.intKey})|] :: Text - [hsx| - - {localTorrent b} - {Html.toHtml @Int b.groupId} - - {artists} - - - - {Html.toHtml @Text b.torrentGroupJson.groupName} - - - {Html.toHtml @Text b.releaseType.stringKey} - {Html.toHtml @Natural b.torrentGroupJson.groupYear} - {Html.toHtml @Int b.seedingWeight} - {Html.toHtml @Text b.torrentFormat} -
    - - |] - ) - - [hsx| -

    {opts.sectionName}

    - - - - - - - - - - - - - - - - {bestRows torrents} - -
    LocalGroup IDArtistNameTypeYearWeightFormatTorrent
    - |] - -mkLinkList :: [T2 "url" Text "content" Html] -> Html -mkLinkList xs = - xs - <&> ( \x -> do - [hsx|{x.content}|] - ) - & List.intersperse ", " - & mconcat - -mkArtistLink :: (HasField "artistId" r Int) => r -> Text -mkArtistLink a = [fmt|/artist?redacted_id={a.artistId}|] - -getTransmissionTorrentsTable :: - (MonadTransmission m, MonadThrow m, MonadLogger m, MonadOtel m) => m Html -getTransmissionTorrentsTable = do - let fields = - [ "hashString", - "name", - "percentDone", - "percentComplete", - "downloadDir", - "files" - ] - doTransmissionRequest' - ( transmissionRequestListAllTorrents fields $ do - Json.asObject <&> KeyMap.toMapText - ) - <&> \resp -> - Html.toTable - ( resp - & List.sortOn (\m -> m & Map.lookup "percentDone" & fromMaybe (Json.Number 0)) - <&> Map.toList - -- TODO - & List.take 100 - ) - -unzip3PGArray :: [(a1, a2, a3)] -> (PGArray a1, PGArray a2, PGArray a3) -unzip3PGArray xs = xs & unzip3 & \(a, b, c) -> (PGArray a, PGArray b, PGArray c) - -assertOneUpdated :: - (HasField "numberOfRowsAffected" r Natural, MonadThrow m, MonadIO m) => - Otel.Span -> - Text -> - r -> - m () -assertOneUpdated span name x = case x.numberOfRowsAffected of - 1 -> pure () - n -> appThrow span ([fmt|{name :: Text}: Expected to update exactly one row, but updated {n :: Natural} row(s)|]) - -migrate :: - ( MonadPostgres m, - MonadOtel m - ) => - Transaction m (Label "numberOfRowsAffected" Natural) -migrate = inSpan "Database Migration" $ do - execute - [sql| - CREATE SCHEMA IF NOT EXISTS redacted; - - CREATE TABLE IF NOT EXISTS redacted.settings ( - id SERIAL PRIMARY KEY, - key TEXT NOT NULL UNIQUE, - value JSONB - ); - - CREATE TABLE IF NOT EXISTS redacted.torrent_groups ( - id SERIAL PRIMARY KEY, - group_id INTEGER, - group_name TEXT, - full_json_result JSONB, - UNIQUE(group_id) - ); - - CREATE TABLE IF NOT EXISTS redacted.torrents_json ( - id SERIAL PRIMARY KEY, - torrent_id INTEGER, - torrent_group SERIAL NOT NULL REFERENCES redacted.torrent_groups(id) ON DELETE CASCADE, - full_json_result JSONB, - UNIQUE(torrent_id) - ); - - CREATE INDEX IF NOT EXISTS redacted_torrents_json_torrent_group_fk ON redacted.torrents_json (torrent_group); - - - ALTER TABLE redacted.torrents_json - ADD COLUMN IF NOT EXISTS torrent_file bytea NULL; - ALTER TABLE redacted.torrents_json - ADD COLUMN IF NOT EXISTS transmission_torrent_hash text NULL; - - -- the seeding weight is used to find the best torrent in a group. - CREATE OR REPLACE FUNCTION calc_seeding_weight(full_json_result jsonb) RETURNS int AS $$ - BEGIN - RETURN - -- three times seeders plus one times snatches - (3 * (full_json_result->'seeders')::integer - + (full_json_result->'snatches')::integer - ) - -- prefer remasters by multiplying them with 3 - * (CASE - WHEN full_json_result->>'remasterTitle' ILIKE '%remaster%' - THEN 3 - ELSE 1 - END) - -- slightly push mp3 V0, to make sure it’s preferred over 320 CBR - * (CASE - WHEN full_json_result->>'encoding' ILIKE '%v0%' - THEN 2 - ELSE 1 - END) - -- remove 24bit torrents from the result (wayyy too big) - * (CASE - WHEN full_json_result->>'encoding' ILIKE '%24bit%' - THEN 0 - ELSE 1 - END) - -- discount FLACS, so we only use them when there’s no mp3 alternative (to save space) - / (CASE - WHEN full_json_result->>'encoding' ILIKE '%lossless%' - THEN 5 - ELSE 1 - END) - ; - END; - $$ LANGUAGE plpgsql IMMUTABLE; - - ALTER TABLE redacted.torrents_json - ADD COLUMN IF NOT EXISTS seeding_weight int NOT NULL GENERATED ALWAYS AS (calc_seeding_weight(full_json_result)) STORED; - - CREATE OR REPLACE FUNCTION artist_record_to_id(artists jsonb) RETURNS int[] - as $$ - SELECT array_agg(x::int) from jsonb_path_query(artists, '$[*].id') j(x); - $$ LANGUAGE sql IMMUTABLE; - - ALTER TABLE redacted.torrents_json - ADD COLUMN IF NOT EXISTS artist_ids int[] NOT NULL GENERATED ALWAYS AS (COALESCE(artist_record_to_id(full_json_result->'artists'), ARRAY[]::int[])) STORED; - ALTER TABLE redacted.torrent_groups - ADD COLUMN IF NOT EXISTS artist_ids int[] NOT NULL GENERATED ALWAYS AS (COALESCE(artist_record_to_id(full_json_result->'artists'), ARRAY[]::int[])) STORED; - - CREATE INDEX IF NOT EXISTS torrents_json_artist_ids ON redacted.torrents_json USING GIN (artist_ids); - CREATE INDEX IF NOT EXISTS torrent_groups_artist_ids ON redacted.torrent_groups USING GIN (artist_ids); - - -- inflect out values of the full json - CREATE OR REPLACE VIEW redacted.torrents AS - SELECT - t.id, - t.torrent_id, - t.torrent_group, - -- the seeding weight is used to find the best torrent in a group. - t.seeding_weight, - t.full_json_result, - t.torrent_file, - t.transmission_torrent_hash, - t.artist_ids - FROM redacted.torrents_json t; - - CREATE INDEX IF NOT EXISTS torrents_json_seeding ON redacted.torrents_json(((full_json_result->'seeding')::integer)); - CREATE INDEX IF NOT EXISTS torrents_json_snatches ON redacted.torrents_json(((full_json_result->'snatches')::integer)); - - CREATE TABLE IF NOT EXISTS redacted.artist_favourites ( - id SERIAL PRIMARY KEY, - artist_id INTEGER NOT NULL, - UNIQUE(artist_id) - ); - - -- for easier query lookup, a mapping from artist ids to names - CREATE OR REPLACE VIEW redacted.artist_names AS - SELECT - t.artist_id, x.name as artist_name - FROM - (SELECT unnest(artist_ids) as artist_id, * FROM redacted.torrents t) as t - join LATERAL - jsonb_to_recordset(full_json_result->'artists') as x(id int, name text) - ON x.id = t.artist_id - WHERE x.id = t.artist_id - UNION ALL - SELECT - t.artist_id, x.name as artist_name - FROM - (SELECT unnest(artist_ids) as artist_id, * FROM redacted.torrent_groups t) as t - join LATERAL - jsonb_to_recordset(full_json_result->'artists') as x(id int, name text) - ON x.id = t.artist_id - WHERE x.id = t.artist_id; - - |] - () - -runAppWith :: AppT IO a -> IO (Either TmpPg.StartError a) -runAppWith appT = withTracer $ \tracer -> withDb $ \db -> do - tool <- readTools (label @"toolsEnvVar" "WHATCD_RESOLVER_TOOLS") (readTool "pg_format") - prettyPrintDatabaseQueries <- - Env.lookupEnv "WHATCD_RESOLVER_PRETTY_PRINT_DATABASE_QUERIES" >>= \case - Nothing -> pure DontPrettyPrintDatabaseQueries - Just _ -> do - pgFormat <- initPgFormatPool (label @"pgFormat" tool) - pure $ PrettyPrintDatabaseQueries pgFormat - let pgConfig = - T2 - (label @"logDatabaseQueries" LogDatabaseQueries) - (label @"prettyPrintDatabaseQueries" prettyPrintDatabaseQueries) - pgConnPool <- - Pool.newPool $ - Pool.defaultPoolConfig - {- resource init action -} (Postgres.connectPostgreSQL (db & TmpPg.toConnectionString)) - {- resource destruction -} Postgres.close - {- unusedResourceOpenTime -} 10 - {- max resources across all stripes -} 20 - transmissionSessionId <- newIORef Nothing - redactedApiKey <- - Env.lookupEnv "WHATCD_RESOLVER_REDACTED_API_KEY" >>= \case - Just k -> pure (k & stringToBytesUtf8) - Nothing -> runStderrLoggingT $ do - logInfo "WHATCD_RESOLVER_REDACTED_API_KEY was not set, trying pass" - runCommandExpect0 "pass" ["internet/redacted/api-keys/whatcd-resolver"] - transmissionDownloadDirectory <- do - mPath <- Env.lookupEnv "WHATCD_RESOLVER_TRANSMISSION_DOWNLOAD_DIRECTORY" - case mPath of - Nothing -> pure $ Left [fmt|WHATCD_RESOLVER_TRANSMISSION_DOWNLOAD_DIRECTORY not set, no file streaming available|] - Just path -> do - Dir.doesDirectoryExist path >>= \case - False -> pure $ Left [fmt|WHATCD_RESOLVER_TRANSMISSION_DOWNLOAD_DIRECTORY directory does not exist: {path}, no file streaming available|] - True -> pure $ Right path - - let newAppT = do - logInfo [fmt|Running with config: {showPretty pgConfig}|] - logInfo [fmt|Connected to database at {db & TmpPg.toDataDirectory} on socket {db & TmpPg.toConnectionString}|] - case transmissionDownloadDirectory of - Left errmsg -> logInfo errmsg - Right dir -> logInfo [fmt|Streaming torrent files from {dir}|] - appT - runReaderT - newAppT.unAppT - Context {..} - `catch` ( \case - AppExceptionPretty p -> throwM $ EscapedException (p & Pretty.prettyErrs) - AppExceptionTree t -> throwM $ EscapedException (t & prettyErrorTree & textToString) - AppExceptionEnc e -> throwM $ EscapedException (e & Enc.encToTextPrettyColored & textToString) - ) - --- | Just a silly wrapper so that correctly format any 'AppException' that would escape the runAppWith scope. -newtype EscapedException = EscapedException String - deriving anyclass (Exception) - -instance Show EscapedException where - show (EscapedException s) = s - -withTracer :: (Otel.Tracer -> IO c) -> IO c -withTracer f = do - setDefaultEnv "OTEL_SERVICE_NAME" "whatcd-resolver" - bracket - -- Install the SDK, pulling configuration from the environment - ( do - (processors, opts) <- Otel.getTracerProviderInitializationOptions - tp <- - Otel.createTracerProvider - processors - -- workaround the attribute length bug https://github.com/iand675/hs-opentelemetry/issues/113 - ( opts - { Otel.tracerProviderOptionsAttributeLimits = - opts.tracerProviderOptionsAttributeLimits - { Otel.attributeCountLimit = Just 65_000 - } - } - ) - Otel.setGlobalTracerProvider tp - pure tp - ) - -- Ensure that any spans that haven't been exported yet are flushed - Otel.shutdownTracerProvider - -- Get a tracer so you can create spans - (\tracerProvider -> f $ Otel.makeTracer tracerProvider "whatcd-resolver" Otel.tracerOptions) - -setDefaultEnv :: String -> String -> IO () -setDefaultEnv envName defaultValue = do - Env.lookupEnv envName >>= \case - Just _env -> pure () - Nothing -> Env.setEnv envName defaultValue - -withDb :: (TmpPg.DB -> IO a) -> IO (Either TmpPg.StartError a) -withDb act = do - dataDir <- Xdg.getXdgDirectory Xdg.XdgData "whatcd-resolver" - let databaseDir = dataDir "database" - let socketDir = dataDir "database-socket" - Dir.createDirectoryIfMissing True socketDir - initDbConfig <- - Dir.doesDirectoryExist databaseDir >>= \case - True -> pure TmpPg.Zlich - False -> do - putStderrLn [fmt|Database does not exist yet, creating in "{databaseDir}"|] - Dir.createDirectoryIfMissing True databaseDir - pure TmpPg.DontCare - let cfg = - mempty - { TmpPg.dataDirectory = TmpPg.Permanent (databaseDir), - TmpPg.socketDirectory = TmpPg.Permanent socketDir, - TmpPg.port = pure $ Just 5431, - TmpPg.initDbConfig - } - TmpPg.withConfig cfg $ \db -> do - -- print [fmt|data dir: {db & TmpPg.toDataDirectory}|] - -- print [fmt|conn string: {db & TmpPg.toConnectionString}|] - act db - -data Settings = Settings - { useFreeleechTokens :: Bool - } - deriving stock (Generic) - -settingFreeleechToken :: Bool -> Settings -settingFreeleechToken b = Settings {useFreeleechTokens = b} - -instance Semigroup Settings where - a <> b = Settings {useFreeleechTokens = a.useFreeleechTokens || b.useFreeleechTokens} - -instance Monoid Settings where - mempty = Settings {useFreeleechTokens = False} - -submitSettingForm :: (HasField "returnUrl" r ByteString, ToHtml a) => r -> a -> Html -submitSettingForm opts inputs = - [hsx| -
    - - {inputs} -
    - |] - -settingButtons :: (HasField "returnUrl" opts ByteString, HasField "settings" opts Settings) => opts -> Html -settingButtons opts = - if opts.settings.useFreeleechTokens - then - submitSettingForm - opts - [hsx|

    Using freeleech tokens!

    |] - else - submitSettingForm - opts - [hsx|

    Not using freeleech tokens

    |] - -settingsMultipartParser :: (Applicative m) => Settings -> MultipartParseT m Settings -settingsMultipartParser old = do - useFreeleechTokens <- do - on <- - Multipart.fieldMay - "useFreeleechTokensON" - (cconst $ True) - off <- - Multipart.fieldMay - "useFreeleechTokensOFF" - (cconst $ False) - pure $ (on <|> off) & fromMaybe old.useFreeleechTokens - pure $ Settings {..} - -getSettings :: (MonadPostgres m, MonadOtel m) => Transaction m Settings -getSettings = inSpan' "Get Settings" $ \span -> do - res <- - foldRowsWithMonoid - [sql| - SELECT key, value - FROM redacted.settings - |] - () - ( do - key <- Dec.text - Dec.jsonMay - ( case key of - "useFreeleechTokens" -> settingFreeleechToken <$> Json.asBool - _ -> pure mempty - ) - <&> fromMaybe mempty - ) - lift $ addAttribute span "settings" (toOtelAttrGenericStruct res) - pure res - -writeSettings :: - (MonadPostgres m, MonadOtel m) => - [T2 "key" Text "val" Json.Value] -> - Transaction m (Label "numberOfRowsAffected" Natural) -writeSettings settings = inSpan' "Write Settings" $ \span -> do - addAttribute - span - "settings" - ( toOtelJsonAttr $ - Enc.list - (\s -> Enc.tuple2 Enc.text Enc.value (s.key, s.val)) - settings - ) - execute - [sql| - INSERT INTO redacted.settings (key, value) - SELECT * FROM UNNEST(?::text[], ?::jsonb[]) - ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value - |] - (settings & unzipPGArray @"key" @Text @"val" @Json.Value) - --- | Given a conduit that produces Html, --- return a htmx html snippet which will regularly poll for new results in the conduit, --- and a handler endpoint that returns the newest output when it happens. -conduitToHtmx :: - (HasField "endpoint" opts Text, MonadUnliftIO m) => - opts -> - -- | initial inner html - Html -> - ConduitT () Html m () -> - m (m Html, HandlerResponse m, Async.Async ()) -conduitToHtmx opts init' conduit = do - let htmlPolling inner = - [hsx| -
    - {inner :: Html} -
    - |] - currentHtml <- newIORef $! htmlPolling init' - collectorHandle <- Async.async $ do - liftIO $ putStderrLn "spawned async collector" - lastVal <- - conduit - .| Conduit.mapMC - ( \html -> do - atomicWriteIORef currentHtml $! (htmlPolling html) - pure html - ) - .| Conduit.lastDefC init' - & Conduit.runConduit - -- when the original conduit finishes, we stop polling for updates. - atomicWriteIORef currentHtml $! [hsx|
    {lastVal}
    |] - - let handler = Html $ \_span -> do - -- TODO: can we use Etags here and return 304 instead? - readIORef currentHtml - - pure (readIORef currentHtml, handler, collectorHandle) - -testCounter :: - (HasField "endpoint" opts Text, MonadUnliftIO m) => - opts -> - m (m Html, HandlerResponse m, Async ()) -testCounter opts = conduitToHtmx opts [hsx|

    0

    |] counterConduit - -counterConduit :: (MonadIO m) => ConduitT i Html m () -counterConduit = - Conduit.yieldMany [0 .. 100] - .| Conduit.awaitForever - ( \(i :: Int) -> do - threadDelay 300_000 - Conduit.yield [hsx|

    {i}

    |] - ) - -data HtmlIntegrity = HtmlIntegrity - { -- | The name of the resource, for debugging purposes - integrityName :: Text, - -- | The URL of the resource content - integrityUrl :: Text, - -- | The integrity hash of the resource - integrityHash :: Text, - -- | The local url path to fetch the cached resource from the frontend - localPath :: Text, - -- | Whether there is a resource map at the URL + `.map` - provideSourceMap :: Bool, - -- | is @@ or @|], - \(Arg giveSourceMap) -> Plain $ do - if - | giveSourceMap, - Just sourceMap <- mSourceMap -> do - pure $ - Wai.responseLBS - Http.ok200 - [ ( "Content-Type", - "application/json" - ), - ("Content-Length", buildBytes intDecimalB (ByteString.length sourceMap)) - ] - (toLazyBytes sourceMap) - | giveSourceMap -> do - pure $ Wai.responseLBS Http.notFound404 [] "" - | otherwise -> do - pure $ - Wai.responseLBS - Http.ok200 - [ ( "Content-Type", - (if dat.ignoreUpstreamContentType then mempty else mContentType) - & fromMaybe - ( tagMatch - #script - "text/javascript; charset=UTF-8" - #link - "text/css; charset=UTF-8" - ) - ), - ("Content-Length", buildBytes intDecimalB bodyLength) - ] - (toLazyBytes $ bodyStrict) - ) - | code <- statusCode -> appThrow span $ AppExceptionPretty [[fmt|Server returned an non-200 error code, code {code}:|], pretty resp] diff --git a/users/Profpatsch/whatcd-resolver/whatcd-resolver.cabal b/users/Profpatsch/whatcd-resolver/whatcd-resolver.cabal deleted file mode 100644 index 12efac557..000000000 --- a/users/Profpatsch/whatcd-resolver/whatcd-resolver.cabal +++ /dev/null @@ -1,136 +0,0 @@ -cabal-version: 3.0 -name: whatcd-resolver -version: 0.1.0.0 -author: Profpatsch -maintainer: mail@profpatsch.de - -common common-options - ghc-options: - -Wall - -Wno-type-defaults - -Wunused-packages - -Wredundant-constraints - -fwarn-missing-deriving-strategies - - -- See https://downloads.haskell.org/ghc/latest/docs/users_guide/exts.html - -- for a description of all these extensions - default-extensions: - -- Infer Applicative instead of Monad where possible - ApplicativeDo - - -- Allow literal strings to be Text - OverloadedStrings - - -- Syntactic sugar improvements - LambdaCase - MultiWayIf - - -- Makes the (deprecated) usage of * instead of Data.Kind.Type an error - NoStarIsType - - -- Convenient and crucial to deal with ambiguous field names, commonly - -- known as RecordDotSyntax - OverloadedRecordDot - - -- Make #labels available - OverloadedLabels - - -- does not export record fields as functions, use OverloadedRecordDot to access instead - NoFieldSelectors - - -- Allow the same record field name to be declared twice per module. - -- This works, because we use `OverloadedRecordDot` everywhere (enforced by `NoFieldSelectors`). - DuplicateRecordFields - - -- Record punning - RecordWildCards - - -- Improved Deriving - DerivingStrategies - DerivingVia - - -- Type-level strings - DataKinds - - -- to enable the `type` keyword in import lists (ormolu uses this automatically) - ExplicitNamespaces - - -- allows defining pattern synonyms, but also the `import Foo (pattern FooPattern)` import syntax - PatternSynonyms - - default-language: GHC2021 - -library - import: common-options - - hs-source-dirs: src - - exposed-modules: - WhatcdResolver - AppT - Bencode - JsonLd - Optional - Http - Html - Transmission - Redacted - - build-depends: - base >=4.15 && <5, - text, - my-prelude, - my-webstuff, - pa-prelude, - pa-error-tree, - pa-label, - pa-field-parser, - pa-run-command, - aeson-better-errors, - aeson, - async, - bencode, - blaze-html, - bytestring, - case-insensitive, - conduit, - containers, - unordered-containers, - directory, - exceptions, - filepath, - hs-opentelemetry-sdk, - hs-opentelemetry-api, - http-conduit, - http-types, - http-client, - ihp-hsx, - monad-logger, - mtl, - network-uri, - random, - resourcet, - resource-pool, - template-haskell, - postgresql-simple, - punycode, - tmp-postgres, - time, - unliftio, - selective, - wai-extra, - wai, - warp, - -executable whatcd-resolver - import: common-options - - main-is: Main.hs - - build-depends: - base >=4.15 && <5, - whatcd-resolver - - ghc-options: - -threaded - diff --git a/users/Profpatsch/writers/default.nix b/users/Profpatsch/writers/default.nix deleted file mode 100644 index 9fb69231a..000000000 --- a/users/Profpatsch/writers/default.nix +++ /dev/null @@ -1,120 +0,0 @@ -{ depot, pkgs, lib, ... }: -let - bins = depot.nix.getBins pkgs.s6-portable-utils [ "s6-mkdir" "s6-cat" "s6-ln" "s6-ls" "s6-touch" ] - // depot.nix.getBins pkgs.coreutils [ "printf" ]; - - inherit (depot.nix.yants) defun struct restrict attrs list string drv any; - - inherit (depot.nix) drvSeqL; - - FlakeError = - restrict - "flake error" - (s: lib.any (prefix: (builtins.substring 0 1 s) == prefix) - [ "E" "W" ]) - string; - Libraries = defun [ (attrs any) (list drv) ]; - - pythonPackages = pkgs.python310Packages; - buildPythonPackages = pkgs.buildPackages.python310Packages; - python = pythonPackages.python; - - python3 = - { name - , libraries ? (_: [ ]) - , flakeIgnore ? [ ] - }: - let - in - pkgs.writers.makePythonWriter python pythonPackages buildPythonPackages name { - libraries = Libraries libraries pythonPackages; - flakeIgnore = - let - ignoreTheseErrors = [ - # whitespace after { - "E201" - # whitespace before } - "E202" - # fuck 4-space indentation - "E121" - "E111" - # who cares about blank lines … - # … at end of files - "W391" - # … between functions - "E302" - "E305" - # … if there’s too many of them - "E303" - # or lines that are too long - "E501" - ]; - in - list FlakeError (ignoreTheseErrors ++ flakeIgnore); - }; - - # TODO: add the same flake check as the pyhon3 writer - python3Lib = { name, libraries ? (_: [ ]) }: moduleString: - let - srcTree = depot.nix.runExecline.local name { stdin = moduleString; } [ - "importas" - "out" - "out" - "if" - [ bins.s6-mkdir "-p" "\${out}/${name}" ] - "if" - [ - "redirfd" - "-w" - "1" - "\${out}/setup.py" - bins.printf - '' - from distutils.core import setup - - setup( - name='%s', - packages=['%s'] - ) - '' - name - name - ] - "if" - [ - # redirect stdin to the init py - "redirfd" - "-w" - "1" - "\${out}/${name}/__init__.py" - bins.s6-cat - ] - ]; - in - pythonPackages.buildPythonPackage { - inherit name; - src = srcTree; - propagatedBuildInputs = libraries pythonPackages; - doCheck = false; - }; - - - ghcBins = libraries: depot.nix.getBins (pkgs.ghc.withPackages (_: libraries)) [ "runghc" ]; - - writeHaskellInteractive = name: { libraries, ghcArgs ? [ ] }: path: - depot.nix.writeExecline name { } ([ - (ghcBins libraries).runghc - "--" - ] ++ ghcArgs ++ [ - "--" - path - ]); - -in -{ - inherit - python3 - python3Lib - writeHaskellInteractive - ; -} diff --git a/users/Profpatsch/writers/tests/default.nix b/users/Profpatsch/writers/tests/default.nix deleted file mode 100644 index 879aae82f..000000000 --- a/users/Profpatsch/writers/tests/default.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.users.Profpatsch.writers) - python3Lib - python3 - ; - - inherit (pkgs) - coreutils - ; - - run = drv: depot.nix.runExecline.local "run-${drv.name}" { } [ - "if" - [ drv ] - "importas" - "out" - "out" - "${coreutils}/bin/touch" - "$out" - ]; - - pythonTransitiveLib = python3Lib - { - name = "transitive"; - } '' - def transitive(s): - return s + " 1 2 3" - ''; - - pythonTestLib = python3Lib - { - name = "test_lib"; - libraries = _: [ pythonTransitiveLib ]; - } '' - import transitive - def test(): - return transitive.transitive("test") - ''; - - pythonWithLib = run (python3 - { - name = "python-with-lib"; - libraries = _: [ pythonTestLib ]; - } '' - import test_lib - - assert test_lib.test() == "test 1 2 3" - ''); - -in -depot.nix.readTree.drvTargets { - inherit - pythonWithLib - ; -} diff --git a/users/Profpatsch/xdg-cache-home.nix b/users/Profpatsch/xdg-cache-home.nix deleted file mode 100644 index 6dc02b7f1..000000000 --- a/users/Profpatsch/xdg-cache-home.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ depot, pkgs, lib, ... }: -depot.nix.writeExecline "xdg-cache-home" { } [ - "if" - "-n" - [ - "printenv" - "XDG_CACHE_HOME" - ] - "importas" - "HOME" - "HOME" - "echo" - "\${HOME}/.cache" -] diff --git a/users/Profpatsch/xdg-config-home.nix b/users/Profpatsch/xdg-config-home.nix deleted file mode 100644 index cc09eb634..000000000 --- a/users/Profpatsch/xdg-config-home.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ depot, pkgs, lib, ... }: -depot.nix.writeExecline "xdg-config-home" { } [ - "if" - "-n" - [ - "printenv" - "XDG_CONFIG_HOME" - ] - "importas" - "HOME" - "HOME" - "echo" - "\${HOME}/.config" -] diff --git a/users/Profpatsch/ytextr/README.md b/users/Profpatsch/ytextr/README.md deleted file mode 100644 index f1e40d8e6..000000000 --- a/users/Profpatsch/ytextr/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# ytextr - -Wrapper around `yt-dlp` for downloading videos in good default quality with good default settings. - -Will always download the most up-to-date `yt-dlp` first, because the software usually stops working after a few weeks and needs to be updated, so just using `` often fails. diff --git a/users/Profpatsch/ytextr/create-symlink-farm.nix b/users/Profpatsch/ytextr/create-symlink-farm.nix deleted file mode 100644 index 7b3a45b91..000000000 --- a/users/Profpatsch/ytextr/create-symlink-farm.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - # list of package attribute names to get at run time - packageNamesAtRuntimeJsonPath -, -}: -let - pkgs = import { }; - - getPkg = pkgName: pkgs.${pkgName}; - - packageNamesAtRuntime = builtins.fromJSON (builtins.readFile packageNamesAtRuntimeJsonPath); - - runtime = map getPkg packageNamesAtRuntime; - -in -pkgs.symlinkJoin { - name = "symlink-farm"; - paths = runtime; -} diff --git a/users/Profpatsch/ytextr/default.nix b/users/Profpatsch/ytextr/default.nix deleted file mode 100644 index 3f3f07311..000000000 --- a/users/Profpatsch/ytextr/default.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ depot, pkgs, lib, ... }: - -# ytextr is a wrapper arount yt-dlp (previously youtube-dl) -# that extracts a single video according to my preferred settings. -# -# It will be sandboxed to the current directory, since I don’t particularly -# trust the massive codebase of that tool (with hundreds of contributors). -# -# Since the rules for downloading videos is usually against the wishes -# of proprietary vendors, and a video is many megabytes anyway, -# it will be fetched from the most recent nixpkgs unstable channel before running. - -let - bins = depot.nix.getBins pkgs.nix [ "nix-build" ] - // depot.nix.getBins pkgs.bubblewrap [ "bwrap" ]; - - # Run a command, with the given packages in scope, and `packageNamesAtRuntime` being fetched at the start in the given nix `channel`. - nix-run-with-channel = - { - # The channel to get `packageNamesAtRuntime` from - channel - , # executable to run with `packageNamesAtRuntime` in PATH - # and the argv - executable - , # A list of nixpkgs package attribute names that should be put into PATH when running `command`. - packageNamesAtRuntime - , - }: depot.nix.writeExecline "nix-run-with-channel-${channel}" { } [ - # TODO: prevent race condition by writing a temporary gc root - "backtick" - "-iE" - "storepath" - [ - bins.nix-build - "-I" - "nixpkgs=channel:${channel}" - "--arg" - "packageNamesAtRuntimeJsonPath" - (pkgs.writeText "packageNamesAtRuntime.json" (builtins.toJSON packageNamesAtRuntime)) - ./create-symlink-farm.nix - ] - "importas" - "-ui" - "PATH" - "PATH" - "export" - "PATH" - "\${storepath}/bin:\${PATH}" - executable - "$@" - ]; - -in -nix-run-with-channel { - channel = "nixos-unstable"; - packageNamesAtRuntime = [ "yt-dlp" ]; - executable = depot.nix.writeExecline "ytextr" { } [ - "getcwd" - "-E" - "cwd" - bins.bwrap - "--ro-bind" - "/nix/store" - "/nix/store" - "--ro-bind" - "/etc" - "/etc" - "--bind" - "$cwd" - "$cwd" - "yt-dlp" - "--no-playlist" - "--write-sub" - "--all-subs" - "--embed-subs" - "--merge-output-format" - "mkv" - "-f" - "bestvideo[height<=?1080]+bestaudio/best" - "$@" - ]; -} diff --git a/users/aaqaishtyaq/OWNERS b/users/aaqaishtyaq/OWNERS deleted file mode 100644 index 99c4a7424..000000000 --- a/users/aaqaishtyaq/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -aaqaishtyaq diff --git a/users/amjoseph/OWNERS b/users/amjoseph/OWNERS deleted file mode 100644 index a99992be6..000000000 --- a/users/amjoseph/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -amjoseph diff --git a/users/amjoseph/keys.nix b/users/amjoseph/keys.nix deleted file mode 100644 index 8cc2f2436..000000000 --- a/users/amjoseph/keys.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ ... }: - -let - # Long-term, air-gapped PGP key. This key is used only for signing other - # keys. It is a minor hassle for me to access this key. - airgap = "F0B74D717CDE8412A3E0D4D5F29AC8080DA8E1E0"; - - # Stored in an HSM. Signed by the above key. - current = "D930411B675A011EB9590713DC4AB809B13BE76D"; - - # Chat protocols that depend on DNS, WebPKI, or E.164 are lame. This is not. - ricochet = "emhxygy5mezcovm5a6q5hze5eqfqgieww56eh4ttwmrolwqmzgb6qiyd"; - - # This ssh key is for depot. Please don't use it elsewhere, except to give - # me the ability to set a system-specific key elsewhere. Not currently - # stored in an HSM, but I'm working on that. - ssh-for-depot = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOE5e0HrwQTI5KOaU12J0AJG5zDpWn4g/U+oFXz7SkbD"; - -in -{ - all = [ ssh-for-depot ]; -} diff --git a/users/aspen/OWNERS b/users/aspen/OWNERS deleted file mode 100644 index 3dff20d57..000000000 --- a/users/aspen/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -aspen diff --git a/users/aspen/achilles/.envrc b/users/aspen/achilles/.envrc deleted file mode 100644 index b80e28b4b..000000000 --- a/users/aspen/achilles/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -eval "$(lorri direnv)" diff --git a/users/aspen/achilles/.gitignore b/users/aspen/achilles/.gitignore deleted file mode 100644 index ea8c4bf7f..000000000 --- a/users/aspen/achilles/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/users/aspen/achilles/Cargo.lock b/users/aspen/achilles/Cargo.lock deleted file mode 100644 index 3c767db1e..000000000 --- a/users/aspen/achilles/Cargo.lock +++ /dev/null @@ -1,885 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "achilles" -version = "0.1.0" -dependencies = [ - "anyhow", - "bimap", - "clap", - "crate-root", - "derive_more", - "inkwell", - "itertools", - "lazy_static", - "llvm-sys", - "nom", - "nom-trace", - "pratt", - "pretty_assertions", - "proptest", - "test-strategy", - "thiserror", - "void", -] - -[[package]] -name = "aho-corasick" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anyhow" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bimap" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0455254eb5c6964c4545d8bac815e1a1be4f3afe0ae695ea539c12d728d44b" - -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "0.19.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "3.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" -dependencies = [ - "atty", - "bitflags", - "clap_lex", - "indexmap", - "strsim", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "crate-root" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6fe4622b269032d2c5140a592d67a9c409031d286174fcde172fbed86f0d3" - -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - -[[package]] -name = "getrandom" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "inkwell" -version = "0.1.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#6ab2b19e1b90be55fa4f9f056f29bd1ed557b990" -dependencies = [ - "either", - "inkwell_internals", - "libc", - "llvm-sys", - "once_cell", - "parking_lot", -] - -[[package]] -name = "inkwell_internals" -version = "0.5.0" -source = "git+https://github.com/TheDan64/inkwell?branch=master#6ab2b19e1b90be55fa4f9f056f29bd1ed557b990" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if", - "ryu", - "static_assertions", -] - -[[package]] -name = "libc" -version = "0.2.125" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" - -[[package]] -name = "llvm-sys" -version = "110.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b918288a585ac36703abefcbc5d4c43137b604ec0c2d39abefb55e25c7501dc" -dependencies = [ - "cc", - "lazy_static", - "libc", - "regex", - "semver 0.11.0", -] - -[[package]] -name = "lock_api" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "memchr" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" - -[[package]] -name = "nom" -version = "6.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" -dependencies = [ - "bitvec", - "funty", - "lexical-core", - "memchr", - "version_check", -] - -[[package]] -name = "nom-trace" -version = "0.2.1" -source = "git+https://github.com/glittershark/nom-trace?branch=nom-6#6168d2e15cc51efd12d80260159b76a764dba138" -dependencies = [ - "nom", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" - -[[package]] -name = "os_str_bytes" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" - -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - -[[package]] -name = "parking_lot" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "pratt" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bbc12f7936a7b195790dd6d9b982b66c54f45ff6766decf25c44cac302dce" - -[[package]] -name = "pretty_assertions" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - -[[package]] -name = "proc-macro2" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9027b48e9d4c9175fa2218adf3557f91c1137021739951d4932f5f8268ac48aa" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "proptest" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" -dependencies = [ - "bit-set", - "bitflags", - "byteorder", - "lazy_static", - "num-traits", - "quick-error 2.0.1", - "rand", - "rand_chacha", - "rand_xorshift", - "regex-syntax", - "rusty-fork", - "tempfile", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.9", -] - -[[package]] -name = "rusty-fork" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" -dependencies = [ - "fnv", - "quick-error 1.2.3", - "tempfile", - "wait-timeout", -] - -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - -[[package]] -name = "smallvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "structmeta" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd9c2155aa89fb2c2cb87d99a610c689e7c47099b3e9f1c8a8f53faf4e3d2e3" -dependencies = [ - "proc-macro2", - "quote", - "structmeta-derive", - "syn", -] - -[[package]] -name = "structmeta-derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafede0d0a2f21910f36d47b1558caae3076ed80f6f3ad0fc85a91e6ba7e5938" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "syn" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07e33e919ebcd69113d5be0e4d70c5707004ff45188910106854f38b960df4a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "test-strategy" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22c726321a7c108ca1de4ed2e6a362ead7193ecfbe0b326c5dff602b65a09e6a" -dependencies = [ - "proc-macro2", - "quote", - "structmeta", - "syn", -] - -[[package]] -name = "textwrap" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" - -[[package]] -name = "thiserror" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - -[[package]] -name = "unicode-xid" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "wait-timeout" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -dependencies = [ - "libc", -] - -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/users/aspen/achilles/Cargo.toml b/users/aspen/achilles/Cargo.toml deleted file mode 100644 index f091399a0..000000000 --- a/users/aspen/achilles/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "achilles" -version = "0.1.0" -authors = ["Griffin Smith "] -edition = "2018" - -[dependencies] -anyhow = "1.0.38" -bimap = "0.6.0" -clap = "3.0.0-beta.2" -derive_more = "0.99.11" -inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm11-0"] } -itertools = "0.10.0" -lazy_static = "1.4.0" -llvm-sys = "110.0.1" -nom = "6.1.2" -nom-trace = { git = "https://github.com/glittershark/nom-trace", branch = "nom-6" } -pratt = "0.3.0" -proptest = "1.0.0" -test-strategy = "0.1.1" -thiserror = "1.0.24" -void = "1.0.2" - -[dev-dependencies] -crate-root = "0.1.3" -pretty_assertions = "0.7.1" diff --git a/users/aspen/achilles/ach/.gitignore b/users/aspen/achilles/ach/.gitignore deleted file mode 100644 index ac5296ebb..000000000 --- a/users/aspen/achilles/ach/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -*.ll -*.o - -functions -simple -externs -units diff --git a/users/aspen/achilles/ach/Makefile b/users/aspen/achilles/ach/Makefile deleted file mode 100644 index 3a8cd2865..000000000 --- a/users/aspen/achilles/ach/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -default: simple - -%.ll: %.ach - cargo run -- compile $< -o $@ -f llvm - -%.o: %.ll - llc $< -o $@ -filetype=obj - -%: %.o - clang $< -o $@ - -.PHONY: clean - -clean: - @rm -f *.ll *.o simple functions diff --git a/users/aspen/achilles/ach/externs.ach b/users/aspen/achilles/ach/externs.ach deleted file mode 100644 index faf8ce90e..000000000 --- a/users/aspen/achilles/ach/externs.ach +++ /dev/null @@ -1,5 +0,0 @@ -extern puts : fn cstring -> int - -fn main = - let _ = puts "foobar" - in 0 diff --git a/users/aspen/achilles/ach/functions.ach b/users/aspen/achilles/ach/functions.ach deleted file mode 100644 index dc6e7a1f3..000000000 --- a/users/aspen/achilles/ach/functions.ach +++ /dev/null @@ -1,8 +0,0 @@ -ty id : fn a -> a -fn id x = x - -ty plus : fn int -> int -fn plus (x: int) (y: int) = x + y - -ty main : fn -> int -fn main = plus (id 2) 7 diff --git a/users/aspen/achilles/ach/simple.ach b/users/aspen/achilles/ach/simple.ach deleted file mode 100644 index 20f167723..000000000 --- a/users/aspen/achilles/ach/simple.ach +++ /dev/null @@ -1 +0,0 @@ -fn main = let x = 2; y = 3 in x + y diff --git a/users/aspen/achilles/ach/units.ach b/users/aspen/achilles/ach/units.ach deleted file mode 100644 index 70635d978..000000000 --- a/users/aspen/achilles/ach/units.ach +++ /dev/null @@ -1,7 +0,0 @@ -extern puts : fn cstring -> int - -ty print : fn cstring -> () -fn print x = let _ = puts x in () - -ty main : fn -> int -fn main = let _ = print "hi" in 0 diff --git a/users/aspen/achilles/default.nix b/users/aspen/achilles/default.nix deleted file mode 100644 index 714be6072..000000000 --- a/users/aspen/achilles/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ depot, pkgs, ... }: - -let - llvmPackages = pkgs.llvmPackages_11; -in - -depot.third_party.naersk.buildPackage { - src = ./.; - - buildInputs = [ - llvmPackages.clang - llvmPackages.llvm - llvmPackages.bintools - llvmPackages.libclang.lib - ] ++ (with pkgs; [ - zlib - ncurses - libxml2 - libffi - pkg-config - ]); - - doCheck = true; - - # Trouble linking against LLVM, maybe since rustc's llvmPackages got bumped? - meta.ci.skip = true; -} diff --git a/users/aspen/achilles/shell.nix b/users/aspen/achilles/shell.nix deleted file mode 100644 index 1434cf8a3..000000000 --- a/users/aspen/achilles/shell.nix +++ /dev/null @@ -1,18 +0,0 @@ -with (import ../../.. { }).third_party.nixpkgs; - -mkShell { - buildInputs = [ - clang_11 - llvm_11.lib - llvmPackages_11.bintools - llvmPackages_11.clang - llvmPackages_11.libclang.lib - zlib - ncurses - libxml2 - libffi - pkg-config - ]; - - LLVM_SYS_110_PREFIX = llvmPackages_11.bintools; -} diff --git a/users/aspen/achilles/src/ast/hir.rs b/users/aspen/achilles/src/ast/hir.rs deleted file mode 100644 index cdfaef567..000000000 --- a/users/aspen/achilles/src/ast/hir.rs +++ /dev/null @@ -1,364 +0,0 @@ -use std::collections::HashMap; - -use itertools::Itertools; - -use super::{BinaryOperator, Ident, Literal, UnaryOperator}; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Pattern<'a, T> { - Id(Ident<'a>, T), - Tuple(Vec>), -} - -impl<'a, T> Pattern<'a, T> { - pub fn to_owned(&self) -> Pattern<'static, T> - where - T: Clone, - { - match self { - Pattern::Id(id, t) => Pattern::Id(id.to_owned(), t.clone()), - Pattern::Tuple(pats) => { - Pattern::Tuple(pats.into_iter().map(Pattern::to_owned).collect()) - } - } - } - - pub fn traverse_type(self, f: F) -> Result, E> - where - F: Fn(T) -> Result + Clone, - { - match self { - Pattern::Id(id, t) => Ok(Pattern::Id(id, f(t)?)), - Pattern::Tuple(pats) => Ok(Pattern::Tuple( - pats.into_iter() - .map(|pat| pat.traverse_type(f.clone())) - .collect::, _>>()?, - )), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Binding<'a, T> { - pub pat: Pattern<'a, T>, - pub body: Expr<'a, T>, -} - -impl<'a, T> Binding<'a, T> { - fn to_owned(&self) -> Binding<'static, T> - where - T: Clone, - { - Binding { - pat: self.pat.to_owned(), - body: self.body.to_owned(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Expr<'a, T> { - Ident(Ident<'a>, T), - - Literal(Literal<'a>, T), - - Tuple(Vec>, T), - - UnaryOp { - op: UnaryOperator, - rhs: Box>, - type_: T, - }, - - BinaryOp { - lhs: Box>, - op: BinaryOperator, - rhs: Box>, - type_: T, - }, - - Let { - bindings: Vec>, - body: Box>, - type_: T, - }, - - If { - condition: Box>, - then: Box>, - else_: Box>, - type_: T, - }, - - Fun { - type_args: Vec>, - args: Vec<(Ident<'a>, T)>, - body: Box>, - type_: T, - }, - - Call { - fun: Box>, - type_args: HashMap, T>, - args: Vec>, - type_: T, - }, -} - -impl<'a, T> Expr<'a, T> { - pub fn type_(&self) -> &T { - match self { - Expr::Ident(_, t) => t, - Expr::Literal(_, t) => t, - Expr::Tuple(_, t) => t, - Expr::UnaryOp { type_, .. } => type_, - Expr::BinaryOp { type_, .. } => type_, - Expr::Let { type_, .. } => type_, - Expr::If { type_, .. } => type_, - Expr::Fun { type_, .. } => type_, - Expr::Call { type_, .. } => type_, - } - } - - pub fn traverse_type(self, f: F) -> Result, E> - where - F: Fn(T) -> Result + Clone, - { - match self { - Expr::Ident(id, t) => Ok(Expr::Ident(id, f(t)?)), - Expr::Literal(lit, t) => Ok(Expr::Literal(lit, f(t)?)), - Expr::UnaryOp { op, rhs, type_ } => Ok(Expr::UnaryOp { - op, - rhs: Box::new(rhs.traverse_type(f.clone())?), - type_: f(type_)?, - }), - Expr::BinaryOp { - lhs, - op, - rhs, - type_, - } => Ok(Expr::BinaryOp { - lhs: Box::new(lhs.traverse_type(f.clone())?), - op, - rhs: Box::new(rhs.traverse_type(f.clone())?), - type_: f(type_)?, - }), - Expr::Let { - bindings, - body, - type_, - } => Ok(Expr::Let { - bindings: bindings - .into_iter() - .map(|Binding { pat, body }| { - Ok(Binding { - pat: pat.traverse_type(f.clone())?, - body: body.traverse_type(f.clone())?, - }) - }) - .collect::, E>>()?, - body: Box::new(body.traverse_type(f.clone())?), - type_: f(type_)?, - }), - Expr::If { - condition, - then, - else_, - type_, - } => Ok(Expr::If { - condition: Box::new(condition.traverse_type(f.clone())?), - then: Box::new(then.traverse_type(f.clone())?), - else_: Box::new(else_.traverse_type(f.clone())?), - type_: f(type_)?, - }), - Expr::Fun { - args, - type_args, - body, - type_, - } => Ok(Expr::Fun { - args: args - .into_iter() - .map(|(id, t)| Ok((id, f.clone()(t)?))) - .collect::, E>>()?, - type_args, - body: Box::new(body.traverse_type(f.clone())?), - type_: f(type_)?, - }), - Expr::Call { - fun, - type_args, - args, - type_, - } => Ok(Expr::Call { - fun: Box::new(fun.traverse_type(f.clone())?), - type_args: type_args - .into_iter() - .map(|(id, ty)| Ok((id, f.clone()(ty)?))) - .collect::, E>>()?, - args: args - .into_iter() - .map(|e| e.traverse_type(f.clone())) - .collect::, E>>()?, - type_: f(type_)?, - }), - Expr::Tuple(members, t) => Ok(Expr::Tuple( - members - .into_iter() - .map(|t| t.traverse_type(f.clone())) - .try_collect()?, - f(t)?, - )), - } - } - - pub fn to_owned(&self) -> Expr<'static, T> - where - T: Clone, - { - match self { - Expr::Ident(id, t) => Expr::Ident(id.to_owned(), t.clone()), - Expr::Literal(lit, t) => Expr::Literal(lit.to_owned(), t.clone()), - Expr::UnaryOp { op, rhs, type_ } => Expr::UnaryOp { - op: *op, - rhs: Box::new((**rhs).to_owned()), - type_: type_.clone(), - }, - Expr::BinaryOp { - lhs, - op, - rhs, - type_, - } => Expr::BinaryOp { - lhs: Box::new((**lhs).to_owned()), - op: *op, - rhs: Box::new((**rhs).to_owned()), - type_: type_.clone(), - }, - Expr::Let { - bindings, - body, - type_, - } => Expr::Let { - bindings: bindings.iter().map(|b| b.to_owned()).collect(), - body: Box::new((**body).to_owned()), - type_: type_.clone(), - }, - Expr::If { - condition, - then, - else_, - type_, - } => Expr::If { - condition: Box::new((**condition).to_owned()), - then: Box::new((**then).to_owned()), - else_: Box::new((**else_).to_owned()), - type_: type_.clone(), - }, - Expr::Fun { - args, - type_args, - body, - type_, - } => Expr::Fun { - args: args - .iter() - .map(|(id, t)| (id.to_owned(), t.clone())) - .collect(), - type_args: type_args.iter().map(|arg| arg.to_owned()).collect(), - body: Box::new((**body).to_owned()), - type_: type_.clone(), - }, - Expr::Call { - fun, - type_args, - args, - type_, - } => Expr::Call { - fun: Box::new((**fun).to_owned()), - type_args: type_args - .iter() - .map(|(id, t)| (id.to_owned(), t.clone())) - .collect(), - args: args.iter().map(|e| e.to_owned()).collect(), - type_: type_.clone(), - }, - Expr::Tuple(members, t) => { - Expr::Tuple(members.into_iter().map(Expr::to_owned).collect(), t.clone()) - } - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Decl<'a, T> { - Fun { - name: Ident<'a>, - type_args: Vec>, - args: Vec<(Ident<'a>, T)>, - body: Box>, - type_: T, - }, - - Extern { - name: Ident<'a>, - arg_types: Vec, - ret_type: T, - }, -} - -impl<'a, T> Decl<'a, T> { - pub fn name(&self) -> &Ident<'a> { - match self { - Decl::Fun { name, .. } => name, - Decl::Extern { name, .. } => name, - } - } - - pub fn set_name(&mut self, new_name: Ident<'a>) { - match self { - Decl::Fun { name, .. } => *name = new_name, - Decl::Extern { name, .. } => *name = new_name, - } - } - - pub fn type_(&self) -> Option<&T> { - match self { - Decl::Fun { type_, .. } => Some(type_), - Decl::Extern { .. } => None, - } - } - - pub fn traverse_type(self, f: F) -> Result, E> - where - F: Fn(T) -> Result + Clone, - { - match self { - Decl::Fun { - name, - type_args, - args, - body, - type_, - } => Ok(Decl::Fun { - name, - type_args, - args: args - .into_iter() - .map(|(id, t)| Ok((id, f(t)?))) - .try_collect()?, - body: Box::new(body.traverse_type(f.clone())?), - type_: f(type_)?, - }), - Decl::Extern { - name, - arg_types, - ret_type, - } => Ok(Decl::Extern { - name, - arg_types: arg_types.into_iter().map(f.clone()).try_collect()?, - ret_type: f(ret_type)?, - }), - } - } -} diff --git a/users/aspen/achilles/src/ast/mod.rs b/users/aspen/achilles/src/ast/mod.rs deleted file mode 100644 index 5438d29d2..000000000 --- a/users/aspen/achilles/src/ast/mod.rs +++ /dev/null @@ -1,484 +0,0 @@ -pub(crate) mod hir; - -use std::borrow::Cow; -use std::collections::HashMap; -use std::convert::TryFrom; -use std::fmt::{self, Display, Formatter}; - -use itertools::Itertools; - -#[derive(Debug, PartialEq, Eq)] -pub struct InvalidIdentifier<'a>(Cow<'a, str>); - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct Ident<'a>(pub Cow<'a, str>); - -impl<'a> From<&'a Ident<'a>> for &'a str { - fn from(id: &'a Ident<'a>) -> Self { - id.0.as_ref() - } -} - -impl<'a> Display for Ident<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -impl<'a> Ident<'a> { - pub fn to_owned(&self) -> Ident<'static> { - Ident(Cow::Owned(self.0.clone().into_owned())) - } - - /// Construct an identifier from a &str without checking that it's a valid identifier - pub fn from_str_unchecked(s: &'a str) -> Self { - debug_assert!(is_valid_identifier(s)); - Self(Cow::Borrowed(s)) - } - - pub fn from_string_unchecked(s: String) -> Self { - debug_assert!(is_valid_identifier(&s)); - Self(Cow::Owned(s)) - } -} - -pub fn is_valid_identifier(s: &S) -> bool -where - S: AsRef + ?Sized, -{ - s.as_ref() - .chars() - .any(|c| !c.is_alphanumeric() || !"_".contains(c)) -} - -impl<'a> TryFrom<&'a str> for Ident<'a> { - type Error = InvalidIdentifier<'a>; - - fn try_from(s: &'a str) -> Result { - if is_valid_identifier(s) { - Ok(Ident(Cow::Borrowed(s))) - } else { - Err(InvalidIdentifier(Cow::Borrowed(s))) - } - } -} - -impl<'a> TryFrom for Ident<'a> { - type Error = InvalidIdentifier<'static>; - - fn try_from(s: String) -> Result { - if is_valid_identifier(&s) { - Ok(Ident(Cow::Owned(s))) - } else { - Err(InvalidIdentifier(Cow::Owned(s))) - } - } -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum BinaryOperator { - /// `+` - Add, - - /// `-` - Sub, - - /// `*` - Mul, - - /// `/` - Div, - - /// `^` - Pow, - - /// `==` - Equ, - - /// `!=` - Neq, -} - -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub enum UnaryOperator { - /// ! - Not, - - /// - - Neg, -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Literal<'a> { - Unit, - Int(u64), - Bool(bool), - String(Cow<'a, str>), -} - -impl<'a> Literal<'a> { - pub fn to_owned(&self) -> Literal<'static> { - match self { - Literal::Int(i) => Literal::Int(*i), - Literal::Bool(b) => Literal::Bool(*b), - Literal::String(s) => Literal::String(Cow::Owned(s.clone().into_owned())), - Literal::Unit => Literal::Unit, - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Pattern<'a> { - Id(Ident<'a>), - Tuple(Vec>), -} - -impl<'a> Pattern<'a> { - pub fn to_owned(&self) -> Pattern<'static> { - match self { - Pattern::Id(id) => Pattern::Id(id.to_owned()), - Pattern::Tuple(pats) => Pattern::Tuple(pats.iter().map(Pattern::to_owned).collect()), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Binding<'a> { - pub pat: Pattern<'a>, - pub type_: Option>, - pub body: Expr<'a>, -} - -impl<'a> Binding<'a> { - fn to_owned(&self) -> Binding<'static> { - Binding { - pat: self.pat.to_owned(), - type_: self.type_.as_ref().map(|t| t.to_owned()), - body: self.body.to_owned(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Expr<'a> { - Ident(Ident<'a>), - - Literal(Literal<'a>), - - UnaryOp { - op: UnaryOperator, - rhs: Box>, - }, - - BinaryOp { - lhs: Box>, - op: BinaryOperator, - rhs: Box>, - }, - - Let { - bindings: Vec>, - body: Box>, - }, - - If { - condition: Box>, - then: Box>, - else_: Box>, - }, - - Fun(Box>), - - Call { - fun: Box>, - args: Vec>, - }, - - Tuple(Vec>), - - Ascription { - expr: Box>, - type_: Type<'a>, - }, -} - -impl<'a> Expr<'a> { - pub fn to_owned(&self) -> Expr<'static> { - match self { - Expr::Ident(ref id) => Expr::Ident(id.to_owned()), - Expr::Literal(ref lit) => Expr::Literal(lit.to_owned()), - Expr::Tuple(ref members) => { - Expr::Tuple(members.into_iter().map(Expr::to_owned).collect()) - } - Expr::UnaryOp { op, rhs } => Expr::UnaryOp { - op: *op, - rhs: Box::new((**rhs).to_owned()), - }, - Expr::BinaryOp { lhs, op, rhs } => Expr::BinaryOp { - lhs: Box::new((**lhs).to_owned()), - op: *op, - rhs: Box::new((**rhs).to_owned()), - }, - Expr::Let { bindings, body } => Expr::Let { - bindings: bindings.iter().map(|binding| binding.to_owned()).collect(), - body: Box::new((**body).to_owned()), - }, - Expr::If { - condition, - then, - else_, - } => Expr::If { - condition: Box::new((**condition).to_owned()), - then: Box::new((**then).to_owned()), - else_: Box::new((**else_).to_owned()), - }, - Expr::Fun(fun) => Expr::Fun(Box::new((**fun).to_owned())), - Expr::Call { fun, args } => Expr::Call { - fun: Box::new((**fun).to_owned()), - args: args.iter().map(|arg| arg.to_owned()).collect(), - }, - Expr::Ascription { expr, type_ } => Expr::Ascription { - expr: Box::new((**expr).to_owned()), - type_: type_.to_owned(), - }, - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Arg<'a> { - pub ident: Ident<'a>, - pub type_: Option>, -} - -impl<'a> Arg<'a> { - pub fn to_owned(&self) -> Arg<'static> { - Arg { - ident: self.ident.to_owned(), - type_: self.type_.as_ref().map(Type::to_owned), - } - } -} - -impl<'a> TryFrom<&'a str> for Arg<'a> { - type Error = as TryFrom<&'a str>>::Error; - - fn try_from(value: &'a str) -> Result { - Ok(Arg { - ident: Ident::try_from(value)?, - type_: None, - }) - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Fun<'a> { - pub args: Vec>, - pub body: Expr<'a>, -} - -impl<'a> Fun<'a> { - pub fn to_owned(&self) -> Fun<'static> { - Fun { - args: self.args.iter().map(|arg| arg.to_owned()).collect(), - body: self.body.to_owned(), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Decl<'a> { - Fun { - name: Ident<'a>, - body: Fun<'a>, - }, - Ascription { - name: Ident<'a>, - type_: Type<'a>, - }, - Extern { - name: Ident<'a>, - type_: FunctionType<'a>, - }, -} - -//// - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct FunctionType<'a> { - pub args: Vec>, - pub ret: Box>, -} - -impl<'a> FunctionType<'a> { - pub fn to_owned(&self) -> FunctionType<'static> { - FunctionType { - args: self.args.iter().map(|a| a.to_owned()).collect(), - ret: Box::new((*self.ret).to_owned()), - } - } -} - -impl<'a> Display for FunctionType<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "fn {} -> {}", self.args.iter().join(", "), self.ret) - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Type<'a> { - Int, - Float, - Bool, - CString, - Unit, - Tuple(Vec>), - Var(Ident<'a>), - Function(FunctionType<'a>), -} - -impl<'a> Type<'a> { - pub fn to_owned(&self) -> Type<'static> { - match self { - Type::Int => Type::Int, - Type::Float => Type::Float, - Type::Bool => Type::Bool, - Type::CString => Type::CString, - Type::Unit => Type::Unit, - Type::Var(v) => Type::Var(v.to_owned()), - Type::Function(f) => Type::Function(f.to_owned()), - Type::Tuple(members) => Type::Tuple(members.iter().map(Type::to_owned).collect()), - } - } - - pub fn alpha_equiv(&self, other: &Self) -> bool { - fn do_alpha_equiv<'a>( - substs: &mut HashMap<&'a Ident<'a>, &'a Ident<'a>>, - lhs: &'a Type, - rhs: &'a Type, - ) -> bool { - match (lhs, rhs) { - (Type::Var(v1), Type::Var(v2)) => substs.entry(v1).or_insert(v2) == &v2, - ( - Type::Function(FunctionType { - args: args1, - ret: ret1, - }), - Type::Function(FunctionType { - args: args2, - ret: ret2, - }), - ) => { - args1.len() == args2.len() - && args1 - .iter() - .zip(args2) - .all(|(a1, a2)| do_alpha_equiv(substs, a1, a2)) - && do_alpha_equiv(substs, ret1, ret2) - } - _ => lhs == rhs, - } - } - - let mut substs = HashMap::new(); - do_alpha_equiv(&mut substs, self, other) - } - - pub fn traverse_type_vars<'b, F>(self, mut f: F) -> Type<'b> - where - F: FnMut(Ident<'a>) -> Type<'b> + Clone, - { - match self { - Type::Var(tv) => f(tv), - Type::Function(FunctionType { args, ret }) => Type::Function(FunctionType { - args: args - .into_iter() - .map(|t| t.traverse_type_vars(f.clone())) - .collect(), - ret: Box::new(ret.traverse_type_vars(f)), - }), - Type::Int => Type::Int, - Type::Float => Type::Float, - Type::Bool => Type::Bool, - Type::CString => Type::CString, - Type::Tuple(members) => Type::Tuple( - members - .into_iter() - .map(|t| t.traverse_type_vars(f.clone())) - .collect(), - ), - Type::Unit => Type::Unit, - } - } - - pub fn as_tuple(&self) -> Option<&Vec>> { - if let Self::Tuple(v) = self { - Some(v) - } else { - None - } - } -} - -impl<'a> Display for Type<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Type::Int => f.write_str("int"), - Type::Float => f.write_str("float"), - Type::Bool => f.write_str("bool"), - Type::CString => f.write_str("cstring"), - Type::Unit => f.write_str("()"), - Type::Var(v) => v.fmt(f), - Type::Function(ft) => ft.fmt(f), - Type::Tuple(ms) => write!(f, "({})", ms.iter().join(", ")), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn type_var(n: &str) -> Type<'static> { - Type::Var(Ident::try_from(n.to_owned()).unwrap()) - } - - mod alpha_equiv { - use super::*; - - #[test] - fn trivial() { - assert!(Type::Int.alpha_equiv(&Type::Int)); - assert!(!Type::Int.alpha_equiv(&Type::Bool)); - } - - #[test] - fn simple_type_var() { - assert!(type_var("a").alpha_equiv(&type_var("b"))); - } - - #[test] - fn function_with_type_vars_equiv() { - assert!(Type::Function(FunctionType { - args: vec![type_var("a")], - ret: Box::new(type_var("b")), - }) - .alpha_equiv(&Type::Function(FunctionType { - args: vec![type_var("b")], - ret: Box::new(type_var("a")), - }))) - } - - #[test] - fn function_with_type_vars_non_equiv() { - assert!(!Type::Function(FunctionType { - args: vec![type_var("a")], - ret: Box::new(type_var("a")), - }) - .alpha_equiv(&Type::Function(FunctionType { - args: vec![type_var("b")], - ret: Box::new(type_var("a")), - }))) - } - } -} diff --git a/users/aspen/achilles/src/codegen/llvm.rs b/users/aspen/achilles/src/codegen/llvm.rs deleted file mode 100644 index 9a71ac954..000000000 --- a/users/aspen/achilles/src/codegen/llvm.rs +++ /dev/null @@ -1,486 +0,0 @@ -use std::convert::{TryFrom, TryInto}; -use std::path::Path; -use std::result; - -use inkwell::basic_block::BasicBlock; -use inkwell::builder::Builder; -pub use inkwell::context::Context; -use inkwell::module::Module; -use inkwell::support::LLVMString; -use inkwell::types::{BasicType, BasicTypeEnum, FunctionType, IntType, StructType}; -use inkwell::values::{AnyValueEnum, BasicValueEnum, FunctionValue, StructValue}; -use inkwell::{AddressSpace, IntPredicate}; -use itertools::Itertools; -use thiserror::Error; - -use crate::ast::hir::{Binding, Decl, Expr, Pattern}; -use crate::ast::{BinaryOperator, Ident, Literal, Type, UnaryOperator}; -use crate::common::env::Env; - -#[derive(Debug, PartialEq, Eq, Error)] -pub enum Error { - #[error("Undefined variable {0}")] - UndefinedVariable(Ident<'static>), - - #[error("LLVM Error: {0}")] - LLVMError(String), -} - -impl From for Error { - fn from(s: LLVMString) -> Self { - Self::LLVMError(s.to_string()) - } -} - -pub type Result = result::Result; - -pub struct Codegen<'ctx, 'ast> { - context: &'ctx Context, - pub module: Module<'ctx>, - builder: Builder<'ctx>, - env: Env<&'ast Ident<'ast>, AnyValueEnum<'ctx>>, - function_stack: Vec>, - identifier_counter: u32, -} - -impl<'ctx, 'ast> Codegen<'ctx, 'ast> { - pub fn new(context: &'ctx Context, module_name: &str) -> Self { - let module = context.create_module(module_name); - let builder = context.create_builder(); - Self { - context, - module, - builder, - env: Default::default(), - function_stack: Default::default(), - identifier_counter: 0, - } - } - - pub fn new_function<'a>( - &'a mut self, - name: &str, - ty: FunctionType<'ctx>, - ) -> &'a FunctionValue<'ctx> { - self.function_stack - .push(self.module.add_function(name, ty, None)); - let basic_block = self.append_basic_block("entry"); - self.builder.position_at_end(basic_block); - self.function_stack.last().unwrap() - } - - pub fn finish_function(&mut self, res: Option<&BasicValueEnum<'ctx>>) -> FunctionValue<'ctx> { - self.builder.build_return(match res { - // lol - Some(val) => Some(val), - None => None, - }); - self.function_stack.pop().unwrap() - } - - pub fn append_basic_block(&self, name: &str) -> BasicBlock<'ctx> { - self.context - .append_basic_block(*self.function_stack.last().unwrap(), name) - } - - fn bind_pattern(&mut self, pat: &'ast Pattern<'ast, Type>, val: AnyValueEnum<'ctx>) { - match pat { - Pattern::Id(id, _) => self.env.set(id, val), - Pattern::Tuple(pats) => { - for (i, pat) in pats.iter().enumerate() { - let member = self - .builder - .build_extract_value( - StructValue::try_from(val).unwrap(), - i as _, - "pat_bind", - ) - .unwrap(); - self.bind_pattern(pat, member.into()); - } - } - } - } - - pub fn codegen_expr( - &mut self, - expr: &'ast Expr<'ast, Type>, - ) -> Result>> { - match expr { - Expr::Ident(id, _) => self - .env - .resolve(id) - .cloned() - .ok_or_else(|| Error::UndefinedVariable(id.to_owned())) - .map(Some), - Expr::Literal(lit, ty) => { - let ty = self.codegen_int_type(ty); - match lit { - Literal::Int(i) => Ok(Some(AnyValueEnum::IntValue(ty.const_int(*i, false)))), - Literal::Bool(b) => Ok(Some(AnyValueEnum::IntValue( - ty.const_int(if *b { 1 } else { 0 }, false), - ))), - Literal::String(s) => Ok(Some( - self.builder - .build_global_string_ptr(s, "s") - .as_pointer_value() - .into(), - )), - Literal::Unit => Ok(None), - } - } - Expr::UnaryOp { op, rhs, .. } => { - let rhs = self.codegen_expr(rhs)?.unwrap(); - match op { - UnaryOperator::Not => unimplemented!(), - UnaryOperator::Neg => Ok(Some(AnyValueEnum::IntValue( - self.builder.build_int_neg(rhs.into_int_value(), "neg"), - ))), - } - } - Expr::BinaryOp { lhs, op, rhs, .. } => { - let lhs = self.codegen_expr(lhs)?.unwrap(); - let rhs = self.codegen_expr(rhs)?.unwrap(); - match op { - BinaryOperator::Add => { - Ok(Some(AnyValueEnum::IntValue(self.builder.build_int_add( - lhs.into_int_value(), - rhs.into_int_value(), - "add", - )))) - } - BinaryOperator::Sub => { - Ok(Some(AnyValueEnum::IntValue(self.builder.build_int_sub( - lhs.into_int_value(), - rhs.into_int_value(), - "add", - )))) - } - BinaryOperator::Mul => { - Ok(Some(AnyValueEnum::IntValue(self.builder.build_int_sub( - lhs.into_int_value(), - rhs.into_int_value(), - "add", - )))) - } - BinaryOperator::Div => Ok(Some(AnyValueEnum::IntValue( - self.builder.build_int_signed_div( - lhs.into_int_value(), - rhs.into_int_value(), - "add", - ), - ))), - BinaryOperator::Pow => unimplemented!(), - BinaryOperator::Equ => Ok(Some(AnyValueEnum::IntValue( - self.builder.build_int_compare( - IntPredicate::EQ, - lhs.into_int_value(), - rhs.into_int_value(), - "eq", - ), - ))), - BinaryOperator::Neq => todo!(), - } - } - Expr::Let { bindings, body, .. } => { - self.env.push(); - for Binding { pat, body, .. } in bindings { - if let Some(val) = self.codegen_expr(body)? { - self.bind_pattern(pat, val); - } - } - let res = self.codegen_expr(body); - self.env.pop(); - res - } - Expr::If { - condition, - then, - else_, - type_, - } => { - let then_block = self.append_basic_block("then"); - let else_block = self.append_basic_block("else"); - let join_block = self.append_basic_block("join"); - let condition = self.codegen_expr(condition)?.unwrap(); - self.builder.build_conditional_branch( - condition.into_int_value(), - then_block, - else_block, - ); - self.builder.position_at_end(then_block); - let then_res = self.codegen_expr(then)?; - self.builder.build_unconditional_branch(join_block); - - self.builder.position_at_end(else_block); - let else_res = self.codegen_expr(else_)?; - self.builder.build_unconditional_branch(join_block); - - self.builder.position_at_end(join_block); - if let Some(phi_type) = self.codegen_type(type_) { - let phi = self.builder.build_phi(phi_type, "join"); - phi.add_incoming(&[ - ( - &BasicValueEnum::try_from(then_res.unwrap()).unwrap(), - then_block, - ), - ( - &BasicValueEnum::try_from(else_res.unwrap()).unwrap(), - else_block, - ), - ]); - Ok(Some(phi.as_basic_value().into())) - } else { - Ok(None) - } - } - Expr::Call { fun, args, .. } => { - if let Expr::Ident(id, _) = &**fun { - let function = self - .module - .get_function(id.into()) - .or_else(|| self.env.resolve(id)?.clone().try_into().ok()) - .ok_or_else(|| Error::UndefinedVariable(id.to_owned()))?; - let args = args - .iter() - .map(|arg| Ok(self.codegen_expr(arg)?.unwrap().try_into().unwrap())) - .collect::>>()?; - Ok(self - .builder - .build_call(function, &args, "call") - .try_as_basic_value() - .left() - .map(|val| val.into())) - } else { - todo!() - } - } - Expr::Fun { args, body, .. } => { - let fname = self.fresh_ident("f"); - let cur_block = self.builder.get_insert_block().unwrap(); - let env = self.env.save(); // TODO: closures - let function = self.codegen_function(&fname, args, body)?; - self.builder.position_at_end(cur_block); - self.env.restore(env); - Ok(Some(function.into())) - } - Expr::Tuple(members, ty) => { - let values = members - .into_iter() - .map(|expr| self.codegen_expr(expr)) - .collect::>>()? - .into_iter() - .filter_map(|x| x) - .map(|x| x.try_into().unwrap()) - .collect_vec(); - let field_types = ty.as_tuple().unwrap(); - let tuple_type = self.codegen_tuple_type(field_types); - Ok(Some(tuple_type.const_named_struct(&values).into())) - } - } - } - - pub fn codegen_function( - &mut self, - name: &str, - args: &'ast [(Ident<'ast>, Type)], - body: &'ast Expr<'ast, Type>, - ) -> Result> { - let arg_types = args - .iter() - .filter_map(|(_, at)| self.codegen_type(at)) - .collect::>(); - - self.new_function( - name, - match self.codegen_type(body.type_()) { - Some(ret_ty) => ret_ty.fn_type(&arg_types, false), - None => self.context.void_type().fn_type(&arg_types, false), - }, - ); - self.env.push(); - for (i, (arg, _)) in args.iter().enumerate() { - self.env.set( - arg, - self.cur_function().get_nth_param(i as u32).unwrap().into(), - ); - } - let res = self.codegen_expr(body)?; - self.env.pop(); - Ok(self.finish_function(res.map(|av| av.try_into().unwrap()).as_ref())) - } - - pub fn codegen_extern( - &mut self, - name: &str, - args: &'ast [Type], - ret: &'ast Type, - ) -> Result<()> { - let arg_types = args - .iter() - .map(|t| self.codegen_type(t).unwrap()) - .collect::>(); - self.module.add_function( - name, - match self.codegen_type(ret) { - Some(ret_ty) => ret_ty.fn_type(&arg_types, false), - None => self.context.void_type().fn_type(&arg_types, false), - }, - None, - ); - Ok(()) - } - - pub fn codegen_decl(&mut self, decl: &'ast Decl<'ast, Type>) -> Result<()> { - match decl { - Decl::Fun { - name, args, body, .. - } => { - self.codegen_function(name.into(), args, body)?; - Ok(()) - } - Decl::Extern { - name, - arg_types, - ret_type, - } => self.codegen_extern(name.into(), arg_types, ret_type), - } - } - - pub fn codegen_main(&mut self, expr: &'ast Expr<'ast, Type>) -> Result<()> { - self.new_function("main", self.context.i64_type().fn_type(&[], false)); - let res = self.codegen_expr(expr)?; - if *expr.type_() != Type::Int { - self.builder - .build_return(Some(&self.context.i64_type().const_int(0, false))); - } else { - self.finish_function(res.map(|r| r.try_into().unwrap()).as_ref()); - } - Ok(()) - } - - fn codegen_type(&self, type_: &'ast Type) -> Option> { - // TODO - match type_ { - Type::Int => Some(self.context.i64_type().into()), - Type::Float => Some(self.context.f64_type().into()), - Type::Bool => Some(self.context.bool_type().into()), - Type::CString => Some( - self.context - .i8_type() - .ptr_type(AddressSpace::Generic) - .into(), - ), - Type::Function(_) => todo!(), - Type::Var(_) => unreachable!(), - Type::Unit => None, - Type::Tuple(ts) => Some(self.codegen_tuple_type(ts).into()), - } - } - - fn codegen_tuple_type(&self, ts: &'ast [Type]) -> StructType<'ctx> { - self.context.struct_type( - ts.iter() - .filter_map(|t| self.codegen_type(t)) - .collect_vec() - .as_slice(), - false, - ) - } - - fn codegen_int_type(&self, type_: &'ast Type) -> IntType<'ctx> { - // TODO - self.context.i64_type() - } - - pub fn print_to_file

    (&self, path: P) -> Result<()> - where - P: AsRef, - { - Ok(self.module.print_to_file(path)?) - } - - pub fn binary_to_file

    (&self, path: P) -> Result<()> - where - P: AsRef, - { - if self.module.write_bitcode_to_path(path.as_ref()) { - Ok(()) - } else { - Err(Error::LLVMError( - "Error writing bitcode to output path".to_owned(), - )) - } - } - - fn fresh_ident(&mut self, prefix: &str) -> String { - self.identifier_counter += 1; - format!("{}{}", prefix, self.identifier_counter) - } - - fn cur_function(&self) -> &FunctionValue<'ctx> { - self.function_stack.last().unwrap() - } -} - -#[cfg(test)] -mod tests { - use inkwell::execution_engine::JitFunction; - use inkwell::OptimizationLevel; - - use super::*; - - fn jit_eval(expr: &str) -> anyhow::Result { - let expr = crate::parser::expr(expr).unwrap().1; - - let expr = crate::tc::typecheck_expr(expr).unwrap(); - - let context = Context::create(); - let mut codegen = Codegen::new(&context, "test"); - let execution_engine = codegen - .module - .create_jit_execution_engine(OptimizationLevel::None) - .unwrap(); - - codegen.codegen_function("test", &[], &expr)?; - - unsafe { - let fun: JitFunction T> = - execution_engine.get_function("test")?; - Ok(fun.call()) - } - } - - #[test] - fn add_literals() { - assert_eq!(jit_eval::("1 + 2").unwrap(), 3); - } - - #[test] - fn variable_shadowing() { - assert_eq!( - jit_eval::("let x = 1 in (let x = 2 in x) + x").unwrap(), - 3 - ); - } - - #[test] - fn eq() { - assert_eq!( - jit_eval::("let x = 1 in if x == 1 then 2 else 4").unwrap(), - 2 - ); - } - - #[test] - fn function_call() { - let res = jit_eval::("let id = fn x = x in id 1").unwrap(); - assert_eq!(res, 1); - } - - #[test] - fn bind_tuple_pattern() { - let res = jit_eval::("let (x, y) = (1, 2) in x + y").unwrap(); - assert_eq!(res, 3); - } -} diff --git a/users/aspen/achilles/src/codegen/mod.rs b/users/aspen/achilles/src/codegen/mod.rs deleted file mode 100644 index 8ef057dba..000000000 --- a/users/aspen/achilles/src/codegen/mod.rs +++ /dev/null @@ -1,25 +0,0 @@ -pub mod llvm; - -use inkwell::execution_engine::JitFunction; -use inkwell::OptimizationLevel; -pub use llvm::*; - -use crate::ast::hir::Expr; -use crate::ast::Type; -use crate::common::Result; - -pub fn jit_eval(expr: &Expr) -> Result { - let context = Context::create(); - let mut codegen = Codegen::new(&context, "eval"); - let execution_engine = codegen - .module - .create_jit_execution_engine(OptimizationLevel::None) - .map_err(Error::from)?; - codegen.codegen_function("test", &[], &expr)?; - - unsafe { - let fun: JitFunction T> = - execution_engine.get_function("eval").unwrap(); - Ok(fun.call()) - } -} diff --git a/users/aspen/achilles/src/commands/check.rs b/users/aspen/achilles/src/commands/check.rs deleted file mode 100644 index 0bea482c1..000000000 --- a/users/aspen/achilles/src/commands/check.rs +++ /dev/null @@ -1,39 +0,0 @@ -use clap::Clap; -use std::path::PathBuf; - -use crate::ast::Type; -use crate::{parser, tc, Result}; - -/// Typecheck a file or expression -#[derive(Clap)] -pub struct Check { - /// File to check - path: Option, - - /// Expression to check - #[clap(long, short = 'e')] - expr: Option, -} - -fn run_expr(expr: String) -> Result> { - let (_, parsed) = parser::expr(&expr)?; - let hir_expr = tc::typecheck_expr(parsed)?; - Ok(hir_expr.type_().to_owned()) -} - -fn run_path(path: PathBuf) -> Result> { - todo!() -} - -impl Check { - pub fn run(self) -> Result<()> { - let type_ = match (self.path, self.expr) { - (None, None) => Err("Must specify either a file or expression to check".into()), - (Some(_), Some(_)) => Err("Cannot specify both a file and expression to check".into()), - (None, Some(expr)) => run_expr(expr), - (Some(path), None) => run_path(path), - }?; - println!("type: {}", type_); - Ok(()) - } -} diff --git a/users/aspen/achilles/src/commands/compile.rs b/users/aspen/achilles/src/commands/compile.rs deleted file mode 100644 index be8767575..000000000 --- a/users/aspen/achilles/src/commands/compile.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::path::PathBuf; - -use clap::Clap; - -use crate::common::Result; -use crate::compiler::{self, CompilerOptions}; - -/// Compile a source file -#[derive(Clap)] -pub struct Compile { - /// File to compile - file: PathBuf, - - /// Output file - #[clap(short = 'o')] - out_file: PathBuf, - - #[clap(flatten)] - options: CompilerOptions, -} - -impl Compile { - pub fn run(self) -> Result<()> { - eprintln!( - ">>> {} -> {}", - &self.file.to_string_lossy(), - self.out_file.to_string_lossy() - ); - compiler::compile_file(&self.file, &self.out_file, &self.options) - } -} diff --git a/users/aspen/achilles/src/commands/eval.rs b/users/aspen/achilles/src/commands/eval.rs deleted file mode 100644 index efd7399ed..000000000 --- a/users/aspen/achilles/src/commands/eval.rs +++ /dev/null @@ -1,28 +0,0 @@ -use clap::Clap; - -use crate::{codegen, interpreter, parser, tc, Result}; - -/// Evaluate an expression and print its result -#[derive(Clap)] -pub struct Eval { - /// JIT-compile with LLVM instead of interpreting - #[clap(long)] - jit: bool, - - /// Expression to evaluate - expr: String, -} - -impl Eval { - pub fn run(self) -> Result<()> { - let (_, parsed) = parser::expr(&self.expr)?; - let hir = tc::typecheck_expr(parsed)?; - let result = if self.jit { - codegen::jit_eval::(&hir)?.into() - } else { - interpreter::eval(&hir)? - }; - println!("{}", result); - Ok(()) - } -} diff --git a/users/aspen/achilles/src/commands/mod.rs b/users/aspen/achilles/src/commands/mod.rs deleted file mode 100644 index fd0a82270..000000000 --- a/users/aspen/achilles/src/commands/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod check; -pub mod compile; -pub mod eval; - -pub use check::Check; -pub use compile::Compile; -pub use eval::Eval; diff --git a/users/aspen/achilles/src/common/env.rs b/users/aspen/achilles/src/common/env.rs deleted file mode 100644 index 59a5e46c4..000000000 --- a/users/aspen/achilles/src/common/env.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::borrow::Borrow; -use std::collections::HashMap; -use std::hash::Hash; -use std::mem; - -/// A lexical environment -#[derive(Debug, PartialEq, Eq)] -pub struct Env(Vec>); - -impl Default for Env -where - K: Eq + Hash, -{ - fn default() -> Self { - Self::new() - } -} - -impl Env -where - K: Eq + Hash, -{ - pub fn new() -> Self { - Self(vec![Default::default()]) - } - - pub fn push(&mut self) { - self.0.push(Default::default()); - } - - pub fn pop(&mut self) { - self.0.pop(); - } - - pub fn save(&mut self) -> Self { - mem::take(self) - } - - pub fn restore(&mut self, saved: Self) { - *self = saved; - } - - pub fn set(&mut self, k: K, v: V) { - self.0.last_mut().unwrap().insert(k, v); - } - - pub fn resolve<'a, Q>(&'a self, k: &Q) -> Option<&'a V> - where - K: Borrow, - Q: Hash + Eq + ?Sized, - { - for ctx in self.0.iter().rev() { - if let Some(res) = ctx.get(k) { - return Some(res); - } - } - None - } -} diff --git a/users/aspen/achilles/src/common/error.rs b/users/aspen/achilles/src/common/error.rs deleted file mode 100644 index 51575a895..000000000 --- a/users/aspen/achilles/src/common/error.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::{io, result}; - -use thiserror::Error; - -use crate::{codegen, interpreter, parser, tc}; - -#[derive(Error, Debug)] -pub enum Error { - #[error(transparent)] - IOError(#[from] io::Error), - - #[error("Error parsing input: {0}")] - ParseError(#[from] parser::Error), - - #[error("Error evaluating expression: {0}")] - EvalError(#[from] interpreter::Error), - - #[error("Compile error: {0}")] - CodegenError(#[from] codegen::Error), - - #[error("Type error: {0}")] - TypeError(#[from] tc::Error), - - #[error("{0}")] - Message(String), -} - -impl From for Error { - fn from(s: String) -> Self { - Self::Message(s) - } -} - -impl<'a> From<&'a str> for Error { - fn from(s: &'a str) -> Self { - Self::Message(s.to_owned()) - } -} - -impl<'a> From>> for Error { - fn from(e: nom::Err>) -> Self { - use nom::error::Error as NomError; - use nom::Err::*; - - Self::ParseError(match e { - Incomplete(i) => Incomplete(i), - Error(NomError { input, code }) => Error(NomError { - input: input.to_owned(), - code, - }), - Failure(NomError { input, code }) => Failure(NomError { - input: input.to_owned(), - code, - }), - }) - } -} - -pub type Result = result::Result; diff --git a/users/aspen/achilles/src/common/mod.rs b/users/aspen/achilles/src/common/mod.rs deleted file mode 100644 index 8368a6dd1..000000000 --- a/users/aspen/achilles/src/common/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub(crate) mod env; -pub(crate) mod error; -pub(crate) mod namer; - -pub use error::{Error, Result}; -pub use namer::{Namer, NamerOf}; diff --git a/users/aspen/achilles/src/common/namer.rs b/users/aspen/achilles/src/common/namer.rs deleted file mode 100644 index 016e9f6ed..000000000 --- a/users/aspen/achilles/src/common/namer.rs +++ /dev/null @@ -1,122 +0,0 @@ -use std::fmt::Display; -use std::marker::PhantomData; - -pub struct Namer { - make_name: F, - counter: u64, - _phantom: PhantomData, -} - -impl Namer { - pub fn new(make_name: F) -> Self { - Namer { - make_name, - counter: 0, - _phantom: PhantomData, - } - } -} - -impl Namer String>> { - pub fn with_prefix(prefix: T) -> Self - where - T: Display + 'static, - { - Namer::new(move |i| format!("{}{}", prefix, i)).boxed() - } - - pub fn with_suffix(suffix: T) -> Self - where - T: Display + 'static, - { - Namer::new(move |i| format!("{}{}", i, suffix)).boxed() - } - - pub fn alphabetic() -> Self { - Namer::new(|i| { - if i <= 26 { - std::char::from_u32((i + 96) as u32).unwrap().to_string() - } else { - format!( - "{}{}", - std::char::from_u32(((i % 26) + 96) as u32).unwrap(), - i - 26 - ) - } - }) - .boxed() - } -} - -impl Namer -where - F: Fn(u64) -> T, -{ - pub fn make_name(&mut self) -> T { - self.counter += 1; - (self.make_name)(self.counter) - } - - pub fn boxed(self) -> NamerOf - where - F: 'static, - { - Namer { - make_name: Box::new(self.make_name), - counter: self.counter, - _phantom: self._phantom, - } - } - - pub fn map(self, f: G) -> NamerOf - where - G: Fn(T) -> U + 'static, - T: 'static, - F: 'static, - { - Namer { - counter: self.counter, - make_name: Box::new(move |x| f((self.make_name)(x))), - _phantom: PhantomData, - } - } -} - -pub type NamerOf = Namer T>>; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn prefix() { - let mut namer = Namer::with_prefix("t"); - assert_eq!(namer.make_name(), "t1"); - assert_eq!(namer.make_name(), "t2"); - } - - #[test] - fn suffix() { - let mut namer = Namer::with_suffix("t"); - assert_eq!(namer.make_name(), "1t"); - assert_eq!(namer.make_name(), "2t"); - } - - #[test] - fn alphabetic() { - let mut namer = Namer::alphabetic(); - assert_eq!(namer.make_name(), "a"); - assert_eq!(namer.make_name(), "b"); - (0..25).for_each(|_| { - namer.make_name(); - }); - assert_eq!(namer.make_name(), "b2"); - } - - #[test] - fn custom_callback() { - let mut namer = Namer::new(|n| n + 1); - assert_eq!(namer.make_name(), 2); - assert_eq!(namer.make_name(), 3); - } -} diff --git a/users/aspen/achilles/src/compiler.rs b/users/aspen/achilles/src/compiler.rs deleted file mode 100644 index 45b215473..000000000 --- a/users/aspen/achilles/src/compiler.rs +++ /dev/null @@ -1,89 +0,0 @@ -use std::fmt::{self, Display}; -use std::path::Path; -use std::str::FromStr; -use std::{fs, result}; - -use clap::Clap; -use test_strategy::Arbitrary; - -use crate::codegen::{self, Codegen}; -use crate::common::Result; -use crate::passes::hir::{monomorphize, strip_positive_units}; -use crate::{parser, tc}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Arbitrary)] -pub enum OutputFormat { - LLVM, - Bitcode, -} - -impl Default for OutputFormat { - fn default() -> Self { - Self::Bitcode - } -} - -impl FromStr for OutputFormat { - type Err = String; - - fn from_str(s: &str) -> result::Result { - match s { - "llvm" => Ok(Self::LLVM), - "binary" => Ok(Self::Bitcode), - _ => Err(format!( - "Invalid output format {}, expected one of {{llvm, binary}}", - s - )), - } - } -} - -impl Display for OutputFormat { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - OutputFormat::LLVM => f.write_str("llvm"), - OutputFormat::Bitcode => f.write_str("binary"), - } - } -} - -#[derive(Clap, Debug, PartialEq, Eq, Default)] -pub struct CompilerOptions { - #[clap(long, short = 'f', default_value)] - format: OutputFormat, -} - -pub fn compile_file(input: &Path, output: &Path, options: &CompilerOptions) -> Result<()> { - let src = fs::read_to_string(input)?; - let (_, decls) = parser::toplevel(&src)?; - let mut decls = tc::typecheck_toplevel(decls)?; - monomorphize::run_toplevel(&mut decls); - strip_positive_units::run_toplevel(&mut decls); - - let context = codegen::Context::create(); - let mut codegen = Codegen::new( - &context, - &input - .file_stem() - .map_or("UNKNOWN".to_owned(), |s| s.to_string_lossy().into_owned()), - ); - for decl in &decls { - codegen.codegen_decl(decl)?; - } - match options.format { - OutputFormat::LLVM => codegen.print_to_file(output)?, - OutputFormat::Bitcode => codegen.binary_to_file(output)?, - } - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use test_strategy::proptest; - - #[proptest] - fn output_format_display_from_str_round_trip(of: OutputFormat) { - assert_eq!(OutputFormat::from_str(&of.to_string()), Ok(of)); - } -} diff --git a/users/aspen/achilles/src/interpreter/error.rs b/users/aspen/achilles/src/interpreter/error.rs deleted file mode 100644 index 268d6f479..000000000 --- a/users/aspen/achilles/src/interpreter/error.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::result; - -use thiserror::Error; - -use crate::ast::{Ident, Type}; - -#[derive(Debug, PartialEq, Eq, Error)] -pub enum Error { - #[error("Undefined variable {0}")] - UndefinedVariable(Ident<'static>), - - #[error("Unexpected type {actual}, expected type {expected}")] - InvalidType { - actual: Type<'static>, - expected: Type<'static>, - }, -} - -pub type Result = result::Result; diff --git a/users/aspen/achilles/src/interpreter/mod.rs b/users/aspen/achilles/src/interpreter/mod.rs deleted file mode 100644 index 70df7a072..000000000 --- a/users/aspen/achilles/src/interpreter/mod.rs +++ /dev/null @@ -1,203 +0,0 @@ -mod error; -mod value; - -use itertools::Itertools; -use value::Val; - -pub use self::error::{Error, Result}; -pub use self::value::{Function, Value}; -use crate::ast::hir::{Binding, Expr, Pattern}; -use crate::ast::{BinaryOperator, FunctionType, Ident, Literal, Type, UnaryOperator}; -use crate::common::env::Env; - -#[derive(Debug, Default)] -pub struct Interpreter<'a> { - env: Env<&'a Ident<'a>, Value<'a>>, -} - -impl<'a> Interpreter<'a> { - pub fn new() -> Self { - Self::default() - } - - fn resolve(&self, var: &'a Ident<'a>) -> Result> { - self.env - .resolve(var) - .cloned() - .ok_or_else(|| Error::UndefinedVariable(var.to_owned())) - } - - fn bind_pattern(&mut self, pattern: &'a Pattern<'a, Type>, value: Value<'a>) { - match pattern { - Pattern::Id(id, _) => self.env.set(id, value), - Pattern::Tuple(pats) => { - for (pat, val) in pats.iter().zip(value.as_tuple().unwrap().clone()) { - self.bind_pattern(pat, val); - } - } - } - } - - pub fn eval(&mut self, expr: &'a Expr<'a, Type>) -> Result> { - let res = match expr { - Expr::Ident(id, _) => self.resolve(id), - Expr::Literal(Literal::Int(i), _) => Ok((*i).into()), - Expr::Literal(Literal::Bool(b), _) => Ok((*b).into()), - Expr::Literal(Literal::String(s), _) => Ok(s.clone().into()), - Expr::Literal(Literal::Unit, _) => unreachable!(), - Expr::UnaryOp { op, rhs, .. } => { - let rhs = self.eval(rhs)?; - match op { - UnaryOperator::Neg => -rhs, - _ => unimplemented!(), - } - } - Expr::BinaryOp { lhs, op, rhs, .. } => { - let lhs = self.eval(lhs)?; - let rhs = self.eval(rhs)?; - match op { - BinaryOperator::Add => lhs + rhs, - BinaryOperator::Sub => lhs - rhs, - BinaryOperator::Mul => lhs * rhs, - BinaryOperator::Div => lhs / rhs, - BinaryOperator::Pow => todo!(), - BinaryOperator::Equ => Ok(lhs.eq(&rhs).into()), - BinaryOperator::Neq => todo!(), - } - } - Expr::Let { bindings, body, .. } => { - self.env.push(); - for Binding { pat, body, .. } in bindings { - let val = self.eval(body)?; - self.bind_pattern(pat, val); - } - let res = self.eval(body)?; - self.env.pop(); - Ok(res) - } - Expr::If { - condition, - then, - else_, - .. - } => { - let condition = self.eval(condition)?; - if *(condition.as_type::()?) { - self.eval(then) - } else { - self.eval(else_) - } - } - Expr::Call { ref fun, args, .. } => { - let fun = self.eval(fun)?; - let expected_type = FunctionType { - args: args.iter().map(|_| Type::Int).collect(), - ret: Box::new(Type::Int), - }; - - let Function { - args: function_args, - body, - .. - } = fun.as_function(expected_type)?; - let arg_values = function_args.iter().zip( - args.iter() - .map(|v| self.eval(v)) - .collect::>>()?, - ); - let mut interpreter = Interpreter::new(); - for (arg_name, arg_value) in arg_values { - interpreter.env.set(arg_name, arg_value); - } - Ok(Value::from(*interpreter.eval(body)?.as_type::()?)) - } - Expr::Fun { - type_args: _, - args, - body, - type_, - } => { - let type_ = match type_ { - Type::Function(ft) => ft.clone(), - _ => unreachable!("Function expression without function type"), - }; - - Ok(Value::from(value::Function { - // TODO - type_, - args: args.iter().map(|(arg, _)| arg.to_owned()).collect(), - body: (**body).to_owned(), - })) - } - Expr::Tuple(members, _) => Ok(Val::Tuple( - members - .into_iter() - .map(|expr| self.eval(expr)) - .try_collect()?, - ) - .into()), - }?; - debug_assert_eq!(&res.type_(), expr.type_()); - Ok(res) - } -} - -pub fn eval<'a>(expr: &'a Expr<'a, Type>) -> Result> { - let mut interpreter = Interpreter::new(); - interpreter.eval(expr) -} - -#[cfg(test)] -mod tests { - use std::convert::TryFrom; - - use super::value::{TypeOf, Val}; - use super::*; - use BinaryOperator::*; - - fn int_lit(i: u64) -> Box>> { - Box::new(Expr::Literal(Literal::Int(i), Type::Int)) - } - - fn do_eval(src: &str) -> T - where - for<'a> &'a T: TryFrom<&'a Val<'a>>, - T: Clone + TypeOf, - { - let expr = crate::parser::expr(src).unwrap().1; - let hir = crate::tc::typecheck_expr(expr).unwrap(); - let res = eval(&hir).unwrap(); - res.as_type::().unwrap().clone() - } - - #[test] - fn simple_addition() { - let expr = Expr::BinaryOp { - lhs: int_lit(1), - op: Mul, - rhs: int_lit(2), - type_: Type::Int, - }; - let res = eval(&expr).unwrap(); - assert_eq!(*res.as_type::().unwrap(), 2); - } - - #[test] - fn variable_shadowing() { - let res = do_eval::("let x = 1 in (let x = 2 in x) + x"); - assert_eq!(res, 3); - } - - #[test] - fn conditional_with_equals() { - let res = do_eval::("let x = 1 in if x == 1 then 2 else 4"); - assert_eq!(res, 2); - } - - #[test] - #[ignore] - fn function_call() { - let res = do_eval::("let id = fn x = x in id 1"); - assert_eq!(res, 1); - } -} diff --git a/users/aspen/achilles/src/interpreter/value.rs b/users/aspen/achilles/src/interpreter/value.rs deleted file mode 100644 index 272d1167a..000000000 --- a/users/aspen/achilles/src/interpreter/value.rs +++ /dev/null @@ -1,224 +0,0 @@ -use std::borrow::Cow; -use std::convert::TryFrom; -use std::fmt::{self, Display}; -use std::ops::{Add, Div, Mul, Neg, Sub}; -use std::rc::Rc; -use std::result; - -use derive_more::{Deref, From, TryInto}; -use itertools::Itertools; - -use super::{Error, Result}; -use crate::ast::hir::Expr; -use crate::ast::{FunctionType, Ident, Type}; - -#[derive(Debug, Clone)] -pub struct Function<'a> { - pub type_: FunctionType<'a>, - pub args: Vec>, - pub body: Expr<'a, Type<'a>>, -} - -#[derive(From, TryInto)] -#[try_into(owned, ref)] -pub enum Val<'a> { - Int(i64), - Float(f64), - Bool(bool), - String(Cow<'a, str>), - Tuple(Vec>), - Function(Function<'a>), -} - -impl<'a> TryFrom> for String { - type Error = (); - - fn try_from(value: Val<'a>) -> result::Result { - match value { - Val::String(s) => Ok(s.into_owned()), - _ => Err(()), - } - } -} - -impl<'a> fmt::Debug for Val<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Val::Int(x) => f.debug_tuple("Int").field(x).finish(), - Val::Float(x) => f.debug_tuple("Float").field(x).finish(), - Val::Bool(x) => f.debug_tuple("Bool").field(x).finish(), - Val::String(s) => f.debug_tuple("String").field(s).finish(), - Val::Function(Function { type_, .. }) => { - f.debug_struct("Function").field("type_", type_).finish() - } - Val::Tuple(members) => f.debug_tuple("Tuple").field(members).finish(), - } - } -} - -impl<'a> PartialEq for Val<'a> { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Val::Int(x), Val::Int(y)) => x == y, - (Val::Float(x), Val::Float(y)) => x == y, - (Val::Bool(x), Val::Bool(y)) => x == y, - (Val::Function(_), Val::Function(_)) => false, - (_, _) => false, - } - } -} - -impl<'a> From for Val<'a> { - fn from(i: u64) -> Self { - Self::from(i as i64) - } -} - -impl<'a> Display for Val<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Val::Int(x) => x.fmt(f), - Val::Float(x) => x.fmt(f), - Val::Bool(x) => x.fmt(f), - Val::String(s) => write!(f, "{:?}", s), - Val::Function(Function { type_, .. }) => write!(f, "<{}>", type_), - Val::Tuple(members) => write!(f, "({})", members.iter().join(", ")), - } - } -} - -impl<'a> Val<'a> { - pub fn type_(&self) -> Type { - match self { - Val::Int(_) => Type::Int, - Val::Float(_) => Type::Float, - Val::Bool(_) => Type::Bool, - Val::String(_) => Type::CString, - Val::Function(Function { type_, .. }) => Type::Function(type_.clone()), - Val::Tuple(members) => Type::Tuple(members.iter().map(|expr| expr.type_()).collect()), - } - } - - pub fn as_type<'b, T>(&'b self) -> Result<&'b T> - where - T: TypeOf + 'b + Clone, - &'b T: TryFrom<&'b Self>, - { - <&T>::try_from(self).map_err(|_| Error::InvalidType { - actual: self.type_().to_owned(), - expected: ::type_of(), - }) - } - - pub fn as_function<'b>(&'b self, function_type: FunctionType) -> Result<&'b Function<'a>> { - match self { - Val::Function(f) if f.type_ == function_type => Ok(&f), - _ => Err(Error::InvalidType { - actual: self.type_().to_owned(), - expected: Type::Function(function_type.to_owned()), - }), - } - } - - pub fn as_tuple(&self) -> Option<&Vec>> { - if let Self::Tuple(v) = self { - Some(v) - } else { - None - } - } - - pub fn try_into_tuple(self) -> result::Result>, Self> { - if let Self::Tuple(v) = self { - Ok(v) - } else { - Err(self) - } - } -} - -#[derive(Debug, PartialEq, Clone, Deref)] -pub struct Value<'a>(Rc>); - -impl<'a> Display for Value<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -impl<'a, T> From for Value<'a> -where - Val<'a>: From, -{ - fn from(x: T) -> Self { - Self(Rc::new(x.into())) - } -} - -impl<'a> Neg for Value<'a> { - type Output = Result>; - - fn neg(self) -> Self::Output { - Ok((-self.as_type::()?).into()) - } -} - -impl<'a> Add for Value<'a> { - type Output = Result>; - - fn add(self, rhs: Self) -> Self::Output { - Ok((self.as_type::()? + rhs.as_type::()?).into()) - } -} - -impl<'a> Sub for Value<'a> { - type Output = Result>; - - fn sub(self, rhs: Self) -> Self::Output { - Ok((self.as_type::()? - rhs.as_type::()?).into()) - } -} - -impl<'a> Mul for Value<'a> { - type Output = Result>; - - fn mul(self, rhs: Self) -> Self::Output { - Ok((self.as_type::()? * rhs.as_type::()?).into()) - } -} - -impl<'a> Div for Value<'a> { - type Output = Result>; - - fn div(self, rhs: Self) -> Self::Output { - Ok((self.as_type::()? / rhs.as_type::()?).into()) - } -} - -pub trait TypeOf { - fn type_of() -> Type<'static>; -} - -impl TypeOf for i64 { - fn type_of() -> Type<'static> { - Type::Int - } -} - -impl TypeOf for bool { - fn type_of() -> Type<'static> { - Type::Bool - } -} - -impl TypeOf for f64 { - fn type_of() -> Type<'static> { - Type::Float - } -} - -impl TypeOf for String { - fn type_of() -> Type<'static> { - Type::CString - } -} diff --git a/users/aspen/achilles/src/main.rs b/users/aspen/achilles/src/main.rs deleted file mode 100644 index 5ae1b59b3..000000000 --- a/users/aspen/achilles/src/main.rs +++ /dev/null @@ -1,36 +0,0 @@ -use clap::Clap; - -pub mod ast; -pub mod codegen; -pub(crate) mod commands; -pub(crate) mod common; -pub mod compiler; -pub mod interpreter; -pub(crate) mod passes; -#[macro_use] -pub mod parser; -pub mod tc; - -pub use common::{Error, Result}; - -#[derive(Clap)] -struct Opts { - #[clap(subcommand)] - subcommand: Command, -} - -#[derive(Clap)] -enum Command { - Eval(commands::Eval), - Compile(commands::Compile), - Check(commands::Check), -} - -fn main() -> anyhow::Result<()> { - let opts = Opts::parse(); - match opts.subcommand { - Command::Eval(eval) => Ok(eval.run()?), - Command::Compile(compile) => Ok(compile.run()?), - Command::Check(check) => Ok(check.run()?), - } -} diff --git a/users/aspen/achilles/src/parser/expr.rs b/users/aspen/achilles/src/parser/expr.rs deleted file mode 100644 index b18ce4a0d..000000000 --- a/users/aspen/achilles/src/parser/expr.rs +++ /dev/null @@ -1,717 +0,0 @@ -use std::borrow::Cow; - -use nom::character::complete::{digit1, multispace0, multispace1}; -use nom::{ - alt, call, char, complete, delimited, do_parse, flat_map, many0, map, named, opt, parse_to, - preceded, separated_list0, separated_list1, tag, tuple, -}; -use pratt::{Affix, Associativity, PrattParser, Precedence}; - -use super::util::comma; -use crate::ast::{BinaryOperator, Binding, Expr, Fun, Literal, Pattern, UnaryOperator}; -use crate::parser::{arg, ident, type_}; - -#[derive(Debug)] -enum TokenTree<'a> { - Prefix(UnaryOperator), - // Postfix(char), - Infix(BinaryOperator), - Primary(Expr<'a>), - Group(Vec>), -} - -named!(prefix(&str) -> TokenTree, map!(alt!( - complete!(char!('-')) => { |_| UnaryOperator::Neg } | - complete!(char!('!')) => { |_| UnaryOperator::Not } -), TokenTree::Prefix)); - -named!(infix(&str) -> TokenTree, map!(alt!( - complete!(tag!("==")) => { |_| BinaryOperator::Equ } | - complete!(tag!("!=")) => { |_| BinaryOperator::Neq } | - complete!(char!('+')) => { |_| BinaryOperator::Add } | - complete!(char!('-')) => { |_| BinaryOperator::Sub } | - complete!(char!('*')) => { |_| BinaryOperator::Mul } | - complete!(char!('/')) => { |_| BinaryOperator::Div } | - complete!(char!('^')) => { |_| BinaryOperator::Pow } -), TokenTree::Infix)); - -named!(primary(&str) -> TokenTree, alt!( - do_parse!( - multispace0 >> - char!('(') >> - multispace0 >> - group: group >> - multispace0 >> - char!(')') >> - multispace0 >> - (TokenTree::Group(group)) - ) | - delimited!(multispace0, simple_expr, multispace0) => { |s| TokenTree::Primary(s) } -)); - -named!( - rest(&str) -> Vec<(TokenTree, Vec, TokenTree)>, - many0!(tuple!( - infix, - delimited!(multispace0, many0!(prefix), multispace0), - primary - // many0!(postfix) - )) -); - -named!(group(&str) -> Vec, do_parse!( - prefix: many0!(prefix) - >> primary: primary - // >> postfix: many0!(postfix) - >> rest: rest - >> ({ - let mut res = prefix; - res.push(primary); - // res.append(&mut postfix); - for (infix, mut prefix, primary/*, mut postfix*/) in rest { - res.push(infix); - res.append(&mut prefix); - res.push(primary); - // res.append(&mut postfix); - } - res - }) -)); - -fn token_tree(i: &str) -> nom::IResult<&str, Vec> { - group(i) -} - -struct ExprParser; - -impl<'a, I> PrattParser for ExprParser -where - I: Iterator>, -{ - type Error = pratt::NoError; - type Input = TokenTree<'a>; - type Output = Expr<'a>; - - fn query(&mut self, input: &Self::Input) -> Result { - use BinaryOperator::*; - use UnaryOperator::*; - - Ok(match input { - TokenTree::Infix(Add) => Affix::Infix(Precedence(6), Associativity::Left), - TokenTree::Infix(Sub) => Affix::Infix(Precedence(6), Associativity::Left), - TokenTree::Infix(Mul) => Affix::Infix(Precedence(7), Associativity::Left), - TokenTree::Infix(Div) => Affix::Infix(Precedence(7), Associativity::Left), - TokenTree::Infix(Pow) => Affix::Infix(Precedence(8), Associativity::Right), - TokenTree::Infix(Equ) => Affix::Infix(Precedence(4), Associativity::Right), - TokenTree::Infix(Neq) => Affix::Infix(Precedence(4), Associativity::Right), - TokenTree::Prefix(Neg) => Affix::Prefix(Precedence(6)), - TokenTree::Prefix(Not) => Affix::Prefix(Precedence(6)), - TokenTree::Primary(_) => Affix::Nilfix, - TokenTree::Group(_) => Affix::Nilfix, - }) - } - - fn primary(&mut self, input: Self::Input) -> Result { - Ok(match input { - TokenTree::Primary(expr) => expr, - TokenTree::Group(group) => self.parse(&mut group.into_iter()).unwrap(), - _ => unreachable!(), - }) - } - - fn infix( - &mut self, - lhs: Self::Output, - op: Self::Input, - rhs: Self::Output, - ) -> Result { - let op = match op { - TokenTree::Infix(op) => op, - _ => unreachable!(), - }; - Ok(Expr::BinaryOp { - lhs: Box::new(lhs), - op, - rhs: Box::new(rhs), - }) - } - - fn prefix(&mut self, op: Self::Input, rhs: Self::Output) -> Result { - let op = match op { - TokenTree::Prefix(op) => op, - _ => unreachable!(), - }; - - Ok(Expr::UnaryOp { - op, - rhs: Box::new(rhs), - }) - } - - fn postfix( - &mut self, - _lhs: Self::Output, - _op: Self::Input, - ) -> Result { - unreachable!() - } -} - -named!(int(&str) -> Literal, map!(flat_map!(digit1, parse_to!(u64)), Literal::Int)); - -named!(bool_(&str) -> Literal, alt!( - complete!(tag!("true")) => { |_| Literal::Bool(true) } | - complete!(tag!("false")) => { |_| Literal::Bool(false) } -)); - -fn string_internal(i: &str) -> nom::IResult<&str, Cow<'_, str>, nom::error::Error<&str>> { - // TODO(grfn): use String::split_once when that's stable - let (s, rem) = if let Some(pos) = i.find('"') { - (&i[..pos], &i[(pos + 1)..]) - } else { - return Err(nom::Err::Error(nom::error::Error::new( - i, - nom::error::ErrorKind::Tag, - ))); - }; - - Ok((rem, Cow::Borrowed(s))) -} - -named!(string(&str) -> Literal, preceded!( - complete!(char!('"')), - map!( - string_internal, - |s| Literal::String(s) - ) -)); - -named!(unit(&str) -> Literal, map!(complete!(tag!("()")), |_| Literal::Unit)); - -named!(literal(&str) -> Literal, alt!(int | bool_ | string | unit)); - -named!(literal_expr(&str) -> Expr, map!(literal, Expr::Literal)); - -named!(tuple(&str) -> Expr, do_parse!( - complete!(tag!("(")) - >> multispace0 - >> fst: expr - >> comma - >> rest: separated_list0!( - comma, - expr - ) - >> multispace0 - >> tag!(")") - >> ({ - let mut members = Vec::with_capacity(rest.len() + 1); - members.push(fst); - members.append(&mut rest.clone()); - Expr::Tuple(members) - }) -)); - -named!(tuple_pattern(&str) -> Pattern, do_parse!( - complete!(tag!("(")) - >> multispace0 - >> pats: separated_list0!( - comma, - pattern - ) - >> multispace0 - >> tag!(")") - >> (Pattern::Tuple(pats)) -)); - -named!(pattern(&str) -> Pattern, alt!( - ident => { |id| Pattern::Id(id) } | - tuple_pattern -)); - -named!(binding(&str) -> Binding, do_parse!( - multispace0 - >> pat: pattern - >> multispace0 - >> type_: opt!(preceded!(tuple!(tag!(":"), multispace0), type_)) - >> multispace0 - >> char!('=') - >> multispace0 - >> body: expr - >> (Binding { - pat, - type_, - body - }) -)); - -named!(let_(&str) -> Expr, do_parse!( - tag!("let") - >> multispace0 - >> bindings: separated_list1!(alt!(char!(';') | char!('\n')), binding) - >> multispace0 - >> tag!("in") - >> multispace0 - >> body: expr - >> (Expr::Let { - bindings, - body: Box::new(body) - }) -)); - -named!(if_(&str) -> Expr, do_parse! ( - tag!("if") - >> multispace0 - >> condition: expr - >> multispace0 - >> tag!("then") - >> multispace0 - >> then: expr - >> multispace0 - >> tag!("else") - >> multispace0 - >> else_: expr - >> (Expr::If { - condition: Box::new(condition), - then: Box::new(then), - else_: Box::new(else_) - }) -)); - -named!(ident_expr(&str) -> Expr, map!(ident, Expr::Ident)); - -fn ascripted<'a>( - p: impl Fn(&'a str) -> nom::IResult<&'a str, Expr, nom::error::Error<&'a str>> + 'a, -) -> impl Fn(&'a str) -> nom::IResult<&str, Expr, nom::error::Error<&'a str>> { - move |i| { - do_parse!( - i, - expr: p - >> multispace0 - >> complete!(tag!(":")) - >> multispace0 - >> type_: type_ - >> (Expr::Ascription { - expr: Box::new(expr), - type_ - }) - ) - } -} - -named!(paren_expr(&str) -> Expr, - delimited!(complete!(tag!("(")), expr, complete!(tag!(")")))); - -named!(funcref(&str) -> Expr, alt!( - ident_expr | - tuple | - paren_expr -)); - -named!(no_arg_call(&str) -> Expr, do_parse!( - fun: funcref - >> complete!(tag!("()")) - >> (Expr::Call { - fun: Box::new(fun), - args: vec![], - }) -)); - -named!(fun_expr(&str) -> Expr, do_parse!( - tag!("fn") - >> multispace1 - >> args: separated_list0!(multispace1, arg) - >> multispace0 - >> char!('=') - >> multispace0 - >> body: expr - >> (Expr::Fun(Box::new(Fun { - args, - body - }))) -)); - -named!(fn_arg(&str) -> Expr, alt!( - ident_expr | - literal_expr | - tuple | - paren_expr -)); - -named!(call_with_args(&str) -> Expr, do_parse!( - fun: funcref - >> multispace1 - >> args: separated_list1!(multispace1, fn_arg) - >> (Expr::Call { - fun: Box::new(fun), - args - }) -)); - -named!(simple_expr_unascripted(&str) -> Expr, alt!( - let_ | - if_ | - fun_expr | - literal_expr | - ident_expr | - tuple -)); - -named!(simple_expr(&str) -> Expr, alt!( - call!(ascripted(simple_expr_unascripted)) | - simple_expr_unascripted -)); - -named!(pub expr(&str) -> Expr, alt!( - no_arg_call | - call_with_args | - map!(token_tree, |tt| { - ExprParser.parse(&mut tt.into_iter()).unwrap() - }) | - simple_expr -)); - -#[cfg(test)] -pub(crate) mod tests { - use super::*; - use crate::ast::{Arg, Ident, Pattern, Type}; - use std::convert::TryFrom; - use BinaryOperator::*; - use Expr::{BinaryOp, If, Let, UnaryOp}; - use UnaryOperator::*; - - pub(crate) fn ident_expr(s: &str) -> Box { - Box::new(Expr::Ident(Ident::try_from(s).unwrap())) - } - - mod operators { - use super::*; - - #[test] - fn mul_plus() { - let (rem, res) = expr("x*y+z").unwrap(); - assert!(rem.is_empty()); - assert_eq!( - res, - BinaryOp { - lhs: Box::new(BinaryOp { - lhs: ident_expr("x"), - op: Mul, - rhs: ident_expr("y") - }), - op: Add, - rhs: ident_expr("z") - } - ) - } - - #[test] - fn mul_plus_ws() { - let (rem, res) = expr("x * y + z").unwrap(); - assert!(rem.is_empty(), "non-empty remainder: \"{}\"", rem); - assert_eq!( - res, - BinaryOp { - lhs: Box::new(BinaryOp { - lhs: ident_expr("x"), - op: Mul, - rhs: ident_expr("y") - }), - op: Add, - rhs: ident_expr("z") - } - ) - } - - #[test] - fn unary() { - let (rem, res) = expr("x * -z").unwrap(); - assert!(rem.is_empty(), "non-empty remainder: \"{}\"", rem); - assert_eq!( - res, - BinaryOp { - lhs: ident_expr("x"), - op: Mul, - rhs: Box::new(UnaryOp { - op: Neg, - rhs: ident_expr("z"), - }) - } - ) - } - - #[test] - fn mul_literal() { - let (rem, res) = expr("x * 3").unwrap(); - assert!(rem.is_empty()); - assert_eq!( - res, - BinaryOp { - lhs: ident_expr("x"), - op: Mul, - rhs: Box::new(Expr::Literal(Literal::Int(3))), - } - ) - } - - #[test] - fn equ() { - let res = test_parse!(expr, "x * 7 == 7"); - assert_eq!( - res, - BinaryOp { - lhs: Box::new(BinaryOp { - lhs: ident_expr("x"), - op: Mul, - rhs: Box::new(Expr::Literal(Literal::Int(7))) - }), - op: Equ, - rhs: Box::new(Expr::Literal(Literal::Int(7))) - } - ) - } - } - - #[test] - fn unit() { - assert_eq!(test_parse!(expr, "()"), Expr::Literal(Literal::Unit)); - } - - #[test] - fn bools() { - assert_eq!( - test_parse!(expr, "true"), - Expr::Literal(Literal::Bool(true)) - ); - assert_eq!( - test_parse!(expr, "false"), - Expr::Literal(Literal::Bool(false)) - ); - } - - #[test] - fn tuple() { - assert_eq!( - test_parse!(expr, "(1, \"seven\")"), - Expr::Tuple(vec![ - Expr::Literal(Literal::Int(1)), - Expr::Literal(Literal::String(Cow::Borrowed("seven"))) - ]) - ) - } - - #[test] - fn simple_string_lit() { - assert_eq!( - test_parse!(expr, "\"foobar\""), - Expr::Literal(Literal::String(Cow::Borrowed("foobar"))) - ) - } - - #[test] - fn let_complex() { - let res = test_parse!(expr, "let x = 1; y = x * 7 in (x + y) * 4"); - assert_eq!( - res, - Let { - bindings: vec![ - Binding { - pat: Pattern::Id(Ident::try_from("x").unwrap()), - type_: None, - body: Expr::Literal(Literal::Int(1)) - }, - Binding { - pat: Pattern::Id(Ident::try_from("y").unwrap()), - type_: None, - body: Expr::BinaryOp { - lhs: ident_expr("x"), - op: Mul, - rhs: Box::new(Expr::Literal(Literal::Int(7))) - } - } - ], - body: Box::new(Expr::BinaryOp { - lhs: Box::new(Expr::BinaryOp { - lhs: ident_expr("x"), - op: Add, - rhs: ident_expr("y"), - }), - op: Mul, - rhs: Box::new(Expr::Literal(Literal::Int(4))), - }) - } - ) - } - - #[test] - fn if_simple() { - let res = test_parse!(expr, "if x == 8 then 9 else 20"); - assert_eq!( - res, - If { - condition: Box::new(BinaryOp { - lhs: ident_expr("x"), - op: Equ, - rhs: Box::new(Expr::Literal(Literal::Int(8))), - }), - then: Box::new(Expr::Literal(Literal::Int(9))), - else_: Box::new(Expr::Literal(Literal::Int(20))) - } - ) - } - - #[test] - fn no_arg_call() { - let res = test_parse!(expr, "f()"); - assert_eq!( - res, - Expr::Call { - fun: ident_expr("f"), - args: vec![] - } - ); - } - - #[test] - fn unit_call() { - let res = test_parse!(expr, "f ()"); - assert_eq!( - res, - Expr::Call { - fun: ident_expr("f"), - args: vec![Expr::Literal(Literal::Unit)] - } - ) - } - - #[test] - fn call_with_args() { - let res = test_parse!(expr, "f x 1"); - assert_eq!( - res, - Expr::Call { - fun: ident_expr("f"), - args: vec![*ident_expr("x"), Expr::Literal(Literal::Int(1))] - } - ) - } - - #[test] - fn call_funcref() { - let res = test_parse!(expr, "(let x = 1 in x) 2"); - assert_eq!( - res, - Expr::Call { - fun: Box::new(Expr::Let { - bindings: vec![Binding { - pat: Pattern::Id(Ident::try_from("x").unwrap()), - type_: None, - body: Expr::Literal(Literal::Int(1)) - }], - body: ident_expr("x") - }), - args: vec![Expr::Literal(Literal::Int(2))] - } - ) - } - - #[test] - fn anon_function() { - let res = test_parse!(expr, "let id = fn x = x in id 1"); - assert_eq!( - res, - Expr::Let { - bindings: vec![Binding { - pat: Pattern::Id(Ident::try_from("id").unwrap()), - type_: None, - body: Expr::Fun(Box::new(Fun { - args: vec![Arg::try_from("x").unwrap()], - body: *ident_expr("x") - })) - }], - body: Box::new(Expr::Call { - fun: ident_expr("id"), - args: vec![Expr::Literal(Literal::Int(1))], - }) - } - ); - } - - #[test] - fn tuple_binding() { - let res = test_parse!(expr, "let (x, y) = (1, 2) in x"); - assert_eq!( - res, - Expr::Let { - bindings: vec![Binding { - pat: Pattern::Tuple(vec![ - Pattern::Id(Ident::from_str_unchecked("x")), - Pattern::Id(Ident::from_str_unchecked("y")) - ]), - body: Expr::Tuple(vec![ - Expr::Literal(Literal::Int(1)), - Expr::Literal(Literal::Int(2)) - ]), - type_: None - }], - body: Box::new(Expr::Ident(Ident::from_str_unchecked("x"))) - } - ) - } - - mod ascriptions { - use super::*; - - #[test] - fn bare_ascription() { - let res = test_parse!(expr, "1: float"); - assert_eq!( - res, - Expr::Ascription { - expr: Box::new(Expr::Literal(Literal::Int(1))), - type_: Type::Float - } - ) - } - - #[test] - fn fn_body_ascription() { - let res = test_parse!(expr, "let const_1 = fn x = 1: int in const_1 2"); - assert_eq!( - res, - Expr::Let { - bindings: vec![Binding { - pat: Pattern::Id(Ident::try_from("const_1").unwrap()), - type_: None, - body: Expr::Fun(Box::new(Fun { - args: vec![Arg::try_from("x").unwrap()], - body: Expr::Ascription { - expr: Box::new(Expr::Literal(Literal::Int(1))), - type_: Type::Int, - } - })) - }], - body: Box::new(Expr::Call { - fun: ident_expr("const_1"), - args: vec![Expr::Literal(Literal::Int(2))] - }) - } - ) - } - - #[test] - fn let_binding_ascripted() { - let res = test_parse!(expr, "let x: int = 1 in x"); - assert_eq!( - res, - Expr::Let { - bindings: vec![Binding { - pat: Pattern::Id(Ident::try_from("x").unwrap()), - type_: Some(Type::Int), - body: Expr::Literal(Literal::Int(1)) - }], - body: ident_expr("x") - } - ) - } - } -} diff --git a/users/aspen/achilles/src/parser/macros.rs b/users/aspen/achilles/src/parser/macros.rs deleted file mode 100644 index 406e5c0e6..000000000 --- a/users/aspen/achilles/src/parser/macros.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[cfg(test)] -#[macro_use] -macro_rules! test_parse { - ($parser: ident, $src: expr) => {{ - let res = $parser($src); - nom_trace::print_trace!(); - let (rem, res) = res.unwrap(); - assert!( - rem.is_empty(), - "non-empty remainder: \"{}\", parsed: {:?}", - rem, - res - ); - res - }}; -} diff --git a/users/aspen/achilles/src/parser/mod.rs b/users/aspen/achilles/src/parser/mod.rs deleted file mode 100644 index e088cbca1..000000000 --- a/users/aspen/achilles/src/parser/mod.rs +++ /dev/null @@ -1,240 +0,0 @@ -use nom::character::complete::{multispace0, multispace1}; -use nom::error::{ErrorKind, ParseError}; -use nom::{alt, char, complete, do_parse, eof, many0, named, separated_list0, tag, terminated}; - -#[macro_use] -pub(crate) mod macros; -mod expr; -mod type_; -mod util; - -use crate::ast::{Arg, Decl, Fun, Ident}; -pub use expr::expr; -use type_::function_type; -pub use type_::type_; - -pub type Error = nom::Err>; - -pub(crate) fn is_reserved(s: &str) -> bool { - matches!( - s, - "if" | "then" - | "else" - | "let" - | "in" - | "fn" - | "ty" - | "int" - | "float" - | "bool" - | "true" - | "false" - | "cstring" - ) -} - -pub(crate) fn ident<'a, E>(i: &'a str) -> nom::IResult<&'a str, Ident, E> -where - E: ParseError<&'a str>, -{ - let mut chars = i.chars(); - if let Some(f) = chars.next() { - if f.is_alphabetic() || f == '_' { - let mut idx = 1; - for c in chars { - if !(c.is_alphanumeric() || c == '_') { - break; - } - idx += 1; - } - let id = &i[..idx]; - if is_reserved(id) { - Err(nom::Err::Error(E::from_error_kind(i, ErrorKind::Satisfy))) - } else { - Ok((&i[idx..], Ident::from_str_unchecked(id))) - } - } else { - Err(nom::Err::Error(E::from_error_kind(i, ErrorKind::Satisfy))) - } - } else { - Err(nom::Err::Error(E::from_error_kind(i, ErrorKind::Eof))) - } -} - -named!(ascripted_arg(&str) -> Arg, do_parse!( - complete!(char!('(')) >> - multispace0 >> - ident: ident >> - multispace0 >> - complete!(char!(':')) >> - multispace0 >> - type_: type_ >> - multispace0 >> - complete!(char!(')')) >> - (Arg { - ident, - type_: Some(type_) - }) -)); - -named!(arg(&str) -> Arg, alt!( - ident => { |ident| Arg {ident, type_: None}} | - ascripted_arg -)); - -named!(extern_decl(&str) -> Decl, do_parse!( - complete!(tag!("extern")) - >> multispace1 - >> name: ident - >> multispace0 - >> char!(':') - >> multispace0 - >> type_: function_type - >> multispace0 - >> (Decl::Extern { - name, - type_ - }) -)); - -named!(fun_decl(&str) -> Decl, do_parse!( - complete!(tag!("fn")) - >> multispace1 - >> name: ident - >> multispace1 - >> args: separated_list0!(multispace1, arg) - >> multispace0 - >> char!('=') - >> multispace0 - >> body: expr - >> (Decl::Fun { - name, - body: Fun { - args, - body - } - }) -)); - -named!(ascription_decl(&str) -> Decl, do_parse!( - complete!(tag!("ty")) - >> multispace1 - >> name: ident - >> multispace0 - >> complete!(char!(':')) - >> multispace0 - >> type_: type_ - >> multispace0 - >> (Decl::Ascription { - name, - type_ - }) -)); - -named!(pub decl(&str) -> Decl, alt!( - ascription_decl | - fun_decl | - extern_decl -)); - -named!(pub toplevel(&str) -> Vec, do_parse!( - decls: many0!(decl) - >> multispace0 - >> eof!() - >> (decls))); - -#[cfg(test)] -mod tests { - use std::convert::TryInto; - - use crate::ast::{BinaryOperator, Expr, FunctionType, Literal, Type}; - - use super::*; - use expr::tests::ident_expr; - - #[test] - fn fn_decl() { - let res = test_parse!(decl, "fn id x = x"); - assert_eq!( - res, - Decl::Fun { - name: "id".try_into().unwrap(), - body: Fun { - args: vec!["x".try_into().unwrap()], - body: *ident_expr("x"), - } - } - ) - } - - #[test] - fn ascripted_fn_args() { - test_parse!(ascripted_arg, "(x : int)"); - let res = test_parse!(decl, "fn plus1 (x : int) = x + 1"); - assert_eq!( - res, - Decl::Fun { - name: "plus1".try_into().unwrap(), - body: Fun { - args: vec![Arg { - ident: "x".try_into().unwrap(), - type_: Some(Type::Int), - }], - body: Expr::BinaryOp { - lhs: ident_expr("x"), - op: BinaryOperator::Add, - rhs: Box::new(Expr::Literal(Literal::Int(1))), - } - } - } - ); - } - - #[test] - fn multiple_decls() { - let res = test_parse!( - toplevel, - "fn id x = x - fn plus x y = x + y - fn main = plus (id 2) 7" - ); - assert_eq!(res.len(), 3); - let res = test_parse!( - toplevel, - "fn id x = x\nfn plus x y = x + y\nfn main = plus (id 2) 7\n" - ); - assert_eq!(res.len(), 3); - } - - #[test] - fn top_level_ascription() { - let res = test_parse!(toplevel, "ty id : fn a -> a"); - assert_eq!( - res, - vec![Decl::Ascription { - name: "id".try_into().unwrap(), - type_: Type::Function(FunctionType { - args: vec![Type::Var("a".try_into().unwrap())], - ret: Box::new(Type::Var("a".try_into().unwrap())) - }) - }] - ) - } - - #[test] - fn return_unit() { - assert_eq!( - test_parse!(decl, "fn g _ = ()"), - Decl::Fun { - name: "g".try_into().unwrap(), - body: Fun { - args: vec![Arg { - ident: "_".try_into().unwrap(), - type_: None, - }], - body: Expr::Literal(Literal::Unit), - }, - } - ) - } -} diff --git a/users/aspen/achilles/src/parser/type_.rs b/users/aspen/achilles/src/parser/type_.rs deleted file mode 100644 index b80f0e086..000000000 --- a/users/aspen/achilles/src/parser/type_.rs +++ /dev/null @@ -1,152 +0,0 @@ -use nom::character::complete::{multispace0, multispace1}; -use nom::{alt, delimited, do_parse, map, named, opt, separated_list0, tag, terminated, tuple}; - -use super::ident; -use super::util::comma; -use crate::ast::{FunctionType, Type}; - -named!(pub function_type(&str) -> FunctionType, do_parse!( - tag!("fn") - >> multispace1 - >> args: map!(opt!(terminated!(separated_list0!( - comma, - type_ - ), multispace1)), |args| args.unwrap_or_default()) - >> tag!("->") - >> multispace1 - >> ret: type_ - >> (FunctionType { - args, - ret: Box::new(ret) - }) -)); - -named!(tuple_type(&str) -> Type, do_parse!( - tag!("(") - >> multispace0 - >> fst: type_ - >> comma - >> rest: separated_list0!( - comma, - type_ - ) - >> multispace0 - >> tag!(")") - >> ({ - let mut members = Vec::with_capacity(rest.len() + 1); - members.push(fst); - members.append(&mut rest.clone()); - Type::Tuple(members) - }) -)); - -named!(pub type_(&str) -> Type, alt!( - tag!("int") => { |_| Type::Int } | - tag!("float") => { |_| Type::Float } | - tag!("bool") => { |_| Type::Bool } | - tag!("cstring") => { |_| Type::CString } | - tag!("()") => { |_| Type::Unit } | - tuple_type | - function_type => { |ft| Type::Function(ft) }| - ident => { |id| Type::Var(id) } | - delimited!( - tuple!(tag!("("), multispace0), - type_, - tuple!(tag!(")"), multispace0) - ) -)); - -#[cfg(test)] -mod tests { - use std::convert::TryFrom; - - use super::*; - use crate::ast::Ident; - - #[test] - fn simple_types() { - assert_eq!(test_parse!(type_, "int"), Type::Int); - assert_eq!(test_parse!(type_, "float"), Type::Float); - assert_eq!(test_parse!(type_, "bool"), Type::Bool); - assert_eq!(test_parse!(type_, "cstring"), Type::CString); - assert_eq!(test_parse!(type_, "()"), Type::Unit); - } - - #[test] - fn no_arg_fn_type() { - assert_eq!( - test_parse!(type_, "fn -> int"), - Type::Function(FunctionType { - args: vec![], - ret: Box::new(Type::Int) - }) - ); - } - - #[test] - fn fn_type_with_args() { - assert_eq!( - test_parse!(type_, "fn int, bool -> int"), - Type::Function(FunctionType { - args: vec![Type::Int, Type::Bool], - ret: Box::new(Type::Int) - }) - ); - } - - #[test] - fn fn_taking_fn() { - assert_eq!( - test_parse!(type_, "fn fn int, bool -> bool, float -> float"), - Type::Function(FunctionType { - args: vec![ - Type::Function(FunctionType { - args: vec![Type::Int, Type::Bool], - ret: Box::new(Type::Bool) - }), - Type::Float - ], - ret: Box::new(Type::Float) - }) - ) - } - - #[test] - fn parenthesized() { - assert_eq!( - test_parse!(type_, "fn (fn int, bool -> bool), float -> float"), - Type::Function(FunctionType { - args: vec![ - Type::Function(FunctionType { - args: vec![Type::Int, Type::Bool], - ret: Box::new(Type::Bool) - }), - Type::Float - ], - ret: Box::new(Type::Float) - }) - ) - } - - #[test] - fn tuple() { - assert_eq!( - test_parse!(type_, "(int, int)"), - Type::Tuple(vec![Type::Int, Type::Int]) - ) - } - - #[test] - fn type_vars() { - assert_eq!( - test_parse!(type_, "fn x, y -> x"), - Type::Function(FunctionType { - args: vec![ - Type::Var(Ident::try_from("x").unwrap()), - Type::Var(Ident::try_from("y").unwrap()), - ], - ret: Box::new(Type::Var(Ident::try_from("x").unwrap())), - }) - ) - } -} diff --git a/users/aspen/achilles/src/parser/util.rs b/users/aspen/achilles/src/parser/util.rs deleted file mode 100644 index bb53fb7ff..000000000 --- a/users/aspen/achilles/src/parser/util.rs +++ /dev/null @@ -1,8 +0,0 @@ -use nom::character::complete::multispace0; -use nom::{complete, map, named, tag, tuple}; - -named!(pub(crate) comma(&str) -> (), map!(tuple!( - multispace0, - complete!(tag!(",")), - multispace0 -) ,|_| ())); diff --git a/users/aspen/achilles/src/passes/hir/mod.rs b/users/aspen/achilles/src/passes/hir/mod.rs deleted file mode 100644 index 872c449eb..000000000 --- a/users/aspen/achilles/src/passes/hir/mod.rs +++ /dev/null @@ -1,211 +0,0 @@ -use std::collections::HashMap; - -use crate::ast::hir::{Binding, Decl, Expr, Pattern}; -use crate::ast::{BinaryOperator, Ident, Literal, UnaryOperator}; - -pub(crate) mod monomorphize; -pub(crate) mod strip_positive_units; - -pub(crate) trait Visitor<'a, 'ast, T: 'ast>: Sized + 'a { - type Error; - - fn visit_type(&mut self, _type: &mut T) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_ident(&mut self, _ident: &mut Ident<'ast>) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_literal(&mut self, _literal: &mut Literal<'ast>) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_unary_operator(&mut self, _op: &mut UnaryOperator) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_binary_operator(&mut self, _op: &mut BinaryOperator) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_pattern(&mut self, _pat: &mut Pattern<'ast, T>) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_binding(&mut self, binding: &mut Binding<'ast, T>) -> Result<(), Self::Error> { - self.visit_pattern(&mut binding.pat)?; - self.visit_expr(&mut binding.body)?; - Ok(()) - } - - fn post_visit_call( - &mut self, - _fun: &mut Expr<'ast, T>, - _type_args: &mut HashMap, T>, - _args: &mut Vec>, - ) -> Result<(), Self::Error> { - Ok(()) - } - - fn pre_visit_call( - &mut self, - _fun: &mut Expr<'ast, T>, - _type_args: &mut HashMap, T>, - _args: &mut Vec>, - ) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_tuple(&mut self, members: &mut Vec>) -> Result<(), Self::Error> { - for expr in members { - self.visit_expr(expr)?; - } - Ok(()) - } - - fn pre_visit_expr(&mut self, _expr: &mut Expr<'ast, T>) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_expr(&mut self, expr: &mut Expr<'ast, T>) -> Result<(), Self::Error> { - self.pre_visit_expr(expr)?; - match expr { - Expr::Ident(id, t) => { - self.visit_ident(id)?; - self.visit_type(t)?; - } - Expr::Literal(lit, t) => { - self.visit_literal(lit)?; - self.visit_type(t)?; - } - Expr::UnaryOp { op, rhs, type_ } => { - self.visit_unary_operator(op)?; - self.visit_expr(rhs)?; - self.visit_type(type_)?; - } - Expr::BinaryOp { - lhs, - op, - rhs, - type_, - } => { - self.visit_expr(lhs)?; - self.visit_binary_operator(op)?; - self.visit_expr(rhs)?; - self.visit_type(type_)?; - } - Expr::Let { - bindings, - body, - type_, - } => { - for binding in bindings.iter_mut() { - self.visit_binding(binding)?; - } - self.visit_expr(body)?; - self.visit_type(type_)?; - } - Expr::If { - condition, - then, - else_, - type_, - } => { - self.visit_expr(condition)?; - self.visit_expr(then)?; - self.visit_expr(else_)?; - self.visit_type(type_)?; - } - Expr::Fun { - args, - body, - type_args, - type_, - } => { - for (ident, t) in args { - self.visit_ident(ident)?; - self.visit_type(t)?; - } - for ta in type_args { - self.visit_ident(ta)?; - } - self.visit_expr(body)?; - self.visit_type(type_)?; - } - Expr::Call { - fun, - args, - type_args, - type_, - } => { - self.pre_visit_call(fun, type_args, args)?; - self.visit_expr(fun)?; - for arg in args.iter_mut() { - self.visit_expr(arg)?; - } - self.visit_type(type_)?; - self.post_visit_call(fun, type_args, args)?; - } - Expr::Tuple(tup, type_) => { - self.visit_tuple(tup)?; - self.visit_type(type_)?; - } - } - - Ok(()) - } - - fn post_visit_decl(&mut self, _decl: &'a Decl<'ast, T>) -> Result<(), Self::Error> { - Ok(()) - } - - fn post_visit_fun_decl( - &mut self, - _name: &mut Ident<'ast>, - _type_args: &mut Vec, - _args: &mut Vec<(Ident, T)>, - _body: &mut Box>, - _type_: &mut T, - ) -> Result<(), Self::Error> { - Ok(()) - } - - fn visit_decl(&mut self, decl: &'a mut Decl<'ast, T>) -> Result<(), Self::Error> { - match decl { - Decl::Fun { - name, - type_args, - args, - body, - type_, - } => { - self.visit_ident(name)?; - for type_arg in type_args.iter_mut() { - self.visit_ident(type_arg)?; - } - for (arg, t) in args.iter_mut() { - self.visit_ident(arg)?; - self.visit_type(t)?; - } - self.visit_expr(body)?; - self.visit_type(type_)?; - self.post_visit_fun_decl(name, type_args, args, body, type_)?; - } - Decl::Extern { - name, - arg_types, - ret_type, - } => { - self.visit_ident(name)?; - for arg_t in arg_types { - self.visit_type(arg_t)?; - } - self.visit_type(ret_type)?; - } - } - - self.post_visit_decl(decl)?; - Ok(()) - } -} diff --git a/users/aspen/achilles/src/passes/hir/monomorphize.rs b/users/aspen/achilles/src/passes/hir/monomorphize.rs deleted file mode 100644 index 251a988f4..000000000 --- a/users/aspen/achilles/src/passes/hir/monomorphize.rs +++ /dev/null @@ -1,139 +0,0 @@ -use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; -use std::convert::TryInto; -use std::mem; - -use void::{ResultVoidExt, Void}; - -use crate::ast::hir::{Decl, Expr}; -use crate::ast::{self, Ident}; - -use super::Visitor; - -#[derive(Default)] -pub(crate) struct Monomorphize<'a, 'ast> { - decls: HashMap<&'a Ident<'ast>, &'a Decl<'ast, ast::Type<'ast>>>, - extra_decls: Vec>>, - remove_decls: HashSet>, -} - -impl<'a, 'ast> Monomorphize<'a, 'ast> { - pub(crate) fn new() -> Self { - Default::default() - } -} - -impl<'a, 'ast> Visitor<'a, 'ast, ast::Type<'ast>> for Monomorphize<'a, 'ast> { - type Error = Void; - - fn post_visit_call( - &mut self, - fun: &mut Expr<'ast, ast::Type<'ast>>, - type_args: &mut HashMap, ast::Type<'ast>>, - args: &mut Vec>>, - ) -> Result<(), Self::Error> { - let new_fun = match fun { - Expr::Ident(id, _) => { - let decl: Decl<_> = (**self.decls.get(id).unwrap()).clone(); - let name = RefCell::new(id.to_string()); - let type_args = mem::take(type_args); - let mut monomorphized = decl - .traverse_type(|ty| -> Result<_, Void> { - Ok(ty.clone().traverse_type_vars(|v| { - let concrete = type_args.get(&v).unwrap(); - name.borrow_mut().push_str(&concrete.to_string()); - concrete.clone() - })) - }) - .void_unwrap(); - let name: Ident = name.into_inner().try_into().unwrap(); - if name != *id { - self.remove_decls.insert(id.clone()); - monomorphized.set_name(name.clone()); - let type_ = monomorphized.type_().unwrap().clone(); - self.extra_decls.push(monomorphized); - Some(Expr::Ident(name, type_)) - } else { - None - } - } - _ => todo!(), - }; - if let Some(new_fun) = new_fun { - *fun = new_fun; - } - Ok(()) - } - - fn post_visit_decl( - &mut self, - decl: &'a Decl<'ast, ast::Type<'ast>>, - ) -> Result<(), Self::Error> { - self.decls.insert(decl.name(), decl); - Ok(()) - } -} - -pub(crate) fn run_toplevel<'a>(toplevel: &mut Vec>>) { - let mut pass = Monomorphize::new(); - for decl in toplevel.iter_mut() { - pass.visit_decl(decl).void_unwrap(); - } - let remove_decls = mem::take(&mut pass.remove_decls); - let mut extra_decls = mem::take(&mut pass.extra_decls); - toplevel.retain(|decl| !remove_decls.contains(decl.name())); - extra_decls.append(toplevel); - *toplevel = extra_decls; -} - -#[cfg(test)] -mod tests { - use std::convert::TryFrom; - - use super::*; - use crate::parser::toplevel; - use crate::tc::typecheck_toplevel; - - #[test] - fn call_id_decl() { - let (_, program) = toplevel( - "ty id : fn a -> a - fn id x = x - - ty main : fn -> int - fn main = id 0", - ) - .unwrap(); - let mut program = typecheck_toplevel(program).unwrap(); - run_toplevel(&mut program); - - let find_decl = |ident: &str| { - program.iter().find(|decl| { - matches!(decl, Decl::Fun {name, ..} if name == &Ident::try_from(ident).unwrap()) - }).unwrap() - }; - - let main = find_decl("main"); - let body = match main { - Decl::Fun { body, .. } => body, - _ => unreachable!(), - }; - - let expected_type = ast::Type::Function(ast::FunctionType { - args: vec![ast::Type::Int], - ret: Box::new(ast::Type::Int), - }); - - match &**body { - Expr::Call { fun, .. } => { - let fun = match &**fun { - Expr::Ident(fun, _) => fun, - _ => unreachable!(), - }; - let called_decl = find_decl(fun.into()); - assert_eq!(called_decl.type_().unwrap(), &expected_type); - } - _ => unreachable!(), - } - } -} diff --git a/users/aspen/achilles/src/passes/hir/strip_positive_units.rs b/users/aspen/achilles/src/passes/hir/strip_positive_units.rs deleted file mode 100644 index 85ee1cce4..000000000 --- a/users/aspen/achilles/src/passes/hir/strip_positive_units.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::collections::HashMap; -use std::mem; - -use ast::hir::{Binding, Pattern}; -use ast::Literal; -use void::{ResultVoidExt, Void}; - -use crate::ast::hir::{Decl, Expr}; -use crate::ast::{self, Ident}; - -use super::Visitor; - -/// Strip all values with a unit type in positive (non-return) position -pub(crate) struct StripPositiveUnits {} - -impl<'a, 'ast> Visitor<'a, 'ast, ast::Type<'ast>> for StripPositiveUnits { - type Error = Void; - - fn pre_visit_expr( - &mut self, - expr: &mut Expr<'ast, ast::Type<'ast>>, - ) -> Result<(), Self::Error> { - let mut extracted = vec![]; - if let Expr::Call { args, .. } = expr { - // TODO(grfn): replace with drain_filter once it's stabilized - let mut i = 0; - while i != args.len() { - if args[i].type_() == &ast::Type::Unit { - let expr = args.remove(i); - if !matches!(expr, Expr::Literal(Literal::Unit, _)) { - extracted.push(expr) - }; - } else { - i += 1 - } - } - } - - if !extracted.is_empty() { - let body = mem::replace(expr, Expr::Literal(Literal::Unit, ast::Type::Unit)); - *expr = Expr::Let { - bindings: extracted - .into_iter() - .map(|expr| Binding { - pat: Pattern::Id( - Ident::from_str_unchecked("___discarded"), - expr.type_().clone(), - ), - body: expr, - }) - .collect(), - type_: body.type_().clone(), - body: Box::new(body), - }; - } - - Ok(()) - } - - fn post_visit_call( - &mut self, - _fun: &mut Expr<'ast, ast::Type<'ast>>, - _type_args: &mut HashMap, ast::Type<'ast>>, - args: &mut Vec>>, - ) -> Result<(), Self::Error> { - args.retain(|arg| arg.type_() != &ast::Type::Unit); - Ok(()) - } - - fn visit_type(&mut self, type_: &mut ast::Type<'ast>) -> Result<(), Self::Error> { - if let ast::Type::Function(ft) = type_ { - ft.args.retain(|a| a != &ast::Type::Unit); - } - Ok(()) - } - - fn post_visit_fun_decl( - &mut self, - _name: &mut Ident<'ast>, - _type_args: &mut Vec, - args: &mut Vec<(Ident, ast::Type<'ast>)>, - _body: &mut Box>>, - _type_: &mut ast::Type<'ast>, - ) -> Result<(), Self::Error> { - args.retain(|(_, ty)| ty != &ast::Type::Unit); - Ok(()) - } -} - -pub(crate) fn run_toplevel<'a>(toplevel: &mut Vec>>) { - let mut pass = StripPositiveUnits {}; - for decl in toplevel.iter_mut() { - pass.visit_decl(decl).void_unwrap(); - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::parser::toplevel; - use crate::tc::typecheck_toplevel; - use pretty_assertions::assert_eq; - - #[test] - fn unit_only_arg() { - let (_, program) = toplevel( - "ty f : fn () -> int - fn f _ = 1 - - ty main : fn -> int - fn main = f ()", - ) - .unwrap(); - - let (_, expected) = toplevel( - "ty f : fn -> int - fn f = 1 - - ty main : fn -> int - fn main = f()", - ) - .unwrap(); - let expected = typecheck_toplevel(expected).unwrap(); - - let mut program = typecheck_toplevel(program).unwrap(); - run_toplevel(&mut program); - - assert_eq!(program, expected); - } - - #[test] - fn unit_and_other_arg() { - let (_, program) = toplevel( - "ty f : fn (), int -> int - fn f _ x = x - - ty main : fn -> int - fn main = f () 1", - ) - .unwrap(); - - let (_, expected) = toplevel( - "ty f : fn int -> int - fn f x = x - - ty main : fn -> int - fn main = f 1", - ) - .unwrap(); - let expected = typecheck_toplevel(expected).unwrap(); - - let mut program = typecheck_toplevel(program).unwrap(); - run_toplevel(&mut program); - - assert_eq!(program, expected); - } - - #[test] - fn unit_expr_and_other_arg() { - let (_, program) = toplevel( - "ty f : fn (), int -> int - fn f _ x = x - - ty g : fn int -> () - fn g _ = () - - ty main : fn -> int - fn main = f (g 2) 1", - ) - .unwrap(); - - let (_, expected) = toplevel( - "ty f : fn int -> int - fn f x = x - - ty g : fn int -> () - fn g _ = () - - ty main : fn -> int - fn main = let ___discarded = g 2 in f 1", - ) - .unwrap(); - assert_eq!(expected.len(), 6); - let expected = typecheck_toplevel(expected).unwrap(); - - let mut program = typecheck_toplevel(program).unwrap(); - run_toplevel(&mut program); - - assert_eq!(program, expected); - } -} diff --git a/users/aspen/achilles/src/passes/mod.rs b/users/aspen/achilles/src/passes/mod.rs deleted file mode 100644 index 306869bef..000000000 --- a/users/aspen/achilles/src/passes/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub(crate) mod hir; diff --git a/users/aspen/achilles/src/tc/mod.rs b/users/aspen/achilles/src/tc/mod.rs deleted file mode 100644 index 5825bab1f..000000000 --- a/users/aspen/achilles/src/tc/mod.rs +++ /dev/null @@ -1,808 +0,0 @@ -use bimap::BiMap; -use derive_more::From; -use itertools::Itertools; -use std::cell::RefCell; -use std::collections::HashMap; -use std::convert::{TryFrom, TryInto}; -use std::fmt::{self, Display}; -use std::{mem, result}; -use thiserror::Error; - -use crate::ast::{self, hir, Arg, BinaryOperator, Ident, Literal, Pattern}; -use crate::common::env::Env; -use crate::common::{Namer, NamerOf}; - -#[derive(Debug, Error)] -pub enum Error { - #[error("Undefined variable {0}")] - UndefinedVariable(Ident<'static>), - - #[error("Mismatched types: expected {expected}, but got {actual}")] - TypeMismatch { expected: Type, actual: Type }, - - #[error("Mismatched types, expected numeric type, but got {0}")] - NonNumeric(Type), - - #[error("Ambiguous type {0}")] - AmbiguousType(TyVar), -} - -pub type Result = result::Result; - -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub struct TyVar(u64); - -impl Display for TyVar { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "t{}", self.0) - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Hash)] -pub struct NullaryType(String); - -impl Display for NullaryType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str(&self.0) - } -} - -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum PrimType { - Int, - Float, - Bool, - CString, -} - -impl<'a> From for ast::Type<'a> { - fn from(pr: PrimType) -> Self { - match pr { - PrimType::Int => ast::Type::Int, - PrimType::Float => ast::Type::Float, - PrimType::Bool => ast::Type::Bool, - PrimType::CString => ast::Type::CString, - } - } -} - -impl Display for PrimType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - PrimType::Int => f.write_str("int"), - PrimType::Float => f.write_str("float"), - PrimType::Bool => f.write_str("bool"), - PrimType::CString => f.write_str("cstring"), - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone, From)] -pub enum Type { - #[from(ignore)] - Univ(TyVar), - #[from(ignore)] - Exist(TyVar), - Nullary(NullaryType), - Prim(PrimType), - Tuple(Vec), - Unit, - Fun { - args: Vec, - ret: Box, - }, -} - -impl<'a> TryFrom for ast::Type<'a> { - type Error = Type; - - fn try_from(value: Type) -> result::Result { - match value { - Type::Unit => Ok(ast::Type::Unit), - Type::Univ(_) => todo!(), - Type::Exist(_) => Err(value), - Type::Nullary(_) => todo!(), - Type::Prim(p) => Ok(p.into()), - Type::Tuple(members) => Ok(ast::Type::Tuple( - members.into_iter().map(|ty| ty.try_into()).try_collect()?, - )), - Type::Fun { ref args, ref ret } => Ok(ast::Type::Function(ast::FunctionType { - args: args - .clone() - .into_iter() - .map(Self::try_from) - .try_collect() - .map_err(|_| value.clone())?, - ret: Box::new((*ret.clone()).try_into().map_err(|_| value.clone())?), - })), - } - } -} - -const INT: Type = Type::Prim(PrimType::Int); -const FLOAT: Type = Type::Prim(PrimType::Float); -const BOOL: Type = Type::Prim(PrimType::Bool); -const CSTRING: Type = Type::Prim(PrimType::CString); - -impl Display for Type { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Type::Nullary(nt) => nt.fmt(f), - Type::Prim(p) => p.fmt(f), - Type::Univ(TyVar(n)) => write!(f, "∀{}", n), - Type::Exist(TyVar(n)) => write!(f, "∃{}", n), - Type::Fun { args, ret } => write!(f, "fn {} -> {}", args.iter().join(", "), ret), - Type::Tuple(members) => write!(f, "({})", members.iter().join(", ")), - Type::Unit => write!(f, "()"), - } - } -} - -struct Typechecker<'ast> { - ty_var_namer: NamerOf, - ctx: HashMap, - env: Env, Type>, - - /// AST type var -> type - instantiations: Env, Type>, - - /// AST type-var -> universal TyVar - type_vars: RefCell<(BiMap, TyVar>, NamerOf>)>, -} - -impl<'ast> Typechecker<'ast> { - fn new() -> Self { - Self { - ty_var_namer: Namer::new(TyVar).boxed(), - type_vars: RefCell::new(( - Default::default(), - Namer::alphabetic().map(|n| Ident::try_from(n).unwrap()), - )), - ctx: Default::default(), - env: Default::default(), - instantiations: Default::default(), - } - } - - fn bind_pattern( - &mut self, - pat: Pattern<'ast>, - type_: Type, - ) -> Result> { - match pat { - Pattern::Id(ident) => { - self.env.set(ident.clone(), type_.clone()); - Ok(hir::Pattern::Id(ident, type_)) - } - Pattern::Tuple(members) => { - let mut tys = Vec::with_capacity(members.len()); - let mut hir_members = Vec::with_capacity(members.len()); - for pat in members { - let ty = self.fresh_ex(); - hir_members.push(self.bind_pattern(pat, ty.clone())?); - tys.push(ty); - } - let tuple_type = Type::Tuple(tys); - self.unify(&tuple_type, &type_)?; - Ok(hir::Pattern::Tuple(hir_members)) - } - } - } - - pub(crate) fn tc_expr(&mut self, expr: ast::Expr<'ast>) -> Result> { - match expr { - ast::Expr::Ident(ident) => { - let type_ = self - .env - .resolve(&ident) - .ok_or_else(|| Error::UndefinedVariable(ident.to_owned()))? - .clone(); - Ok(hir::Expr::Ident(ident, type_)) - } - ast::Expr::Literal(lit) => { - let type_ = match lit { - Literal::Int(_) => Type::Prim(PrimType::Int), - Literal::Bool(_) => Type::Prim(PrimType::Bool), - Literal::String(_) => Type::Prim(PrimType::CString), - Literal::Unit => Type::Unit, - }; - Ok(hir::Expr::Literal(lit.to_owned(), type_)) - } - ast::Expr::Tuple(members) => { - let members = members - .into_iter() - .map(|expr| self.tc_expr(expr)) - .collect::>>()?; - let type_ = Type::Tuple(members.iter().map(|expr| expr.type_().clone()).collect()); - Ok(hir::Expr::Tuple(members, type_)) - } - ast::Expr::UnaryOp { op, rhs } => todo!(), - ast::Expr::BinaryOp { lhs, op, rhs } => { - let lhs = self.tc_expr(*lhs)?; - let rhs = self.tc_expr(*rhs)?; - let type_ = match op { - BinaryOperator::Equ | BinaryOperator::Neq => { - self.unify(lhs.type_(), rhs.type_())?; - Type::Prim(PrimType::Bool) - } - BinaryOperator::Add | BinaryOperator::Sub | BinaryOperator::Mul => { - let ty = self.unify(lhs.type_(), rhs.type_())?; - // if !matches!(ty, Type::Int | Type::Float) { - // return Err(Error::NonNumeric(ty)); - // } - ty - } - BinaryOperator::Div => todo!(), - BinaryOperator::Pow => todo!(), - }; - Ok(hir::Expr::BinaryOp { - lhs: Box::new(lhs), - op, - rhs: Box::new(rhs), - type_, - }) - } - ast::Expr::Let { bindings, body } => { - self.env.push(); - let bindings = bindings - .into_iter() - .map( - |ast::Binding { pat, type_, body }| -> Result> { - let body = self.tc_expr(body)?; - if let Some(type_) = type_ { - let type_ = self.type_from_ast_type(type_); - self.unify(body.type_(), &type_)?; - } - let pat = self.bind_pattern(pat, body.type_().clone())?; - Ok(hir::Binding { pat, body }) - }, - ) - .collect::>>>()?; - let body = self.tc_expr(*body)?; - self.env.pop(); - Ok(hir::Expr::Let { - bindings, - type_: body.type_().clone(), - body: Box::new(body), - }) - } - ast::Expr::If { - condition, - then, - else_, - } => { - let condition = self.tc_expr(*condition)?; - self.unify(&Type::Prim(PrimType::Bool), condition.type_())?; - let then = self.tc_expr(*then)?; - let else_ = self.tc_expr(*else_)?; - let type_ = self.unify(then.type_(), else_.type_())?; - Ok(hir::Expr::If { - condition: Box::new(condition), - then: Box::new(then), - else_: Box::new(else_), - type_, - }) - } - ast::Expr::Fun(f) => { - let ast::Fun { args, body } = *f; - self.env.push(); - let args: Vec<_> = args - .into_iter() - .map(|Arg { ident, type_ }| { - let ty = match type_ { - Some(t) => self.type_from_ast_type(t), - None => self.fresh_ex(), - }; - self.env.set(ident.clone(), ty.clone()); - (ident, ty) - }) - .collect(); - let body = self.tc_expr(body)?; - self.env.pop(); - Ok(hir::Expr::Fun { - type_: Type::Fun { - args: args.iter().map(|(_, ty)| ty.clone()).collect(), - ret: Box::new(body.type_().clone()), - }, - type_args: vec![], // TODO fill in once we do let generalization - args, - body: Box::new(body), - }) - } - ast::Expr::Call { fun, args } => { - let ret_ty = self.fresh_ex(); - let arg_tys = args.iter().map(|_| self.fresh_ex()).collect::>(); - let ft = Type::Fun { - args: arg_tys.clone(), - ret: Box::new(ret_ty.clone()), - }; - let fun = self.tc_expr(*fun)?; - self.instantiations.push(); - self.unify(&ft, fun.type_())?; - let args = args - .into_iter() - .zip(arg_tys) - .map(|(arg, ty)| { - let arg = self.tc_expr(arg)?; - self.unify(&ty, arg.type_())?; - Ok(arg) - }) - .try_collect()?; - let type_args = self.commit_instantiations(); - Ok(hir::Expr::Call { - fun: Box::new(fun), - type_args, - args, - type_: ret_ty, - }) - } - ast::Expr::Ascription { expr, type_ } => { - let expr = self.tc_expr(*expr)?; - let type_ = self.type_from_ast_type(type_); - self.unify(expr.type_(), &type_)?; - Ok(expr) - } - } - } - - pub(crate) fn tc_decl( - &mut self, - decl: ast::Decl<'ast>, - ) -> Result>> { - match decl { - ast::Decl::Fun { name, body } => { - let mut expr = ast::Expr::Fun(Box::new(body)); - if let Some(type_) = self.env.resolve(&name) { - expr = ast::Expr::Ascription { - expr: Box::new(expr), - type_: self.finalize_type(type_.clone())?, - }; - } - - self.env.push(); - let body = self.tc_expr(expr)?; - let type_ = body.type_().clone(); - self.env.set(name.clone(), type_); - self.env.pop(); - match body { - hir::Expr::Fun { - type_args, - args, - body, - type_, - } => Ok(Some(hir::Decl::Fun { - name, - type_args, - args, - body, - type_, - })), - _ => unreachable!(), - } - } - ast::Decl::Ascription { name, type_ } => { - let type_ = self.type_from_ast_type(type_); - self.env.set(name.clone(), type_); - Ok(None) - } - ast::Decl::Extern { name, type_ } => { - let type_ = self.type_from_ast_type(ast::Type::Function(type_)); - self.env.set(name.clone(), type_.clone()); - let (arg_types, ret_type) = match type_ { - Type::Fun { args, ret } => (args, *ret), - _ => unreachable!(), - }; - Ok(Some(hir::Decl::Extern { - name, - arg_types, - ret_type, - })) - } - } - } - - fn fresh_tv(&mut self) -> TyVar { - self.ty_var_namer.make_name() - } - - fn fresh_ex(&mut self) -> Type { - Type::Exist(self.fresh_tv()) - } - - fn fresh_univ(&mut self) -> Type { - Type::Univ(self.fresh_tv()) - } - - fn unify(&mut self, ty1: &Type, ty2: &Type) -> Result { - match (ty1, ty2) { - (Type::Unit, Type::Unit) => Ok(Type::Unit), - (Type::Exist(tv), ty) | (ty, Type::Exist(tv)) => match self.resolve_tv(*tv)? { - Some(existing_ty) if self.types_match(ty, &existing_ty) => Ok(ty.clone()), - Some(var @ ast::Type::Var(_)) => { - let var = self.type_from_ast_type(var); - self.unify(&var, ty) - } - Some(existing_ty) => match ty { - Type::Exist(_) => { - let rhs = self.type_from_ast_type(existing_ty); - self.unify(ty, &rhs) - } - _ => Err(Error::TypeMismatch { - expected: ty.clone(), - actual: self.type_from_ast_type(existing_ty), - }), - }, - None => match self.ctx.insert(*tv, ty.clone()) { - Some(existing) => self.unify(&existing, ty), - None => Ok(ty.clone()), - }, - }, - (Type::Univ(u1), Type::Univ(u2)) if u1 == u2 => Ok(ty2.clone()), - (Type::Univ(u), ty) | (ty, Type::Univ(u)) => { - let ident = self.name_univ(*u); - match self.instantiations.resolve(&ident) { - Some(existing_ty) if ty == existing_ty => Ok(ty.clone()), - Some(existing_ty) => Err(Error::TypeMismatch { - expected: ty.clone(), - actual: existing_ty.clone(), - }), - None => { - self.instantiations.set(ident, ty.clone()); - Ok(ty.clone()) - } - } - } - (Type::Prim(p1), Type::Prim(p2)) if p1 == p2 => Ok(ty2.clone()), - (Type::Tuple(t1), Type::Tuple(t2)) if t1.len() == t2.len() => { - let ts = t1 - .iter() - .zip(t2.iter()) - .map(|(t1, t2)| self.unify(t1, t2)) - .try_collect()?; - Ok(Type::Tuple(ts)) - } - ( - Type::Fun { - args: args1, - ret: ret1, - }, - Type::Fun { - args: args2, - ret: ret2, - }, - ) => { - let args = args1 - .iter() - .zip(args2) - .map(|(t1, t2)| self.unify(t1, t2)) - .try_collect()?; - let ret = self.unify(ret1, ret2)?; - Ok(Type::Fun { - args, - ret: Box::new(ret), - }) - } - (Type::Nullary(_), _) | (_, Type::Nullary(_)) => todo!(), - _ => Err(Error::TypeMismatch { - expected: ty1.clone(), - actual: ty2.clone(), - }), - } - } - - fn finalize_expr( - &self, - expr: hir::Expr<'ast, Type>, - ) -> Result>> { - expr.traverse_type(|ty| self.finalize_type(ty)) - } - - fn finalize_decl( - &mut self, - decl: hir::Decl<'ast, Type>, - ) -> Result>> { - let res = decl.traverse_type(|ty| self.finalize_type(ty))?; - if let Some(type_) = res.type_() { - let ty = self.type_from_ast_type(type_.clone()); - self.env.set(res.name().clone(), ty); - } - Ok(res) - } - - fn finalize_type(&self, ty: Type) -> Result> { - let ret = match ty { - Type::Exist(tv) => self.resolve_tv(tv)?.ok_or(Error::AmbiguousType(tv)), - Type::Univ(tv) => Ok(ast::Type::Var(self.name_univ(tv))), - Type::Unit => Ok(ast::Type::Unit), - Type::Nullary(_) => todo!(), - Type::Prim(pr) => Ok(pr.into()), - Type::Tuple(members) => Ok(ast::Type::Tuple( - members - .into_iter() - .map(|ty| self.finalize_type(ty)) - .try_collect()?, - )), - Type::Fun { args, ret } => Ok(ast::Type::Function(ast::FunctionType { - args: args - .into_iter() - .map(|ty| self.finalize_type(ty)) - .try_collect()?, - ret: Box::new(self.finalize_type(*ret)?), - })), - }; - ret - } - - fn resolve_tv(&self, tv: TyVar) -> Result>> { - let mut res = &Type::Exist(tv); - Ok(loop { - match res { - Type::Exist(tv) => { - res = match self.ctx.get(tv) { - Some(r) => r, - None => return Ok(None), - }; - } - Type::Univ(tv) => { - let ident = self.name_univ(*tv); - if let Some(r) = self.instantiations.resolve(&ident) { - res = r; - } else { - break Some(ast::Type::Var(ident)); - } - } - Type::Nullary(_) => todo!(), - Type::Prim(pr) => break Some((*pr).into()), - Type::Unit => break Some(ast::Type::Unit), - Type::Fun { args, ret } => todo!(), - Type::Tuple(_) => break Some(self.finalize_type(res.clone())?), - } - }) - } - - fn type_from_ast_type(&mut self, ast_type: ast::Type<'ast>) -> Type { - match ast_type { - ast::Type::Unit => Type::Unit, - ast::Type::Int => INT, - ast::Type::Float => FLOAT, - ast::Type::Bool => BOOL, - ast::Type::CString => CSTRING, - ast::Type::Tuple(members) => Type::Tuple( - members - .into_iter() - .map(|ty| self.type_from_ast_type(ty)) - .collect(), - ), - ast::Type::Function(ast::FunctionType { args, ret }) => Type::Fun { - args: args - .into_iter() - .map(|t| self.type_from_ast_type(t)) - .collect(), - ret: Box::new(self.type_from_ast_type(*ret)), - }, - ast::Type::Var(id) => Type::Univ({ - let opt_tv = { self.type_vars.borrow_mut().0.get_by_left(&id).copied() }; - opt_tv.unwrap_or_else(|| { - let tv = self.fresh_tv(); - self.type_vars - .borrow_mut() - .0 - .insert_no_overwrite(id, tv) - .unwrap(); - tv - }) - }), - } - } - - fn name_univ(&self, tv: TyVar) -> Ident<'static> { - let mut vars = self.type_vars.borrow_mut(); - vars.0 - .get_by_right(&tv) - .map(Ident::to_owned) - .unwrap_or_else(|| { - let name = loop { - let name = vars.1.make_name(); - if !vars.0.contains_left(&name) { - break name; - } - }; - vars.0.insert_no_overwrite(name.clone(), tv).unwrap(); - name - }) - } - - fn commit_instantiations(&mut self) -> HashMap, Type> { - let mut res = HashMap::new(); - let mut ctx = mem::take(&mut self.ctx); - for (_, v) in ctx.iter_mut() { - if let Type::Univ(tv) = v { - let tv_name = self.name_univ(*tv); - if let Some(concrete) = self.instantiations.resolve(&tv_name) { - res.insert(tv_name, concrete.clone()); - *v = concrete.clone(); - } - } - } - self.ctx = ctx; - self.instantiations.pop(); - res - } - - fn types_match(&self, type_: &Type, ast_type: &ast::Type<'ast>) -> bool { - match (type_, ast_type) { - (Type::Univ(u), ast::Type::Var(v)) => { - Some(u) == self.type_vars.borrow().0.get_by_left(v) - } - (Type::Univ(_), _) => false, - (Type::Exist(_), _) => false, - (Type::Unit, ast::Type::Unit) => true, - (Type::Unit, _) => false, - (Type::Nullary(_), _) => todo!(), - (Type::Prim(pr), ty) => ast::Type::from(*pr) == *ty, - (Type::Tuple(members), ast::Type::Tuple(members2)) => members - .iter() - .zip(members2.iter()) - .all(|(t1, t2)| self.types_match(t1, t2)), - (Type::Tuple(members), _) => false, - (Type::Fun { args, ret }, ast::Type::Function(ft)) => { - args.len() == ft.args.len() - && args - .iter() - .zip(&ft.args) - .all(|(a1, a2)| self.types_match(a1, &a2)) - && self.types_match(&*ret, &*ft.ret) - } - (Type::Fun { .. }, _) => false, - } - } -} - -pub fn typecheck_expr(expr: ast::Expr) -> Result> { - let mut typechecker = Typechecker::new(); - let typechecked = typechecker.tc_expr(expr)?; - typechecker.finalize_expr(typechecked) -} - -pub fn typecheck_toplevel(decls: Vec) -> Result>> { - let mut typechecker = Typechecker::new(); - let mut res = Vec::with_capacity(decls.len()); - for decl in decls { - if let Some(hir_decl) = typechecker.tc_decl(decl)? { - let hir_decl = typechecker.finalize_decl(hir_decl)?; - res.push(hir_decl); - } - typechecker.ctx.clear(); - } - Ok(res) -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! assert_type { - ($expr: expr, $type: expr) => { - use crate::parser::{expr, type_}; - let parsed_expr = test_parse!(expr, $expr); - let parsed_type = test_parse!(type_, $type); - let res = typecheck_expr(parsed_expr).unwrap_or_else(|e| panic!("{}", e)); - assert!( - res.type_().alpha_equiv(&parsed_type), - "{} inferred type {}, but expected {}", - $expr, - res.type_(), - $type - ); - }; - - (toplevel($program: expr), $($decl: ident => $type: expr),+ $(,)?) => {{ - use crate::parser::{toplevel, type_}; - let program = test_parse!(toplevel, $program); - let res = typecheck_toplevel(program).unwrap_or_else(|e| panic!("{}", e)); - $( - let parsed_type = test_parse!(type_, $type); - let ident = Ident::try_from(::std::stringify!($decl)).unwrap(); - let decl = res.iter().find(|decl| { - matches!(decl, crate::ast::hir::Decl::Fun { name, .. } if name == &ident) - }).unwrap_or_else(|| panic!("Could not find declaration for {}", ident)); - assert!( - decl.type_().unwrap().alpha_equiv(&parsed_type), - "inferred type {} for {}, but expected {}", - decl.type_().unwrap(), - ident, - $type - ); - )+ - }}; - } - - macro_rules! assert_type_error { - ($expr: expr) => { - use crate::parser::expr; - let parsed_expr = test_parse!(expr, $expr); - let res = typecheck_expr(parsed_expr); - assert!( - res.is_err(), - "Expected type error, but got type: {}", - res.unwrap().type_() - ); - }; - } - - #[test] - fn literal_int() { - assert_type!("1", "int"); - } - - #[test] - fn conditional() { - assert_type!("if 1 == 2 then 3 else 4", "int"); - } - - #[test] - #[ignore] - fn add_bools() { - assert_type_error!("true + false"); - } - - #[test] - fn call_generic_function() { - assert_type!("(fn x = x) 1", "int"); - } - - #[test] - fn call_let_bound_generic() { - assert_type!("let id = fn x = x in id 1", "int"); - } - - #[test] - fn universal_ascripted_let() { - assert_type!("let id: fn a -> a = fn x = x in id 1", "int"); - } - - #[test] - fn call_generic_function_toplevel() { - assert_type!( - toplevel( - "ty id : fn a -> a - fn id x = x - - fn main = id 0" - ), - main => "fn -> int", - id => "fn a -> a", - ); - } - - #[test] - #[ignore] - fn let_generalization() { - assert_type!("let id = fn x = x in if id true then id 1 else 2", "int"); - } - - #[test] - fn concrete_function() { - assert_type!("fn x = x + 1", "fn int -> int"); - } - - #[test] - fn arg_ascriptions() { - assert_type!("fn (x: int) = x", "fn int -> int"); - } - - #[test] - fn call_concrete_function() { - assert_type!("(fn x = x + 1) 2", "int"); - } - - #[test] - fn conditional_non_bool() { - assert_type_error!("if 3 then true else false"); - } - - #[test] - fn let_int() { - assert_type!("let x = 1 in x", "int"); - } -} diff --git a/users/aspen/achilles/tests/compile.rs b/users/aspen/achilles/tests/compile.rs deleted file mode 100644 index 0f1086bfd..000000000 --- a/users/aspen/achilles/tests/compile.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::process::Command; - -use crate_root::root; - -struct Fixture { - name: &'static str, - exit_code: i32, - expected_output: &'static str, -} - -const FIXTURES: &[Fixture] = &[ - Fixture { - name: "simple", - exit_code: 5, - expected_output: "", - }, - Fixture { - name: "functions", - exit_code: 9, - expected_output: "", - }, - Fixture { - name: "externs", - exit_code: 0, - expected_output: "foobar\n", - }, - Fixture { - name: "units", - exit_code: 0, - expected_output: "hi\n", - }, -]; - -#[test] -fn compile_and_run_files() { - let ach = root().unwrap().join("ach"); - - println!("Running: `make clean`"); - assert!( - Command::new("make") - .arg("clean") - .current_dir(&ach) - .spawn() - .unwrap() - .wait() - .unwrap() - .success(), - "make clean failed" - ); - - for Fixture { - name, - exit_code, - expected_output, - } in FIXTURES - { - println!(">>> Testing: {}", name); - - println!(" Running: `make {}`", name); - assert!( - Command::new("make") - .arg(name) - .current_dir(&ach) - .spawn() - .unwrap() - .wait() - .unwrap() - .success(), - "make failed" - ); - - let out_path = ach.join(name); - println!(" Running: `{}`", out_path.to_str().unwrap()); - let output = Command::new(out_path).output().unwrap(); - assert_eq!(output.status.code().unwrap(), *exit_code,); - assert_eq!(output.stdout, expected_output.as_bytes()); - println!(" OK"); - } -} diff --git a/users/aspen/bbbg/.clj-kondo/config.edn b/users/aspen/bbbg/.clj-kondo/config.edn deleted file mode 100644 index 8faddb77e..000000000 --- a/users/aspen/bbbg/.clj-kondo/config.edn +++ /dev/null @@ -1 +0,0 @@ -{:lint-as {garden.def/defstyles clojure.core/def}} diff --git a/users/aspen/bbbg/.envrc b/users/aspen/bbbg/.envrc deleted file mode 100644 index 051d09d29..000000000 --- a/users/aspen/bbbg/.envrc +++ /dev/null @@ -1 +0,0 @@ -eval "$(lorri direnv)" diff --git a/users/aspen/bbbg/.gitignore b/users/aspen/bbbg/.gitignore deleted file mode 100644 index 99dbfc443..000000000 --- a/users/aspen/bbbg/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -/target -/classes -*.jar -*.class -/.nrepl-port -/.cpcache -/.clojure -/result -/.clj-kondo/.cache diff --git a/users/aspen/bbbg/Makefile b/users/aspen/bbbg/Makefile deleted file mode 100644 index fc4547798..000000000 --- a/users/aspen/bbbg/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -deps.nix: deps.edn - clj2nix ./deps.edn ./deps.nix '-A:uberjar' '-A:clj-test' diff --git a/users/aspen/bbbg/README.md b/users/aspen/bbbg/README.md deleted file mode 100644 index 41f59319c..000000000 --- a/users/aspen/bbbg/README.md +++ /dev/null @@ -1,129 +0,0 @@ -# Brooklyn-Based Board Gaming signup sheet - -This directory contains a small web application that acts as a signup -sheet and attendee tracking system for [my local board gaming -meetup](https://www.meetup.com/brooklyn-based-board-gaming/). - -## Development - -### Installing dependencies - -#### With Nix + Docker ("blessed way") - -Prerequisites: - -- [Nix](https://nixos.org/) -- [lorri](https://github.com/nix-community/lorri) -- [Docker](https://www.docker.com/) - -From this directory in a full checkout of depot, run the following -commands to install all development dependencies: - -``` shell-session -$ pwd -/path/to/depot/users/aspen/bbbg -$ direnv allow -$ lorri watch --once # Wait for a single nix shell build -``` - -Then, to run a docker container with the development database: - -``` shell-session -$ pwd -/path/to/depot/users/aspen/bbbg -$ arion up -d -``` - -#### Choose-your-own-adventure - -Note that the **authoritative** source for dev dependencies is the `shell.nix` -file in this directory - those may diverge from what's written here; if so -follow those versions rather than these. - -- Install the [clojure command-line - tools](https://clojure.org/guides/getting_started), with openjdk 11 -- Install and run a postgresql 12 database, with: - - A user with superuser priveleges, the username `bbbg` and the - password `password` - - A database called `bbbg` owned by that user. -- Export the following environment variables in a context visible by - whatever method you use to run the application: - - `PGHOST=localhost` - - `PGUSER=bbbg` - - `PGDATABASE=bbbg` - - `PGPASSWORD=bbbg` - -### Running the application - -Before running the app, you'll need an oauth2 client-id and client secret for a -Discord app. The application can either load those from a -[pass](https://www.passwordstore.org/) password store, or read them from -plaintext files in a directory. In either case, they should be accessible at the -paths `bbbg/discord-client-id` and `bbbg/discord-client-secret` respectively. - -#### From the command line - -``` shell-session -$ clj -A:dev -Clojure 1.11.0-alpha3 -user=> (require 'bbbg.core) -nil -user=> ;; Optionally, if you're using a directory with plaintext files for the discord client ID and client secret: -user=> (bbbg.util.dev-secrets/set-backend! [:dir "/path/to/that/directory"]) -user=> (bbbg.core/run-dev) -## -user=> (bbbg.db/migrate! (:db bbbg.core/system)) -11:57:26.536 [main] INFO migratus.core - Starting migrations { } -11:57:26.538 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... { } -11:57:26.883 [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.impossibl.postgres.jdbc.PGDirectConnection@3cae770e { } -11:57:26.884 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. { } -11:57:26.923 [main] INFO migratus.core - Ending migrations { } -nil -``` - -This will run a web server for the application listening at - - -#### In Emacs, with [CIDER](https://docs.cider.mx/cider/index.html) + [direnv](https://github.com/wbolster/emacs-direnv) - -Open `//users/aspen/bbbg/src/bbbg/core.clj` in a buffer, then follow the -instructions at the end of the file - -## Deployment - -### With nix+terraform - -Deployment configuration is located in the `tf.nix` file, which is -currently tightly coupled to my own infrastructure and AWS account but -could hypothetically be adjusted to be general-purpose. - -To deploy a new version of the application, after following "installing -dependencies" above, run the following command in a context with ec2 -credentials available: - -``` shell-session -$ terraform apply -``` - -The current deploy configuration includes: - -- An ec2 instance running nixos, with a postgresql database and the - bbbg application running as a service, behind nginx with an - auto-renewing letsencrypt cert -- The DNS A record for `bbbg.gws.fyi` pointing at that ec2 instance, - in the cloudflare zone for `gws.fyi` - -### Otherwise - -¯\\\_(ツ)_/¯ - -You'll need: - -- An uberjar for bbbg; the canonical way of building that is `nix-build - /path/to/depot -A users.aspen.bbbg.server-jar` but I\'m not sure how that - works outside of nix -- A postgresql database -- Environment variables telling the app how to connect to that - database. See `config.systemd.services.bbbg-server.environment` in - `module.nix` for which env vars are currently being exported by the - NixOS module that runs the production version of the app diff --git a/users/aspen/bbbg/arion-compose.nix b/users/aspen/bbbg/arion-compose.nix deleted file mode 100644 index c8a6dd156..000000000 --- a/users/aspen/bbbg/arion-compose.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ ... }: - -{ - services = { - postgres.service = { - image = "postgres:12"; - environment = { - POSTGRES_DB = "bbbg"; - POSTGRES_USER = "bbbg"; - POSTGRES_PASSWORD = "password"; - }; - ports = [ "5432:5432" ]; - }; - }; -} diff --git a/users/aspen/bbbg/arion-pkgs.nix b/users/aspen/bbbg/arion-pkgs.nix deleted file mode 100644 index c6d603be2..000000000 --- a/users/aspen/bbbg/arion-pkgs.nix +++ /dev/null @@ -1,2 +0,0 @@ -let depot = import ../../.. { }; -in depot.third_party.nixpkgs diff --git a/users/aspen/bbbg/default.nix b/users/aspen/bbbg/default.nix deleted file mode 100644 index 6afb68353..000000000 --- a/users/aspen/bbbg/default.nix +++ /dev/null @@ -1,82 +0,0 @@ -args@{ depot, pkgs, ... }: - -with pkgs.lib; - -let - inherit (depot.third_party) gitignoreSource; - - deps = import ./deps.nix { - inherit (pkgs) fetchMavenArtifact fetchgit lib; - }; -in -rec { - meta.ci.targets = [ - "db-util" - "server" - "tf" - ]; - - depsPaths = deps.makePaths { }; - - resources = builtins.filterSource (_: type: type != "symlink") ./resources; - - classpath.dev = concatStringsSep ":" ( - (map gitignoreSource [ ./src ./test ./env/dev ]) ++ [ resources ] ++ depsPaths - ); - - classpath.test = concatStringsSep ":" ( - (map gitignoreSource [ ./src ./test ./env/test ]) ++ [ resources ] ++ depsPaths - ); - - classpath.prod = concatStringsSep ":" ( - (map gitignoreSource [ ./src ./env/prod ]) ++ [ resources ] ++ depsPaths - ); - - testClojure = pkgs.writeShellScript "test-clojure" '' - export HOME=$(pwd) - ${pkgs.clojure}/bin/clojure -Scp ${depsPaths} - ''; - - mkJar = name: opts: - with pkgs; - assert (hasSuffix ".jar" name); - stdenv.mkDerivation rec { - inherit name; - dontUnpack = true; - buildPhase = '' - export HOME=$(pwd) - cp ${./pom.xml} pom.xml - cp ${./deps.edn} deps.edn - ${clojure}/bin/clojure \ - -Scp ${classpath.prod} \ - -A:uberjar \ - ${name} \ - -C ${opts} - ''; - - doCheck = true; - - checkPhase = '' - echo "checking for existence of ${name}" - [ -f ${name} ] - ''; - - installPhase = '' - cp ${name} $out - ''; - }; - - db-util-jar = mkJar "bbbg-db-util.jar" "-m bbbg.db"; - - db-util = pkgs.writeShellScriptBin "bbbg-db-util" '' - exec ${pkgs.openjdk17_headless}/bin/java -jar ${db-util-jar} "$@" - ''; - - server-jar = mkJar "bbbg-server.jar" "-m bbbg.core"; - - server = pkgs.writeShellScriptBin "bbbg-server" '' - exec ${pkgs.openjdk17_headless}/bin/java -jar ${server-jar} "$@" - ''; - - tf = import ./tf.nix args; -} diff --git a/users/aspen/bbbg/deps.edn b/users/aspen/bbbg/deps.edn deleted file mode 100644 index 39ce843c2..000000000 --- a/users/aspen/bbbg/deps.edn +++ /dev/null @@ -1,70 +0,0 @@ -{:deps - {org.clojure/clojure {:mvn/version "1.11.0-alpha3"} - - ;; DB - com.github.seancorfield/next.jdbc {:mvn/version "1.2.761"} - com.impossibl.pgjdbc-ng/pgjdbc-ng {:mvn/version "0.8.9"} - com.zaxxer/HikariCP {:mvn/version "5.0.0"} - migratus/migratus {:mvn/version "1.3.5"} - com.github.seancorfield/honeysql {:mvn/version "2.2.840"} - nilenso/honeysql-postgres {:mvn/version "0.4.112"} - - ;; HTTP - http-kit/http-kit {:mvn/version "2.5.3"} - ring/ring {:mvn/version "1.9.4"} - compojure/compojure {:mvn/version "1.6.2"} - javax.servlet/servlet-api {:mvn/version "2.5"} - ring-oauth2/ring-oauth2 {:mvn/version "0.2.0"} - clj-http/clj-http {:mvn/version "3.12.3"} - ring-logger/ring-logger {:mvn/version "1.0.1"} - - ;; Web - hiccup/hiccup {:mvn/version "1.0.5"} - garden/garden {:mvn/version "1.3.10"} - - - ;; Logging + Observability - ch.qos.logback/logback-classic {:mvn/version "1.3.0-alpha12"} - org.slf4j/jul-to-slf4j {:mvn/version "2.0.0-alpha4"} - org.slf4j/jcl-over-slf4j {:mvn/version "2.0.0-alpha4"} - org.slf4j/log4j-over-slf4j {:mvn/version "2.0.0-alpha4"} - cambium/cambium.core {:mvn/version "1.1.1"} - cambium/cambium.codec-cheshire {:mvn/version "1.0.0"} - cambium/cambium.logback.core {:mvn/version "0.4.5"} - cambium/cambium.logback.json {:mvn/version "0.4.5"} - clj-commons/iapetos {:mvn/version "0.1.12"} - - ;; Utilities - com.stuartsierra/component {:mvn/version "1.0.0"} - yogthos/config {:mvn/version "1.1.9"} - clojure.java-time/clojure.java-time {:mvn/version "0.3.3"} - cheshire/cheshire {:mvn/version "5.10.1"} - org.apache.commons/commons-lang3 {:mvn/version "3.12.0"} - org.clojure/data.csv {:mvn/version "1.0.0"} - - ;; Spec - org.clojure/spec.alpha {:mvn/version "0.3.218"} - org.clojure/core.specs.alpha {:mvn/version "0.2.62"} - expound/expound {:mvn/version "0.8.10"} - org.clojure/test.check {:mvn/version "1.1.1"}} - - :paths - ["src" - "test" - "resources" - "target/classes"] - :aliases - {:dev {:extra-paths ["env/dev"] - :jvm-opts ["-XX:-OmitStackTraceInFastThrow"]} - :clj-test {:extra-paths ["test" "env/test"] - :extra-deps {io.github.cognitect-labs/test-runner - {:git/url "https://github.com/cognitect-labs/test-runner" - :sha "cc75980b43011773162b485f46f939dc5fba91e4"}} - :main-opts ["-m" "cognitect.test-runner" - "-d" "test"]} - :uberjar {:extra-deps {seancorfield/depstar {:mvn/version "1.0.94"}} - :extra-paths ["env/prod"] - :main-opts ["-m" "hf.depstar.uberjar"]} - - :outdated {:extra-deps {com.github.liquidz/antq {:mvn/version "1.3.1"}} - :main-opts ["-m" "antq.core"]}}} diff --git a/users/aspen/bbbg/deps.nix b/users/aspen/bbbg/deps.nix deleted file mode 100644 index 02f5ecb46..000000000 --- a/users/aspen/bbbg/deps.nix +++ /dev/null @@ -1,1494 +0,0 @@ -# generated by clj2nix-1.1.0-rc -{ fetchMavenArtifact, fetchgit, lib }: - -let - repos = [ - "https://repo1.maven.org/maven2/" - "https://repo.clojars.org/" - ]; - -in -rec { - makePaths = { extraClasspaths ? [ ] }: - if (builtins.typeOf extraClasspaths != "list") - then builtins.throw "extraClasspaths must be of type 'list'!" - else (lib.concatMap - (dep: - builtins.map - (path: - if builtins.isString path then - path - else if builtins.hasAttr "jar" path then - path.jar - else if builtins.hasAttr "outPath" path then - path.outPath - else - path - ) - dep.paths) - packages) ++ extraClasspaths; - makeClasspaths = { extraClasspaths ? [ ] }: - if (builtins.typeOf extraClasspaths != "list") - then builtins.throw "extraClasspaths must be of type 'list'!" - else builtins.concatStringsSep ":" (makePaths { inherit extraClasspaths; }); - packageSources = builtins.map (dep: dep.src) packages; - packages = [ - rec { - name = "cambium.logback.json/cambium"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "cambium.logback.json"; - groupId = "cambium"; - sha512 = "8e3f32bc1e11071ddc8700204333ba653585de7985c03d14c351950a7896975092e9deffd658bfec7b0b8b9cc72dc025d8e5179a185bd25da26e500218ec37a5"; - version = "0.4.5"; - - }; - paths = [ src ]; - } - - rec { - name = "clojure/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "clojure"; - groupId = "org.clojure"; - sha512 = "a242514f623a17601b360886563c4a4fe09335e4e16522ac42bbcacda073ae77651cfed446daae7fe74061bb7dff5adc454769c0edc0ded350136c3c707e75b9"; - version = "1.11.0-alpha3"; - - }; - paths = [ src ]; - } - - rec { - name = "joda-time/joda-time"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "joda-time"; - groupId = "joda-time"; - sha512 = "012fb9aa9b00b456f72a92374855a7f062f8617c026c436eee2cda67dffa2f8622201909c0f4f454bb346ff5a3ed6f60c236fafb19fa66f612d9861f27b38d3a"; - version = "2.10"; - - }; - paths = [ src ]; - } - - rec { - name = "commons-codec/commons-codec"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "commons-codec"; - groupId = "commons-codec"; - sha512 = "da30a716770795fce390e4dd340a8b728f220c6572383ffef55bd5839655d5611fcc06128b2144f6cdcb36f53072a12ec80b04afee787665e7ad0b6e888a6787"; - version = "1.15"; - - }; - paths = [ src ]; - } - - rec { - name = "HikariCP/com.zaxxer"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "HikariCP"; - groupId = "com.zaxxer"; - sha512 = "a41b6d8b1c4656e633459824f10320965976eeead01bd5cb24911040073181730e61feb797aef89d9e01c922e89cb58654f364df0a6b1bf62ab3e6f9cc367d77"; - version = "5.0.0"; - - }; - paths = [ src ]; - } - - rec { - name = "ring-devel/ring"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ring-devel"; - groupId = "ring"; - sha512 = "79a1ec9f9d03aa4fa0426353970b13468ee65ce314b51ab7a2682212a196a9b5c985eacdee5dbc6ff2f1b536a4e06d0e85e9dd7cc9a49958735c9c4e6d427fd5"; - version = "1.9.4"; - - }; - paths = [ src ]; - } - - rec { - name = "simpleclient/io.prometheus"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "simpleclient"; - groupId = "io.prometheus"; - sha512 = "60af1cefff04e7036467eae54f5930d5677e4ab066f8ed38a391b54df17733acfefac45e19ee53cef289347bddce5fc69a2766f4e580d21a22cfd9e2348e2723"; - version = "0.12.0"; - - }; - paths = [ src ]; - } - - rec { - name = "commons-lang3/org.apache.commons"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "commons-lang3"; - groupId = "org.apache.commons"; - sha512 = "fbdbc0943cb3498b0148e86a39b773f97c8e6013740f72dbc727faeabea402073e2cc8c4d68198e5fc6b08a13b7700236292e99d4785f2c9989f2e5fac11fd81"; - version = "3.12.0"; - - }; - paths = [ src ]; - } - - rec { - name = "tools.logging/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "tools.logging"; - groupId = "org.clojure"; - sha512 = "b7a9680f1156fc7c1574a4364ca550d47668ba727fc80110fdd00c159bedb45c5be82f09cdfb8e8e988e3381e2cf8881ea70651e38001e3eaa4ece31ad0bf0c5"; - version = "1.2.2"; - - }; - paths = [ src ]; - } - - rec { - name = "core.specs.alpha/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "core.specs.alpha"; - groupId = "org.clojure"; - sha512 = "f521f95b362a47bb35f7c85528c34537f905fb3dd24f2284201e445635a0df701b35d8419d53c6507cc78d3717c1f83cda35ea4c82abd8943cd2ab3de3fcad70"; - version = "0.2.62"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-common/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-common"; - groupId = "io.netty"; - sha512 = "7efc2f6774a3dbe8408fe182e19830b5b7a994a0d1b0eb50699df691c2450befa05ac205bbf341ad57bef3a04281ce435031e97e725c5c4edfc705a418828ce8"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "jackson-databind/com.fasterxml.jackson.core"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jackson-databind"; - groupId = "com.fasterxml.jackson.core"; - sha512 = "9f771e78af669b1e1683d6c5903bbf4790aaa88b6b420c2018437da318c3fa4220cd7fa726f3e42a1b8075def1fdbd3744937c15f3bcedfca3050199247363e8"; - version = "2.12.4"; - - }; - paths = [ src ]; - } - - rec { - name = "expound/expound"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "expound"; - groupId = "expound"; - sha512 = "ca0a57cfd215cff6be36d1f83461ec2d0559c0eae172c8a8bd6e1676d49933d3c30a71192889bd75d813581707d5eda0ec05de03326396bc0cedebf2d71811e5"; - version = "0.8.10"; - - }; - paths = [ src ]; - } - - rec { - name = "spec.alpha/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "spec.alpha"; - groupId = "org.clojure"; - sha512 = "ddfe4fa84622abd8ac56e2aa565a56e6bdc0bf330f377ff3e269ddc241bb9dbcac332c13502dfd4c09c2c08fe24d8d2e8cf3d04a1bc819ca5657b4e41feaa7c2"; - version = "0.3.218"; - - }; - paths = [ src ]; - } - - rec { - name = "tools.cli/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "tools.cli"; - groupId = "org.clojure"; - sha512 = "1d88aa03eb6a664bf2c0ce22c45e7296d54d716e29b11904115be80ea1661623cf3e81fc222d164047058239010eb678af92ffedc7c3006475cceb59f3b21265"; - version = "1.0.206"; - - }; - paths = [ src ]; - } - - rec { - name = "compojure/compojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "compojure"; - groupId = "compojure"; - sha512 = "1f4ba1354bd95772963a4ef0e129dde59d16f4f9fac0f89f2505a1d5de3b4527e45073219c0478e0b3285da46793e7c145ec5a55a9dae2fca6b77dc8d67b4db6"; - version = "1.6.2"; - - }; - paths = [ src ]; - } - - rec { - name = "commons-fileupload/commons-fileupload"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "commons-fileupload"; - groupId = "commons-fileupload"; - sha512 = "a8780b7dd7ab68f9e1df38e77a5207c45ff50ec53d8b1476570d069edc8f59e52fb1d0fc534d7e513ac5a01b385ba73c320794c82369a72bd6d817a3b3b21f39"; - version = "1.4"; - - }; - paths = [ src ]; - } - - rec { - name = "jetty-http/org.eclipse.jetty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jetty-http"; - groupId = "org.eclipse.jetty"; - sha512 = "60422ff3ef311f1d9d7340c2accdf611d40e738a39e9128967175ede4990439f4725995988849957742d488f749dd2e0740f74dc5bd9b3364e32fbaa66689308"; - version = "9.4.42.v20210604"; - - }; - paths = [ src ]; - } - - rec { - name = "jetty-util/org.eclipse.jetty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jetty-util"; - groupId = "org.eclipse.jetty"; - sha512 = "d69084e2cfe0c3af1dc7ee2745d563549a4068b6e8aed5cd2b9f31167168fb64d418c4134a6dfb811b627ec0051d7ff71e0a02e4e775d18a53543d0871c44730"; - version = "9.4.42.v20210604"; - - }; - paths = [ src ]; - } - - rec { - name = "janino/org.codehaus.janino"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "janino"; - groupId = "org.codehaus.janino"; - sha512 = "6853d7d53d3629df43a3a17ff5c989f59ec14e9030be5f67426deb9d0797fa3996b0609d582c65f22a4f7680c941b39ab6d466c480b2fea4bf92218a9b89651d"; - version = "3.1.2"; - - }; - paths = [ src ]; - } - - rec { - name = "jcl-over-slf4j/org.slf4j"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jcl-over-slf4j"; - groupId = "org.slf4j"; - sha512 = "23662fe407fcdbcba8865a8cd3f8bb09d4eb178a2a6511a32e35b995722b345e73f5dc1dd85d2d0a5c707db05aa57e0b3d0b96b59e55403fc486343d5ca4c0d6"; - version = "2.0.0-alpha4"; - - }; - paths = [ src ]; - } - - (rec { - name = "io.github.cognitect-labs/test-runner"; - src = fetchgit { - name = "test-runner"; - url = "https://github.com/cognitect-labs/test-runner"; - rev = "cc75980b43011773162b485f46f939dc5fba91e4"; - sha256 = "1661ddmmqva1yiz9p09i5l32lfpi0a99h56022zgvz03nca2ksbg"; - }; - paths = map (path: src + path) [ - "/src" - ]; - }) - - rec { - name = "cambium.logback.core/cambium"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "cambium.logback.core"; - groupId = "cambium"; - sha512 = "83ee9a583dd8a7b2e82e0981b4e51b005095a27257eb1b07165d9701645609060c466ae67fb9431f524a544d52b71fa00009b8acf05aadbeb549043515f9b382"; - version = "0.4.5"; - - }; - paths = [ src ]; - } - - rec { - name = "httpasyncclient/org.apache.httpcomponents"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "httpasyncclient"; - groupId = "org.apache.httpcomponents"; - sha512 = "0a80db5dbf772f02d02ba6c7c163e8da9517dd7195714b495acb845c429580c1fc926d3e71c115e75be8c145651dce2fdfa0dc380132f7809c14b3ad95492aee"; - version = "4.1.4"; - - }; - paths = [ src ]; - } - - rec { - name = "logback-jackson/ch.qos.logback.contrib"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "logback-jackson"; - groupId = "ch.qos.logback.contrib"; - sha512 = "d9a3d4cb6cf4eda6fc18e2d374007d27c6ddba98e989a8d8a01b49859b280450113f685df6e16c5fbe0472bc9e26308bc7e8b7e0aedab9404cf0b492d7511685"; - version = "0.1.5"; - - }; - paths = [ src ]; - } - - rec { - name = "simpleclient_tracer_otel/io.prometheus"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "simpleclient_tracer_otel"; - groupId = "io.prometheus"; - sha512 = "bce192e6162cb3ada7dd6c2d10456e78bce71c170faa09bad2896272fa1bd4a036288d707f3d47747991d8946c74fe21c565713fb15c7052305eb753c94dd939"; - version = "0.12.0"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-codec/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-codec"; - groupId = "io.netty"; - sha512 = "f6d9c4a5b508ca0d5f0e213473088f5d7b2e184e447dc092e69227109e28da9b8e68b2238ca6ab4e9915bacacf59cc0dce6ebcbbb05dad34a03b7976d9670c51"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "ring-oauth2/ring-oauth2"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ring-oauth2"; - groupId = "ring-oauth2"; - sha512 = "3ed765b4bbb5749fcdcdb501b93ab656a413ade5af24c7aa34639718ed1fd0a5f325b05bd135540d56e55cbb456a2cb7852ba0e45bc5233e28229986eef75bb9"; - version = "0.2.0"; - - }; - paths = [ src ]; - } - - rec { - name = "tools.macro/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "tools.macro"; - groupId = "org.clojure"; - sha512 = "65ce5e29379620ac458274c53cd9926e4b764fcaebb1a2b3bc8aef86bbe10c79e654b028bc4328905d2495a680fa90f5002cf5c47885f6449fad43a04a594b26"; - version = "0.1.5"; - - }; - paths = [ src ]; - } - - rec { - name = "jackson-dataformat-cbor/com.fasterxml.jackson.dataformat"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jackson-dataformat-cbor"; - groupId = "com.fasterxml.jackson.dataformat"; - sha512 = "ea5d049eac1b94666479c5e36de14d8fa4b7f24cb92f0f310d2ec2b4de66ef9023161060e67228ef2d7420a002ef861db12a29cad0864638c21612da49686f4f"; - version = "2.12.4"; - - }; - paths = [ src ]; - } - - rec { - name = "depstar/seancorfield"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "depstar"; - groupId = "seancorfield"; - sha512 = "0f4458b39b8b1949755bc2fe64b239673a9efa3a0140998464bbbcab216ec847344c1b8920611f7c9ca07261850f3a08144ae221cc2c41813a080189e32f9c10"; - version = "1.0.94"; - - }; - paths = [ src ]; - } - - rec { - name = "logback-core/ch.qos.logback"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "logback-core"; - groupId = "ch.qos.logback"; - sha512 = "fc554548f499e284007eeecf76bf4e1995effb6ac8a6262aa96118f623bf9085a9d5bec3741833dd3cae6a76b2ff78c6d0a1fe68bc01213207c93d8e2da345ca"; - version = "1.3.0-alpha12"; - - }; - paths = [ src ]; - } - - rec { - name = "honeysql/honeysql"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "honeysql"; - groupId = "honeysql"; - sha512 = "74d1d93c968b33686848e3bf8934f3b5f002c2b69b1b55a3a3b172c952e9991324e6e95e3a0ce2fecf1de0d3a036f4dff7286df689f0733f253909464e0269f6"; - version = "1.0.461"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-buffer/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-buffer"; - groupId = "io.netty"; - sha512 = "181b55d99d8d46bbf5f67f05bdccb0381af23a9fca3e6d935e6cde727b132c67133de1c3d81ed19b04c1a5b232be0de16ec1de7e81b532878bc69564237c15dc"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "slingshot/slingshot"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "slingshot"; - groupId = "slingshot"; - sha512 = "ff2b2a27b441d230261c7f3ec8c38aa551865e05ab6438a74bd12bfcbc5f6bdc88199d42aaf5932b47df84f3d2700c8f514b9f4e9b5da28d29da7ff6b09a7fb5"; - version = "0.12.2"; - - }; - paths = [ src ]; - } - - rec { - name = "httpcore-nio/org.apache.httpcomponents"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "httpcore-nio"; - groupId = "org.apache.httpcomponents"; - sha512 = "002af5f72b68a4ff1b1ff46b788013283d195e1d62ee1d7b102aa930b30f77f7e215a6d18edbea0fccd18fb1fa3a66cc4aef6070d72d6d1886f0044dfe0e16c7"; - version = "4.4.10"; - - }; - paths = [ src ]; - } - - rec { - name = "ring-jetty-adapter/ring"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ring-jetty-adapter"; - groupId = "ring"; - sha512 = "93075903ad73a8b73cb77ee9f53ed33594f40a5dafe8129089adb4cfa333e37468764203c00244568f02abf0c0eee9f5d9a9f96c420919027cf2746a41ec38e3"; - version = "1.9.4"; - - }; - paths = [ src ]; - } - - rec { - name = "simpleclient_tracer_common/io.prometheus"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "simpleclient_tracer_common"; - groupId = "io.prometheus"; - sha512 = "6f717af63340efd84c5467ae752be7e66f586f0e8b57adb5b7a8ef99b223203ed829aad6797f6ef1811d6d861b00a621a1288c9271ec2ba77018d6d9eb9e7987"; - version = "0.12.0"; - - }; - paths = [ src ]; - } - - rec { - name = "component/com.stuartsierra"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "component"; - groupId = "com.stuartsierra"; - sha512 = "108b02f51165ad07c2cf5232fbd954d052880c2456e6fb6db3342bda6851c76b73bf9145f03fb0df2b5782fe39f368b2868780c1e8e2dfa2ab2c68dd97f34ab7"; - version = "1.0.0"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-handler/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-handler"; - groupId = "io.netty"; - sha512 = "48874727553dd7084f5c48d90de123704ae334837c3a103f598887bb21405dd62c57603b59300ac2fcdd936f0af99ed0730487fb9fb8917d236b8fe3f78f3c02"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "yuicompressor/com.yahoo.platform.yui"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "yuicompressor"; - groupId = "com.yahoo.platform.yui"; - sha512 = "ba2588bd50eaa3005b1919daad9f9c86a33351ceb9b7b5f0a9a498a548cc523e99f9345917a64303f8e23925feea226386d3eac01f640f788d1be4c7cf0315e0"; - version = "2.4.8"; - - }; - paths = [ src ]; - } - - rec { - name = "commons-io/commons-io"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "commons-io"; - groupId = "commons-io"; - sha512 = "6af22dffaaecd1553147e788b5cf50368582318f396e456fe9ff33f5175836713a5d700e51720465c932c2b1987daa83027358005812d6a95d5755432de3a79d"; - version = "2.10.0"; - - }; - paths = [ src ]; - } - - rec { - name = "tools.namespace/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "tools.namespace"; - groupId = "org.clojure"; - sha512 = "2cdb9c5d9bc4fd01dae182e9ad4b91eeaa2487003a977e7d8d5e66f562a9544b59f558710eccf421ea63cbbfa953ac8944fe9b9a76049fb82a47eb2bdcb3a4d7"; - version = "1.1.1"; - - }; - paths = [ src ]; - } - - rec { - name = "honeysql/com.github.seancorfield"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "honeysql"; - groupId = "com.github.seancorfield"; - sha512 = "a0e5ebbf922aaf170c2d74ec0efc0df7e3bda92d0b8cc5f40ee4c8ddcb8c7e0e46556fac381513e0ac76b10f681c14c2d2569010c2f8eab4ff04f6373c2bf229"; - version = "2.2.840"; - - }; - paths = [ src ]; - } - - rec { - name = "jackson-core/com.fasterxml.jackson.core"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jackson-core"; - groupId = "com.fasterxml.jackson.core"; - sha512 = "428e0ebb16dd4c74ab0adf712058fd0dc0cd788f6e6f90c60c627da6577b345fac60a30694e111f1cd4e3e8bf79a1f1b820d30ada114984b26c28e299e326eaa"; - version = "2.12.4"; - - }; - paths = [ src ]; - } - - rec { - name = "clj-time/clj-time"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "clj-time"; - groupId = "clj-time"; - sha512 = "cfeb46af59fd4112aa5a5d0087a39355f0fc19514b4c02bc6c3d9f81c9bda40491686207836e9a7943aebeb82a3b36f4e8b7407a8908c5ef151122644b278d75"; - version = "0.15.2"; - - }; - paths = [ src ]; - } - - rec { - name = "clj-http/clj-http"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "clj-http"; - groupId = "clj-http"; - sha512 = "9884557d4f38068cb3234aec80acc0de8f9716645529693ffd9bd6db8221f5d1cf9e2d1b8bf7c7df4215d71372b02d83043ebf8fc27dc422552b32c9bdba1602"; - version = "3.12.3"; - - }; - paths = [ src ]; - } - - rec { - name = "jul-to-slf4j/org.slf4j"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jul-to-slf4j"; - groupId = "org.slf4j"; - sha512 = "350cfb889248d724b27dce697f635f12d9db463f107830b9518ce184dc4cc1ab3933eb5bdab08515e69766c3d5be24547dac289d6406c44eca90717230714b91"; - version = "2.0.0-alpha4"; - - }; - paths = [ src ]; - } - - rec { - name = "migratus/migratus"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "migratus"; - groupId = "migratus"; - sha512 = "ee5ce8601930d063e0d9d90fc8e165b78fc1587bfd7e0fc9922735bc2f9fc27f8cf8bf10d49d6fd57b899ac4b250145bd653915ed770424416e026ba37d1b604"; - version = "1.3.5"; - - }; - paths = [ src ]; - } - - rec { - name = "httpcore/org.apache.httpcomponents"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "httpcore"; - groupId = "org.apache.httpcomponents"; - sha512 = "f16a652f4a7b87dbf7cb16f8590d54a3f719c4c7b2f8883ce59db2d73be4701b64f2ca8a2c45aca6a5dbeaddeedff0c280a03722f70c076e239b645faa54eff9"; - version = "4.4.14"; - - }; - paths = [ src ]; - } - - rec { - name = "httpclient-cache/org.apache.httpcomponents"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "httpclient-cache"; - groupId = "org.apache.httpcomponents"; - sha512 = "e150e8dc49c8c9972d8b324b56bb292b15e2f0e686f1292c4edac975615dfb16e5edb8ab325e614732a7d43a03061ca4fe93fe1e1f7487851a4d4d3af50a61f9"; - version = "4.5.13"; - - }; - paths = [ src ]; - } - - rec { - name = "instaparse/instaparse"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "instaparse"; - groupId = "instaparse"; - sha512 = "ec2fcf4a09319a8fa9489b08fd9c9a5fe6e63155dde74d096f947fabc4f68d3d1bf68faf21e175e80eaee785f563a1903d30c550f93fb13a16a240609e3dfa2e"; - version = "1.4.8"; - - }; - paths = [ src ]; - } - - rec { - name = "honeysql-postgres/nilenso"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "honeysql-postgres"; - groupId = "nilenso"; - sha512 = "d4accd3b8819cf715ecdb29496cf5a6a5ad3871fd579e55c7148d4e05774cb896c681b0c6f84df88aa9cd8e6ef9bfd65788ede9a49ba365ad0e32ee350091879"; - version = "0.4.112"; - - }; - paths = [ src ]; - } - - rec { - name = "clj-tuple/clj-tuple"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "clj-tuple"; - groupId = "clj-tuple"; - sha512 = "dd626944d0aba679a21b164ed0c77ea84449359361496cba810f83b9fdeab751e5889963888098ce4bf8afa112dbda0a46ed60348a9c01ad36a2e255deb7ab6d"; - version = "0.2.2"; - - }; - paths = [ src ]; - } - - rec { - name = "jackson-annotations/com.fasterxml.jackson.core"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jackson-annotations"; - groupId = "com.fasterxml.jackson.core"; - sha512 = "6fdad6c5bb71a97331a662fe26265aacab6869f3307a710697d5c2f256fd48935764bfb0b3505a2cbb1605daf0b7350abdf84a1b1cf2bb1e91d9184565243c8e"; - version = "2.12.4"; - - }; - paths = [ src ]; - } - - rec { - name = "hiccup/hiccup"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "hiccup"; - groupId = "hiccup"; - sha512 = "034f15be46c35029f41869c912f82cb2929fbbb0524ea64bd98dcdb9cf09875b28c75e926fa5fff53942b0f9e543e85a73a2d03c3f2112eecae30fcef8b148f4"; - version = "1.0.5"; - - }; - paths = [ src ]; - } - - rec { - name = "riddley/riddley"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "riddley"; - groupId = "riddley"; - sha512 = "b478ecba9d1ab9d38c84a42354586fcece763000907b40c97bc43c0f16dc560b0860144efe410193cb3b7cb0149fbc1724fdd737cc3ba53de23618f5b30e6f9f"; - version = "0.1.12"; - - }; - paths = [ src ]; - } - - rec { - name = "java.classpath/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "java.classpath"; - groupId = "org.clojure"; - sha512 = "90cd8edeaea02bd908d8cfb0cf5b1cf901aeb38ea3f4971c4b813d33210438aae6fff8e724a8272d2ea9441d373e7d936fa5870e309c1e9721299f662dbbdb9a"; - version = "1.0.0"; - - }; - paths = [ src ]; - } - - rec { - name = "simpleclient_pushgateway/io.prometheus"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "simpleclient_pushgateway"; - groupId = "io.prometheus"; - sha512 = "31c8878929f516ba7030cc9ec4ac4cbcb09955a9fdae23c6904bc481e40e70e1b3e05619c49b646119077ef6f57c430cc7944f6bafdbca24c9efa8145474fcf7"; - version = "0.12.0"; - - }; - paths = [ src ]; - } - - rec { - name = "ns-tracker/ns-tracker"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ns-tracker"; - groupId = "ns-tracker"; - sha512 = "cfb6c2c9f899b43d1284acdc572b34b977936c4df734b38137dfea045421b74d529509cde23695f1dc5ee06d046c2f6b61a2cd98058da1c7220c21dd0361964f"; - version = "0.4.0"; - - }; - paths = [ src ]; - } - - rec { - name = "clout/clout"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "clout"; - groupId = "clout"; - sha512 = "99d6e1a8c5726ca4e5d12b280a39e6d1182d734922600f27d588d3d65fbc830c5e03f9e0421ff25c819deee4d1f389fd3906222716ace1eb17ce70ef9c5e8f4b"; - version = "2.2.1"; - - }; - paths = [ src ]; - } - - rec { - name = "commons-logging/commons-logging"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "commons-logging"; - groupId = "commons-logging"; - sha512 = "ed00dbfabd9ae00efa26dd400983601d076fe36408b7d6520084b447e5d1fa527ce65bd6afdcb58506c3a808323d28e88f26cb99c6f5db9ff64f6525ecdfa557"; - version = "1.2"; - - }; - paths = [ src ]; - } - - rec { - name = "clojure.java-time/clojure.java-time"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "clojure.java-time"; - groupId = "clojure.java-time"; - sha512 = "62d8a286ec3393594e7f84eba22dbb02c1305a80a18b2574058ae963d3f3e829ff960c8b66e89069e6c071a11f869203134c6c4cdec6f8e516c9b314796c8108"; - version = "0.3.3"; - - }; - paths = [ src ]; - } - - rec { - name = "data.csv/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "data.csv"; - groupId = "org.clojure"; - sha512 = "b039775a859ed27eca8f8ae74ccb6afde3ad1fe2b3cbe542240c324d60fe1237e495eb1300ee9eb4ff4ef59f01faf7aec6ef1dd6a025ee4fe556c1d91acfcf1b"; - version = "1.0.0"; - - }; - paths = [ src ]; - } - - rec { - name = "simpleclient_tracer_otel_agent/io.prometheus"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "simpleclient_tracer_otel_agent"; - groupId = "io.prometheus"; - sha512 = "97694210d9a5b48a7cb9dda2a187432c4813edb3051edfa5832a0a471e0b2d5988dab92b70c292e78f59b169345deb5c1c706361fd726f3dc2480766dedfdcec"; - version = "0.12.0"; - - }; - paths = [ src ]; - } - - rec { - name = "next.jdbc/com.github.seancorfield"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "next.jdbc"; - groupId = "com.github.seancorfield"; - sha512 = "0b4b01ba126bb8b1e2c14262db9fca75456b274d09535d9a7bb386699bf20dc9ac11590d210769e7429ca59ebfdfbb06916b3ff275cc817d74eac5bbabdab8f2"; - version = "1.2.761"; - - }; - paths = [ src ]; - } - - rec { - name = "java.jdbc/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "java.jdbc"; - groupId = "org.clojure"; - sha512 = "6162b7774dca58b62a94bc5a04ba845e4c7065c9c589cc3bb802becfec0baf0989a338c1bf9a5db7c3128873702840d5f2451628f3aac977245975d65a683b7d"; - version = "0.7.11"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-transport/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-transport"; - groupId = "io.netty"; - sha512 = "c11d690ffeaf3267b2166f73a43108fb89d588fcef3f6d3053bf4b6f6669483baa618fd97438010692a6fa28334372d5a31b7c0996961d4eabb60cbdc358a536"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "crypto-random/crypto-random"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "crypto-random"; - groupId = "crypto-random"; - sha512 = "3520df744f250dbe061d1a5d7a05b7143f3a67a4c3f9ad87b8044ee68a36a702a0bcb3a203e35d380899dd01c28e01988b0a7af914b942ccbe0c35c9bdb22e11"; - version = "1.2.1"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-transport-native-unix-common/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-transport-native-unix-common"; - groupId = "io.netty"; - sha512 = "b63e5f8a44b7f37f3dba378bd06af64dd1d7be3f0b1a7d47ad139ff06e0212b4c7081275b1b5b12183aeb72eb5f9bf9ef03ed8c78bc302aeb4817dca7bd89f3a"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "ring-codec/ring"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ring-codec"; - groupId = "ring"; - sha512 = "38b9775a794831b8afd8d66991a75aa5910cd50952c9035866bf9cc01353810aedafbc3f35d8f9e56981ebf9e5c37c00b968759ed087d2855348b3f46d8d0487"; - version = "1.1.3"; - - }; - paths = [ src ]; - } - - rec { - name = "spy/com.impossibl.pgjdbc-ng"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "spy"; - groupId = "com.impossibl.pgjdbc-ng"; - sha512 = "173615c39aa6015a732e329217b40e3ea1c304c9c168d2764d6ef23ab8775e2f4432339bc22d049662561f09d3fd890b5415738620d64dcedb762d5da26b4ebb"; - version = "0.8.9"; - - }; - paths = [ src ]; - } - - rec { - name = "logback-json-core/ch.qos.logback.contrib"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "logback-json-core"; - groupId = "ch.qos.logback.contrib"; - sha512 = "2a826036f21997e2979fda83ae3e33cf62f3b2b2df15a7b11d1fd8a52163b09f0f2f8d72f5fdcea0ec1289b3d27727ed5e6b0bcdf4c5d741f4bac07b7b6139e8"; - version = "0.1.5"; - - }; - paths = [ src ]; - } - - rec { - name = "httpclient/org.apache.httpcomponents"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "httpclient"; - groupId = "org.apache.httpcomponents"; - sha512 = "3567739186e551f84cad3e4b6b270c5b8b19aba297675a96bcdff3663ff7d20d188611d21f675fe5ff1bfd7d8ca31362070910d7b92ab1b699872a120aa6f089"; - version = "4.5.13"; - - }; - paths = [ src ]; - } - - rec { - name = "crypto-equality/crypto-equality"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "crypto-equality"; - groupId = "crypto-equality"; - sha512 = "54cf3bd28f633665962bf6b41f5ccbf2634d0db210a739e10a7b12f635e13c7ef532efe1d5d8c0120bb46478bbd08000b179f4c2dd52123242dab79fea97d6a6"; - version = "1.0.0"; - - }; - paths = [ src ]; - } - - rec { - name = "cheshire/cheshire"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "cheshire"; - groupId = "cheshire"; - sha512 = "855e9c42a8d1c64f4db5cda45e31e914eb5ed99a715e8d7a5759a9c4ab6c69a82353635ca7b0837880c6cf9b41b11184ae11e09cbf2c07aa13db32c539e5dfd4"; - version = "5.10.1"; - - }; - paths = [ src ]; - } - - rec { - name = "tigris/tigris"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "tigris"; - groupId = "tigris"; - sha512 = "fdff4ef5e7175a973aaef98de4f37dee8e125fc711c495382e280aaf3e11341fe8925d52567ca60f3f1795511ade11bc23461c88959632dfae3cf50374d02bf6"; - version = "0.1.2"; - - }; - paths = [ src ]; - } - - rec { - name = "config/yogthos"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "config"; - groupId = "yogthos"; - sha512 = "3437992d192465edc74aec5259d5e0c0ad7e631dff860b2ee14cef27f13cee7c60487202cf00fc160a95fb0b85ce1ddf56cbdd0c008b47ac598061bf115f6a23"; - version = "1.1.9"; - - }; - paths = [ src ]; - } - - rec { - name = "jetty-io/org.eclipse.jetty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jetty-io"; - groupId = "org.eclipse.jetty"; - sha512 = "a8c5f73089daa0c8b27f836acddf40bcbf07bbb2571a4d73653be8aac3fb339022f546326722f216bad78a68886934d24db9bec54235124592dd29dbeab69051"; - version = "9.4.42.v20210604"; - - }; - paths = [ src ]; - } - - rec { - name = "logback-json-classic/ch.qos.logback.contrib"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "logback-json-classic"; - groupId = "ch.qos.logback.contrib"; - sha512 = "d30bf70217d316914d83d46cc15783f656354084087d59cbc0620a746f10b4a42e56d33b3e50a8b3596a64ec8314730bf5ff9a3f7dc3417bdd0582665be009ec"; - version = "0.1.5"; - - }; - paths = [ src ]; - } - - rec { - name = "tools.reader/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "tools.reader"; - groupId = "org.clojure"; - sha512 = "3481259c7a1eac719db2921e60173686726a0c2b65879d51a64d516a37f6120db8ffbb74b8bd273404285d7b25143ab5c7ced37e7c0eaf4ab1e44586ccd3c651"; - version = "1.3.6"; - - }; - paths = [ src ]; - } - - rec { - name = "simpleclient_common/io.prometheus"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "simpleclient_common"; - groupId = "io.prometheus"; - sha512 = "dedd003638eb3651c112e2d697ac94eb4e3b3e32c94fa41bb1efe2c889a347cdc7bd13256e05423f3370592d4fd65faf8db57f0387ab75814d7fa77b14cbbadf"; - version = "0.12.0"; - - }; - paths = [ src ]; - } - - rec { - name = "commons-compiler/org.codehaus.janino"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "commons-compiler"; - groupId = "org.codehaus.janino"; - sha512 = "f0778b891ef14d8ee6776747eab0b25da716cdc530752a81aedec2a77570e2f66402179b9408a6efde8125c808eb060a720d2f4977c1f1d022bdaae7eac8d011"; - version = "3.1.2"; - - }; - paths = [ src ]; - } - - rec { - name = "servlet-api/javax.servlet"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "servlet-api"; - groupId = "javax.servlet"; - sha512 = "363ba5590436ab82067b7a2e14b481aeb2b12ca4048d7a1519a2e549b2d3c09ddf718ac64dc2be6c2fc24c51fdc9c8160261329403113369588ce27d87771db6"; - version = "2.5"; - - }; - paths = [ src ]; - } - - rec { - name = "iapetos/clj-commons"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "iapetos"; - groupId = "clj-commons"; - sha512 = "d17f36c0cf0ec78db5e893e5c033f8562b31650bda6f5ee582e68f84a07a3631d04d6f69e4e18b1ca64e732c180fa669dfb69a78849e13f601cd563a7a8aab94"; - version = "0.1.12"; - - }; - paths = [ src ]; - } - - rec { - name = "javax.servlet-api/javax.servlet"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "javax.servlet-api"; - groupId = "javax.servlet"; - sha512 = "32f7e3565c6cdf3d9a562f8fd597fe5059af0cf6b05b772a144a74bbc95927ac275eb38374538ec1c72adcce4c8e1e2c9f774a7b545db56b8085af0065e4a1e5"; - version = "3.1.0"; - - }; - paths = [ src ]; - } - - rec { - name = "potemkin/potemkin"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "potemkin"; - groupId = "potemkin"; - sha512 = "5abc050bf7ff0b27d8c45aaa5e378201980815b711b2db99735db73304576c17e285026ea48a714bf0b0df7ad7a008de38b7d182cdc0e8989f4be1e6b3afa8aa"; - version = "0.4.5"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-resolver/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-resolver"; - groupId = "io.netty"; - sha512 = "fabf893de74264caa1799c15d184ed8f20b7bf9b1c41abb29f29adf728a934951f97892a4924634f9efbda17c8cf74ea3ff97bafca616711e3c5f79b8ed9ef3e"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-transport-native-epoll/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-transport-native-epoll"; - groupId = "io.netty"; - sha512 = "6fbc2dd2622699f3fc1f329acbd94baf7f1d8923c5cfcae262e6f2d64b4fd71b606561bce5e2b511dff8e052cdade930091fab683fd98713f6b62a622a2c6254"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "clj-stacktrace/clj-stacktrace"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "clj-stacktrace"; - groupId = "clj-stacktrace"; - sha512 = "993f8a544203801fc074eefacee8e553e426422b3492d47b857d87ac73cde72c91e29f629382b9eae8cf9600bc2c4c29d2e7169e509c46302ab973c86e73af0c"; - version = "0.2.8"; - - }; - paths = [ src ]; - } - - rec { - name = "cambium.codec-cheshire/cambium"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "cambium.codec-cheshire"; - groupId = "cambium"; - sha512 = "614491cf752a597f29ae29885db6c1ed191341303d89183bee52e4e2c76eb8eb14693562ad09484f379a074b36d97085e848ec3845e069440e6422506c1636f1"; - version = "1.0.0"; - - }; - paths = [ src ]; - } - - rec { - name = "slf4j-api/org.slf4j"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "slf4j-api"; - groupId = "org.slf4j"; - sha512 = "ad705ab6fd5cd904ef6861c0adf08af19593cf6a486b18de548fe3d68e57b1baa7e02947584fd4dcc350ddcddcf906c01e8d9ba7943a202690d0d788627696b5"; - version = "2.0.0-alpha4"; - - }; - paths = [ src ]; - } - - rec { - name = "test.check/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "test.check"; - groupId = "org.clojure"; - sha512 = "b8d7a330b0b5514cd6a00c4382052fab51c3c9d3bc53133f8506791fa670e7c5ecd65094977ea5ced91f59623b0abd1ab8feeec96d63c5c6e459b265a655c577"; - version = "1.1.1"; - - }; - paths = [ src ]; - } - - rec { - name = "ring-logger/ring-logger"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ring-logger"; - groupId = "ring-logger"; - sha512 = "b675a61c173289fc610d84920ba40178bf62b3bc680923cb66866d78ee2a508296b27a1ab14b66bfbe0304a64166a7e3c3ddee36564dd4a2f988861bce455a3a"; - version = "1.0.1"; - - }; - paths = [ src ]; - } - - rec { - name = "ring-servlet/ring"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ring-servlet"; - groupId = "ring"; - sha512 = "3d8e6ec224e13d54810a945c0b6c0d2d863736a48d8c4bfc8fadb96b6b0fa9baa638644d0d92d8a53650b188e6e75d391731b08b26eb0f551e90a7504e7f4267"; - version = "1.9.4"; - - }; - paths = [ src ]; - } - - rec { - name = "logback-classic/ch.qos.logback"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "logback-classic"; - groupId = "ch.qos.logback"; - sha512 = "f9fe0f126061f4abe3973b631b8d8244ba9e9d77783479a6500d629d772050dee508a001fc14d2131407fbdd0d33dd6b8aeb9b1ea9125b471bb8412e8de659e6"; - version = "1.3.0-alpha12"; - - }; - paths = [ src ]; - } - - rec { - name = "dependency/com.stuartsierra"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "dependency"; - groupId = "com.stuartsierra"; - sha512 = "d32fbc4813bd16f2ed8c82e2915e1fb564e88422159bd3580a85c8cd969d1bbbe315bdc13d29c2f0eaceeeafcf649ee712c8df4532464d560aaeae4ae5953866"; - version = "1.0.0"; - - }; - paths = [ src ]; - } - - rec { - name = "camel-snake-kebab/camel-snake-kebab"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "camel-snake-kebab"; - groupId = "camel-snake-kebab"; - sha512 = "589d34b500560b7113760a16bfb6f0ccd8f162a1ce8c9bc829495432159ba9c95aebf6bc43aa126237a0525806a205a05f9910122074902b659e7fd151d176b1"; - version = "0.4.2"; - - }; - paths = [ src ]; - } - - rec { - name = "ring/ring"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ring"; - groupId = "ring"; - sha512 = "93c48fb670736b91fb41d8076e1e9c4f53c67693d15e75290da319e7d7881b829a24180029b3a0fa051473c6c77ac3c97b519254ebf2b2c9538b185e79b69162"; - version = "1.9.4"; - - }; - paths = [ src ]; - } - - rec { - name = "netty-transport-native-kqueue/io.netty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "netty-transport-native-kqueue"; - groupId = "io.netty"; - sha512 = "87e10c06e394a1698d65381d3be8336f753c55e3e899e297510161d0c72540023f30f9032322957e035ead793204a084b988bc21a2bc312fcf7567a22d02a3c4"; - version = "4.1.63.Final"; - - }; - paths = [ src ]; - } - - rec { - name = "java.data/org.clojure"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "java.data"; - groupId = "org.clojure"; - sha512 = "225e1eafd1a659278212d831f7cd8609359f8c880ef3d69b4ade6301ce3c511307ce31d94cb82d5407314b990bd04714ec26273bb3036b248116a7a75fa75e1f"; - version = "1.0.95"; - - }; - paths = [ src ]; - } - - rec { - name = "jetty-server/org.eclipse.jetty"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jetty-server"; - groupId = "org.eclipse.jetty"; - sha512 = "b347f8a6e5b84e0f460037027e238a61edec710ade768c95e7be13dcea498abe43d5e622ee69ac7494138d1a8fcf92e07b7deab569c554831c57baad71c53b9b"; - version = "9.4.42.v20210604"; - - }; - paths = [ src ]; - } - - rec { - name = "httpmime/org.apache.httpcomponents"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "httpmime"; - groupId = "org.apache.httpcomponents"; - sha512 = "e1b0ee84bce78576074dc1b6836a69d8f5518eade38562e6890e3ddaa72b7f54bf735c8e2286142c58cddf45f745da31261e5d73b7d8092eb6ecfb20946eb36c"; - version = "4.5.13"; - - }; - paths = [ src ]; - } - - rec { - name = "log4j-over-slf4j/org.slf4j"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "log4j-over-slf4j"; - groupId = "org.slf4j"; - sha512 = "48fa023c57294b73b9bd2f53e3dd3169e03426e5b3aa9d80e1bb1a9abf927fc26ef9f64d02b9769d5577d83094d0f41f044d35bb3b4f6037d66d6b2f19b484a1"; - version = "2.0.0-alpha4"; - - }; - paths = [ src ]; - } - - rec { - name = "ring-core/ring"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "ring-core"; - groupId = "ring"; - sha512 = "38d7214a3fc1b80ab55999036638dd1971272e01bec4cb8e0ee0a4aa83f51b8c41ba8a5850b0660227f067d2f9c6d75c0c0737725ea02762bbf8d192dc72febe"; - version = "1.9.4"; - - }; - paths = [ src ]; - } - - rec { - name = "cambium.core/cambium"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "cambium.core"; - groupId = "cambium"; - sha512 = "0e1fe626c6d0b31aad84ea2e4466273065925548ee5915f442b7997ebfe795faea36dbeac50a0f8c16bbd20d877511e3f8c4ff4f2b916a4538513aaa5cc20112"; - version = "1.1.1"; - - }; - paths = [ src ]; - } - - rec { - name = "medley/medley"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "medley"; - groupId = "medley"; - sha512 = "749ef43b5ea2cae7dc96db871cdd15c7b3c9cfbd96828c20ab08e67d39a5e938357d15994d8d413bc68678285d6c666f2a7296fbf305706d03b3007254e3c55c"; - version = "1.3.0"; - - }; - paths = [ src ]; - } - - rec { - name = "garden/garden"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "garden"; - groupId = "garden"; - sha512 = "2cc29f071b68bf451835f76de351ac2efb930b5df9ca7237fdca439d3c4d797d7fa207a147886efe1738ab1c50b76c1e366bf9ffcd6f286b0b211260aedd0b25"; - version = "1.3.10"; - - }; - paths = [ src ]; - } - - rec { - name = "jackson-dataformat-smile/com.fasterxml.jackson.dataformat"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jackson-dataformat-smile"; - groupId = "com.fasterxml.jackson.dataformat"; - sha512 = "69676964a2b09516b8ffd0d847b6f9a9b843424185453731b548c25e7e9ce30e808c56d66923f9183e2b5c1ba007421b146a6806e768b8e6b07470d60227f1dd"; - version = "2.12.4"; - - }; - paths = [ src ]; - } - - rec { - name = "jaxb-api/javax.xml.bind"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "jaxb-api"; - groupId = "javax.xml.bind"; - sha512 = "0c5bfc2c9f655bf5e6d596e0c196dcb9344d6dc78bf774207c8f8b6be59f69addf2b3121e81491983eff648dfbd55002b9878132de190825dad3ef3a1265b367"; - version = "2.3.0"; - - }; - paths = [ src ]; - } - - rec { - name = "pgjdbc-ng/com.impossibl.pgjdbc-ng"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "pgjdbc-ng"; - groupId = "com.impossibl.pgjdbc-ng"; - sha512 = "a34ac9146257329f6e9b354f13f564c65dbea6463addae383e3918d3a64c90c67f5f7fda6b5c3866de991a568d6690edb3fb09f2507593390a6e30ec0c79e02c"; - version = "0.8.9"; - - }; - paths = [ src ]; - } - - rec { - name = "http-kit/http-kit"; - src = fetchMavenArtifact { - inherit repos; - artifactId = "http-kit"; - groupId = "http-kit"; - sha512 = "4186a2429984745e18730aa8fd545f1fc1812083819ebf77aecfc04e0d31585358a5e25a308c7f21d81359418bbc72390c281f5ed91ae116cf1af79860ba22c3"; - version = "2.5.3"; - - }; - paths = [ src ]; - } - - ]; -} - \ No newline at end of file diff --git a/users/aspen/bbbg/env/dev/bbbg-signup/env.clj b/users/aspen/bbbg/env/dev/bbbg-signup/env.clj deleted file mode 100644 index c30e328ff..000000000 --- a/users/aspen/bbbg/env/dev/bbbg-signup/env.clj +++ /dev/null @@ -1,3 +0,0 @@ -(ns bbbg.env) - -(def environment :env/dev) diff --git a/users/aspen/bbbg/env/dev/logback.xml b/users/aspen/bbbg/env/dev/logback.xml deleted file mode 100644 index 7aa21978b..000000000 --- a/users/aspen/bbbg/env/dev/logback.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg { %mdc }%n - - - - - - - - - - diff --git a/users/aspen/bbbg/env/prod/bbbg-signup/env.clj b/users/aspen/bbbg/env/prod/bbbg-signup/env.clj deleted file mode 100644 index 46e8cd67e..000000000 --- a/users/aspen/bbbg/env/prod/bbbg-signup/env.clj +++ /dev/null @@ -1,3 +0,0 @@ -(ns bbbg.env) - -(def environment :env/prod) diff --git a/users/aspen/bbbg/env/prod/logback.xml b/users/aspen/bbbg/env/prod/logback.xml deleted file mode 100644 index b81118ed6..000000000 --- a/users/aspen/bbbg/env/prod/logback.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - INFO - - - - - false - - - yyyy-MM-dd'T'HH:mm:ss.SSS'Z' - UTC - true - - - - - - - - - - - diff --git a/users/aspen/bbbg/env/test/bbbg-signup/env.clj b/users/aspen/bbbg/env/test/bbbg-signup/env.clj deleted file mode 100644 index 352147a6d..000000000 --- a/users/aspen/bbbg/env/test/bbbg-signup/env.clj +++ /dev/null @@ -1,3 +0,0 @@ -(ns bbbg.env) - -(def environment :env/test) diff --git a/users/aspen/bbbg/env/test/logback.xml b/users/aspen/bbbg/env/test/logback.xml deleted file mode 100644 index 8554f3d0e..000000000 --- a/users/aspen/bbbg/env/test/logback.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - %msg%n - - - - - - diff --git a/users/aspen/bbbg/module.nix b/users/aspen/bbbg/module.nix deleted file mode 100644 index c5bacdf4d..000000000 --- a/users/aspen/bbbg/module.nix +++ /dev/null @@ -1,137 +0,0 @@ -{ config, lib, pkgs, depot, ... }: - -let - bbbg = depot.users.aspen.bbbg; - cfg = config.services.bbbg; -in -{ - options = with lib; { - services.bbbg = { - enable = mkEnableOption "BBBG Server"; - - port = mkOption { - type = types.int; - default = 7222; - description = "Port to listen to for the HTTP server"; - }; - - domain = mkOption { - type = types.str; - default = "bbbg.gws.fyi"; - description = "Domain to host under"; - }; - - proxy = { - enable = mkEnableOption "NGINX reverse proxy"; - }; - - database = { - enable = mkEnableOption "BBBG Database Server"; - - user = mkOption { - type = types.str; - default = "bbbg"; - description = "Database username"; - }; - - host = mkOption { - type = types.str; - default = "localhost"; - description = "Database host"; - }; - - name = mkOption { - type = types.str; - default = "bbbg"; - description = "Database name"; - }; - - port = mkOption { - type = types.int; - default = 5432; - description = "Database host"; - }; - }; - }; - }; - - config = lib.mkMerge [ - (lib.mkIf cfg.enable { - systemd.services.bbbg-server = { - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - serviceConfig = { - DynamicUser = true; - Restart = "always"; - EnvironmentFile = config.age.secretsDir + "/bbbg"; - }; - - environment = { - PGHOST = cfg.database.host; - PGUSER = cfg.database.user; - PGDATABASE = cfg.database.name; - PORT = toString cfg.port; - BASE_URL = "https://${cfg.domain}"; - }; - - script = "${bbbg.server}/bin/bbbg-server"; - }; - - systemd.services.migrate-bbbg = { - description = "Run database migrations for BBBG"; - wantedBy = [ "bbbg-server.service" ]; - after = ([ "network.target" ] - ++ (if cfg.database.enable - then [ "postgresql.service" ] - else [ ])); - - serviceConfig = { - Type = "oneshot"; - EnvironmentFile = config.age.secretsDir + "/bbbg"; - }; - - environment = { - PGHOST = cfg.database.host; - PGUSER = cfg.database.user; - PGDATABASE = cfg.database.name; - }; - - script = "${bbbg.db-util}/bin/bbbg-db-util migrate"; - }; - }) - (lib.mkIf cfg.database.enable { - services.postgresql = { - enable = true; - authentication = lib.mkForce '' - local all all trust - host all all 127.0.0.1/32 password - host all all ::1/128 password - hostnossl all all 127.0.0.1/32 password - hostnossl all all ::1/128 password - ''; - - ensureDatabases = [ - cfg.database.name - ]; - - ensureUsers = [{ - name = cfg.database.user; - ensurePermissions = { - "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; - }; - }]; - }; - }) - (lib.mkIf cfg.proxy.enable { - services.nginx = { - enable = true; - virtualHosts."${cfg.domain}" = { - enableACME = true; - forceSSL = true; - locations."/".proxyPass = "http://localhost:${toString cfg.port}"; - }; - }; - }) - ]; -} diff --git a/users/aspen/bbbg/pom.xml b/users/aspen/bbbg/pom.xml deleted file mode 100644 index 012c0985f..000000000 --- a/users/aspen/bbbg/pom.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - 4.0.0 - fyi.gws - bbbg - 0.1.0-SNAPSHOT - fyi.gws/bbbg - webhook listener for per-branch deploys - https://bbbg.gws.fyi - - - Griffin Smith - - - - - org.clojure - clojure - 1.11.0-alpha3 - - - - src - - - - clojars - https://repo.clojars.org/ - - - sonatype - https://oss.sonatype.org/content/repositories/snapshots/ - - - - - clojars - Clojars repository - https://clojars.org/repo - - - diff --git a/users/aspen/bbbg/resources/base.css b/users/aspen/bbbg/resources/base.css deleted file mode 100644 index c86c3f24f..000000000 --- a/users/aspen/bbbg/resources/base.css +++ /dev/null @@ -1,152 +0,0 @@ -/* montserrat-italic - latin */ -@font-face { - font-family: "Montserrat"; - font-style: italic; - font-weight: 400; - src: local("Montserrat Italic"), local("Montserrat-Italic"), - url("/fonts/montserrat-v15-latin-italic.woff2") format("woff2"), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url("/fonts/montserrat-v15-latin-italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ -} - -/* montserrat-regular - latin */ -@font-face { - font-family: "Montserrat"; - font-style: normal; - font-weight: 400; - src: local("Montserrat Regular"), local("Montserrat-Regular"), - url("/fonts/montserrat-v15-latin-regular.woff2") format("woff2"), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url("/fonts/montserrat-v15-latin-regular.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ -} - -/* montserrat-500 - latin */ -@font-face { - font-family: "Montserrat"; - font-style: normal; - font-weight: 500; - src: local("Montserrat Medium"), local("Montserrat-Medium"), - url("/fonts/montserrat-v15-latin-500.woff2") format("woff2"), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url("/fonts/montserrat-v15-latin-500.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ -} - -/* montserrat-500italic - latin */ -@font-face { - font-family: "Montserrat"; - font-style: italic; - font-weight: 500; - src: local("Montserrat Medium Italic"), local("Montserrat-MediumItalic"), - url("/fonts/montserrat-v15-latin-500italic.woff2") format("woff2"), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url("/fonts/montserrat-v15-latin-500italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ -} - -/* montserrat-600 - latin */ -@font-face { - font-family: "Montserrat"; - font-style: normal; - font-weight: 600; - src: local("Montserrat SemiBold"), local("Montserrat-SemiBold"), - url("/fonts/montserrat-v15-latin-600.woff2") format("woff2"), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url("/fonts/montserrat-v15-latin-600.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ -} - -/* montserrat-800 - latin */ -@font-face { - font-family: "Montserrat"; - font-style: normal; - font-weight: 800; - src: local("Montserrat ExtraBold"), local("Montserrat-ExtraBold"), - url("/fonts/montserrat-v15-latin-800.woff2") format("woff2"), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url("/fonts/montserrat-v15-latin-800.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ -} - -/* montserrat-800italic - latin */ -@font-face { - font-family: "Montserrat"; - font-style: italic; - font-weight: 800; - src: local("Montserrat ExtraBold Italic"), local("Montserrat-ExtraBoldItalic"), - url("/fonts/montserrat-v15-latin-800italic.woff2") format("woff2"), - /* Chrome 26+, Opera 23+, Firefox 39+ */ - url("/fonts/montserrat-v15-latin-800italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ -} - -body { - width: 100%; - font-family: "Montserrat", Helvetica, sans-serif; - margin: 0; - box-sizing: border-box; -} - -*, -::before, -::after { - box-sizing: border-box; -} - -ul, -ol { - padding: 0; -} - -body, -h1, -h2, -h3, -h4, -p, -ul, -ol, -li, -figure, -figcaption, -blockquote, -dl, -dd { - margin: 0; -} - -body { - min-height: 100vh; - scroll-behavior: smooth; - text-rendering: optimizeSpeed; - line-height: 1.5; -} - -ul[class], -ol[class] { - list-style: none; -} - -a:not([class]) { - text-decoration-skip-ink: auto; -} - -img { - max-width: 100%; - display: block; -} - -article > * + * { - margin-top: 1em; -} - -input, -button, -textarea, -select { - font: inherit; -} - -@media (prefers-reduced-motion: reduce) { - * { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - scroll-behavior: auto !important; - } -} diff --git a/users/aspen/bbbg/resources/migrations/20211212165646-init-schema.down.sql b/users/aspen/bbbg/resources/migrations/20211212165646-init-schema.down.sql deleted file mode 100644 index 69b818a4f..000000000 --- a/users/aspen/bbbg/resources/migrations/20211212165646-init-schema.down.sql +++ /dev/null @@ -1,14 +0,0 @@ -drop table "public"."user"; - --- ;; - -drop table "public"."event_attendee"; - - --- ;; - -drop table "public"."event"; - --- ;; - -drop table "public"."attendee"; diff --git a/users/aspen/bbbg/resources/migrations/20211212165646-init-schema.up.sql b/users/aspen/bbbg/resources/migrations/20211212165646-init-schema.up.sql deleted file mode 100644 index 9718d8474..000000000 --- a/users/aspen/bbbg/resources/migrations/20211212165646-init-schema.up.sql +++ /dev/null @@ -1,32 +0,0 @@ -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; --- ;; -CREATE TABLE "attendee" ( - "id" UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), - "meetup_name" TEXT NOT NULL, - "discord_name" TEXT, - "meetup_user_id" TEXT, - "organizer_notes" TEXT NOT NULL DEFAULT '', - "created_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now() -); --- ;; -CREATE TABLE "event" ( - "id" UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), - "date" DATE NOT NULL, - "created_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now() -); --- ;; -CREATE TABLE "event_attendee" ( - "event_id" UUID NOT NULL REFERENCES "event" ("id"), - "attendee_id" UUID NOT NULL REFERENCES "attendee" ("id"), - "rsvpd_attending" BOOL, - "attended" BOOL, - "created_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(), - PRIMARY KEY ("event_id", "attendee_id") -); --- ;; -CREATE TABLE "user" ( - "id" UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), - "username" TEXT NOT NULL, - "discord_user_id" TEXT NOT NULL, - "created_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now() -); diff --git a/users/aspen/bbbg/resources/migrations/20211220002229-add-attendee-checks.down.sql b/users/aspen/bbbg/resources/migrations/20211220002229-add-attendee-checks.down.sql deleted file mode 100644 index 936abf6c7..000000000 --- a/users/aspen/bbbg/resources/migrations/20211220002229-add-attendee-checks.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE "attendee_check"; diff --git a/users/aspen/bbbg/resources/migrations/20211220002229-add-attendee-checks.up.sql b/users/aspen/bbbg/resources/migrations/20211220002229-add-attendee-checks.up.sql deleted file mode 100644 index 5e82dcb17..000000000 --- a/users/aspen/bbbg/resources/migrations/20211220002229-add-attendee-checks.up.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE attendee_check ( - "id" UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(), - "attendee_id" UUID NOT NULL REFERENCES attendee ("id"), - "user_id" UUID NOT NULL REFERENCES "public"."user" ("id"), - "last_dose_at" DATE, - "checked_at" TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now() -); diff --git a/users/aspen/bbbg/resources/migrations/20211224161028-add-attendee-unique-meetup-id.down.sql b/users/aspen/bbbg/resources/migrations/20211224161028-add-attendee-unique-meetup-id.down.sql deleted file mode 100644 index cbee0c00a..000000000 --- a/users/aspen/bbbg/resources/migrations/20211224161028-add-attendee-unique-meetup-id.down.sql +++ /dev/null @@ -1 +0,0 @@ -drop index attendee_uniq_meetup_user_id; diff --git a/users/aspen/bbbg/resources/migrations/20211224161028-add-attendee-unique-meetup-id.up.sql b/users/aspen/bbbg/resources/migrations/20211224161028-add-attendee-unique-meetup-id.up.sql deleted file mode 100644 index 5895cad56..000000000 --- a/users/aspen/bbbg/resources/migrations/20211224161028-add-attendee-unique-meetup-id.up.sql +++ /dev/null @@ -1,2 +0,0 @@ -create unique index "attendee_uniq_meetup_user_id" on attendee (meetup_user_id); --- ;; diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500.woff b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500.woff deleted file mode 100644 index 1c83d8518..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500.woff and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500.woff2 b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500.woff2 deleted file mode 100644 index 9dc5c7f15..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500.woff2 and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500italic.woff b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500italic.woff deleted file mode 100644 index 71476d858..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500italic.woff and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500italic.woff2 b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500italic.woff2 deleted file mode 100644 index 0fb9838c9..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-500italic.woff2 and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-600.woff b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-600.woff deleted file mode 100644 index e7f8a31ba..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-600.woff and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-600.woff2 b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-600.woff2 deleted file mode 100644 index 29cc1a973..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-600.woff2 and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800.woff b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800.woff deleted file mode 100644 index 79203dd78..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800.woff and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800.woff2 b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800.woff2 deleted file mode 100644 index 0abb707ae..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800.woff2 and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800italic.woff b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800italic.woff deleted file mode 100644 index 65415571a..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800italic.woff and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800italic.woff2 b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800italic.woff2 deleted file mode 100644 index 674e6eabe..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-800italic.woff2 and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-italic.woff b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-italic.woff deleted file mode 100644 index 67f1e8537..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-italic.woff and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-italic.woff2 b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-italic.woff2 deleted file mode 100644 index 469aede09..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-italic.woff2 and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-regular.woff b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-regular.woff deleted file mode 100644 index 676a065e2..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-regular.woff and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-regular.woff2 b/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-regular.woff2 deleted file mode 100644 index 70788c273..000000000 Binary files a/users/aspen/bbbg/resources/public/fonts/montserrat-v15-latin-regular.woff2 and /dev/null differ diff --git a/users/aspen/bbbg/resources/public/main.js b/users/aspen/bbbg/resources/public/main.js deleted file mode 100644 index 87c0b64d0..000000000 --- a/users/aspen/bbbg/resources/public/main.js +++ /dev/null @@ -1,73 +0,0 @@ -window.onload = () => { - const input = document.getElementById("name-autocomplete"); - if (input != null) { - const attendeeList = document.getElementById("attendees-list"); - const filterAttendees = (filter) => { - if (filter == "") { - for (let elt of attendeeList.querySelectorAll("li")) { - elt.classList.remove("hidden"); - } - - return; - } - - let re = ""; - for (let c of filter) { - re += `${c}.*`; - } - let filterRe = new RegExp(re, "i"); - - for (let elt of attendeeList.querySelectorAll("li")) { - const attendee = JSON.parse(elt.dataset.attendee); - if (attendee["bbbg.attendee/meetup-name"].match(filterRe) == null) { - elt.classList.add("hidden"); - } else { - elt.classList.remove("hidden"); - } - } - }; - - const attendeeIDInput = document.getElementById("attendee-id"); - const submit = document.querySelector("#submit-button"); - const signupForm = document.getElementById("signup-form"); - - input.oninput = (e) => { - filterAttendees(e.target.value); - attendeeIDInput.value = null; - submit.classList.add("hidden"); - submit.setAttribute("disabled", "disabled"); - signupForm.setAttribute("disabled", "disabled"); - }; - - attendeeList.addEventListener("click", (e) => { - if (!(e.target instanceof HTMLLIElement)) { - return; - } - if (e.target.dataset.attendee == null) { - return; - } - - const attendee = JSON.parse(e.target.dataset.attendee); - input.value = attendee["bbbg.attendee/meetup-name"]; - attendeeIDInput.value = attendee["bbbg.attendee/id"]; - - submit.classList.remove("hidden"); - submit.removeAttribute("disabled"); - signupForm.removeAttribute("disabled"); - }); - } - - document.querySelectorAll("form").forEach((form) => { - form.addEventListener("submit", (e) => { - if (e.target.attributes.disabled) { - e.preventDefault(); - } - - const confirmMessage = e.target.dataset.confirm; - if (confirmMessage != null && !confirm(confirmMessage)) { - e.stopImmediatePropagation(); - e.preventDefault(); - } - }); - }); -}; diff --git a/users/aspen/bbbg/resources/public/robots.txt b/users/aspen/bbbg/resources/public/robots.txt deleted file mode 100644 index 1f53798bb..000000000 --- a/users/aspen/bbbg/resources/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/users/aspen/bbbg/shell.nix b/users/aspen/bbbg/shell.nix deleted file mode 100644 index c253a2b9b..000000000 --- a/users/aspen/bbbg/shell.nix +++ /dev/null @@ -1,29 +0,0 @@ -let - depot = import ../../.. { }; -in -with depot.third_party.nixpkgs; - -mkShell { - buildInputs = [ - arion - depot.third_party.clj2nix - clojure - openjdk11_headless - postgresql_12 - nix-prefetch-git - (writeShellScriptBin "terraform" '' - set -e - module=$(nix-build ~/code/depot -A users.grfn.bbbg.tf.module) - rm -f ~/tfstate/bbbg/*.json - cp ''${module}/*.json ~/tfstate/bbbg - exec ${depot.users.aspen.bbbg.tf.terraform}/bin/terraform \ - -chdir=/home/grfn/tfstate/bbbg \ - "$@" - '') - ]; - - PGHOST = "localhost"; - PGUSER = "bbbg"; - PGDATABASE = "bbbg"; - PGPASSWORD = "password"; -} diff --git a/users/aspen/bbbg/src/bbbg/attendee.clj b/users/aspen/bbbg/src/bbbg/attendee.clj deleted file mode 100644 index 49a6d621d..000000000 --- a/users/aspen/bbbg/src/bbbg/attendee.clj +++ /dev/null @@ -1,10 +0,0 @@ -(ns bbbg.attendee - (:require [clojure.spec.alpha :as s])) - -(s/def ::id uuid?) - -(s/def ::meetup-name (s/and string? seq)) - -(s/def ::discord-name (s/nilable string?)) - -(s/def ::organizer-notes string?) diff --git a/users/aspen/bbbg/src/bbbg/attendee_check.clj b/users/aspen/bbbg/src/bbbg/attendee_check.clj deleted file mode 100644 index f34c41198..000000000 --- a/users/aspen/bbbg/src/bbbg/attendee_check.clj +++ /dev/null @@ -1,4 +0,0 @@ -(ns bbbg.attendee-check - (:require [clojure.spec.alpha :as s])) - -(s/def ::id uuid?) diff --git a/users/aspen/bbbg/src/bbbg/core.clj b/users/aspen/bbbg/src/bbbg/core.clj deleted file mode 100644 index 632774d5c..000000000 --- a/users/aspen/bbbg/src/bbbg/core.clj +++ /dev/null @@ -1,69 +0,0 @@ -(ns bbbg.core - (:gen-class) - (:require - [bbbg.db :as db] - [bbbg.web :as web] - [clojure.spec.alpha :as s] - [clojure.spec.test.alpha :as stest] - [com.stuartsierra.component :as component] - [expound.alpha :as exp])) - -(s/def ::config - (s/merge - ::db/config - ::web/config)) - -(defn make-system [config] - (component/system-map - :db (db/make-database config) - :web (web/make-server config))) - -(defn env->config [] - (s/assert - ::config - (merge - (db/env->config) - (web/env->config)))) - -(defn dev-config [] - (s/assert - ::config - (merge - (db/dev-config) - (web/dev-config)))) - -(defonce system nil) - -(defn init-dev [] - (s/check-asserts true) - (set! s/*explain-out* exp/printer) - (stest/instrument)) - -(defn run-dev [] - (init-dev) - (alter-var-root - #'system - (fn [sys] - (when sys - (component/start sys)) - (component/start (make-system (dev-config)))))) - -(defn -main [& _args] - (alter-var-root - #'system - (constantly (component/start (make-system (env->config)))))) - -(comment - ;; To run the application: - ;; 1. `M-x cider-jack-in` - ;; 2. `M-x cider-load-buffer` in this buffer - ;; 3. (optionally) configure the secrets backend in `bbbg.util.dev-secrets` - ;; 4. Put your cursor after the following form and run `M-x cider-eval-last-sexp` - ;; - ;; A web server will be listening on http://localhost:8888 - - (do - (run-dev) - (bbbg.db/migrate! (:db system))) - - ) diff --git a/users/aspen/bbbg/src/bbbg/db.clj b/users/aspen/bbbg/src/bbbg/db.clj deleted file mode 100644 index 5bbf88925..000000000 --- a/users/aspen/bbbg/src/bbbg/db.clj +++ /dev/null @@ -1,366 +0,0 @@ -(ns bbbg.db - (:gen-class) - (:refer-clojure :exclude [get list count]) - (:require [camel-snake-kebab.core :as csk :refer [->kebab-case ->snake_case]] - [bbbg.util.core :as u] - [clojure.set :as set] - [clojure.spec.alpha :as s] - [clojure.string :as str] - [com.stuartsierra.component :as component] - [config.core :refer [env]] - [honeysql.format :as hformat] - [migratus.core :as migratus] - [next.jdbc :as jdbc] - [next.jdbc.connection :as jdbc.conn] - next.jdbc.date-time - [next.jdbc.optional :as jdbc.opt] - [next.jdbc.result-set :as rs] - [next.jdbc.sql :as sql]) - (:import [com.impossibl.postgres.jdbc PGSQLSimpleException] - com.zaxxer.hikari.HikariDataSource - [java.sql Connection ResultSet Types] - javax.sql.DataSource)) - -(s/def ::host string?) -(s/def ::database string?) -(s/def ::user string?) -(s/def ::password string?) - -(s/def ::config - (s/keys :opt [::host - ::database - ::user - ::password])) - -(s/fdef make-database - :args - (s/cat :config (s/keys :opt [::config]))) - -(s/fdef env->config :ret ::config) - -(s/def ::db any?) - -;;; - -(def default-config - (s/assert - ::config - {::host "localhost" - ::database "bbbg" - ::user "bbbg" - ::password "password"})) - -(defn dev-config [] default-config) - -(defn env->config [] - (->> - {::host (:pghost env) - ::database (:pgdatabase env) - ::user (:pguser env) - ::password (:pgpassword env)} - u/remove-nils - (s/assert ::config))) - -(defn ->db-spec [config] - (-> default-config - (merge config) - (set/rename-keys - {::host :host - ::database :dbname - ::user :username - ::password :password}) - (assoc :dbtype "pgsql"))) - -(defn connection - "Make a one-off connection from the given `::config` map, or the environment - if not provided" - ([] (connection (env->config))) - ([config] - (-> config - ->db-spec - (set/rename-keys {:username :user}) - jdbc/get-datasource - jdbc/get-connection))) - -(defrecord Database [config] - component/Lifecycle - (start [this] - (assoc this :pool (jdbc.conn/->pool HikariDataSource (->db-spec config)))) - (stop [this] - (some-> this :pool .close) - (dissoc this :pool)) - - clojure.lang.IFn - (invoke [this] (:pool this))) - -(defn make-database [config] - (map->Database {:config config})) - -(defn database? [x] - (or - (instance? Database x) - (and (map? x) (contains? x :pool)))) - -;;; -;;; Migrations -;;; - -(defn migratus-config - [db] - {:store :database - :migration-dir "migrations/" - :migration-table-name "__migrations__" - :db - (let [db (if (ifn? db) (db) db)] - (cond - (.isInstance Connection db) - {:connection db} - (.isInstance DataSource db) - {:datasource db} - :else (throw - (ex-info "migratus-config called with value of unrecognized type" - {:value db}))))}) - -(defn generate-migration - ([db name] (generate-migration db name :sql)) - ([db name type] (migratus/create (migratus-config db) name type))) - -(defn migrate! - [db] (migratus/migrate (migratus-config db))) - -(defn rollback! - [db] (migratus/rollback (migratus-config db))) - -;;; -;;; Database interaction -;;; - -(defn ->key-ns [tn] - (let [tn (name tn) - tn (if (str/starts-with? tn "public.") - (second (str/split tn #"\." 2)) - tn)] - (str "bbbg." (->kebab-case tn)))) - -(defn ->table-name [kns] - (let [kns (name kns)] - (->snake_case - (if (str/starts-with? kns "public.") - kns - (str "public." (last (str/split kns #"\."))))))) - -(defn ->column - ([col] (->column nil col)) - ([table col] - (let [col-table (some-> col namespace ->table-name) - snake-col (-> col name ->snake_case (str/replace #"\?$" ""))] - (if (or (not (namespace col)) - (not table) - (= (->table-name table) col-table)) - snake-col - ;; different table, assume fk - (str - (str/replace-first col-table "public." "") - "_" - snake-col))))) - -(defn ->value [v] - (if (keyword? v) - (-> v name csk/->snake_case_string) - v)) - -(defn process-key-map [table key-map] - (into {} - (map (fn [[k v]] [(->column table k) - (->value v)])) - key-map)) - -(defn fkize [col] - (if (str/ends-with? col "-id") - (let [table (str/join "-" (butlast (str/split (name col) #"-")))] - (keyword (->key-ns table) "id")) - col)) - -(def ^:private enum-members-cache (atom {})) -(defn- enum-members - "Returns a set of enum members as strings for the enum with the given name" - [db name] - (if-let [e (find @enum-members-cache name)] - (val e) - (let [r (try - (-> (jdbc/execute-one! - (db) - [(format "select enum_range(null::%s) as members" name)]) - :members - .getArray - set) - (catch PGSQLSimpleException _ - nil))] - (swap! enum-members-cache assoc name r) - r))) - -(def ^{:private true - :dynamic true} - *meta-db* - "Database connection to use to query metadata" - nil) - -(extend-protocol rs/ReadableColumn - String - (read-column-by-label [x _] x) - (read-column-by-index [x rsmeta idx] - (if-not *meta-db* - x - (let [typ (.getColumnTypeName rsmeta idx)] - ;; TODO: Is there a better way to figure out if a type is an enum? - (if (enum-members *meta-db* typ) - (keyword (csk/->kebab-case-string typ) - (csk/->kebab-case-string x)) - x))))) - -(comment - (->key-ns :public.user) - (->key-ns :public.api-token) - (->key-ns :api-token) - (->table-name :api-token) - (->table-name :public.user) - (->table-name :bbbg.user) - ) - -(defn as-fq-maps [^ResultSet rs _opts] - (let [qualify #(when (seq %) (str "bbbg." (->kebab-case %))) - rsmeta (.getMetaData rs) - cols (mapv - (fn [^Integer i] - (let [ty (.getColumnType rsmeta i) - lab (.getColumnLabel rsmeta i) - n (str (->kebab-case lab) - (when (= ty Types/BOOLEAN) "?"))] - (fkize - (if-let [q (some-> rsmeta (.getTableName i) qualify not-empty)] - (keyword q n) - (keyword n))))) - (range 1 (inc (.getColumnCount rsmeta))))] - (jdbc.opt/->MapResultSetOptionalBuilder rs rsmeta cols))) - -(def jdbc-opts - {:builder-fn as-fq-maps - :column-fn ->snake_case - :table-fn ->snake_case}) - -(defmethod hformat/fn-handler "count-distinct" [_ field] - (str "count(distinct " (hformat/to-sql field) ")")) - -(defn fetch - "Fetch a single row from the db matching the given `sql-map` or query" - [db sql-map & [opts]] - (s/assert - (s/nilable (s/keys)) - (binding [*meta-db* db] - (jdbc/execute-one! - (db) - (if (map? sql-map) - (hformat/format sql-map) - sql-map) - (merge jdbc-opts opts))))) - -(defn get - "Retrieve a single record from the given table by ID" - [db table id & [opts]] - (when id - (fetch - db - {:select [:*] - :from [table] - :where [:= :id id]} - opts))) - -(defn list - "Returns a list of rows from the db matching the given sql-map, table or - query" - [db sql-map-or-table & [opts]] - (s/assert - (s/coll-of (s/keys)) - (binding [*meta-db* db] - (jdbc/execute! - (db) - (cond - (map? sql-map-or-table) - (hformat/format sql-map-or-table) - (keyword? sql-map-or-table) - (hformat/format {:select [:*] :from [sql-map-or-table]}) - :else - sql-map-or-table) - (merge jdbc-opts opts))))) - -(defn count - [db sql-map] - (binding [*meta-db* db] - (:count - (fetch db {:select [[:%count.* :count]], :from [[sql-map :sq]]})))) - -(defn exists? - "Returns true if the given sql query-map would return any results" - [db sql-map] - (binding [*meta-db* db] - (pos? - (count db sql-map)))) - -(defn execute! - "Given a database and a honeysql query map, perform an operation on the - database and discard the results" - [db sql-map & [opts]] - (jdbc/execute! - (db) - (hformat/format sql-map) - (merge jdbc-opts opts))) - -(defn insert! - "Given a database, a table name, and a data hash map, inserts the - data as a single row in the database and attempts to return a map of generated - keys." - [db table key-map & [opts]] - (binding [*meta-db* db] - (sql/insert! - (db) - table - (process-key-map table key-map) - (merge jdbc-opts opts)))) - -(defn update! - "Given a database, a table name, a hash map of columns and values - to set, and a honeysql predicate, perform an update on the table. - Will " - [db table key-map where-params & [opts]] - (binding [*meta-db* db] - (execute! db - {:update table - :set (u/map-keys keyword (process-key-map table key-map)) - :where where-params - :returning [:id]} - opts))) - -(defn delete! - "Delete all rows from the given table matching the given where clause" - [db table where-clause] - (binding [*meta-db* db] - (sql/delete! (db) table (hformat/format-predicate where-clause)))) - -(defmacro with-transaction [[sym db opts] & body] - `(jdbc/with-transaction - [tx# (~db) ~opts] - (let [~sym (constantly tx#)] - ~@body))) - -(defn -main [& args] - (let [db (component/start (make-database (env->config)))] - (case (first args) - "migrate" (migrate! db) - "rollback" (rollback! db)))) - -(comment - (def db (:db bbbg.core/system)) - (generate-migration db "add-attendee-unique-meetup-id") - (migrate! db) - - ) diff --git a/users/aspen/bbbg/src/bbbg/db/attendee.clj b/users/aspen/bbbg/src/bbbg/db/attendee.clj deleted file mode 100644 index da5ee2932..000000000 --- a/users/aspen/bbbg/src/bbbg/db/attendee.clj +++ /dev/null @@ -1,85 +0,0 @@ -(ns bbbg.db.attendee - (:require - [bbbg.attendee :as attendee] - [bbbg.db :as db] - [bbbg.util.sql :refer [count-where]] - honeysql-postgres.helpers - [honeysql.helpers - :refer - [merge-group-by merge-join merge-left-join merge-select merge-where]] - [bbbg.util.core :as u])) - -(defn search - ([q] (search {:select [:attendee.*] :from [:attendee]} q)) - ([db-or-query q] - (if (db/database? db-or-query) - (db/list db-or-query (search q)) - (cond-> db-or-query - q (merge-where - [:or - [:ilike :meetup_name (str "%" q "%")] - [:ilike :discord_name (str "%" q "%")]])))) - ([db query q] - (db/list db (search query q)))) - -(defn for-event - ([event-id] - (for-event {:select [:attendee.*] - :from [:attendee]} - event-id)) - ([db-or-query event-id] - (if (db/database? db-or-query) - (db/list db-or-query (for-event event-id)) - (-> db-or-query - (merge-select :event-attendee.*) - (merge-join :event_attendee [:= :attendee.id :event_attendee.attendee_id]) - (merge-where [:= :event_attendee.event_id event-id])))) - ([db query event-id] - (db/list db (for-event query event-id)))) - -(defn with-stats - ([] (with-stats {:select [:attendee.*] - :from [:attendee]})) - ([query] - (-> query - (merge-left-join :event_attendee [:= :attendee.id :event_attendee.attendee_id]) - (merge-group-by :attendee.id) - (merge-select - [(count-where :event_attendee.rsvpd_attending) :events-rsvpd] - [(count-where :event_attendee.attended) :events-attended] - [(count-where [:and - :event_attendee.rsvpd_attending - [:not :event_attendee.attended]]) - :no-shows])))) - -(defn upsert-all! - [db attendees] - (when (seq attendees) - (db/list - db - {:insert-into :attendee - :values (map #(->> % - (db/process-key-map :attendee) - (u/map-keys keyword)) - attendees) - :upsert {:on-conflict [:meetup-user-id] - :do-update-set [:meetup-name]} - :returning [:id :meetup-user-id]}))) - -(comment - (def db (:db bbbg.core/system)) - (db/database? db) - (search db "gri") - (db/insert! db :attendee {::attendee/meetup-name "Griffin Smith" - ::attendee/discord-name "grfn" - }) - - (search db (with-stats) "gri") - - (search (with-stats) "gri") - - (db/list db (with-stats)) - - (db/insert! db :attendee {::attendee/meetup-name "Rando Guy" - ::attendee/discord-name "rando"}) - ) diff --git a/users/aspen/bbbg/src/bbbg/db/attendee_check.clj b/users/aspen/bbbg/src/bbbg/db/attendee_check.clj deleted file mode 100644 index 492f786bd..000000000 --- a/users/aspen/bbbg/src/bbbg/db/attendee_check.clj +++ /dev/null @@ -1,55 +0,0 @@ -(ns bbbg.db.attendee-check - (:require - [bbbg.attendee :as attendee] - [bbbg.attendee-check :as attendee-check] - [bbbg.db :as db] - [bbbg.user :as user] - [bbbg.util.core :as u])) - -(defn create! [db params] - (db/insert! db :attendee-check - (select-keys params [::attendee/id - ::user/id - ::attendee-check/last-dose-at]))) - -(defn attendees-with-last-checks - [db attendees] - (when (seq attendees) - (let [ids (map ::attendee/id attendees) - checks - (db/list db {:select [:attendee-check.*] - :from [:attendee-check] - :join [[{:select [:%max.attendee-check.checked-at - :attendee-check.attendee-id] - :from [:attendee-check] - :group-by [:attendee-check.attendee-id] - :where [:in :attendee-check.attendee-id ids]} - :last-check] - [:= - :attendee-check.attendee-id - :last-check.attendee-id]]}) - users (if (seq checks) - (u/key-by - ::user/id - (db/list db {:select [:public.user.*] - :from [:public.user] - :where [:in :id (map ::user/id checks)]})) - {}) - checks (map #(assoc % :user (users (::user/id %))) checks) - attendee-id->check (u/key-by ::attendee/id checks)] - (map #(assoc % :last-check (attendee-id->check (::attendee/id %))) - attendees)))) - -(comment - (def db (:db bbbg.core/system)) - - (attendees-with-last-checks - db - (db/list db :attendee) - ) - - (db/insert! db :attendee-check - {::attendee/id #uuid "58bcd372-ff6e-49df-b280-23d24c5ba0f0" - ::user/id #uuid "303fb606-5ef0-4682-ad7d-6429c670cd78" - ::attendee-check/last-dose-at "2021-12-19"}) - ) diff --git a/users/aspen/bbbg/src/bbbg/db/event.clj b/users/aspen/bbbg/src/bbbg/db/event.clj deleted file mode 100644 index 1b5a4e11e..000000000 --- a/users/aspen/bbbg/src/bbbg/db/event.clj +++ /dev/null @@ -1,94 +0,0 @@ -(ns bbbg.db.event - (:require - [bbbg.attendee :as attendee] - [bbbg.db :as db] - [bbbg.event :as event] - [bbbg.util.sql :refer [count-where]] - [honeysql.helpers - :refer [merge-group-by merge-left-join merge-select merge-where]] - [java-time :refer [local-date local-date-time local-time]])) - -(defn create! [db event] - (db/insert! db :event (select-keys event [::event/date]))) - -(defn attended! - [db params] - (db/execute! - db - {:insert-into :event-attendee - :values [{:event_id (::event/id params) - :attendee_id (::attendee/id params) - :attended true}] - :upsert {:on-conflict [:event-id :attendee-id] - :do-update-set! {:attended true}}})) - -(defn on-day - ([day] {:select [:event.*] - :from [:event] - :where [:= :date (str day)]}) - ([db day] - (db/list db (on-day day)))) - - -(def end-of-day-hour - ;; 7am utc = 3am nyc - 7) - -(defn current-day - ([] (current-day (local-date-time))) - ([dt] - (if (<= 0 - (.getHour (local-time dt)) - end-of-day-hour) - (java-time/minus - (local-date dt) - (java-time/days 1)) - (local-date dt)))) - -(comment - (current-day - (local-date-time - 2022 5 1 - 1 13 0)) - ) - -(defn today - ([] (on-day (current-day))) - ([db] (db/list db (today)))) - -(defn upcoming - ([] (upcoming {:select [:event.*] :from [:event]})) - ([query] - (merge-where query [:>= :date (local-date)]))) - -(defn past - ([] (past {:select [:event.*] :from [:event]})) - ([query] - (merge-where query [:< :date (local-date)]))) - -(defn with-attendee-counts - [query] - (-> query - (merge-left-join :event_attendee [:= :event.id :event_attendee.event-id]) - (merge-select :%count.event_attendee.attendee_id) - (merge-group-by :event.id :event_attendee.event-id))) - -(defn with-stats - [query] - (-> query - (merge-left-join :event_attendee [:= :event.id :event_attendee.event-id]) - (merge-select - [(count-where :event-attendee.rsvpd_attending) :num-rsvps] - [(count-where :event-attendee.attended) :num-attendees]) - (merge-group-by :event.id))) - -(comment - (def db (:db bbbg.core/system)) - (db/list db (-> (today) (with-attendee-counts))) - - (honeysql.format/format - (honeysql-postgres.helpers/upsert {:insert-into :foo - :values {:bar 1}} - (-> (honeysql-postgres.helpers/on-conflict :did) - (honeysql-postgres.helpers/do-update-set! [:did true])))) - ) diff --git a/users/aspen/bbbg/src/bbbg/db/event_attendee.clj b/users/aspen/bbbg/src/bbbg/db/event_attendee.clj deleted file mode 100644 index 31411e5d4..000000000 --- a/users/aspen/bbbg/src/bbbg/db/event_attendee.clj +++ /dev/null @@ -1,17 +0,0 @@ -(ns bbbg.db.event-attendee - (:require honeysql-postgres.format - [bbbg.db :as db] - [bbbg.util.core :as u])) - -(defn upsert-all! - [db attendees] - (when (seq attendees) - (db/execute! - db - {:insert-into :event-attendee - :values (map #(->> % - (db/process-key-map :event-attendee) - (u/map-keys keyword)) - attendees) - :upsert {:on-conflict [:event-id :attendee-id] - :do-update-set [:rsvpd-attending]}}))) diff --git a/users/aspen/bbbg/src/bbbg/db/user.clj b/users/aspen/bbbg/src/bbbg/db/user.clj deleted file mode 100644 index 700105ef6..000000000 --- a/users/aspen/bbbg/src/bbbg/db/user.clj +++ /dev/null @@ -1,19 +0,0 @@ -(ns bbbg.db.user - (:require [bbbg.db :as db] - [bbbg.user :as user])) - -(defn create! [db attrs] - (db/insert! db - :public.user - (select-keys attrs [::user/id - ::user/username - ::user/discord-user-id]))) - -(defn find-or-create! [db attrs] - (or - (db/fetch db {:select [:*] - :from [:public.user] - :where [:= - :discord-user-id - (::user/discord-user-id attrs)]}) - (create! db attrs))) diff --git a/users/aspen/bbbg/src/bbbg/discord.clj b/users/aspen/bbbg/src/bbbg/discord.clj deleted file mode 100644 index e854ec1d1..000000000 --- a/users/aspen/bbbg/src/bbbg/discord.clj +++ /dev/null @@ -1,44 +0,0 @@ -(ns bbbg.discord - (:refer-clojure :exclude [get]) - (:require - [bbbg.util.dev-secrets :refer [secret]] - [clj-http.client :as http] - [clojure.string :as str])) - -(def base-uri "https://discord.com/api") - -(defn api-uri [path] - (str base-uri - (when-not (str/starts-with? path "/") "/") - path)) - -(defn get - ([token path] - (get token path {})) - ([token path params] - (:body - (http/get (api-uri path) - (-> params - (assoc :accept :json - :as :json) - (assoc-in [:headers "authorization"] - (str "Bearer " (:token token)))))))) - -(defn me [token] - (get token "/users/@me")) - -(defn guilds [token] - (get token "/users/@me/guilds")) - -(defn guild-member [token guild-id] - (get token (str "/users/@me/guilds/" guild-id "/member"))) - -(comment - (def token {:token (secret "bbbg/test-token")}) - (me token) - (guilds token) - (guild-member token "841295283564052510") - - (get token "/guilds/841295283564052510/roles") - - ) diff --git a/users/aspen/bbbg/src/bbbg/discord/auth.clj b/users/aspen/bbbg/src/bbbg/discord/auth.clj deleted file mode 100644 index 35bc580e3..000000000 --- a/users/aspen/bbbg/src/bbbg/discord/auth.clj +++ /dev/null @@ -1,90 +0,0 @@ -(ns bbbg.discord.auth - (:require - [bbbg.discord :as discord] - [bbbg.util.core :as u] - [bbbg.util.dev-secrets :refer [secret]] - clj-time.coerce - [clojure.spec.alpha :as s] - [config.core :refer [env]] - [ring.middleware.oauth2 :refer [wrap-oauth2]])) - -(s/def ::client-id string?) -(s/def ::client-secret string?) -(s/def ::bbbg-guild-id string?) -(s/def ::bbbg-organizer-role string?) - -(s/def ::config (s/keys :req [::client-id - ::client-secret - ::bbbg-guild-id - ::bbbg-organizer-role])) - -;;; - -(defn env->config [] - (s/assert - ::config - {::client-id (:discord-client-id env) - ::client-secret (:discord-client-secret env) - ::bbbg-guild-id (:bbbg-guild-id env "841295283564052510") - ::bbbg-organizer-role (:bbbg-organizer-role - env - ;; TODO this might not be the right id - "908428000817725470")})) - -(defn dev-config [] - (s/assert - ::config - {::client-id (secret "bbbg/discord-client-id") - ::client-secret (secret "bbbg/discord-client-secret") - ::bbbg-guild-id "841295283564052510" - ::bbbg-organizer-role "908428000817725470"})) - -;;; - -(def access-token-url - "https://discord.com/api/oauth2/token") - -(def authorization-url - "https://discord.com/api/oauth2/authorize") - -(def revoke-url - "https://discord.com/api/oauth2/token/revoke") - -(def scopes ["guilds" - "guilds.members.read" - "identify"]) - -(defn discord-oauth-profile [{:keys [base-url] :as env}] - {:authorize-uri authorization-url - :access-token-uri access-token-url - :client-id (::client-id env) - :client-secret (::client-secret env) - :scopes scopes - :launch-uri "/auth/discord" - :redirect-uri (str base-url "/auth/discord/redirect") - :landing-uri (str base-url "/auth/success")}) - -(comment - (-> "https://bbbg-staging.gws.fyi/auth/login" - (java.net.URI/create) - (.resolve "https://bbbg.gws.fyi/auth/discord/redirect") - str) - ) - -(defn wrap-discord-auth [handler env] - (wrap-oauth2 handler {:discord (discord-oauth-profile env)})) - -(defn check-discord-auth - "Check that the user with the given token has the correct level of discord - auth" - [{::keys [bbbg-guild-id bbbg-organizer-role]} token] - (and (some (comp #{bbbg-guild-id} :id) - (discord/guilds token)) - (some #{bbbg-organizer-role} - (:roles (discord/guild-member token bbbg-guild-id))))) - -(comment - (#'ring.middleware.oauth2/valid-profile? - (discord-oauth-profile - (dev-config))) - ) diff --git a/users/aspen/bbbg/src/bbbg/event.clj b/users/aspen/bbbg/src/bbbg/event.clj deleted file mode 100644 index aa0578f35..000000000 --- a/users/aspen/bbbg/src/bbbg/event.clj +++ /dev/null @@ -1,4 +0,0 @@ -(ns bbbg.event - (:require [clojure.spec.alpha :as s])) - -(s/def ::id uuid?) diff --git a/users/aspen/bbbg/src/bbbg/event_attendee.clj b/users/aspen/bbbg/src/bbbg/event_attendee.clj deleted file mode 100644 index 7b6b4c276..000000000 --- a/users/aspen/bbbg/src/bbbg/event_attendee.clj +++ /dev/null @@ -1,6 +0,0 @@ -(ns bbbg.event-attendee - (:require [clojure.spec.alpha :as s])) - -(s/def ::attended? boolean?) - -(s/def ::rsvpd-attending? boolean?) diff --git a/users/aspen/bbbg/src/bbbg/handlers/attendee_checks.clj b/users/aspen/bbbg/src/bbbg/handlers/attendee_checks.clj deleted file mode 100644 index d7307c406..000000000 --- a/users/aspen/bbbg/src/bbbg/handlers/attendee_checks.clj +++ /dev/null @@ -1,68 +0,0 @@ -(ns bbbg.handlers.attendee-checks - (:require - [bbbg.attendee :as attendee] - [bbbg.attendee-check :as attendee-check] - [bbbg.db :as db] - [bbbg.db.attendee-check :as db.attendee-check] - [bbbg.handlers.core :refer [page-response wrap-auth-required]] - [bbbg.user :as user] - [bbbg.util.display :refer [format-date]] - [compojure.coercions :refer [as-uuid]] - [compojure.core :refer [context GET POST]] - [ring.util.response :refer [not-found redirect]] - [bbbg.views.flash :as flash])) - -(defn- edit-attendee-checks-page [{:keys [existing-check] - attendee-id ::attendee/id}] - [:div.page - (when existing-check - [:p - "Already checked on " - (-> existing-check ::attendee-check/checked-at format-date) - " by " - (::user/username existing-check)]) - [:form.attendee-checks-form - {:method :post - :action (str "/attendees/" attendee-id "/checks")} - [:div.form-group - [:label - "Last Dose" - [:input {:type :date - :name :last-dose-at}]]] - [:div.form-group - [:input {:type :submit - :value "Mark Checked"}]]]]) - -(defn attendee-checks-routes [{:keys [db]}] - (wrap-auth-required - (context "/attendees/:attendee-id/checks" [attendee-id :<< as-uuid] - (GET "/edit" [] - (if (db/exists? db {:select [1] - :from [:attendee] - :where [:= :id attendee-id]}) - (let [existing-check (db/fetch - db - {:select [:attendee-check.* - :public.user.*] - :from [:attendee-check] - :join [:public.user - [:= - :attendee-check.user-id - :public.user.id]] - :where [:= :attendee-id attendee-id]})] - (page-response - (edit-attendee-checks-page - {:existing-check existing-check - ::attendee/id attendee-id}))) - (not-found "Attendee not found"))) - (POST "/" {{:keys [last-dose-at]} :params - {user-id ::user/id} :session} - (db.attendee-check/create! - db - {::attendee/id attendee-id - ::user/id user-id - ::attendee-check/last-dose-at last-dose-at}) - (-> (redirect "/attendees") - (flash/add-flash - #:flash{:type :success - :message "Successfully updated vaccination status"})))))) diff --git a/users/aspen/bbbg/src/bbbg/handlers/attendees.clj b/users/aspen/bbbg/src/bbbg/handlers/attendees.clj deleted file mode 100644 index ce84b88e9..000000000 --- a/users/aspen/bbbg/src/bbbg/handlers/attendees.clj +++ /dev/null @@ -1,162 +0,0 @@ -(ns bbbg.handlers.attendees - (:require - [bbbg.attendee :as attendee] - [bbbg.attendee-check :as attendee-check] - [bbbg.db :as db] - [bbbg.db.attendee :as db.attendee] - [bbbg.db.attendee-check :as db.attendee-check] - [bbbg.db.event :as db.event] - [bbbg.event :as event] - [bbbg.handlers.core :refer [page-response wrap-auth-required]] - [bbbg.user :as user] - [bbbg.util.display :refer [format-date]] - [bbbg.views.flash :as flash] - [cheshire.core :as json] - [compojure.coercions :refer [as-uuid]] - [compojure.core :refer [GET POST routes]] - [honeysql.helpers :refer [merge-where]] - [ring.util.response :refer [content-type not-found redirect response]]) - (:import - java.util.UUID)) - -(defn- attendees-page [{:keys [attendees q edit-notes]}] - [:div.page - [:form.search-form {:method :get :action "/attendees"} - [:input.search-input - {:type "search" - :name "q" - :value q - :title "Search Attendees"}] - [:input {:type "submit" - :value "Search Attendees"}]] - [:table.attendees - [:thead - [:tr - [:th "Meetup Name"] - [:th "Discord Name"] - [:th "Events RSVPd"] - [:th "Events Attended"] - [:th "No-Shows"] - [:th "Last Vaccination Check"] - [:th "Notes"]]] - [:tbody - (for [attendee (sort-by - (comp #{edit-notes} ::attendee/id) - (comp - compare) - attendees) - :let [id (::attendee/id attendee)]] - [:tr - [:td.attendee-name (::attendee/meetup-name attendee)] - [:td - [:label.mobile-label "Discord Name: "] - (or (not-empty (::attendee/discord-name attendee)) - "—")] - [:td - [:label.mobile-label "Events RSVPd: "] - (:events-rsvpd attendee)] - [:td - [:label.mobile-label "Events Attended: "] - (:events-attended attendee)] - [:td - [:label.mobile-label "No-shows: "] - (:no-shows attendee)] - [:td - [:label.mobile-label "Last Vaccination Check: "] - (if-let [last-check (:last-check attendee)] - (str "✔️ "(-> last-check - ::attendee-check/checked-at - format-date) - ", by " - (get-in last-check [:user ::user/username])) - (list - [:span {:title "Not Checked"} - "❌"] - " " - [:a {:href (str "/attendees/" id "/checks/edit")} - "Edit"] ))] - (if (= edit-notes id) - [:td - [:form.organizer-notes {:method :post - :action (str "/attendees/" id "/notes")} - [:div.form-group - [:input {:type :text :name "notes" - :value (::attendee/organizer-notes attendee) - :autofocus true}]] - [:div.form-group - [:input {:type "Submit" :value "Save Notes"}]]]] - [:td - [:p - (::attendee/organizer-notes attendee)] - [:p - [:a {:href (str "/attendees?edit-notes=" id)} - "Edit Notes"]]])])]]]) - -(defn attendees-routes [{:keys [db]}] - (routes - (wrap-auth-required - (routes - (GET "/attendees" [q edit-notes] - (let [attendees (db/list db (cond-> (db.attendee/with-stats) - q (db.attendee/search q))) - attendees (db.attendee-check/attendees-with-last-checks - db - attendees) - edit-notes (some-> edit-notes UUID/fromString)] - (page-response (attendees-page {:attendees attendees - :q q - :edit-notes edit-notes})))) - - (POST "/attendees/:id/notes" [id :<< as-uuid notes] - (if (seq (db/update! db - :attendee - {::attendee/organizer-notes notes} - [:= :id id])) - (-> (redirect "/attendees") - (flash/add-flash - #:flash{:type :success - :message "Notes updated successfully"})) - (not-found "Attendee not found"))))) - - (GET "/attendees.json" [q event_id attended] - (let [results - (db/list - db - (cond-> - (if q - (db.attendee/search q) - {:select [:attendee.*] :from [:attendee]}) - event_id (db.attendee/for-event event_id) - (some? attended) - (merge-where - (case attended - "true" :attended - "false" [:or [:= :attended nil] [:not :attended]]))))] - (-> {:results results} - json/generate-string - response - (content-type "application/json")))) - - (POST "/event_attendees" [event_id attendee_id] - (if (and (db/exists? db {:select [:id] :from [:event] :where [:= :id event_id]}) - (db/exists? db {:select [:id] :from [:attendee] :where [:= :id attendee_id]})) - (do - (db.event/attended! db {::event/id event_id - ::attendee/id attendee_id}) - (-> (redirect (str "/signup-forms/" event_id)) - (flash/add-flash - #:flash{:type :success - :message "Thank you for signing in! Enjoy the event."}))) - (response "Something went wrong"))))) - -(comment - (def db (:db bbbg.core/system)) - (db/list db :attendee) - (db/list db - (-> - (db.attendee/search "gr") - (db.attendee/for-event #uuid "9f4f3eae-3317-41a7-843c-81bcae52aebf"))) - (honeysql.format/format - (-> - (db.attendee/search "gr") - (db.attendee/for-event #uuid "9f4f3eae-3317-41a7-843c-81bcae52aebf"))) - ) diff --git a/users/aspen/bbbg/src/bbbg/handlers/core.clj b/users/aspen/bbbg/src/bbbg/handlers/core.clj deleted file mode 100644 index caa679ee8..000000000 --- a/users/aspen/bbbg/src/bbbg/handlers/core.clj +++ /dev/null @@ -1,91 +0,0 @@ -(ns bbbg.handlers.core - (:require - [bbbg.user :as user] - [bbbg.views.flash :as flash] - [hiccup.core :refer [html]] - [ring.util.response :refer [content-type response]] - [clojure.string :as str])) - -(def ^:dynamic *authenticated?* false) - -(defn authenticated? [request] - (some? (get-in request [:session ::user/id]))) - -(defn wrap-auth-required [handler] - (fn [req] - (when (authenticated? req) - (handler req)))) - -(defn wrap-dynamic-auth [handler] - (fn [req] - (binding [*authenticated?* (authenticated? req)] - (handler req)))) - -(def ^:dynamic *current-uri*) - -(defn wrap-current-uri [handler] - (fn [req] - (binding [*current-uri* (:uri req)] - (handler req)))) - -(defn nav-item [href label] - (let [active? - (when *current-uri* - (str/starts-with? - *current-uri* - href))] - [:li {:class (when active? "active")} - [:a {:href href} - label]])) - -(defn global-nav [] - [:nav.global-nav - [:ul - (nav-item "/events" "Events") - (when *authenticated?* - (nav-item "/attendees" "Attendees")) - [:li.spacer] - [:li - (if *authenticated?* - [:form.link-form - {:method :post - :action "/auth/sign-out"} - [:input {:type "submit" - :value "Sign Out"}]] - [:a {:href "/auth/discord"} - "Sign In"])]]]) - -(defn render-page [opts & body] - (let [[{:keys [title]} body] - (if (map? opts) - [opts body] - [{} (concat [opts] body)])] - (html - [:html {:lang "en"} - [:head - [:meta {:charset "UTF-8"}] - [:meta {:name "viewport" - :content "width=device-width,initial-scale=1"}] - [:title (if title - (str title " - BBBG") - "BBBG")] - [:link {:rel "stylesheet" - :type "text/css" - :href "/main.css"}]] - [:body - [:div.content - (global-nav) - #_(flash/render-flash flash/test-flash) - (flash/render-flash) - body] - [:script {:src "/main.js"}]]]))) - -(defn page-response [& render-page-args] - (-> (apply render-page render-page-args) - response - (content-type "text/html"))) - -(comment - (render-page - [:h1 "hi"]) - ) diff --git a/users/aspen/bbbg/src/bbbg/handlers/events.clj b/users/aspen/bbbg/src/bbbg/handlers/events.clj deleted file mode 100644 index 6f6d6f358..000000000 --- a/users/aspen/bbbg/src/bbbg/handlers/events.clj +++ /dev/null @@ -1,259 +0,0 @@ -(ns bbbg.handlers.events - (:require - [bbbg.db :as db] - [bbbg.db.attendee :as db.attendee] - [bbbg.db.event :as db.event] - [bbbg.event :as event] - [bbbg.handlers.core :refer [*authenticated?* page-response]] - [bbbg.meetup.import :refer [import-attendees!]] - [bbbg.util.display :refer [format-date pluralize]] - [bbbg.util.time :as t] - [bbbg.views.flash :as flash] - [compojure.coercions :refer [as-uuid]] - [compojure.core :refer [context GET POST]] - [java-time :refer [local-date]] - [ring.util.response :refer [not-found redirect]] - [bbbg.attendee :as attendee] - [bbbg.event-attendee :as event-attendee] - [bbbg.db.attendee-check :as db.attendee-check] - [bbbg.attendee-check :as attendee-check] - [bbbg.user :as user]) - (:import - java.time.format.FormatStyle)) - -(defn- num-attendees [event] - (str - (:num-attendees event) - (if (= (t/->LocalDate (::event/date event)) - (local-date)) - " Signed In" - (str " Attendee" (when-not (= 1 (:num-attendees event)) "s"))))) - -(def index-type->label - {:upcoming "Upcoming" - :past "Past"}) -(def other-index-type - {:upcoming :past - :past :upcoming}) - -(defn events-index - [{:keys [events num-events type]}] - [:div.page - [:div.page-header - [:h1 - (pluralize - num-events - (str (index-type->label type) " Event"))] - [:a {:href (str "/events" - (when (= :upcoming type) - "/past"))} - "View " - (index-type->label (other-index-type type)) - " Events"]] - (when *authenticated?* - [:a.button {:href "/events/new"} - "Create New Event"]) - [:ul.events-list - (for [event (sort-by - ::event/date - (comp - compare) - events)] - [:li - [:p - [:a {:href (str "/events/" (::event/id event))} - (format-date (::event/date event) - FormatStyle/FULL)]] - [:p - (pluralize (:num-rsvps event) "RSVP") - ", " - (num-attendees event)]])]]) - -(defn- import-attendee-list-form-group [] - [:div.form-group - [:label "Import Attendee List" - [:br] - [:input {:type :file - :name :attendees}]]]) - -(defn import-attendees-form [event] - [:form {:method :post - :action (str "/events/" (::event/id event) "/attendees") - :enctype "multipart/form-data"} - (import-attendee-list-form-group) - [:div.form-group - [:input {:type :submit - :value "Import"}]]]) - -(defn event-page [{:keys [event attendees]}] - [:div.page - [:div.page-header - [:h1 (format-date (::event/date event) - FormatStyle/FULL)] - [:div.spacer] - [:a.button {:href (str "/signup-forms/" (::event/id event) )} - "Go to Signup Form"] - [:form#delete-event - {:method :post - :action (str "/events/" (::event/id event) "/delete") - :data-confirm "Are you sure you want to delete this event?"} - [:input.error {:type "submit" - :value "Delete Event"}]]] - [:div.stats - [:p (pluralize (:num-rsvps event) "RSVP")] - [:p (num-attendees event)]] - [:div - (import-attendees-form event)] - [:div - [:table.attendees - [:thead - [:th "Meetup Name"] - [:th "Discord Name"] - [:th "RSVP"] - [:th "Signed In"] - [:th "Last Vaccination Check"]] - [:tbody - (for [attendee (sort-by (juxt (comp not ::event-attendee/rsvpd-attending?) - (comp not ::event-attendee/attended?) - (comp some? :last-check) - ::attendee/meetup-name) - attendees)] - [:tr - [:td.attendee-name (::attendee/meetup-name attendee)] - [:td - [:label.mobile-label "Discord Name: "] - (or (not-empty (::attendee/discord-name attendee)) - "—")] - [:td - [:label.mobile-label "RSVP: "] - (if (::event-attendee/rsvpd-attending? attendee) - [:span {:title "Yes"} "✔️"] - [:span {:title "No"} "❌"])] - [:td - [:label.mobile-label "Signed In: "] - (if (::event-attendee/attended? attendee) - [:span {:title "Yes"} "✔️"] - [:span {:title "No"} "❌"])] - [:td - [:label.mobile-label "Last Vaccination Check: "] - (if-let [last-check (:last-check attendee)] - (str "✔️ "(-> last-check - ::attendee-check/checked-at - format-date) - ", by " - (get-in last-check [:user ::user/username])) - (list - [:span {:title "Not Checked"} - "❌"] - " " - [:a {:href (str "/attendees/" - (::attendee/id attendee) - "/checks/edit")} - "Edit"]))]])]]]]) - -(defn import-attendees-page [{:keys [event]}] - [:div.page - [:h1 "Import Attendees for " (format-date (::event/date event))] - (import-attendees-form event)]) - -(defn event-form - ([] (event-form {})) - ([event] - [:div.page - [:div.page-header - [:h1 "Create New Event"]] - [:form {:method "POST" - :action "/events" - :enctype "multipart/form-data"} - [:div.form-group - [:label "Date" - [:input {:type "date" - :id "date" - :name "date" - :value (str (::event/date event))}]]] - (import-attendee-list-form-group) - [:div.form-group - [:input {:type "submit" - :value "Create Event"}]]]])) - -(defn- events-list-handler [db query type] - (let [events (db/list db (db.event/with-stats query)) - num-events (db/count db query)] - (page-response - (events-index {:events events - :num-events num-events - :type type})))) - -(defn events-routes [{:keys [db]}] - (context "/events" [] - (GET "/" [] - (events-list-handler db (db.event/upcoming) :upcoming)) - - (GET "/past" [] - (events-list-handler db (db.event/past) :past)) - - (GET "/new" [date] - (page-response - {:title "New Event"} - (event-form {::event/date date}))) - - (POST "/" [date attendees] - (let [event (db.event/create! db {::event/date date}) - message - (if attendees - (let [num-attendees - (import-attendees! db - (::event/id event) - (:tempfile attendees))] - (format "Event created with %d attendees" - num-attendees)) - "Event created")] - (-> (str "/signup-forms/" (::event/id event)) - redirect - (flash/add-flash {:flash/type :success - :flash/message message})))) - - (context "/:id" [id :<< as-uuid] - (GET "/" [] - (if-let [event (db/fetch db - (-> {:select [:event.*] - :from [:event] - :where [:= :event.id id]} - (db.event/with-stats)))] - (let [attendees (db.attendee-check/attendees-with-last-checks - db - (db/list db (db.attendee/for-event id)))] - (page-response - (event-page {:event event - :attendees attendees}))) - (not-found "Event Not Found"))) - - (POST "/delete" [] - (db/delete! db :event_attendee [:= :event-id id]) - (db/delete! db :event [:= :id id]) - (-> (redirect "/events") - (flash/add-flash - #:flash {:type :success - :message "Successfully deleted event"}))) - - (GET "/attendees/import" [] - (if-let [event (db/get db :event id)] - (page-response - (import-attendees-page {:event event})) - (not-found "Event Not Found"))) - - (POST "/attendees" [attendees] - (let [num-imported (import-attendees! db id (:tempfile attendees))] - (-> (redirect (str "/events/" id)) - (flash/add-flash - #:flash{:type :success - :message (format "Successfully imported %d attendees" - num-imported)}))))))) - -(comment - (def db (:db bbbg.core/system)) - - (-> (db/list db :event) - first - ::event/date - format-date) - ) diff --git a/users/aspen/bbbg/src/bbbg/handlers/home.clj b/users/aspen/bbbg/src/bbbg/handlers/home.clj deleted file mode 100644 index 17d487553..000000000 --- a/users/aspen/bbbg/src/bbbg/handlers/home.clj +++ /dev/null @@ -1,52 +0,0 @@ -(ns bbbg.handlers.home - (:require - [bbbg.db.user :as db.user] - [bbbg.discord.auth :as discord.auth] - [bbbg.handlers.core :refer [page-response authenticated?]] - [bbbg.user :as user] - [bbbg.views.flash :as flash] - [compojure.core :refer [GET POST routes]] - [ring.util.response :refer [redirect]] - [bbbg.discord :as discord])) - -(defn- home-page [] - [:div.home-page - [:a.signup-form-link {:href "/signup-forms"} - "Event Signup Form"]]) - -(defn auth-failure [] - [:div.auth-failure - [:p - "Sorry, only users with the Organizers role in discord can sign in"] - [:p - [:a {:href "/"} "Go Back"]]]) - -(defn home-routes [{:keys [db] :as env}] - (routes - (GET "/" [] (page-response (home-page))) - - (POST "/auth/sign-out" request - (if (authenticated? request) - (-> (redirect "/") - (update :session dissoc ::user/id) - (flash/add-flash - {:flash/message "Successfully Signed Out" - :flash/type :success})) - (redirect "/"))) - - (GET "/auth/success" request - (let [token (get-in request [:oauth2/access-tokens :discord])] - (if (discord.auth/check-discord-auth env token) - (let [discord-user (discord/me token) - user (db.user/find-or-create! - db - #::user{:username (:username discord-user) - :discord-user-id (:id discord-user)})] - (-> (redirect "/") - (assoc-in [:session ::user/id] (::user/id user)) - (flash/add-flash - {:flash/message "Successfully Signed In" - :flash/type :success}))) - (-> - (page-response (auth-failure)) - (assoc :status 401))))))) diff --git a/users/aspen/bbbg/src/bbbg/handlers/signup_form.clj b/users/aspen/bbbg/src/bbbg/handlers/signup_form.clj deleted file mode 100644 index ed1d7644f..000000000 --- a/users/aspen/bbbg/src/bbbg/handlers/signup_form.clj +++ /dev/null @@ -1,93 +0,0 @@ -(ns bbbg.handlers.signup-form - (:require - [bbbg.attendee :as attendee] - [bbbg.db :as db] - [bbbg.db.attendee :as db.attendee] - [bbbg.db.event :as db.event] - [bbbg.event :as event] - [bbbg.handlers.core - :refer [*authenticated?* authenticated? page-response]] - [cheshire.core :as json] - [compojure.core :refer [context GET]] - [honeysql.helpers :refer [merge-where]] - [java-time :refer [local-date]] - [ring.util.response :refer [redirect]])) - -(defn no-events-page [{:keys [authenticated?]}] - [:div.page - [:p - "There are no events for today"] - (when authenticated? - [:p - [:a.button {:href (str "/events/new?date=" (str (local-date)))} - "Create New Event"]])]) - -(defn signup-page [{:keys [event attendees]}] - [:div.signup-page - [:form#signup-form - {:method "POST" - :action "/event_attendees" - :disabled "disabled"} - [:input#name-autocomplete - {:type "search" - :title "Name" - :name "name" - :spellcheck "false" - :autocorrect "off" - :autocomplete "off" - :autocapitalize "off" - :maxlength "2048"}] - [:input#attendee-id {:type "hidden" :name "attendee_id"}] - [:input#event-id {:type "hidden" :name "event_id" :value (::event/id event)}] - [:input#submit-button.hidden - {:type "submit" - :value "Sign In" - :disabled "disabled"}]] - [:ul#attendees-list - (if (seq attendees) - (for [attendee attendees] - [:li {:data-attendee (json/generate-string attendee) - :role "button"} - (::attendee/meetup-name attendee)]) - [:li.no-attendees - [:p - "Nobody has RSVPed to this event yet, or no attendee list has been - imported"] - (when *authenticated?* - [:p - [:a.button - {:href (str "/events/" - (::event/id event) - "/attendees/import")} - "Import Attendee List"]])])]]) - -(defn event-not-found [] - [:div.event-not-found - [:p "Event not found"] - [:p [:a {:href (str "/events/new")} "Create a new event"]]]) - -;;; - -(defn signup-form-routes [{:keys [db]}] - (context "/signup-forms" [] - (GET "/" request - (if-let [event (db/fetch db (db.event/today))] - (redirect (str "/signup-forms/" (::event/id event))) - (page-response (no-events-page - {:authenticated? (authenticated? request)})))) - - (GET "/:event-id" [event-id] - (if-let [event (db/get db :event event-id)] - (let [attendees (db/list db - (-> - (db.attendee/for-event event-id) - (merge-where - [:and - [:or - [:= :attended nil] - [:not :attended]] - :rsvpd_attending])))] - (page-response - (signup-page {:event event - :attendees attendees}))) - (event-not-found))))) diff --git a/users/aspen/bbbg/src/bbbg/meetup/import.clj b/users/aspen/bbbg/src/bbbg/meetup/import.clj deleted file mode 100644 index bbf867897..000000000 --- a/users/aspen/bbbg/src/bbbg/meetup/import.clj +++ /dev/null @@ -1,125 +0,0 @@ -(ns bbbg.meetup.import - (:require - [bbbg.attendee :as attendee] - [bbbg.db.attendee :as db.attendee] - [bbbg.db.event-attendee :as db.event-attendee] - [bbbg.event :as event] - [bbbg.event-attendee :as event-attendee] - [bbbg.meetup-user :as meetup-user] - [bbbg.util.core :as u] - [bbbg.util.spec :as u.s] - [clojure.data.csv :as csv] - [clojure.java.io :as io] - [clojure.spec.alpha :as s] - [clojure.string :as str] - [expound.alpha :as exp])) - -(def spreadsheet-column->key - {"Name" :name - "User ID" :user-id - "Title" :title - "Event Host" :event-host - "RSVP" :rsvp - "Guests" :guests - "RSVPed on" :rsvped-on - "Joined Group on" :joined-group-on - "URL of Member Profile" :member-profile-url}) - -(defn read-attendees [f] - (with-open [reader (io/reader f)] - (let [[headers & rows] (-> reader (csv/read-csv :separator \tab)) - keys (map spreadsheet-column->key headers)] - (doall - (->> rows - (map (partial zipmap keys)) - (map (partial u/filter-kv (fn [k _] (some? k)))) - (filter (partial some (comp seq val)))))))) - -;;; - -(s/def ::imported-attendee - (s/keys :req [::attendee/meetup-name - ::meetup-user/id])) - -(def key->attendee-col - {:name ::attendee/meetup-name - :user-id ::meetup-user/id}) - -(defn row-user-id->user-id [row-id] - (str/replace-first row-id "user " "")) - -(defn check-attendee [attendee] - () - (if (s/valid? ::imported-attendee attendee) - attendee - (throw (ex-info - (str "Invalid imported attendee\n" - (exp/expound-str ::imported-attendee attendee)) - (assoc (s/explain-data ::imported-attendee attendee) - ::s/failure - ::s/assertion-failed))))) - -(defn row->attendee [r] - (u.s/assert! - ::imported-attendee - (update (u/keep-keys key->attendee-col r) - ::meetup-user/id row-user-id->user-id))) - -;;; - -(s/def ::imported-event-attendee - (s/keys :req [::event-attendee/rsvpd-attending? - ::attendee/id - ::event/id])) - -(def key->event-attendee-col - {:rsvp ::event-attendee/rsvpd-attending?}) - -(defn row->event-attendee - [{event-id ::event/id :keys [meetup-id->attendee-id]} r] - (let [attendee-id (-> r :user-id row-user-id->user-id meetup-id->attendee-id)] - (u.s/assert! - ::imported-event-attendee - (-> (u/keep-keys key->event-attendee-col r) - (update ::event-attendee/rsvpd-attending? - (partial = "Yes")) - (assoc ::event/id event-id - ::attendee/id attendee-id))))) - -;;; - -(defn import-attendees! [db event-id f] - (let [rows (read-attendees f) - attendees (db.attendee/upsert-all! db (map row->attendee rows)) - meetup-id->attendee-id (into {} - (map (juxt ::meetup-user/id ::attendee/id)) - attendees)] - (db.event-attendee/upsert-all! - db - (map (partial row->event-attendee - {::event/id event-id - :meetup-id->attendee-id meetup-id->attendee-id}) - rows)) - (count rows))) - -;;; Spreadsheet columns: -;;; -;;; Name -;;; User ID -;;; Title -;;; Event Host -;;; RSVP -;;; Guests -;;; RSVPed on -;;; Joined Group on -;;; URL of Member Profile -;;; Have you been to one of our events before? Note, attendance at all events will require proof of vaccination until further notice. - -(comment - (def -filename- "/home/aspen/code/depot/users/aspen/bbbg/sample-data.tsv") - (def event-id #uuid "09f8fed6-7480-451b-89a2-bb4edaeae657") - - (read-attendees -filename-) - (import-attendees! (:db bbbg.core/system) event-id -filename-) - - ) diff --git a/users/aspen/bbbg/src/bbbg/meetup_user.clj b/users/aspen/bbbg/src/bbbg/meetup_user.clj deleted file mode 100644 index 945d681c6..000000000 --- a/users/aspen/bbbg/src/bbbg/meetup_user.clj +++ /dev/null @@ -1,6 +0,0 @@ -(ns bbbg.meetup-user - (:require [clojure.spec.alpha :as s])) - -(s/def ::id - (s/nilable - (s/and string? seq))) diff --git a/users/aspen/bbbg/src/bbbg/styles.clj b/users/aspen/bbbg/src/bbbg/styles.clj deleted file mode 100644 index a860ae607..000000000 --- a/users/aspen/bbbg/src/bbbg/styles.clj +++ /dev/null @@ -1,407 +0,0 @@ -;; -*- eval: (rainbow-mode) -*- -(ns bbbg.styles - (:require - [garden.color :as color] - [garden.compiler :refer [compile-css]] - [garden.def :refer [defstyles]] - [garden.selectors - :refer [& active attr= descendant focus hover nth-child]] - [garden.stylesheet :refer [at-media]] - [garden.units :refer [px]])) - -(def black "#342e37") - -(def silver "#f9fafb") - -(def gray "#aaa") - -(def gray-light "#ddd") - -(def purple "#837aff") - -(def red "#c42348") - -(def orange "#fa824c") - -(def yellow "#FACB0F") - -(def blue "#026fb1") - -(def green "#87E24B") - -(def contextual-colors - {:success green - :info blue - :warning yellow - :error red}) - -;;; - -(def content-width (px 1200)) -(def mobile-width (px 480)) - -(defn desktop [& rules] - (at-media - {:screen true - :min-width content-width} - [:& rules])) - -(defn mobile [& rules] - (at-media - {:screen true - :max-width mobile-width} - [:& rules])) - -(defn not-mobile [& rules] - (at-media - {:screen true - :min-width mobile-width} - [:& rules])) - - -;;; - -(defstyles global-nav - [:.global-nav - {:background-color silver} - - [:>ul - {:display :flex - :flex-direction :row - :list-style :none} - - (desktop - {:width content-width - :margin "0 auto"})] - - [:a (descendant :.link-form (attr= "type" "submit")) - {:padding "1rem 1.5rem" - :display :block - :color black - :text-decoration :none} - - [(& hover) - {:color blue}]] - - [:li.active - {:font-weight "bold" - :border-bottom [["1px" "solid" black]]}]] - - [:.spacer - {:flex 1}]) - -(def link-conditional-styles - (list - [(& hover) (& active) - {:text-decoration :underline}] - [(& active) - {:color purple}])) - -(defstyles link-form - [:form.link-form - {:margin 0} - [(attr= "type" "submit") - {:background "none" - :border "none" - :padding 0 - :color blue - :text-decoration :none - :cursor :pointer} - link-conditional-styles]]) - -(defstyles search-form - [:.search-form - {:display :flex - :flex-direction :row - :width "100%"} - - [:>*+* - {:margin-left "0.75rem"}] - - [:input - {:flex 1}] - - [(attr= "type" "submit") - {:flex 0}]]) - -(defstyles forms - (let [text-input-types - #{"date" - "datetime-local" - "email" - "month" - "number" - "password" - "search" - "tel" - "text" - "time" - "url" - "week"} - each-text-type (fn [& rules] - (into - [] - (concat - (map (comp & (partial attr= "type")) - text-input-types) - rules)))] - (each-text-type - {:width "100%" - :display "block" - :padding "0.6rem 0.75rem" - :border [["1px" "solid" gray-light]] - :border-radius "3px" - :box-shadow [["inset" 0 "1px" "5px" "rgba(0,0,0,0.075)"]] - :transition "border-color 150ms" - :background "none"} - [(& focus) - {:outline "none" - :border-color purple}])) - - [(attr= "type" "submit") :button :.button - {:background-color (color/lighten blue 30) - :padding "0.6rem 0.75rem" - :border-radius "3px" - :border [[(px 1) "solid" (color/lighten blue 30)]] - :cursor :pointer - :display :inline-block} - - [(& hover) - {:border-color blue - :text-decoration :none - :box-shadow [[0 "1px" "5px" "rgba(0,0,0,0.075)"]]} - [(:a &) - {:text-decoration :none}]] - - [(& active) - {:background-color blue - :color :white - :box-shadow :none} - [(& :a) - {:text-decoration :none}]] - - (for [[context color] contextual-colors] - [(& (keyword (str "." (name context)))) - {:background-color (color/lighten color 30) - :border-color (color/lighten color 30) - :color black} - - [(& hover) - {:border-color color}]])] - - [:label - {:font-weight 600 - :width "100%"} - - [:input - {:font-weight "initial" - :margin-top "0.3rem"}]] - - [:.form-group - {:display :flex - :margin-bottom "0.8rem" - :flex-direction :column} - - [(attr= "type" "submit") - {:text-align :right - :align-self :flex-end}]]) - -(defstyles tables - [:table - {:width "100%" - :border-collapse "collapse"}] - - [:th - {:text-align "left"}] - - [:td :th - {:padding "0.75rem 1rem" - :border-spacing 0 - :border "none"}] - - [:tr - {:border-spacing 0 - :border "none"} - [(& (nth-child :even)) - {:background-color silver}]]) - -(defstyles flash - [:.flash-messages - {:max-width "800px" - :margin "1rem auto"} - - (at-media - {:screen true - :max-width "800px"} - [:& - {:margin-left "1rem" - :margin-right "1rem"}])] - - [:.flash-message - {:padding "1rem 1.5rem" - :border "1px solid" - :margin-bottom "1rem"}] - - (for [[context color] contextual-colors] - [(& (keyword (str ".flash-" (name context)))) - {:border-color color - :background-color (color/lighten color 30) - :border-radius "3px"}])) - -(defstyles home-page - [:.home-page - {:display :flex - :flex 1 - :justify-content :center - :align-items :center} - [:.signup-form-link - {:display :block - :border [["1px" :solid blue]] - :border-radius "3px" - :color black - :font-size "2rem" - :background-color (color/lighten blue 50) - :margin-left "auto" - :margin-right "auto" - :padding "2rem"} - (desktop - {:padding "5rem" - :margin-left 0 - :margin-right 0}) - [(& hover) (& active) - {:text-decoration :none}] - [(& active) - {:background-color (color/lighten blue 30)}]]]) - -(defstyles signup-page - [:.signup-page - {:margin "1rem"} - (desktop - {:width content-width - :margin "1rem auto"})] - - [:#signup-form - {:display :flex - :flex-direction :row - :width "100%"} - - [:* - {:flex 1}] - - [:*+* - {:margin-left "1rem"}] - - [(attr= "type" "submit") - {:flex 0}]] - - [:#attendees-list - {:list-style "none" - :overflow-y "auto" - :height "calc(100vh - 8.32425rem)"} - - [:li - {:padding "0.75rem 1rem" - :margin "0.35rem 0" - :border-radius "3px" - :background-color silver}]] - - [:.no-attendees - {:text-align "center" - :margin-top "6rem"} - - [:.button - {:margin-top "0.5rem"}]] - - [:.hidden - {:display :none}]) - -(defstyles attendees - [:.attendee-checks-form - {:max-width "340px" - :margin-left "auto" - :margin-right "auto"}] - - [:.attendees - (mobile - {:display :block} - - [:thead {:display :none}] - [:tbody :tr :td - {:display :block}] - - [:tr - {:background-color silver - :padding "0.5rem 0.8rem" - :margin-bottom "1rem" - :border-radius "3px"}] - [:td {:padding "0.2rem 0"}] - - [:.attendee-name - {:font-weight "bold" - :margin-bottom "0.9rem"}]) - - (not-mobile - [:.mobile-label - {:display :none}])]) - -(defstyles events - [:.events-list - {:margin-top "1rem"} - - [:li - {:margin-bottom "1rem"}]]) - -(defstyles styles - forms - tables - global-nav - link-form - search-form - flash - home-page - signup-page - attendees - events - - [:body - {:color black}] - - [:.content - {:display :flex - :flex-direction :column - :height "100%" - :width "100%"}] - - [:.page - {:margin-top "1rem" - :margin-left "1rem" - :margin-right "1rem"} - - (desktop - {:width content-width - :margin-left "auto" - :margin-right "auto"})] - - [:.page-header - {:display :flex - :flex-wrap :wrap - :padding-bottom "0.7rem" - :margin-bottom "1rem" - :border-bottom [["1px" "solid" silver]] - :align-items :center} - - [:*+* - {:margin-left "0.5rem"}] - - [:form - {:margin-block-end 0}]] - - [(attr= "role" "button") - {:cursor :pointer}] - - [:a {:color blue - :text-decoration :none} - link-conditional-styles]) - -(def stylesheet - (compile-css styles)) diff --git a/users/aspen/bbbg/src/bbbg/user.clj b/users/aspen/bbbg/src/bbbg/user.clj deleted file mode 100644 index f48c8d733..000000000 --- a/users/aspen/bbbg/src/bbbg/user.clj +++ /dev/null @@ -1,8 +0,0 @@ -(ns bbbg.user - (:require [clojure.spec.alpha :as s])) - -(s/def ::id uuid?) - -(s/def ::discord-id string?) - -(s/def ::username string?) diff --git a/users/aspen/bbbg/src/bbbg/util/core.clj b/users/aspen/bbbg/src/bbbg/util/core.clj deleted file mode 100644 index d458aa559..000000000 --- a/users/aspen/bbbg/src/bbbg/util/core.clj +++ /dev/null @@ -1,138 +0,0 @@ -(ns bbbg.util.core - (:require - [clojure.java.shell :refer [sh]] - [clojure.string :as str]) - (:import - java.util.UUID)) - -(defn remove-nils - "Remove all keys with nil values from m" - [m] - (let [!m (transient m)] - (doseq [[k v] m] - (when (nil? v) - (dissoc! !m k))) - (persistent! !m))) - - -(defn alongside - "Apply a pair of functions to the first and second element of a two element - vector, respectively. The two argument form partially applies, such that: - - ((alongside f g) xy) ≡ (alongside f g xy) - - This is equivalent to (***) in haskell's Control.Arrow" - ([f g] (partial alongside f g)) - ([f g [x y]] [(f x) (g y)])) - -(defn map-kv - "Map a pair of functions over the keys and values of a map, respectively. - Preserves metadata on the incoming map. - The two argument form returns a transducer that yields map-entries. - - (partial map-kv identity identity) ≡ identity" - ([kf vf] - (map (fn [[k v]] - ;; important to return a map-entry here so that callers down the road - ;; can use `key` or `val` - (first {(kf k) (vf v)})))) - ([kf vf m] - (into (empty m) (map-kv kf vf) m))) - -(defn filter-kv - "Returns a map containing the elements of m for which (f k v) returns logical - true. The one-argument form returns a transducer that yields map entries" - ([f] (filter (partial apply f))) - ([f m] - (into (empty m) (filter-kv f) m))) - -(defn map-keys - "Map f over the keys of m. Preserves metadata on the incoming map. The - one-argument form returns a transducer that yields map-entries." - ([f] (map-kv f identity)) - ([f m] (map-kv f identity m))) - -(defn keep-keys - "Map f over the keys of m, keeping only those entries for which f does not - return nil. Preserves metadata on the incoming map. The one-argument form - returns a transducer that yields map-entries." - ([f] (keep (fn [[k v]] (when-let [k' (f k)] - (first {k' v}))))) - ([f m] (into (empty m) (keep-keys f) m))) - -(defn map-vals - "Map f over the values of m. Preserves metadata on the incoming map. The - one-argument form returns a transducer that yields map-entries." - ([f] (map-kv identity f)) - ([f m] (map-kv identity f m))) - -(defn map-keys-recursive [f x] - (cond - (map? x) (map-kv f (partial map-keys-recursive f) x) - (sequential? x) (map (partial map-keys-recursive f) x) - :else x)) - -(defn denamespace [x] - (if (keyword? x) - (keyword (name x)) - (map-keys-recursive denamespace x))) - -(defn reverse-merge - "Like `clojure.core/merge`, except duplicate keys from maps earlier in the - argument list take precedence - - => (merge {:x 1} {:x 2}) - {:x 2} - - => (sut/reverse-merge {:x 1} {:x 2}) - {:x 1}" - [& ms] - (apply merge (reverse ms))) - -(defn invert-map - "Invert the keys and vals of m. Behavior with duplicate vals is undefined. - - => (sut/invert-map {:x 1 :y 2}) - {1 :x 2 :y}" - [m] - (into {} (map (comp vec reverse)) m)) - -(defn ->uuid - "Converts x to uuid, returning nil if x is nil or empty" - [x] - (cond - (not x) nil - (uuid? x) x - (and (string? x) (seq x)) - (UUID/fromString x))) - -(defn key-by - "Create a map from a seq obtaining keys via f - - => (sut/key-by :x [{:x 1} {:x 2 :y 3}]) - {1 {:x 1}, 2 {:x 2 :y 3}}" - [f l] - (into {} (map (juxt f identity)) l)) - -(defn distinct-by - "Like clojure.core/distinct, but can take a function f by which - distinctiveness is calculated" - [distinction-fn coll] - (let [step (fn step [xs seen] - (lazy-seq - ((fn [[f :as xs] seen] - (when-let [s (seq xs)] - (if (contains? seen (distinction-fn f)) - (recur (rest s) seen) - (cons f (step (rest s) (conj seen (distinction-fn f))))))) - xs seen)))] - (step coll #{}))) - -(defn pass [n] - (let [{:keys [exit out err]} (sh "pass" n)] - (if (= 0 exit) - (str/trim out) - (throw (Exception. - (format "`pass` command failed\nStandard output:%s\nStandard Error:%s" - out - err)))))) diff --git a/users/aspen/bbbg/src/bbbg/util/dev_secrets.clj b/users/aspen/bbbg/src/bbbg/util/dev_secrets.clj deleted file mode 100644 index 88f1b50ca..000000000 --- a/users/aspen/bbbg/src/bbbg/util/dev_secrets.clj +++ /dev/null @@ -1,59 +0,0 @@ -(ns bbbg.util.dev-secrets - "Utility library for loading secrets during development from multiple - backends. - - # Supported backends - - - [Pass][0] (the default) - - (bbbg.util.dev-secrets/set-backend! :pass) - - Loads all secrets by shelling out to `pass ` - - [0]: https://www.passwordstore.org/ - - - Directory - - (bbbg.util.dev-secrets/set-backend! [:dir \"/path/to/secret/directory\"]) - - Loads all secrets by reading the secret name as a (plaintext!) file rooted - at the given directory" - (:require [bbbg.util.core :as u] - [clojure.string :as str] - [clojure.java.io :as io])) - -(def ^:dynamic *secret-backend* :pass) - -(defn set-backend! - "Change the default secret-backend" - [backend] - (alter-var-root #'*secret-backend* (constantly backend))) - -(defmulti ^:private load-secret - (fn [backend _secret] - (if (coll? backend) (first backend) backend))) - -(defmethod load-secret :pass [_ secret] - (u/pass secret)) - -(defmethod load-secret :dir [[_ dir] secret] - (str/trim (slurp (io/file dir secret)))) - -(defn secret - "Load the value for the given `secret-name' from the currently selected - backend" - [secret-name] - (load-secret *secret-backend* secret-name)) - -(comment - (secret "bbbg/discord-client-id") - - (binding [*secret-backend* [:dir "/tmp/bbbg-secrets"]] - (secret "bbbg/discord-client-id")) - - (set-backend! [:dir "/tmp/bbbg-secrets"]) - (secret "bbbg/discord-client-id") - - (set-backend! :pass) - (secret "bbbg/discord-client-id") - ) diff --git a/users/aspen/bbbg/src/bbbg/util/display.clj b/users/aspen/bbbg/src/bbbg/util/display.clj deleted file mode 100644 index 40716632a..000000000 --- a/users/aspen/bbbg/src/bbbg/util/display.clj +++ /dev/null @@ -1,23 +0,0 @@ -(ns bbbg.util.display - (:require - [bbbg.util.time :as t]) - (:import - [java.time.format DateTimeFormatter FormatStyle])) - -(defn format-date - ([d] (format-date d FormatStyle/MEDIUM)) - ([d ^FormatStyle format-style] - (let [formatter (DateTimeFormatter/ofLocalizedDate format-style)] - (.format (t/->LocalDate d) formatter)))) - -(defn pluralize - ([n sing plur] - (str (or n 0) " " (if (= 1 n) sing plur))) - ([n sing] - (pluralize n sing (str sing "s")))) - -(comment - (format-date #inst "2021-12-19T05:00:00.000-00:00") - (format-date #inst "2021-12-19T05:00:00.000-00:00" - FormatStyle/FULL) - ) diff --git a/users/aspen/bbbg/src/bbbg/util/spec.clj b/users/aspen/bbbg/src/bbbg/util/spec.clj deleted file mode 100644 index 89ac92669..000000000 --- a/users/aspen/bbbg/src/bbbg/util/spec.clj +++ /dev/null @@ -1,16 +0,0 @@ -(ns bbbg.util.spec - (:require [expound.alpha :as exp] - [clojure.spec.alpha :as s])) - -(defn assert! - ([spec s] (assert! "Spec assertion failed" spec s)) - ([message spec x] - (if (s/valid? spec x) - x - (throw (ex-info - (str message - "\n" - (exp/expound-str spec x)) - (assoc (s/explain-data spec x) - ::s/failure - ::s/assertion-failed)))))) diff --git a/users/aspen/bbbg/src/bbbg/util/sql.clj b/users/aspen/bbbg/src/bbbg/util/sql.clj deleted file mode 100644 index 988959fd0..000000000 --- a/users/aspen/bbbg/src/bbbg/util/sql.clj +++ /dev/null @@ -1,5 +0,0 @@ -(ns bbbg.util.sql - (:require [honeysql.core :as hsql])) - -(defn count-where [cond] - (hsql/call :count (hsql/call :case cond #sql/raw "1" :else nil))) diff --git a/users/aspen/bbbg/src/bbbg/util/time.clj b/users/aspen/bbbg/src/bbbg/util/time.clj deleted file mode 100644 index 0278f89f5..000000000 --- a/users/aspen/bbbg/src/bbbg/util/time.clj +++ /dev/null @@ -1,152 +0,0 @@ -(ns bbbg.util.time - "Utilities for dealing with date/time" - (:require [clojure.spec.alpha :as s] - [clojure.test.check.generators :as gen] - [java-time :as jt]) - (:import [java.time - LocalDateTime LocalTime OffsetDateTime ZoneId ZoneOffset - LocalDate Year] - [java.time.format DateTimeFormatter DateTimeParseException] - java.util.Calendar - org.apache.commons.lang3.time.DurationFormatUtils)) - -(set! *warn-on-reflection* true) - -(defprotocol ToOffsetDateTime - (->OffsetDateTime [this] - "Coerces its argument to a `java.time.OffsetDateTime`")) - -(extend-protocol ToOffsetDateTime - OffsetDateTime - (->OffsetDateTime [odt] odt) - - java.util.Date - (->OffsetDateTime [d] - (-> d - .toInstant - (OffsetDateTime/ofInstant (ZoneId/of "UTC"))))) - -(defprotocol ToLocalTime (->LocalTime [this])) -(extend-protocol ToLocalTime - LocalTime - (->LocalTime [lt] lt) - - java.sql.Time - (->LocalTime [t] - (let [^Calendar cal (doto (Calendar/getInstance) - (.setTime t))] - (LocalTime/of - (.get cal Calendar/HOUR_OF_DAY) - (.get cal Calendar/MINUTE) - (.get cal Calendar/SECOND)))) - - java.util.Date - (->LocalTime [d] - (-> d .toInstant (LocalTime/ofInstant (ZoneId/of "UTC"))))) - -(defn local-time? [x] (satisfies? ToLocalTime x)) -(s/def ::local-time - (s/with-gen local-time? - #(gen/let [hour (gen/choose 0 23) - minute (gen/choose 0 59) - second (gen/choose 0 59) - nanos gen/nat] - (LocalTime/of hour minute second nanos)))) - -(defprotocol ToLocalDate (->LocalDate [this])) -(extend-protocol ToLocalDate - LocalDate - (->LocalDate [ld] ld) - - java.sql.Date - (->LocalDate [sd] (.toLocalDate sd)) - - java.util.Date - (->LocalDate [d] - (-> d .toInstant (LocalDate/ofInstant (ZoneId/of "UTC"))))) - -(defn local-date? [x] (satisfies? ToLocalDate x)) -(s/def ::local-date - (s/with-gen local-date? - #(gen/let [year (gen/choose Year/MIN_VALUE Year/MAX_VALUE) - day (gen/choose 1 (if (.isLeap (Year/of year)) - 366 - 365))] - (LocalDate/ofYearDay year day)))) - -(extend-protocol Inst - OffsetDateTime - (inst-ms* [zdt] - (inst-ms* (.toInstant zdt))) - - LocalDateTime - (inst-ms* [^LocalDateTime ldt] - (inst-ms* (.toInstant ldt ZoneOffset/UTC)))) - -(let [formatter DateTimeFormatter/ISO_OFFSET_DATE_TIME] - (defn ^OffsetDateTime parse-iso-8601 - "Parse s as an iso-8601 datetime, returning nil if invalid" - [^String s] - (try - (OffsetDateTime/parse s formatter) - (catch DateTimeParseException _ nil))) - - (defn format-iso-8601 - "Format dt, which can be an OffsetDateTime or java.util.Date, as iso-8601" - [dt] - (some->> dt ->OffsetDateTime (.format formatter)))) - -(let [formatter DateTimeFormatter/ISO_TIME] - (defn parse-iso-8601-time - "Parse s as an iso-8601 timestamp, returning nil if invalid" - [^String s] - (try - (LocalTime/parse s formatter) - (catch DateTimeParseException _ nil))) - - (defn format-iso-8601-time - "Format lt, which can be a LocalTime or java.sql.Time, as an iso-8601 - formatted timestamp without a date." - [lt] - (some->> lt ->LocalTime (.format formatter)))) - -(defmethod print-dup LocalTime [t w] - (binding [*out* w] - (print "#local-time ") - (print (str "\"" (format-iso-8601-time t) "\"")))) - -(defmethod print-method LocalTime [t w] - (print-dup t w)) - -(let [formatter DateTimeFormatter/ISO_LOCAL_DATE] - (defn parse-iso-8601-date - "Parse s as an iso-8601 date, returning nil if invalid" - [^String s] - (try - (LocalDate/parse s formatter) - (catch DateTimeParseException _ nil))) - - (defn format-iso-8601-date - "Format lt, which can be a LocalDate, as an iso-8601 formatted date without - a timestamp." - [lt] - (some->> lt ->LocalDate (.format formatter)))) - -(defmethod print-dup LocalDate [t w] - (binding [*out* w] - (print "#local-date ") - (print (str "\"" (format-iso-8601-date t) "\"")))) - -(defmethod print-method LocalDate [t w] - (print-dup t w)) - - -(defn ^String human-format-duration - "Human-format the given duration" - [^java.time.Duration dur] - (DurationFormatUtils/formatDurationWords (Math/abs (.toMillis dur)) true true)) - -(comment - (human-format-duration (jt/hours 5)) - (human-format-duration (jt/plus (jt/hours 5) (jt/minutes 7))) - ) diff --git a/users/aspen/bbbg/src/bbbg/views/flash.clj b/users/aspen/bbbg/src/bbbg/views/flash.clj deleted file mode 100644 index a44b21d4c..000000000 --- a/users/aspen/bbbg/src/bbbg/views/flash.clj +++ /dev/null @@ -1,39 +0,0 @@ -(ns bbbg.views.flash - (:require [clojure.spec.alpha :as s])) - -(s/def :flash/type #{:success :error :warning :info}) -(s/def :flash/message string?) -(s/def ::flash (s/keys :req [:flash/type :flash/message])) -(s/fdef add-flash :args (s/cat :resp map? :flash ::flash) :ret map?) - -;;; - -(def ^:dynamic *flash* nil) - -(defn wrap-page-flash [handler] - (fn - ([request] - (binding [*flash* (:flash request)] - (handler request))) - ([request respond raise] - (binding [*flash* (:flash request)] - (handler request respond raise))))) - -(defn add-flash [resp flash] - (update-in resp [:flash :flash/messages] conj flash)) - -(defn render-flash - ([] (render-flash *flash*)) - ([flash] - (when-some [messages (not-empty (:flash/messages flash))] - [:ul.flash-messages - (for [message messages] - [:li.flash-message - {:class (str "flash-" (-> message :flash/type name))} - (:flash/message message)])]))) - -(def test-flash - {:flash/messages - (for [type [:success :error :warning :info]] - {:flash/type type - :flash/message (str "Sample " type " message")})}) diff --git a/users/aspen/bbbg/src/bbbg/web.clj b/users/aspen/bbbg/src/bbbg/web.clj deleted file mode 100644 index f9755577a..000000000 --- a/users/aspen/bbbg/src/bbbg/web.clj +++ /dev/null @@ -1,140 +0,0 @@ -(ns bbbg.web - (:require - [bbbg.discord.auth :as discord.auth :refer [wrap-discord-auth]] - [bbbg.handlers.attendee-checks :as attendee-checks] - [bbbg.handlers.attendees :as attendees] - [bbbg.handlers.core :refer [wrap-current-uri wrap-dynamic-auth]] - [bbbg.handlers.events :as events] - [bbbg.handlers.home :as home] - [bbbg.handlers.signup-form :as signup-form] - [bbbg.styles :refer [stylesheet]] - [bbbg.util.core :as u] - [bbbg.views.flash :refer [wrap-page-flash]] - [cambium.core :as log] - clj-time.coerce - [clojure.java.io :as io] - [clojure.spec.alpha :as s] - [com.stuartsierra.component :as component] - [compojure.core :refer [GET routes]] - [config.core :refer [env]] - [org.httpkit.server :as http-kit] - [ring.logger :refer [wrap-with-logger]] - [ring.middleware.flash :refer [wrap-flash]] - [ring.middleware.keyword-params :refer [wrap-keyword-params]] - [ring.middleware.multipart-params :refer [wrap-multipart-params]] - [ring.middleware.params :refer [wrap-params]] - [ring.middleware.resource :refer [wrap-resource]] - [ring.middleware.session :refer [wrap-session]] - [ring.middleware.session.cookie :refer [cookie-store]] - [ring.util.response :refer [content-type response]]) - (:import - java.util.Base64)) - -(s/def ::port pos-int?) - -(s/def ::cookie-secret - (s/and bytes? #(= 16 (count %)))) - -(s/def ::config - (s/merge - (s/keys :req [::port] - :opt [::cookie-secret - ::base-url]) - ::discord.auth/config)) - -(s/fdef make-server - :args (s/cat :config ::config)) - - -(defn- string->cookie-secret [raw] - (s/assert - ::cookie-secret - (when raw - (.decode (Base64/getDecoder) - (.getBytes raw "UTF-8"))))) - -(defn env->config [] - (s/assert - ::config - (u/remove-nils - (merge - {::port (:port env 8888) - ::cookie-secret (some-> env :cookie-secret string->cookie-secret) - ::base-url (:base-url env)} - (discord.auth/env->config))))) - -(defn dev-config [] - (s/assert - ::config - (merge - {::port 8888 - ::cookie-secret (into-array Byte/TYPE (repeat 16 0))} - (discord.auth/dev-config)))) - -;;; - -(defn app-routes [env] - (routes - (GET "/main.css" [] - (-> (response - (str - "\n/* begin base.css */\n" - (slurp (io/resource "base.css")) - "\n/* end base.css */\n" - stylesheet)) - (content-type "text/css"))) - - (attendees/attendees-routes env) - (attendee-checks/attendee-checks-routes env) - (signup-form/signup-form-routes env) - (events/events-routes env) - (home/home-routes env))) - -(defn middleware [app env] - (-> app - (wrap-resource "public") - (wrap-with-logger - {:log-fn - (fn [{:keys [level throwable message]}] - (log/log level {} throwable message))}) - wrap-current-uri - wrap-dynamic-auth - (wrap-discord-auth env) - wrap-keyword-params - wrap-multipart-params - wrap-params - wrap-page-flash - wrap-flash - (wrap-session {:store (cookie-store - {:key (:cookie-secret env) - :readers {'clj-time/date-time - clj-time.coerce/from-string}}) - :cookie-attrs {:same-site :lax}}))) - -(defn handler [env] - (-> (app-routes env) - (middleware env))) - -(defrecord WebServer [port cookie-secret db] - component/Lifecycle - (start [this] - (assoc this - ::shutdown-fn - (http-kit/run-server - (fn [r] ((handler this) r)) - {:port port}))) - (stop [this] - (if-let [shutdown-fn (::shutdown-fn this)] - (do (shutdown-fn :timeout 100) - (dissoc this ::shutdown-fn)) - this))) - -(defn make-server [{::keys [port cookie-secret] - :as env}] - (component/using - (map->WebServer - (merge - {:port port - :cookie-secret cookie-secret} - env)) - [:db])) diff --git a/users/aspen/bbbg/test/bbbg/meetup/import_test.clj b/users/aspen/bbbg/test/bbbg/meetup/import_test.clj deleted file mode 100644 index d7d698a58..000000000 --- a/users/aspen/bbbg/test/bbbg/meetup/import_test.clj +++ /dev/null @@ -1,7 +0,0 @@ -(ns bbbg.meetup.import-test - (:require [bbbg.meetup.import :as sut] - [clojure.test :refer :all])) - -(deftest test-row-user-id->user-id - (is (= "246364067" (sut/row-user-id->user-id "user 246364067"))) - (is (= "246364067" (sut/row-user-id->user-id "246364067")))) diff --git a/users/aspen/bbbg/tf.nix b/users/aspen/bbbg/tf.nix deleted file mode 100644 index e6ea69dfd..000000000 --- a/users/aspen/bbbg/tf.nix +++ /dev/null @@ -1,96 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.users.aspen) - terraform - ; - -in -terraform.workspace "bbbg" -{ - plugins = (p: with p; [ - aws - cloudflare - ]); -} -{ - machine = terraform.nixosMachine { - name = "bbbg"; - instanceType = "t3a.small"; - rootVolumeSizeGb = 250; - extraIngressPorts = [ 80 443 ]; - configuration = { pkgs, lib, config, depot, ... }: { - imports = [ - ./module.nix - "${depot.third_party.agenix.src}/modules/age.nix" - ]; - - services.openssh.enable = true; - - services.nginx = { - enable = true; - recommendedTlsSettings = true; - recommendedOptimisation = true; - recommendedGzipSettings = true; - recommendedProxySettings = true; - }; - - networking.firewall.enable = false; - - programs.zsh.enable = true; - - users.users.grfn = { - isNormalUser = true; - initialPassword = "password"; - extraGroups = [ - "wheel" - "networkmanager" - "audio" - "docker" - ]; - shell = pkgs.zsh; - openssh.authorizedKeys.keys = [ - depot.users.aspen.keys.main - ]; - }; - - security.sudo.extraRules = [{ - groups = [ "wheel" ]; - commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }]; - }]; - - nix.gc = { - automatic = true; - dates = "weekly"; - options = "--delete-older-than 30d"; - }; - - age.secrets = { - bbbg.file = - depot.users.aspen.secrets."bbbg.age"; - }; - - services.bbbg.enable = true; - services.bbbg.database.enable = true; - services.bbbg.proxy.enable = true; - services.bbbg.domain = "bbbg.gws.fyi"; - - security.acme.defaults.email = "root@gws.fyi"; - security.acme.acceptTerms = true; - }; - }; - - dns = { - data.cloudflare_zone.gws-fyi = { - name = "gws.fyi"; - }; - - resource.cloudflare_record.bbbg = { - zone_id = "\${data.cloudflare_zone.gws-fyi.id}"; - name = "bbbg"; - type = "A"; - value = "\${aws_instance.bbbg_machine.public_ip}"; - proxied = false; - }; - }; -} diff --git a/users/aspen/emacs.d/+bindings.el b/users/aspen/emacs.d/+bindings.el deleted file mode 100644 index 0bcc92263..000000000 --- a/users/aspen/emacs.d/+bindings.el +++ /dev/null @@ -1,1439 +0,0 @@ -;; -*- lexical-binding: t; -*- - -(load! "utils") -(require 'f) -(require 'predd) - -(undefine-key! :keymaps 'doom-leader-map "/") - -(defmacro find-file-in! (path &optional project-p) - "Returns an interactive function for searching files." - `(lambda () (interactive) - (let ((default-directory ,path)) - (call-interactively - ',(command-remapping - (if project-p - #'projectile-find-file - #'find-file)))))) - -(defun dired-mode-p () (eq 'dired-mode major-mode)) - -(defun grfn/dired-minus () - (interactive) - (if (dired-mode-p) - (dired-up-directory) - (when buffer-file-name - (-> (buffer-file-name) - (f-dirname) - (dired))))) - -(defmacro define-move-and-insert - (name &rest body) - `(defun ,name (count &optional vcount skip-empty-lines) - ;; Following interactive form taken from the source for `evil-insert' - (interactive - (list (prefix-numeric-value current-prefix-arg) - (and (evil-visual-state-p) - (memq (evil-visual-type) '(line block)) - (save-excursion - (let ((m (mark))) - ;; go to upper-left corner temporarily so - ;; `count-lines' yields accurate results - (evil-visual-rotate 'upper-left) - (prog1 (count-lines evil-visual-beginning evil-visual-end) - (set-mark m))))) - (evil-visual-state-p))) - (atomic-change-group - ,@body - (evil-insert count vcount skip-empty-lines)))) - -(define-move-and-insert grfn/insert-at-sexp-end - (when (not (equal (get-char) "(")) - (backward-up-list)) - (forward-sexp) - (backward-char)) - -(define-move-and-insert grfn/insert-at-sexp-start - (backward-up-list) - (forward-char)) - -(define-move-and-insert grfn/insert-at-form-start - (backward-sexp) - (backward-char) - (insert " ")) - -(define-move-and-insert grfn/insert-at-form-end - (forward-sexp) - (insert " ")) - -(load! "splitjoin") - -(defun +hlissner/install-snippets () - "Install my snippets from https://github.com/hlissner/emacs-snippets into -private/hlissner/snippets." - (interactive) - (doom-fetch :github "hlissner/emacs-snippets" - (expand-file-name "snippets" (doom-module-path :private 'hlissner)))) - -(defun +hlissner/yank-buffer-filename () - "Copy the current buffer's path to the kill ring." - (interactive) - (if-let* ((filename (or buffer-file-name (bound-and-true-p list-buffers-directory)))) - (message (kill-new (abbreviate-file-name filename))) - (error "Couldn't find filename in current buffer"))) - -(defmacro +def-finder! (name dir) - "Define a pair of find-file and browse functions." - `(progn - (defun ,(intern (format "+find-in-%s" name)) () - (interactive) - (let ((default-directory ,dir) - projectile-project-name - projectile-require-project-root - projectile-cached-buffer-file-name - projectile-cached-project-root) - (call-interactively #'projectile-find-file))) - (defun ,(intern (format "+hlissner/browse-%s" name)) () - (interactive) - (let ((default-directory ,dir)) - (call-interactively (command-remapping #'find-file)))))) - -(+def-finder! templates +file-templates-dir) -(+def-finder! snippets +grfn-snippets-dir) -(+def-finder! dotfiles (expand-file-name ".dotfiles" "~")) -(+def-finder! doomd (expand-file-name ".doom.d" "~")) -(+def-finder! notes +org-dir) -(+def-finder! home-config (expand-file-name "code/system/home" "~")) -(+def-finder! system-config (expand-file-name "code/system/system" "~")) - -(defun +grfn/paxedit-kill (&optional n) - (interactive "p") - (or (paxedit-comment-kill) - (when (paxedit-symbol-cursor-within?) - (paxedit-symbol-kill)) - (paxedit-implicit-sexp-kill n) - (paxedit-sexp-kill n) - (message paxedit-message-kill))) - -;;; - -(evil-set-command-property 'flycheck-next-error :repeat nil) -(evil-set-command-property 'flycheck-prev-error :repeat nil) -(evil-set-command-property 'flycheck-previous-error :repeat nil) -(evil-set-command-property 'smerge-next :repeat nil) -(evil-set-command-property 'smerge-prev :repeat nil) - -;;; - -(map! - [remap evil-jump-to-tag] #'projectile-find-tag - [remap find-tag] #'projectile-find-tag - ;; ensure there are no conflicts - :nmvo doom-leader-key nil - :nmvo doom-localleader-key nil) - -(undefine-key! :keymaps 'doom-leader-map "/") - -(map! - ;; --- Global keybindings --------------------------- - ;; Make M-x available everywhere - :gnvime "M-x" #'execute-extended-command - :gnvime "A-x" #'execute-extended-command - ;; Emacs debug utilities - :gnvime "M-;" #'eval-expression - :gnvime "M-:" #'doom/open-scratch-buffer - ;; Text-scaling - "M-+" (λ! (text-scale-set 0)) - "M-=" #'text-scale-increase - "M--" #'text-scale-decrease - ;; Simple window navigation/manipulation - "C-`" #'doom/popup-toggle - "C-~" #'doom/popup-raise - "M-t" #'+workspace/new - "M-T" #'+workspace/display - "M-w" #'delete-window - "M-W" #'+workspace/close-workspace-or-frame - "M-n" #'evil-buffer-new - "M-N" #'make-frame - "M-1" (λ! (+workspace/switch-to 0)) - "M-2" (λ! (+workspace/switch-to 1)) - "M-3" (λ! (+workspace/switch-to 2)) - "M-4" (λ! (+workspace/switch-to 3)) - "M-5" (λ! (+workspace/switch-to 4)) - "M-6" (λ! (+workspace/switch-to 5)) - "M-7" (λ! (+workspace/switch-to 6)) - "M-8" (λ! (+workspace/switch-to 7)) - "M-9" (λ! (+workspace/switch-to 8)) - "M-0" #'+workspace/switch-to-last - ;; Other sensible, textmate-esque global bindings - :ne "M-r" #'+eval/buffer - :ne "M-R" #'+eval/region-and-replace - :ne "M-b" #'+eval/build - :ne "M-a" #'mark-whole-buffer - :ne "M-c" #'evil-yank - :ne "M-q" (if (daemonp) #'delete-frame #'save-buffers-kill-emacs) - :ne "M-f" #'swiper - :ne "C-M-f" #'doom/toggle-fullscreen - :n "M-s" #'save-buffer - :m "A-j" #'+hlissner:multi-next-line - :m "A-k" #'+hlissner:multi-previous-line - :nv "C-SPC" #'+evil:fold-toggle - :gnvimer "M-v" #'clipboard-yank - ;; Easier window navigation - :en "C-h" #'evil-window-left - :en "C-j" #'evil-window-down - :en "C-k" #'evil-window-up - :en "C-l" #'evil-window-right - :n "U" #'undo-tree-visualize - - "C-x p" #'doom/other-popup - - :n "K" #'+lookup/documentation - :n "g d" #'+lookup/definition - - - ;; --- ------------------------------------- - (:leader - :desc "Ex command" :nv ";" #'evil-ex - :desc "M-x" :nv ":" #'execute-extended-command - :desc "Pop up scratch buffer" :nv "x" #'doom/open-scratch-buffer - :desc "Org Capture" :nv "X" #'org-capture - :desc "Org Capture" :nv "a" #'org-capture - - ;; Most commonly used - :desc "Find file in project" :n "SPC" #'projectile-find-file - :desc "Switch workspace buffer" :n "," #'persp-switch-to-buffer - :desc "Switch buffer" :n "<" #'switch-to-buffer - :desc "Browse files" :n "." #'find-file - :desc "Toggle last popup" :n "~" #'doom/popup-toggle - :desc "Eval expression" :n "`" #'eval-expression - :desc "Blink cursor line" :n "DEL" #'+doom/blink-cursor - :desc "Jump to bookmark" :n "RET" #'bookmark-jump - - ;; C-u is used by evil - :desc "Universal argument" :n "u" #'universal-argument - :desc "window" :n "w" evil-window-map - - (:desc "previous..." :prefix "[" - :desc "Text size" :nv "[" #'text-scale-decrease - :desc "Buffer" :nv "b" #'doom/previous-buffer - :desc "Diff Hunk" :nv "d" #'git-gutter:previous-hunk - :desc "Todo" :nv "t" #'hl-todo-previous - :desc "Error" :nv "e" #'flycheck-previous-error - :desc "Workspace" :nv "w" #'+workspace/switch-left - :desc "Smart jump" :nv "h" #'smart-backward - :desc "Spelling error" :nv "s" #'evil-prev-flyspell-error - :desc "Spelling correction" :n "S" #'flyspell-correct-previous-word-generic - :desc "Git conflict" :n "n" #'smerge-prev) - - (:desc "next..." :prefix "]" - :desc "Text size" :nv "]" #'text-scale-increase - :desc "Buffer" :nv "b" #'doom/next-buffer - :desc "Diff Hunk" :nv "d" #'git-gutter:next-hunk - :desc "Todo" :nv "t" #'hl-todo-next - :desc "Error" :nv "e" #'flycheck-next-error - :desc "Workspace" :nv "w" #'+workspace/switch-right - :desc "Smart jump" :nv "l" #'smart-forward - :desc "Spelling error" :nv "s" #'evil-next-flyspell-error - :desc "Spelling correction" :n "S" #'flyspell-correct-word-generic - :desc "Git conflict" :n "n" #'smerge-next) - - (:desc "search" :prefix "/" - :desc "Swiper" :nv "/" #'swiper - :desc "Imenu" :nv "i" #'imenu - :desc "Imenu across buffers" :nv "I" #'imenu-anywhere - :desc "Online providers" :nv "o" #'+lookup/online-select) - - (:desc "workspace" :prefix "TAB" - :desc "Display tab bar" :n "TAB" #'+workspace/display - :desc "New workspace" :n "n" #'+workspace/new - :desc "Load workspace from file" :n "l" #'+workspace/load - :desc "Load last session" :n "L" (λ! (+workspace/load-session)) - :desc "Save workspace to file" :n "s" #'+workspace/save - :desc "Autosave current session" :n "S" #'+workspace/save-session - :desc "Switch workspace" :n "." #'+workspace/switch-to - :desc "Kill all buffers" :n "x" #'doom/kill-all-buffers - :desc "Delete session" :n "X" #'+workspace/kill-session - :desc "Delete this workspace" :n "d" #'+workspace/delete - :desc "Load session" :n "L" #'+workspace/load-session - :desc "Next workspace" :n "]" #'+workspace/switch-right - :desc "Previous workspace" :n "[" #'+workspace/switch-left - :desc "Switch to 1st workspace" :n "1" (λ! (+workspace/switch-to 0)) - :desc "Switch to 2nd workspace" :n "2" (λ! (+workspace/switch-to 1)) - :desc "Switch to 3rd workspace" :n "3" (λ! (+workspace/switch-to 2)) - :desc "Switch to 4th workspace" :n "4" (λ! (+workspace/switch-to 3)) - :desc "Switch to 5th workspace" :n "5" (λ! (+workspace/switch-to 4)) - :desc "Switch to 6th workspace" :n "6" (λ! (+workspace/switch-to 5)) - :desc "Switch to 7th workspace" :n "7" (λ! (+workspace/switch-to 6)) - :desc "Switch to 8th workspace" :n "8" (λ! (+workspace/switch-to 7)) - :desc "Switch to 9th workspace" :n "9" (λ! (+workspace/switch-to 8)) - :desc "Switch to last workspace" :n "0" #'+workspace/switch-to-last) - - (:desc "buffer" :prefix "b" - :desc "New empty buffer" :n "n" #'evil-buffer-new - :desc "Switch workspace buffer" :n "b" #'switch-to-buffer - :desc "Switch buffer" :n "B" #'switch-to-buffer - :desc "Kill buffer" :n "k" #'doom/kill-this-buffer - :desc "Kill other buffers" :n "o" #'doom/kill-other-buffers - :desc "Save buffer" :n "s" #'save-buffer - :desc "Pop scratch buffer" :n "x" #'doom/open-scratch-buffer - :desc "Bury buffer" :n "z" #'bury-buffer - :desc "Next buffer" :n "]" #'doom/next-buffer - :desc "Previous buffer" :n "[" #'doom/previous-buffer - :desc "Sudo edit this file" :n "S" #'doom/sudo-this-file) - - (:desc "code" :prefix "c" - :desc "List errors" :n "x" #'flycheck-list-errors - :desc "Evaluate buffer/region" :n "e" #'+eval/buffer - :v "e" #'+eval/region - :desc "Evaluate & replace region" :nv "E" #'+eval:replace-region - :desc "Build tasks" :nv "b" #'+eval/build - :desc "Jump to definition" :n "d" #'+lookup/definition - :desc "Jump to references" :n "D" #'+lookup/references - :desc "Open REPL" :n "r" #'+eval/open-repl - :v "r" #'+eval:repl) - - (:desc "file" :prefix "f" - :desc "Find file" :n "." #'find-file - :desc "Sudo find file" :n ">" #'doom/sudo-find-file - :desc "Find file in project" :n "/" #'projectile-find-file - :desc "Find file from here" :n "?" #'counsel-file-jump - :desc "Find other file" :n "a" #'projectile-find-other-file - :desc "Open project editorconfig" :n "c" #'editorconfig-find-current-editorconfig - :desc "Find file in dotfiles" :n "d" #'+find-in-dotfiles - :desc "Find file in system config" :n "s" #'+find-in-system-config - :desc "Find file in home config" :n "h" #'+find-in-home-config - :desc "Browse dotfiles" :n "D" #'+hlissner/browse-dotfiles - :desc "Find file in emacs.d" :n "e" #'+find-in-doomd - :desc "Browse emacs.d" :n "E" #'+hlissner/browse-doomd - :desc "Recent files" :n "r" #'recentf-open-files - :desc "Recent project files" :n "R" #'projectile-recentf - :desc "Yank filename" :n "y" #'+hlissner/yank-buffer-filename) - - (:desc "git" :prefix "g" - :desc "Git status" :n "S" #'magit-status - :desc "Git blame" :n "b" #'magit-blame - :desc "Git time machine" :n "t" #'git-timemachine-toggle - :desc "Git stage hunk" :n "s" #'git-gutter:stage-hunk - :desc "Git revert hunk" :n "r" #'git-gutter:revert-hunk - :desc "Git revert buffer" :n "R" #'vc-revert - ;; :desc "List gists" :n "g" #'+gist:list - :desc "Git grep" :n "g" #'counsel-projectile-rg - :desc "Checkout Branch" :n "c" #'counsel-git-checkout - :desc "Next hunk" :nv "]" #'git-gutter:next-hunk - :desc "Previous hunk" :nv "[" #'git-gutter:previous-hunk - - (:desc "smerge" :prefix "m" - :desc "Keep Current" :n "SPC" #'smerge-keep-current - :desc "Keep All" :n "a" #'smerge-keep-all - :desc "Keep Upper" :n "u" #'smerge-keep-upper - :desc "Keep Lower" :n "l" #'smerge-keep-lower)) - - (:desc "help" :prefix "h" - :n "h" help-map - :desc "Apropos" :n "a" #'apropos - :desc "Reload theme" :n "R" #'doom//reload-theme - :desc "Find library" :n "l" #'find-library - :desc "Toggle Emacs log" :n "m" #'doom/popup-toggle-messages - :desc "Command log" :n "L" #'global-command-log-mode - :desc "Describe function" :n "f" #'describe-function - :desc "Describe key" :n "k" #'describe-key - :desc "Describe char" :n "c" #'describe-char - :desc "Describe mode" :n "M" #'describe-mode - :desc "Describe variable" :n "v" #'describe-variable - :desc "Describe face" :n "F" #'describe-face - :desc "Describe DOOM setting" :n "s" #'doom/describe-setting - :desc "Describe DOOM module" :n "d" #'doom/describe-module - :desc "Find definition" :n "." #'+lookup/definition - :desc "Find references" :n "/" #'+lookup/references - :desc "Find documentation" :n "h" #'+lookup/documentation - :desc "What face" :n "'" #'doom/what-face - :desc "What minor modes" :n ";" #'doom/what-minor-mode - :desc "Info" :n "i" #'info - :desc "Toggle profiler" :n "p" #'doom/toggle-profiler) - - (:desc "insert" :prefix "i" - :desc "From kill-ring" :nv "y" #'counsel-yank-pop - :desc "From snippet" :nv "s" #'yas-insert-snippet) - - (:desc "notes" :prefix "n" - :desc "Agenda" :n "a" #'org-agenda - :desc "Find file in notes" :n "n" #'+find-in-notes - :desc "Store link" :n "l" #'org-store-link - :desc "Browse notes" :n "N" #'+hlissner/browse-notes - :desc "Org capture" :n "x" #'+org-capture/open - :desc "Create clubhouse story" :n "c" #'org-tracker-create-issue - :desc "Archive subtree" :n "k" #'org-archive-subtree - :desc "Goto clocked-in note" :n "g" #'org-clock-goto - :desc "Clock Out" :n "o" #'org-clock-out) - - - (:desc "open" :prefix "o" - :desc "Default browser" :n "b" #'browse-url-of-file - :desc "Debugger" :n "d" #'+debug/open - :desc "Terminal in project" :n "T" #'+term/open-popup-in-project - - :desc "Slack IM" :n "i" #'slack-im-select - :desc "Slack Channel" :n "c" #'slack-channel-select - :desc "Slack Group" :n "g" #'slack-group-select - :desc "Slack Unreads" :n "u" #'slack-select-unread-rooms - :desc "Slack Threads" :n "r" #'slack-all-threads - - :desc "Email" :n "m" #'notmuch-jump-search - - (:desc "ERC" :prefix "e" - :desc "Channel" :n "c" #'erc-switch-to-buffer) - - ;; applications - :desc "APP: elfeed" :n "E" #'=rss - :desc "APP: twitter" :n "T" #'=twitter - - (:desc "spotify" :prefix "s" - :desc "Search track" :n "t" #'counsel-spotify-search-track - :desc "Search album" :n "a" #'counsel-spotify-search-album - :desc "Search artist" :n "A" #'counsel-spotify-search-artist) - - ;; macos - (:when IS-MAC - :desc "Reveal in Finder" :n "o" #'+macos/reveal-in-finder - :desc "Reveal project in Finder" :n "O" #'+macos/reveal-project-in-finder - :desc "Send to Transmit" :n "u" #'+macos/send-to-transmit - :desc "Send project to Transmit" :n "U" #'+macos/send-project-to-transmit - :desc "Send to Launchbar" :n "l" #'+macos/send-to-launchbar - :desc "Send project to Launchbar" :n "L" #'+macos/send-project-to-launchbar)) - - (:desc "Email" :prefix "M" - :desc "Compose" :n "m" #'+notmuch/compose) - - (:desc "project" :prefix "p" - :desc "Browse project" :n "." (find-file-in! (doom-project-root)) - :desc "Find file in project" :n "/" #'projectile-find-file - :desc "Run cmd in project root" :nv "!" #'projectile-run-shell-command-in-root - :desc "Switch project" :n "p" #'projectile-switch-project - :desc "Recent project files" :n "r" #'projectile-recentf - :desc "List project tasks" :n "t" #'+ivy/tasks - :desc "Pop term in project" :n "o" #'+term/open-popup-in-project - :desc "Invalidate cache" :n "x" #'projectile-invalidate-cache) - - (:desc "quit" :prefix "q" - :desc "Quit" :n "q" #'evil-save-and-quit - :desc "Quit (forget session)" :n "Q" #'+workspace/kill-session-and-quit) - - (:desc "remote" :prefix "r" - :desc "Upload local" :n "u" #'+upload/local - :desc "Upload local (force)" :n "U" (λ! (+upload/local t)) - :desc "Download remote" :n "d" #'+upload/remote-download - :desc "Diff local & remote" :n "D" #'+upload/diff - :desc "Browse remote files" :n "." #'+upload/browse - :desc "Detect remote changes" :n ">" #'+upload/check-remote) - - (:desc "snippets" :prefix "s" - :desc "New snippet" :n "n" #'yas-new-snippet - :desc "Insert snippet" :nv "i" #'yas-insert-snippet - :desc "Find snippet for mode" :n "s" #'yas-visit-snippet-file - :desc "Find snippet" :n "S" #'+find-in-snippets) - - (:desc "toggle" :prefix "t" - :desc "Flyspell" :n "s" #'flyspell-mode - :desc "Flycheck" :n "f" #'flycheck-mode - :desc "Line numbers" :n "l" #'doom/toggle-line-numbers - :desc "Fullscreen" :n "f" #'doom/toggle-fullscreen - :desc "Indent guides" :n "i" #'highlight-indentation-mode - :desc "Indent guides (column)" :n "I" #'highlight-indentation-current-column-mode - :desc "Impatient mode" :n "h" #'+impatient-mode/toggle - :desc "Big mode" :n "b" #'doom-big-font-mode - :desc "Evil goggles" :n "g" #'+evil-goggles/toggle)) - - - ;; --- vim-vinegar - :n "-" #'grfn/dired-minus - (:after dired-mode - (:map dired-mode-map - "-" #'grfn/dired-minus)) - - (:map smartparens-mode-map - :n "g o" #'sp-raise-sexp) - - ;; --- vim-sexp-mappings-for-regular-people - (:after paxedit - (:map paxedit-mode-map - :i ";" #'paxedit-insert-semicolon - :i "(" #'paxedit-open-round - :i "[" #'paxedit-open-bracket - :i "{" #'paxedit-open-curly - :n [remap evil-yank-line] #'paxedit-copy - :n [remap evil-delete-line] #'+grfn/paxedit-kill - :n "g o" #'paxedit-sexp-raise - :n [remap evil-join-whitespace] #'paxedit-compress - :n "g S" #'paxedit-format-1 - :n "g k" #'paxedit-backward-up - :n "g j" #'paxedit-backward-end)) - - ;; --- vim-splitjoin - :n [remap evil-join-whitespace] #'+splitjoin/join - :n "gS" #'+splitjoin/split - - ;; --- Personal vim-esque bindings ------------------ - :n "zx" #'doom/kill-this-buffer - :n "ZX" #'bury-buffer - :n "]b" #'doom/next-buffer - :n "[b" #'doom/previous-buffer - :n "]w" #'+workspace/switch-right - :n "[w" #'+workspace/switch-left - :m "gt" #'+workspace/switch-right - :m "gT" #'+workspace/switch-left - :m "gd" #'+lookup/definition - :m "gD" #'+lookup/references - :m "K" #'+lookup/documentation - :n "gp" #'+evil/reselect-paste - :n "gr" #'+eval:region - :n "gR" #'+eval/buffer - :v "gR" #'+eval:replace-region - :v "@" #'+evil:macro-on-all-lines - :n "g@" #'+evil:macro-on-all-lines - ;; repeat in visual mode (FIXME buggy) - :v "." #'evil-repeat - ;; don't leave visual mode after shifting - ;; :v "<" #'+evil/visual-dedent ; vnoremap < " #'+evil/visual-indent ; vnoremap > >gv - ;; paste from recent yank register (which isn't overwritten) - :v "C-p" "\"0p" - - (:map evil-window-map ; prefix "C-w" - ;; Navigation - "C-h" #'evil-window-left - "C-j" #'evil-window-down - "C-k" #'evil-window-up - "C-l" #'evil-window-right - "C-w" #'ace-window - ;; Swapping windows - "H" #'+evil/window-move-left - "J" #'+evil/window-move-down - "K" #'+evil/window-move-up - "L" #'+evil/window-move-right - "C-S-w" #'ace-swap-window - ;; Window undo/redo - "u" #'winner-undo - "C-u" #'winner-undo - "C-r" #'winner-redo - "o" #'doom/window-enlargen - ;; Delete window - "c" #'+workspace/close-window-or-workspace - "C-C" #'ace-delete-window - ;; Popups - "p" #'doom/popup-toggle - "m" #'doom/popup-toggle-messages - "P" #'doom/popup-close-all) - - - ;; --- Plugin bindings ------------------------------ - ;; auto-yasnippet - :i [C-tab] #'aya-expand - :nv [C-tab] #'aya-create - - ;; company-mode (vim-like omnicompletion) - :i "C-SPC" #'+company/complete - (:prefix "C-x" - :i "C-l" #'+company/whole-lines - :i "C-k" #'+company/dict-or-keywords - :i "C-f" #'company-files - :i "C-]" #'company-etags - :i "s" #'company-ispell - :i "C-s" #'company-yasnippet - :i "C-o" #'company-capf - :i "C-n" #'company-dabbrev-code - :i "C-p" #'+company/dabbrev-code-previous) - (:after company - (:map company-active-map - ;; Don't interfere with `evil-delete-backward-word' in insert mode - "C-w" nil - "C-o" #'company-search-kill-others - "C-n" #'company-select-next - "C-p" #'company-select-previous - "C-h" #'company-quickhelp-manual-begin - "C-S-h" #'company-show-doc-buffer - "C-S-s" #'company-search-candidates - "C-s" #'company-filter-candidates - "C-SPC" #'company-complete-common - "C-h" #'company-quickhelp-manual-begin - [tab] #'company-complete-common-or-cycle - [backtab] #'company-select-previous - [escape] (λ! (company-abort) (evil-normal-state 1))) - ;; Automatically applies to `company-filter-map' - (:map company-search-map - "C-n" #'company-search-repeat-forward - "C-p" #'company-search-repeat-backward - "C-s" (λ! (company-search-abort) (company-filter-candidates)) - [escape] #'company-search-abort)) - - ;; counsel -; (:after counsel -; (:map counsel-ag-map -; [backtab] #'+ivy/wgrep-occur ; search/replace on results -; "C-SPC" #'ivy-call-and-recenter ; preview)) - - ;; evil-commentary - ;; :n "gc" #'evil-commentary - - ;; evil-exchange - :n "gx" #'evil-exchange - - ;; evil-magit - (:after evil-magit - :map (magit-status-mode-map magit-revision-mode-map) - :n "C-j" nil - :n "C-k" nil) - - ;; Smerge - :n "]n" #'smerge-next - :n "[n" #'smerge-prev - - ;; evil-mc - (:prefix "gz" - :nv "m" #'evil-mc-make-all-cursors - :nv "u" #'evil-mc-undo-all-cursors - :nv "z" #'+evil/mc-make-cursor-here - :nv "t" #'+evil/mc-toggle-cursors - :nv "n" #'evil-mc-make-and-goto-next-cursor - :nv "p" #'evil-mc-make-and-goto-prev-cursor - :nv "N" #'evil-mc-make-and-goto-last-cursor - :nv "P" #'evil-mc-make-and-goto-first-cursor - :nv "d" #'evil-mc-make-and-goto-next-match - :nv "D" #'evil-mc-make-and-goto-prev-match) - (:after evil-mc - :map evil-mc-key-map - :nv "C-n" #'evil-mc-make-and-goto-next-cursor - :nv "C-N" #'evil-mc-make-and-goto-last-cursor - :nv "C-p" #'evil-mc-make-and-goto-prev-cursor - :nv "C-P" #'evil-mc-make-and-goto-first-cursor) - - ;; evil-multiedit - :v "R" #'evil-multiedit-match-all - :n "M-d" #'evil-multiedit-match-symbol-and-next - :n "M-D" #'evil-multiedit-match-symbol-and-prev - :v "M-d" #'evil-multiedit-match-and-next - :v "M-D" #'evil-multiedit-match-and-prev - :nv "C-M-d" #'evil-multiedit-restore - (:after evil-multiedit - (:map evil-multiedit-state-map - "M-d" #'evil-multiedit-match-and-next - "M-D" #'evil-multiedit-match-and-prev - "RET" #'evil-multiedit-toggle-or-restrict-region) - (:map (evil-multiedit-state-map evil-multiedit-insert-state-map) - "C-n" #'evil-multiedit-next - "C-p" #'evil-multiedit-prev)) - - ;; evil-snipe - (:after evil-snipe - ;; Binding to switch to evil-easymotion/avy after a snipe - :map evil-snipe-parent-transient-map - "C-;" (λ! (require 'evil-easymotion) - (call-interactively - (evilem-create #'evil-snipe-repeat - :bind ((evil-snipe-scope 'whole-buffer) - (evil-snipe-enable-highlight) - (evil-snipe-enable-incremental-highlight)))))) - - ;; evil-surround - :v "S" #'evil-surround-region - :o "s" #'evil-surround-edit - :o "S" #'evil-Surround-edit - - ;; expand-region - :v "v" #'er/expand-region - :v "V" #'er/contract-region - - ;; flycheck - :m "]e" #'flycheck-next-error - :m "[e" #'flycheck-previous-error - (:after flycheck - :map flycheck-error-list-mode-map - :n "C-n" #'flycheck-error-list-next-error - :n "C-p" #'flycheck-error-list-previous-error - :n "j" #'flycheck-error-list-next-error - :n "k" #'flycheck-error-list-previous-error - :n "RET" #'flycheck-error-list-goto-error) - - ;; flyspell - :m "]S" #'flyspell-correct-word-generic - :m "[S" #'flyspell-correct-previous-word-generic - - ;; git-gutter - :m "]d" #'git-gutter:next-hunk - :m "[d" #'git-gutter:previous-hunk - - ;; git-timemachine - (:after git-timemachine - (:map git-timemachine-mode-map - :n "C-p" #'git-timemachine-show-previous-revision - :n "C-n" #'git-timemachine-show-next-revision - :n "[[" #'git-timemachine-show-previous-revision - :n "]]" #'git-timemachine-show-next-revision - :n "q" #'git-timemachine-quit - :n "gb" #'git-timemachine-blame)) - - ;; gist - (:after gist - :map gist-list-menu-mode-map - :n "RET" #'+gist/open-current - :n "b" #'gist-browse-current-url - :n "c" #'gist-add-buffer - :n "d" #'gist-kill-current - :n "f" #'gist-fork - :n "q" #'quit-window - :n "r" #'gist-list-reload - :n "s" #'gist-star - :n "S" #'gist-unstar - :n "y" #'gist-print-current-url) - - ;; helm - (:after helm - (:map helm-map - "ESC" nil - "C-S-n" #'helm-next-source - "C-S-p" #'helm-previous-source - "C-u" #'helm-delete-minibuffer-contents - "C-w" #'backward-kill-word - "C-r" #'evil-paste-from-register ; Evil registers in helm! Glorious! - "C-b" #'backward-word - [left] #'backward-char - [right] #'forward-char - [escape] #'helm-keyboard-quit - [tab] #'helm-execute-persistent-action) - - (:after helm-files - (:map helm-generic-files-map - :e "ESC" #'helm-keyboard-quit) - (:map helm-find-files-map - "C-w" #'helm-find-files-up-one-level - "TAB" #'helm-execute-persistent-action)) - - (:after helm-ag - (:map helm-ag-map - "" #'helm-ag-edit))) - - ;; hl-todo - :m "]t" #'hl-todo-next - :m "[t" #'hl-todo-previous - - ;; ivy - (:after ivy - :map ivy-minibuffer-map - [escape] #'keyboard-escape-quit - "C-SPC" #'ivy-call-and-recenter - "TAB" #'ivy-partial - "M-v" #'yank - "M-z" #'undo - "C-r" #'evil-paste-from-register - "C-k" #'ivy-previous-line - "C-j" #'ivy-next-line - "C-l" #'ivy-alt-done - "C-w" #'ivy-backward-kill-word - "C-u" #'ivy-kill-line - "C-b" #'backward-word - "C-f" #'forward-word) - - ;; neotree - (:after neotree - :map neotree-mode-map - :n "g" nil - :n [tab] #'neotree-quick-look - :n "RET" #'neotree-enter - :n [backspace] #'evil-window-prev - :n "c" #'neotree-create-node - :n "r" #'neotree-rename-node - :n "d" #'neotree-delete-node - :n "j" #'neotree-next-line - :n "k" #'neotree-previous-line - :n "n" #'neotree-next-line - :n "p" #'neotree-previous-line - :n "h" #'+neotree/collapse-or-up - :n "l" #'+neotree/expand-or-open - :n "J" #'neotree-select-next-sibling-node - :n "K" #'neotree-select-previous-sibling-node - :n "H" #'neotree-select-up-node - :n "L" #'neotree-select-down-node - :n "G" #'evil-goto-line - :n "gg" #'evil-goto-first-line - :n "v" #'neotree-enter-vertical-split - :n "s" #'neotree-enter-horizontal-split - :n "q" #'neotree-hide - :n "R" #'neotree-refresh) - - ;; realgud - (:after realgud - :map realgud:shortkey-mode-map - :n "j" #'evil-next-line - :n "k" #'evil-previous-line - :n "h" #'evil-backward-char - :n "l" #'evil-forward-char - :m "n" #'realgud:cmd-next - :m "b" #'realgud:cmd-break - :m "B" #'realgud:cmd-clear - :n "c" #'realgud:cmd-continue) - - ;; rotate-text - :n "gs" #'rotate-text - - ;; smart-forward - :m "g]" #'smart-forward - :m "g[" #'smart-backward - - ;; undo-tree -- undo/redo for visual regions - :v "C-u" #'undo-tree-undo - :v "C-r" #'undo-tree-redo - - ;; yasnippet - (:after yasnippet - (:map yas-keymap - "C-e" #'+snippets/goto-end-of-field - "C-a" #'+snippets/goto-start-of-field - "" #'+snippets/goto-end-of-field - "" #'+snippets/goto-start-of-field - "" #'+snippets/delete-to-start-of-field - [escape] #'evil-normal-state - [backspace] #'+snippets/delete-backward-char - [delete] #'+snippets/delete-forward-char-or-field) - (:map yas-minor-mode-map - :i "" yas-maybe-expand - :v "" #'+snippets/expand-on-region)) - - - ;; --- Major mode bindings -------------------------- - - ;; Markdown - (:after markdown-mode - (:map markdown-mode-map - ;; fix conflicts with private bindings - "" nil - "" nil - "" nil)) - - ;; Rust - (:after rust - (:map rust-mode-map - "g RET" #'cargo-process-test)) - - ;; Elixir - (:after alchemist - (:map elixir-mode-map - :n "K" #'alchemist-help-search-at-point - :n "g RET" #'alchemist-project-run-tests-for-current-file - :n "g \\" #'alchemist-mix-test-at-point - :n "g SPC" #'alchemist-mix-compile)) - - ;; Haskell - (:after haskell-mode - (:map haskell-mode-map - ;; :n "K" #'intero-info - :n "K" #'lsp-describe-thing-at-point - ;; :n "g d" #'lsp-ui-peek-find-definitions - :n "g d" #'lsp-ui-peek-find-definitions - :n "g R" #'lsp-find-references - ;; :n "g SPC" #'intero-repl-load - ;; :n "g y" #'lsp-ui- - )) - - ;; Javascript - ;; (:after rjsx-mode - ;; (:map rjsx-mode-map - ;; :n "g d" #'flow-minor-jump-to-definition - ;; :n "K" #'flow-minor-type-at-pos)) - - (:after js2-mode - (:map js2-mode-map - :n "g d" #'flow-minor-jump-to-definition - :n "K" #'flow-minor-type-at-pos)) - - ;; Elisp - (:map emacs-lisp-mode-map - :n "g SPC" #'eval-buffer - :n "g RET" (λ! () (ert t))) - - - ;; --- Custom evil text-objects --------------------- - :textobj "a" #'evil-inner-arg #'evil-outer-arg - :textobj "B" #'evil-textobj-anyblock-inner-block #'evil-textobj-anyblock-a-block - :textobj "i" #'evil-indent-plus-i-indent #'evil-indent-plus-a-indent - :textobj "I" #'evil-indent-plus-i-indent-up #'evil-indent-plus-a-indent-up - :textobj "J" #'evil-indent-plus-i-indent-up-down #'evil-indent-plus-a-indent-up-down - - - ;; --- Built-in plugins ----------------------------- - (:after comint - ;; TAB auto-completion in term buffers - :map comint-mode-map [tab] #'company-complete) - - (:after debug - ;; For elisp debugging - :map debugger-mode-map - :n "RET" #'debug-help-follow - :n "e" #'debugger-eval-expression - :n "n" #'debugger-step-through - :n "c" #'debugger-continue) - - (:map help-mode-map - :n "[[" #'help-go-back - :n "]]" #'help-go-forward - :n "o" #'ace-link-help - :n "q" #'quit-window - :n "Q" #'+ivy-quit-and-resume) - - (:after vc-annotate - :map vc-annotate-mode-map - :n "q" #'kill-this-buffer - :n "d" #'vc-annotate-show-diff-revision-at-line - :n "D" #'vc-annotate-show-changeset-diff-revision-at-line - :n "SPC" #'vc-annotate-show-log-revision-at-line - :n "]]" #'vc-annotate-next-revision - :n "[[" #'vc-annotate-prev-revision - :n "TAB" #'vc-annotate-toggle-annotation-visibility - :n "RET" #'vc-annotate-find-revision-at-line)) - -;; evil-easymotion -(after! evil-easymotion - (let ((prefix (concat doom-leader-key " /"))) - ;; NOTE `evilem-default-keybinds' unsets all other keys on the prefix (in - ;; motion state) - (evilem-default-keybindings prefix) - (evilem-define (kbd (concat prefix " n")) #'evil-ex-search-next) - (evilem-define (kbd (concat prefix " N")) #'evil-ex-search-previous) - (evilem-define (kbd (concat prefix " s")) #'evil-snipe-repeat - :pre-hook (save-excursion (call-interactively #'evil-snipe-s)) - :bind ((evil-snipe-scope 'buffer) - (evil-snipe-enable-highlight) - (evil-snipe-enable-incremental-highlight))) - (evilem-define (kbd (concat prefix " S")) #'evil-snipe-repeat-reverse - :pre-hook (save-excursion (call-interactively #'evil-snipe-s)) - :bind ((evil-snipe-scope 'buffer) - (evil-snipe-enable-highlight) - (evil-snipe-enable-incremental-highlight))))) - - -;; -;; Keybinding fixes -;; - -;; This section is dedicated to "fixing" certain keys so that they behave -;; properly, more like vim, or how I like it. - -(map! (:map input-decode-map - [S-iso-lefttab] [backtab] - (:unless window-system "TAB" [tab])) ; Fix TAB in terminal - - ;; I want C-a and C-e to be a little smarter. C-a will jump to - ;; indentation. Pressing it again will send you to the true bol. Same goes - ;; for C-e, except it will ignore comments and trailing whitespace before - ;; jumping to eol. - :i "C-a" #'doom/backward-to-bol-or-indent - :i "C-e" #'doom/forward-to-last-non-comment-or-eol - :i "C-u" #'doom/backward-kill-to-bol-and-indent - - ;; Emacsien motions for insert mode - :i "C-b" #'backward-word - :i "C-f" #'forward-word - - ;; Highjacks space/backspace to: - ;; a) balance spaces inside brackets/parentheses ( | ) -> (|) - ;; b) delete space-indented blocks intelligently - ;; c) do none of this when inside a string - ;; :i "SPC" #'doom/inflate-space-maybe - ;; :i [remap delete-backward-char] #'doom/deflate-space-maybe - ;; :i [remap newline] #'doom/newline-and-indent - - (:map org-mode-map - :i [remap doom/inflate-space-maybe] #'org-self-insert-command - "C-c C-x C-i" #'org-clock-in - "C-c C-x " #'org-clock-in) - - (:map org-agenda-mode-map - "C-c C-x C-i" #'org-agenda-clock-in - "C-c C-x " #'org-agenda-clock-in) - - ;; Restore common editing keys (and ESC) in minibuffer - (:map (minibuffer-local-map - minibuffer-local-ns-map - minibuffer-local-completion-map - minibuffer-local-must-match-map - minibuffer-local-isearch-map - evil-ex-completion-map - evil-ex-search-keymap - read-expression-map) - ;; [escape] #'abort-recursive-edit - "C-r" #'evil-paste-from-register - "C-a" #'move-beginning-of-line - "C-w" #'doom/minibuffer-kill-word - "C-u" #'doom/minibuffer-kill-line - "C-b" #'backward-word - "C-f" #'forward-word - "M-z" #'doom/minibuffer-undo) - - (:map messages-buffer-mode-map - "M-;" #'eval-expression - "A-;" #'eval-expression) - - (:map tabulated-list-mode-map - [remap evil-record-macro] #'doom/popup-close-maybe) - - (:after view - (:map view-mode-map "" #'View-quit-all))) - -(defun +sexp-transpose () - (interactive) - (case evil-this-operator - ('evil-shift-right (paxedit-transpose-forward)) - ('evil-shift-left (paxedit-transpose-backward)))) - -;; (defun nmap (&rest keys-and-ops) -;; (->> -;; (seq-partition keys-and-ops 2) -;; (seq-map -;; (lambda (k-op) -;; (let* ((k (car k-op)) -;; (op (cadr k-op)) -;; (prefix (substring k 0 1)) -;; (prefix-sym (lookup-key evil-normal-state-map prefix)) -;; (keyseq (substring k 1))) -;; (list keyseq prefix-sym op)))) -;; (seq-group-by #'car) -;; (seq-map -;; (lambda (k-ops) -;; (let* ((keyseq (car k-ops)) -;; (ops (cdr k-ops)) -;; (existing-binding (lookup-key evil-operator-state-map keyseq)) -;; (handler (λ! () -;; (if-let -;; ((oplist -;; (seq-find (lambda (op) -;; (equal (nth 1 op) -;; evil-this-operator)) -;; ops))) -;; (message "calling oplist") -;; (->> oplist (nth 2) funcall) -;; (when existing-binding -;; (funcall existing-binding)))))) -;; (if existing-binding -;; (progn -;; (define-key evil-operator-state-map -;; (vector 'remap existing-binding) -;; handler) -;; (define-key evil-motion-state-map -;; (vector 'remap existing-binding) -;; handler)) -;; (define-key evil-operator-state-map keyseq handler))))))) - -;; (nmap -;; ">e" #'paxedit-transpose-forward -;; "" (general-key-dispatch 'evil-shift-right - "e" 'paxedit-transpose-forward - ")" 'sp-forward-slurp-sexp - "(" 'sp-backward-barf-sexp - "I" 'grfn/insert-at-sexp-end - ;; "a" 'grfn/insert-at-form-end - )) - -(nmap - "<" (general-key-dispatch 'evil-shift-left - "e" 'paxedit-transpose-backward - ")" 'sp-forward-barf-sexp - "(" 'sp-backward-slurp-sexp - "I" 'grfn/insert-at-sexp-start - ;; "a" 'grfn/insert-at-form-start - )) - - -(defmacro saving-excursion (&rest body) - `(λ! () (save-excursion ,@body))) - -(nmap "c" (general-key-dispatch 'evil-change - "r c" (saving-excursion (string-inflection-lower-camelcase)) - "r C" (saving-excursion (string-inflection-camelcase)) - "r m" (saving-excursion (string-inflection-camelcase)) - "r s" (saving-excursion (string-inflection-underscore)) - "r u" (saving-excursion (string-inflection-upcase)) - "r -" (saving-excursion (string-inflection-kebab-case)) - "r k" (saving-excursion (string-inflection-kebab-case)) - ;; "r ." (saving-excursion (string-inflection-dot-case)) - ;; "r ." (saving-excursion (string-inflection-space-case)) - ;; "r ." (saving-excursion (string-inflection-title-case)) - )) - - -(predd-defmulti eval-sexp (lambda (form) major-mode)) - -(predd-defmethod eval-sexp 'clojure-mode (form) - (cider-interactive-eval form)) - -(predd-defmethod eval-sexp 'emacs-lisp-mode (form) - (pp-eval-expression form)) - -(predd-defmulti eval-sexp-region (lambda (_beg _end) major-mode)) - -(predd-defmethod eval-sexp-region 'clojure-mode (beg end) - (cider-interactive-eval nil nil (list beg end))) - -(predd-defmethod eval-sexp-region 'emacs-lisp-mode (beg end) - (pp-eval-expression (read (buffer-substring beg end)))) - -(predd-defmulti eval-sexp-region-context (lambda (_beg _end _context) major-mode)) - -(predd-defmethod eval-sexp-region-context 'clojure-mode (beg end context) - (cider--eval-in-context (buffer-substring beg end))) - -(defun pp-eval-context-region (beg end context) - (interactive "r\nxContext: ") - (let* ((inner-expr (read (buffer-substring beg end))) - (full-expr (list 'let* context inner-expr))) - (pp-eval-expression full-expr))) - -(predd-defmethod eval-sexp-region-context 'emacs-lisp-mode (beg end context) - (pp-eval-context-region beg end context)) - -(predd-defmulti preceding-sexp (lambda () major-mode)) - -(predd-defmethod preceding-sexp 'clojure-mode () - (cider-last-sexp)) - -(predd-defmethod preceding-sexp 'emacs-lisp-mode () - (elisp--preceding-sexp)) - -(defun eval-sexp-at-point () - (interactive) - (let ((bounds (bounds-of-thing-at-point 'sexp))) - (eval-sexp-region (car bounds) - (cdr bounds)))) - -(defun eval-last-sexp (_) - (interactive) - (eval-sexp (preceding-sexp))) - -;;; - -(defun cider-insert-current-sexp-in-repl (&optional arg) - "Insert the expression at point in the REPL buffer. -If invoked with a prefix ARG eval the expression after inserting it" - (interactive "P") - (cider-insert-in-repl (cider-sexp-at-point) arg)) - -(evil-define-operator fireplace-send (beg end) - (cider-insert-current-sexp-in-repl nil nil (list beg end))) - -(defun +clojure-pprint-expr (form) - (format "(with-out-str (clojure.pprint/pprint %s))" - form)) - -(defun cider-eval-read-and-print-handler (&optional buffer) - "Make a handler for evaluating and reading then printing result in BUFFER." - (nrepl-make-response-handler - (or buffer (current-buffer)) - (lambda (buffer value) - (let ((value* (read value))) - (with-current-buffer buffer - (insert - (if (derived-mode-p 'cider-clojure-interaction-mode) - (format "\n%s\n" value*) - value*))))) - (lambda (_buffer out) (cider-emit-interactive-eval-output out)) - (lambda (_buffer err) (cider-emit-interactive-eval-err-output err)) - '())) - -(defun cider-eval-and-replace (beg end) - "Evaluate the expression in region and replace it with its result" - (interactive "r") - (let ((form (buffer-substring beg end))) - (cider-nrepl-sync-request:eval form) - (kill-region beg end) - (cider-interactive-eval - (+clojure-pprint-expr form) - (cider-eval-read-and-print-handler)))) - -(defun cider-eval-current-sexp-and-replace () - "Evaluate the expression at point and replace it with its result" - (interactive) - (apply #'cider-eval-and-replace (cider-sexp-at-point 'bounds))) - -;;; - -(evil-define-operator fireplace-eval (beg end) - (eval-sexp-region beg end)) - -(evil-define-operator fireplace-replace (beg end) - (cider-eval-and-replace beg end)) - -(evil-define-operator fireplace-eval-context (beg end) - (eval-sexp-region-context beg end)) - -;;; fireplace-esque eval binding -(nmap :keymaps 'cider-mode-map - "c" (general-key-dispatch 'evil-change - "p" (general-key-dispatch 'fireplace-eval - "p" 'cider-eval-sexp-at-point - "c" 'cider-eval-last-sexp - "d" 'cider-eval-defun-at-point - "r" 'cider-test-run-test) - "q" (general-key-dispatch 'fireplace-send - "q" 'cider-insert-current-sexp-in-repl - "c" 'cider-insert-last-sexp-in-repl) - "x" (general-key-dispatch 'fireplace-eval-context - "x" 'cider-eval-sexp-at-point-in-context - "c" 'cider-eval-last-sexp-in-context) - "!" (general-key-dispatch 'fireplace-replace - "!" 'cider-eval-current-sexp-and-replace - "c" 'cider-eval-last-sexp-and-replace) - "y" 'cider-copy-last-result)) - -;;; - -(nmap :keymaps 'emacs-lisp-mode-map - "c" (general-key-dispatch 'evil-change - "p" (general-key-dispatch 'fireplace-eval - "p" 'eval-sexp-at-point - "c" 'eval-last-sexp - "d" 'eval-defun - "r" 'cider-test-run-test) - "x" (general-key-dispatch 'fireplace-eval-context - "x" 'cider-eval-sexp-at-point-in-context - "c" 'cider-eval-last-sexp-in-context) - "!" (general-key-dispatch 'fireplace-replace - "!" 'cider-eval-current-sexp-and-replace - "c" 'cider-eval-last-sexp-and-replace) - "y" 'cider-copy-last-result)) - -(nmap :keymaps 'sly-mode-map - "c" (general-key-dispatch 'evil-change - "p" (general-key-dispatch 'sly-eval - ;; "p" 'eval-sexp-at-point - "c" 'sly-eval-last-expression - "d" 'sly-eval-defun - ;; "r" 'cider-test-run-test - ) - ;; "x" (general-key-dispatch 'fireplace-eval-context - ;; "x" 'cider-eval-sexp-at-point-in-context - ;; "c" 'cider-eval-last-sexp-in-context - ;; ) - ;; "!" (general-key-dispatch 'fireplace-replace - ;; "!" 'cider-eval-current-sexp-and-replace - ;; "c" 'cider-eval-last-sexp-and-replace) - ;; "y" 'cider-copy-last-result - )) - - -;; >) ; slurp forward -;; <) ; barf forward -;; <( ; slurp backward -;; >( ; slurp backward - -;; (require 'doom-themes) -(defun grfn/haskell-test-file-p () - (string-match-p (rx (and "Spec.hs" eol)) - (buffer-file-name))) - -(require 'haskell) - -(defun grfn/intero-run-main () - (interactive) - (intero-repl-load) - (intero-with-repl-buffer nil - (comint-simple-send - (get-buffer-process (current-buffer)) - "main"))) - -(defun grfn/run-clj-or-cljs-test () - (interactive) - (message "Running tests...") - (cl-case (cider-repl-type-for-buffer) - ('cljs - (cider-interactive-eval - "(with-out-str (cljs.test/run-tests))" - (nrepl-make-response-handler - (current-buffer) - (lambda (_ value) - (with-output-to-temp-buffer "*cljs-test-results*" - (print - (->> value - (s-replace "\"" "") - (s-replace "\\n" "\n"))))) - nil nil nil))) - (('clj 'multi) - (funcall-interactively - #'cider-test-run-ns-tests - nil)))) - -(defun cider-copy-last-result () - (interactive) - (cider-interactive-eval - "*1" - (nrepl-make-response-handler - (current-buffer) - (lambda (_ value) - (kill-new value) - (message "Copied last result (%s) to clipboard" - (if (= (length value) 1) "1 char" - (format "%d chars" (length value))))) - nil nil nil))) - - -(defun grfn/insert-new-src-block () - (interactive) - (let* ((current-src-block (org-element-at-point)) - (src-block-head (save-excursion - (goto-char (org-element-property - :begin current-src-block)) - (let ((line (thing-at-point 'line t))) - (if (not (s-starts-with? "#+NAME:" (s-trim line))) - line - (forward-line) - (thing-at-point 'line t))))) - (point-to-insert - (if-let (results-loc (org-babel-where-is-src-block-result)) - (save-excursion - (goto-char results-loc) - (org-element-property - :end - (org-element-at-point))) - (org-element-property :end (org-element-at-point))))) - (goto-char point-to-insert) - (insert "\n") - (insert src-block-head) - (let ((contents (point-marker))) - (insert "\n#+END_SRC\n") - (goto-char contents)))) - -(defun grfn/+org-insert-item (orig direction) - (interactive) - (if (and (org-in-src-block-p) - (equal direction 'below)) - (grfn/insert-new-src-block) - (funcall orig direction))) - -(advice-add #'+org--insert-item :around #'grfn/+org-insert-item) -;; (advice-add #'+org/insert-item-below :around -;; (lambda (orig) (grfn/+org-insert-item orig 'below))) - -(defun set-pdb-trace () - (interactive) - (end-of-line) - (insert (format "\n%simport pdb;pdb.set_trace()" - (make-string (python-indent-calculate-indentation) - ?\s))) - (evil-indent (line-beginning-position) - (line-end-position))) - -(map! - - (:map magit-mode-map - :n "#" 'forge-dispatch) - - (:map haskell-mode-map - :n "K" 'lsp-info-under-point - :n "g d" 'lsp-ui-peek-find-definitions - :n "g r" 'lsp-ui-peek-find-references - :n "g \\" '+haskell/repl - ;; :n "K" 'intero-info - ;; :n "g d" 'intero-goto-definition - ;; :n "g SPC" 'intero-repl-load - ;; :n "g \\" 'intero-repl - ;; :n "g y" 'intero-type-at - ;; :n "g RET" 'grfn/run-sputnik-test-for-file - - (:localleader - :desc "Apply action" :n "e" 'intero-repl-eval-region - :desc "Rename symbol" :n "r" 'intero-apply-suggestions)) - - (:map python-mode-map - :n "K" #'anaconda-mode-show-doc - :n "g SPC" #'+eval/buffer - :n "g RET" #'python-pytest-file - :n "g \\" #'+python/open-ipython-repl - [remap evil-commentary-yank] #'set-pdb-trace) - - (:after agda2-mode - (:map agda2-mode-map - :n "g SPC" 'agda2-load - :n "g d" 'agda2-goto-definition-keyboard - :n "] g" 'agda2-next-goal - :n "[ g" 'agda2-previous-goal - - (:localleader - :desc "Give" :n "SPC" 'agda2-give - :desc "Case Split" :n "c" 'agda2-make-case - :desc "Make Helper" :n "h" 'agda2-helper-function-type - :desc "Refine" :n "r" 'agda2-refine - :desc "Auto" :n "a" 'agda2-auto-maybe-all - :desc "Goal type and context" :n "t" 'agda2-goal-and-context - :desc "Goal type and context and inferred" :n ";" 'agda2-goal-and-context-and-inferred))) - - (:after clojure-mode - (:map clojure-mode-map - :n "] f" 'forward-sexp - :n "[ f" 'backward-sexp)) - - (:after cider-mode - (:map cider-mode-map - :n "g SPC" 'cider-eval-buffer - :n "g \\" 'cider-switch-to-repl-buffer - :n "K" 'cider-doc - :n "g K" 'cider-apropos - :n "g d" 'cider-find-dwim - :n "C-w ]" 'cider-find-dwim-other-window - ;; :n "g RET" 'cider-test-run-ns-tests - :n "g RET" 'grfn/run-clj-or-cljs-test - :n "g r" #'cljr-rename-symbol - - "C-c C-r r" 'cljr-add-require-to-ns - "C-c C-r i" 'cljr-add-import-to-ns - - (:localleader - ;; :desc "Inspect last result" :n "i" 'cider-inspect-last-result - ;; :desc "Search for documentation" :n "h s" 'cider-apropos-doc - :desc "Add require to ns" :n "n r" 'cljr-add-require-to-ns - :desc "Add import to ns" :n "n i" 'cljr-add-import-to-ns)) - (:map cider-repl-mode-map - :n "g \\" 'cider-switch-to-last-clojure-buffer)) - - (:after w3m - (:map w3m-mode-map - "/" #'evil-search-forward - "?" #'evil-search-backward - "r" #'w3m-reload-this-page)) - - (:after slack - (:map slack-message-buffer-mode-map - :i "" #'slack-message-edit)) - - (:after org - :n "C-c C-x C-o" #'org-clock-out - (:map org-mode-map - [remap counsel-imenu] #'counsel-org-goto - "M-k" #'org-move-subtree-up - "M-j" #'org-move-subtree-down - (:localleader - :n "g" #'counsel-org-goto)) - - (:map org-capture-mode-map - :n "g RET" #'org-capture-finalize - :n "g \\" #'org-captue-refile)) - - (:map lsp-mode-map - :n "K" #'lsp-describe-thing-at-point - :n "g r" #'lsp-rename - (:localleader - :n "a" #'lsp-execute-code-action)) - - (:map prolog-mode-map - :n "g SPC" #'prolog-compile-buffer - :n "g \\" #'run-prolog) - - (:map tuareg-mode-map - :n "g RET" (λ! () (compile "dune build @@runtest")) - :n "g SPC" #'dune-promote - :n "g \\" #'utop - :n "g y" #'merlin-locate-type - "C-c C-f" (λ! () (compile "dune fmt")))) diff --git a/users/aspen/emacs.d/+commands.el b/users/aspen/emacs.d/+commands.el deleted file mode 100644 index 518f185cb..000000000 --- a/users/aspen/emacs.d/+commands.el +++ /dev/null @@ -1,149 +0,0 @@ -;; -*- lexical-binding: t; -*- - -(defalias 'ex! 'evil-ex-define-cmd) - -(defun delete-file-and-buffer () - "Kill the current buffer and deletes the file it is visiting." - (interactive) - (let ((filename (buffer-file-name))) - (when filename - (if (vc-backend filename) - (vc-delete-file filename) - (progn - (delete-file filename) - (message "Deleted file %s" filename) - (kill-buffer)))))) - -;;; Commands defined elsewhere -;;(ex! "al[ign]" #'+evil:align) -;;(ex! "g[lobal]" #'+evil:global) - -;;; Custom commands -;; Editing -(ex! "@" #'+evil:macro-on-all-lines) ; TODO Test me -(ex! "al[ign]" #'+evil:align) -(ex! "enhtml" #'+web:encode-html-entities) -(ex! "dehtml" #'+web:decode-html-entities) -(ex! "mc" #'+evil:mc) -(ex! "iedit" #'evil-multiedit-ex-match) -(ex! "na[rrow]" #'+evil:narrow-buffer) -(ex! "retab" #'+evil:retab) - -(ex! "glog" #'magit-log-buffer-file) - -;; External resources -;; TODO (ex! "db" #'doom:db) -;; TODO (ex! "dbu[se]" #'doom:db-select) -;; TODO (ex! "go[ogle]" #'doom:google-search) -(ex! "lo[okup]" #'+jump:online) -(ex! "dash" #'+lookup:dash) -(ex! "dd" #'+lookup:devdocs) -(ex! "http" #'httpd-start) ; start http server -(ex! "repl" #'+eval:repl) ; invoke or send to repl -;; TODO (ex! "rx" 'doom:regex) ; open re-builder -(ex! "sh[ell]" #'+eshell:run) -(ex! "t[mux]" #'+tmux:run) ; send to tmux -(ex! "tcd" #'+tmux:cd-here) ; cd to default-directory in tmux -(ex! "x" #'doom/open-project-scratch-buffer) - -;; GIT -(ex! "gist" #'+gist:send) ; send current buffer/region to gist -(ex! "gistl" #'+gist:list) ; list gists by user -(ex! "gbrowse" #'+vcs/git-browse) ; show file in github/gitlab -(ex! "gissues" #'+vcs/git-browse-issues) ; show github issues -(ex! "git" #'magit-status) ; open magit status window -(ex! "gstage" #'magit-stage) -(ex! "gunstage" #'magit-unstage) -(ex! "gblame" #'magit-blame) -(ex! "grevert" #'git-gutter:revert-hunk) - -;; Dealing with buffers -(ex! "clean[up]" #'doom/cleanup-buffers) -(ex! "k[ill]" #'doom/kill-this-buffer) -(ex! "k[ill]all" #'+hlissner:kill-all-buffers) -(ex! "k[ill]m" #'+hlissner:kill-matching-buffers) -(ex! "k[ill]o" #'doom/kill-other-buffers) -(ex! "l[ast]" #'doom/popup-restore) -(ex! "m[sg]" #'view-echo-area-messages) -(ex! "pop[up]" #'doom/popup-this-buffer) - -;; Project navigation -(ex! "a" #'projectile-toggle-between-implementation-and-test) -(ex! "as" #'projectile-find-implementation-or-test-other-window) -(ex! "av" #'projectile-find-implementation-or-test-other-window) -(ex! "cd" #'+hlissner:cd) -(cond ((featurep! :completion ivy) - (ex! "ag" #'+ivy:ag) - (ex! "agc[wd]" #'+ivy:ag-cwd) - (ex! "rg" #'+ivy:rg) - (ex! "rgc[wd]" #'+ivy:rg-cwd) - (ex! "sw[iper]" #'+ivy:swiper) - (ex! "todo" #'+ivy:todo)) - ((featurep! :completion helm) - (ex! "ag" #'+helm:ag) - (ex! "agc[wd]" #'+helm:ag-cwd) - (ex! "rg" #'+helm:rg) - (ex! "rgc[wd]" #'+helm:rg-cwd) - (ex! "sw[oop]" #'+helm:swoop) - (ex! "todo" #'+helm:todo))) - -;; Project tools -(ex! "build" #'+eval/build) -(ex! "debug" #'+debug/run) -(ex! "er[rors]" #'flycheck-list-errors) - -;; File operations -(ex! "cp" #'+evil:copy-this-file) -(ex! "mv" #'+evil:move-this-file) -(ex! "rm" #'+evil:delete-this-file) - -;; Sessions/tabs -(ex! "sclear" #'+workspace/kill-session) -(ex! "sl[oad]" #'+workspace:load-session) -(ex! "ss[ave]" #'+workspace:save-session) -(ex! "tabcl[ose]" #'+workspace:delete) -(ex! "tabclear" #'doom/kill-all-buffers) -(ex! "tabl[ast]" #'+workspace/switch-to-last) -(ex! "tabload" #'+workspace:load) -(ex! "tabn[ew]" #'+workspace:new) -(ex! "tabn[ext]" #'+workspace:switch-next) -(ex! "tabp[rev]" #'+workspace:switch-previous) -(ex! "tabr[ename]" #'+workspace:rename) -(ex! "tabs" #'+workspace/display) -(ex! "tabsave" #'+workspace:save) - -(ex! "scr[atch]" #'cider-scratch) - -;; Org-mode -(ex! "cap" #'+org-capture/dwim) - -(evil-define-command evil-alembic-revision (args) - (interactive "") - (apply - #'generate-alembic-migration - (read-string "Message: ") - (s-split "\\s+" (or args "")))) -(ex! "arev[ision]" #'evil-alembic-revision) - -(evil-define-command evil-alembic-upgrade (&optional revision) - (interactive "") - (alembic-upgrade (or revision "head"))) - -(ex! "aup[grade]" #'evil-alembic-upgrade) - -(evil-define-command evil-alembic-downgrade (&optional revision) - (interactive "") - (alembic-downgrade revision)) - -(ex! "adown[grade]" #'evil-alembic-downgrade) - -(evil-define-command evil-alembic (args) - (interactive "") - (run-alembic args)) - -(ex! "alemb[ic]" #'evil-alembic) - -;; Elixir -(add-hook! elixir-mode - (ex! "AV" #'alchemist-project-toggle-file-and-tests-other-window) - (ex! "A" #'alchemist-project-toggle-file-and-tests)) diff --git a/users/aspen/emacs.d/+private.el.gpg b/users/aspen/emacs.d/+private.el.gpg deleted file mode 100644 index 6273c67d6..000000000 Binary files a/users/aspen/emacs.d/+private.el.gpg and /dev/null differ diff --git a/users/aspen/emacs.d/.gitignore b/users/aspen/emacs.d/.gitignore deleted file mode 100644 index 1fd0e3988..000000000 --- a/users/aspen/emacs.d/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.authinfo.gpg -+private.el diff --git a/users/aspen/emacs.d/autoload/evil.el b/users/aspen/emacs.d/autoload/evil.el deleted file mode 100644 index 319c93c05..000000000 --- a/users/aspen/emacs.d/autoload/evil.el +++ /dev/null @@ -1,37 +0,0 @@ -;;; /autoload/evil.el -*- lexical-binding: t; -*- -;;;###if (featurep! :feature evil) - -;;;###autoload (autoload '+hlissner:multi-next-line "/autoload/evil" nil t) -(evil-define-motion +hlissner:multi-next-line (count) - "Move down 6 lines." - :type line - (let ((line-move-visual (or visual-line-mode (derived-mode-p 'text-mode)))) - (evil-line-move (* 6 (or count 1))))) - -;;;###autoload (autoload '+hlissner:multi-previous-line "/autoload/evil" nil t) -(evil-define-motion +hlissner:multi-previous-line (count) - "Move up 6 lines." - :type line - (let ((line-move-visual (or visual-line-mode (derived-mode-p 'text-mode)))) - (evil-line-move (- (* 6 (or count 1)))))) - -;;;###autoload (autoload '+hlissner:cd "/autoload/evil" nil t) -(evil-define-command +hlissner:cd () - "Change `default-directory' with `cd'." - (interactive "") - (cd input)) - -;;;###autoload (autoload '+hlissner:kill-all-buffers "/autoload/evil" nil t) -(evil-define-command +hlissner:kill-all-buffers (&optional bang) - "Kill all buffers. If BANG, kill current session too." - (interactive "") - (if bang - (+workspace/kill-session) - (doom/kill-all-buffers))) - -;;;###autoload (autoload '+hlissner:kill-matching-buffers "/autoload/evil" nil t) -(evil-define-command +hlissner:kill-matching-buffers (&optional bang pattern) - "Kill all buffers matching PATTERN regexp. If BANG, only match project -buffers." - (interactive "") - (doom/kill-matching-buffers pattern bang)) diff --git a/users/aspen/emacs.d/autoload/hlissner.el b/users/aspen/emacs.d/autoload/hlissner.el deleted file mode 100644 index 87b2236d1..000000000 --- a/users/aspen/emacs.d/autoload/hlissner.el +++ /dev/null @@ -1,53 +0,0 @@ -;;; autoload/hlissner.el -*- lexical-binding: t; -*- - -;;;###autoload -(defun +hlissner/install-snippets () - "Install my snippets from https://github.com/hlissner/emacs-snippets into -private/hlissner/snippets." - (interactive) - (doom-fetch :github "hlissner/emacs-snippets" - (expand-file-name "snippets" (doom-module-path :private 'hlissner)))) - -;;;###autoload -(defun +hlissner/yank-buffer-filename () - "Copy the current buffer's path to the kill ring." - (interactive) - (if-let* ((filename (or buffer-file-name (bound-and-true-p list-buffers-directory)))) - (message (kill-new (abbreviate-file-name filename))) - (error "Couldn't find filename in current buffer"))) - -(defmacro +hlissner-def-finder! (name dir) - "Define a pair of find-file and browse functions." - `(progn - (defun ,(intern (format "+hlissner/find-in-%s" name)) () - (interactive) - (let ((default-directory ,dir) - projectile-project-name - projectile-require-project-root - projectile-cached-buffer-file-name - projectile-cached-project-root) - (call-interactively (command-remapping #'projectile-find-file)))) - (defun ,(intern (format "+hlissner/browse-%s" name)) () - (interactive) - (let ((default-directory ,dir)) - (call-interactively (command-remapping #'find-file)))))) - -;;;###autoload (autoload '+hlissner/find-in-templates "autoload/hlissner" nil t) -;;;###autoload (autoload '+hlissner/browse-templates "autoload/hlissner" nil t) -(+hlissner-def-finder! templates +file-templates-dir) - -;;;###autoload (autoload '+hlissner/find-in-snippets "autoload/hlissner" nil t) -;;;###autoload (autoload '+hlissner/browse-snippets "autoload/hlissner" nil t) -(+hlissner-def-finder! snippets +hlissner-snippets-dir) - -;;;###autoload (autoload '+hlissner/find-in-dotfiles "autoload/hlissner" nil t) -;;;###autoload (autoload '+hlissner/browse-dotfiles "autoload/hlissner" nil t) -(+hlissner-def-finder! dotfiles (expand-file-name ".dotfiles" "~")) - -;;;###autoload (autoload '+hlissner/find-in-emacsd "autoload/hlissner" nil t) -;;;###autoload (autoload '+hlissner/browse-emacsd "autoload/hlissner" nil t) -(+hlissner-def-finder! emacsd doom-emacs-dir) - -;;;###autoload (autoload '+hlissner/find-in-notes "autoload/hlissner" nil t) -;;;###autoload (autoload '+hlissner/browse-notes "autoload/hlissner" nil t) -(+hlissner-def-finder! notes +org-dir) diff --git a/users/aspen/emacs.d/clocked-in-elt.el b/users/aspen/emacs.d/clocked-in-elt.el deleted file mode 100644 index be4161441..000000000 --- a/users/aspen/emacs.d/clocked-in-elt.el +++ /dev/null @@ -1,17 +0,0 @@ -;;; -*- lexical-binding: t; -*- -(load (expand-file-name "init" (or (getenv "EMACSDIR") - (expand-file-name - "../.emacs.d" - (file-name-directory (file-truename load-file-name)))))) - -(require 'org-clock) -(require 'org-element) - -(let ((item (or org-clock-marker - (car org-clock-history)))) - (when item - (with-current-buffer (marker-buffer item) - (goto-char (marker-position item)) - (let ((element (org-element-at-point))) - (when (eq 'headline (car element)) - (message "%s" (plist-get (cadr element) :raw-value))))))) diff --git a/users/aspen/emacs.d/clojure.el b/users/aspen/emacs.d/clojure.el deleted file mode 100644 index f001a3e12..000000000 --- a/users/aspen/emacs.d/clojure.el +++ /dev/null @@ -1,53 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(defun clojure-thing-at-point-setup () - (interactive) - ;; Used by cider-find-dwim to parse the symbol at point - (setq-local - thing-at-point-file-name-chars - (concat thing-at-point-file-name-chars - ">string (x) - (cond - ((stringp x) x) - ((symbolp x) (symbol-name x)))) - -(defun alist-get-equal (key alist) - "Like `alist-get', but uses `equal' instead of `eq' for comparing keys" - (->> alist - (-find (lambda (pair) (equal key (car pair)))) - (cdr))) - -;;; Listing relations - -(cl-defun company-sql/list-tables (conn) - (with-timeout (3) - (-map (-compose 'symbol-name 'car) - (emacsql conn - [:select [tablename] - :from pg_catalog:pg_tables - :where (and (!= schemaname '"information_schema") - (!= schemaname '"pg_catalog"))])))) - -(cl-defun company-sql/list-columns (conn) - (with-timeout (3) - (-map - (lambda (row) - (propertize (symbol-name (nth 0 row)) - 'table-name (nth 1 row) - 'data-type (nth 2 row))) - (emacsql conn - [:select [column_name - table_name - data_type] - :from information_schema:columns])))) - -;;; Keywords - -(defvar company-postgresql/keywords - (list -"a" "abort" "abs" "absent" "absolute" "access" "according" "action" "ada" "add" -"admin" "after" "aggregate" "all" "allocate" "also" "alter" "always" "analyse" -"analyze" "and" "any" "are" "array" "array_agg" "array_max_cardinality" "as" -"asc" "asensitive" "assertion" "assignment" "asymmetric" "at" "atomic" "attach" -"attribute" "attributes" "authorization" "avg" "backward" "base64" "before" -"begin" "begin_frame" "begin_partition" "bernoulli" "between" "bigint" "binary" -"bit" "bit_length" "blob" "blocked" "bom" "boolean" "both" "breadth" "by" "c" -"cache" "call" "called" "cardinality" "cascade" "cascaded" "case" "cast" -"catalog" "catalog_name" "ceil" "ceiling" "chain" "char" "character" -"characteristics" "characters" "character_length" "character_set_catalog" -"character_set_name" "character_set_schema" "char_length" "check" "checkpoint" -"class" "class_origin" "clob" "close" "cluster" "coalesce" "cobol" "collate" -"collation" "collation_catalog" "collation_name" "collation_schema" "collect" -"column" "columns" "column_name" "command_function" "command_function_code" -"comment" "comments" "commit" "committed" "concurrently" "condition" -"condition_number" "configuration" "conflict" "connect" "connection" -"connection_name" "constraint" "constraints" "constraint_catalog" -"constraint_name" "constraint_schema" "constructor" "contains" "content" -"continue" "control" "conversion" "convert" "copy" "corr" "corresponding" "cost" -"count" "covar_pop" "covar_samp" "create" "cross" "csv" "cube" "cume_dist" -"current" "current_catalog" "current_date" "current_default_transform_group" -"current_path" "current_role" "current_row" "current_schema" "current_time" -"current_timestamp" "current_transform_group_for_type" "current_user" "cursor" -"cursor_name" "cycle" "data" "database" "datalink" "date" -"datetime_interval_code" "datetime_interval_precision" "day" "db" "deallocate" -"dec" "decimal" "declare" "default" "defaults" "deferrable" "deferred" "defined" -"definer" "degree" "delete" "delimiter" "delimiters" "dense_rank" "depends" -"depth" "deref" "derived" "desc" "describe" "descriptor" "detach" -"deterministic" "diagnostics" "dictionary" "disable" "discard" "disconnect" -"dispatch" "distinct" "dlnewcopy" "dlpreviouscopy" "dlurlcomplete" -"dlurlcompleteonly" "dlurlcompletewrite" "dlurlpath" "dlurlpathonly" -"dlurlpathwrite" "dlurlscheme" "dlurlserver" "dlvalue" "do" "document" "domain" -"double" "drop" "dynamic" "dynamic_function" "dynamic_function_code" "each" -"element" "else" "empty" "enable" "encoding" "encrypted" "end" "end-exec" -"end_frame" "end_partition" "enforced" "enum" "equals" "escape" "event" "every" -"except" "exception" "exclude" "excluding" "exclusive" "exec" "execute" "exists" -"exp" "explain" "expression" "extension" "external" "extract" "false" "family" -"fetch" "file" "filter" "final" "first" "first_value" "flag" "float" "floor" -"following" "for" "force" "foreign" "fortran" "forward" "found" "frame_row" -"free" "freeze" "from" "fs" "full" "function" "functions" "fusion" "g" "general" -"generated" "get" "global" "go" "goto" "grant" "granted" "greatest" "group" -"grouping" "groups" "handler" "having" "header" "hex" "hierarchy" "hold" "hour" -"id" "identity" "if" "ignore" "ilike" "immediate" "immediately" "immutable" -"implementation" "implicit" "import" "in" "include" "including" "increment" -"indent" "index" "indexes" "indicator" "inherit" "inherits" "initially" "inline" -"inner" "inout" "input" "insensitive" "insert" "instance" "instantiable" -"instead" "int" "integer" "integrity" "intersect" "intersection" "interval" -"into" "invoker" "is" "isnull" "isolation" "join" "k" "key" "key_member" -"key_type" "label" "lag" "language" "large" "last" "last_value" "lateral" "lead" -"leading" "leakproof" "least" "left" "length" "level" "library" "like" -"like_regex" "limit" "link" "listen" "ln" "load" "local" "localtime" -"localtimestamp" "location" "locator" "lock" "locked" "logged" "lower" "m" "map" -"mapping" "match" "matched" "materialized" "max" "maxvalue" "max_cardinality" -"member" "merge" "message_length" "message_octet_length" "message_text" "method" -"min" "minute" "minvalue" "mod" "mode" "modifies" "module" "month" "more" "move" -"multiset" "mumps" "name" "names" "namespace" "national" "natural" "nchar" -"nclob" "nesting" "new" "next" "nfc" "nfd" "nfkc" "nfkd" "nil" "no" "none" -"normalize" "normalized" "not" "nothing" "notify" "notnull" "nowait" "nth_value" -"ntile" "null" "nullable" "nullif" "nulls" "number" "numeric" "object" -"occurrences_regex" "octets" "octet_length" "of" "off" "offset" "oids" "old" -"on" "only" "open" "operator" "option" "options" "or" "order" "ordering" -"ordinality" "others" "out" "outer" "output" "over" "overlaps" "overlay" -"overriding" "owned" "owner" "p" "pad" "parallel" "parameter" "parameter_mode" -"parameter_name" "parameter_ordinal_position" "parameter_specific_catalog" -"parameter_specific_name" "parameter_specific_schema" "parser" "partial" -"partition" "pascal" "passing" "passthrough" "password" "path" "percent" -"percentile_cont" "percentile_disc" "percent_rank" "period" "permission" -"placing" "plans" "pli" "policy" "portion" "position" "position_regex" "power" -"precedes" "preceding" "precision" "prepare" "prepared" "preserve" "primary" -"prior" "privileges" "procedural" "procedure" "procedures" "program" "public" -"publication" "quote" "range" "rank" "read" "reads" "real" "reassign" "recheck" -"recovery" "recursive" "ref" "references" "referencing" "refresh" "regr_avgx" -"regr_avgy" "regr_count" "regr_intercept" "regr_r2" "regr_slope" "regr_sxx" -"regr_sxy" "regr_syy" "reindex" "relative" "release" "rename" "repeatable" -"replace" "replica" "requiring" "reset" "respect" "restart" "restore" "restrict" -"result" "return" "returned_cardinality" "returned_length" -"returned_octet_length" "returned_sqlstate" "returning" "returns" "revoke" -"right" "role" "rollback" "rollup" "routine" "routines" "routine_catalog" -"routine_name" "routine_schema" "row" "rows" "row_count" "row_number" "rule" -"savepoint" "scale" "schema" "schemas" "schema_name" "scope" "scope_catalog" -"scope_name" "scope_schema" "scroll" "search" "second" "section" "security" -"select" "selective" "self" "sensitive" "sequence" "sequences" "serializable" -"server" "server_name" "session" "session_user" "set" "setof" "sets" "share" -"show" "similar" "simple" "size" "skip" "smallint" "snapshot" "some" "source" -"space" "specific" "specifictype" "specific_name" "sql" "sqlcode" "sqlerror" -"sqlexception" "sqlstate" "sqlwarning" "sqrt" "stable" "standalone" "start" -"state" "statement" "static" "statistics" "stddev_pop" "stddev_samp" "stdin" -"stdout" "storage" "strict" "strip" "structure" "style" "subclass_origin" -"submultiset" "subscription" "substring" "substring_regex" "succeeds" "sum" -"symmetric" "sysid" "system" "system_time" "system_user" "t" "table" "tables" -"tablesample" "tablespace" "table_name" "temp" "template" "temporary" "text" -"then" "ties" "time" "timestamp" "timezone_hour" "timezone_minute" "to" "token" -"top_level_count" "trailing" "transaction" "transactions_committed" -"transactions_rolled_back" "transaction_active" "transform" "transforms" -"translate" "translate_regex" "translation" "treat" "trigger" "trigger_catalog" -"trigger_name" "trigger_schema" "trim" "trim_array" "true" "truncate" "trusted" -"type" "types" "uescape" "unbounded" "uncommitted" "under" "unencrypted" "union" -"unique" "unknown" "unlink" "unlisten" "unlogged" "unnamed" "unnest" "until" -"untyped" "update" "upper" "uri" "usage" "user" "user_defined_type_catalog" -"user_defined_type_code" "user_defined_type_name" "user_defined_type_schema" -"using" "vacuum" "valid" "validate" "validator" "value" "values" "value_of" -"varbinary" "varchar" "variadic" "varying" "var_pop" "var_samp" "verbose" -"version" "versioning" "view" "views" "volatile" "when" "whenever" "where" -"whitespace" "width_bucket" "window" "with" "within" "without" "work" "wrapper" -"write" "xml" "xmlagg" "xmlattributes" "xmlbinary" "xmlcast" "xmlcomment" -"xmlconcat" "xmldeclaration" "xmldocument" "xmlelement" "xmlexists" "xmlforest" -"xmliterate" "xmlnamespaces" "xmlparse" "xmlpi" "xmlquery" "xmlroot" "xmlschema" -"xmlserialize" "xmltable" "xmltext" "xmlvalidate" "year" "yes" "zone")) - -;;; Company backend - -(cl-defun company-postgresql/candidates (prefix conn) - (-filter - (apply-partially #'s-starts-with? prefix) - (append (-map (lambda (s) - (propertize s 'company-postgresql-annotation "table")) - - (-map (lambda (s) - (propertize s 'company-postgresql-annotation - (format "%s.%s %s" - (get-text-property 0 'table-name s) - s - (-> - (get-text-property 0 'data-type s) - (->string) - (upcase))))) - (company-sql/list-columns conn)) - (-map (lambda (s) - (propertize s 'company-postgresql-annotation "keyword")) - company-postgresql/keywords))))) - -(defun company-postgresql (command &optional arg &rest _) - (interactive (list 'interactive)) - (cl-case command - (interactive (company-begin-backend 'company-postgresql)) - (init (company-sql/connect)) - (prefix (company-grab-symbol)) - (annotation - (get-text-property 0 'company-postgresql-annotation arg)) - (candidates (company-postgresql/candidates - arg - (company-sql/connect))) - (duplicates t) - (ignore-case t))) - -;;; org-babel company sql - -(defvar-local org-company-sql/connections - ()) - -(defun org-company-sql/connect (conn-params) - (or (alist-get-equal conn-params org-company-sql/connections) - (let ((conn (apply 'emacsql-psql conn-params))) - (add-to-list 'org-company-sql/connections (cons conn-params conn)) - conn))) - -(defun org-company-sql/in-sql-source-block-p () - (let ((org-elt (org-element-at-point))) - (and (eq 'src-block (car org-elt)) - (equal "sql" (plist-get (cadr org-elt) - :language))))) - -(defun org-company-sql/parse-cmdline (cmdline) - (let* ((lexed (s-split (rx (one-or-more blank)) cmdline)) - (go (lambda (state tokens) - (if (null tokens) () - (let ((token (car tokens)) - (tokens (cdr tokens))) - (if (null state) - (if (s-starts-with? "-" token) - (funcall go token tokens) - (cons token (funcall go state tokens))) - (cons (cons state token) ; ("-h" . "localhost") - (funcall go nil tokens))))))) - (opts (funcall go nil lexed))) - opts)) - -(defun org-company-sql/source-block-conn-params () - (let* ((block-info (org-babel-get-src-block-info)) - (params (caddr block-info)) - (cmdline (alist-get :cmdline params)) - (parsed (org-company-sql/parse-cmdline cmdline)) - (opts (-filter #'listp parsed)) - (positional (-filter #'stringp parsed)) - (host (alist-get-equal "-h" opts)) - (port (or (alist-get-equal "-p" opts) - "5432")) - (dbname (or (alist-get-equal "-d" opts) - (car positional))) - (username (or (alist-get-equal "-U" opts) - (cadr positional)))) - (list dbname - :hostname host - :username username - :port port))) - -(defun org-company-sql/connection-for-source-block () - (org-company-sql/connect - (org-company-sql/source-block-conn-params))) - - -(defun company-ob-postgresql (command &optional arg &rest _) - (interactive (list 'interactive)) - (cl-case command - (interactive (company-begin-backend 'company-ob-postgresql)) - (prefix (and (org-company-sql/in-sql-source-block-p) - (company-grab-symbol))) - (annotation (get-text-property 0 'company-postgresql-annotation arg)) - (candidates - (company-postgresql/candidates - arg - (org-company-sql/connection-for-source-block))) - (duplicates t) - (ignore-case t))) - -;;; - -(provide 'company-sql) diff --git a/users/aspen/emacs.d/config.el b/users/aspen/emacs.d/config.el deleted file mode 100644 index 6398feace..000000000 --- a/users/aspen/emacs.d/config.el +++ /dev/null @@ -1,1139 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -;; I've swapped these keys on my keyboard -(setq x-super-keysym 'alt - x-alt-keysym 'meta) - -(setq user-mail-address "root@gws.fyi" - user-full-name "Griffin Smith") - -(let ((font-family (pcase system-type - ('darwin "MesloLGSDZ NF") - ('gnu/linux "Meslo LGSDZ Nerd Font")))) - (setq doom-font (font-spec :family font-family :size 14) - doom-big-font (font-spec :family font-family :size 24) - doom-big-font-increment 5 - doom-variable-pitch-font (font-spec :family font-family) - doom-unicode-font (font-spec :family font-family))) - -(require 's) - -(undefine-key! :keymaps 'doom-leader-map "/") - -(load! "utils") -(load! "company-sql") -(load! "show-matching-paren") -(load! "irc") -(load! "github-org") -(load! "org-gcal") -(load! "grid") -(load! "nix") -(load! "email") -(load! "cpp") -(load! "lisp") -(load! "clojure") -(load! "rust") -(load! "terraform") - -(require 'tvl) - -(add-hook! elixir-mode - (require 'flycheck-credo) - (setq flycheck-elixir-credo-strict t) - (flycheck-credo-setup) - - (require 'flycheck-mix) (flycheck-mix-setup) - - (require 'flycheck-dialyxir) (flycheck-dialyxir-setup) - - (flycheck-mode)) - -(setq +solarized-s-base03 "#002b36" - +solarized-s-base02 "#073642" - ;; emphasized content - +solarized-s-base01 "#586e75" - ;; primary content - +solarized-s-base00 "#657b83" - +solarized-s-base0 "#839496" - ;; comments - +solarized-s-base1 "#93a1a1" - ;; background highlight light - +solarized-s-base2 "#eee8d5" - ;; background light - +solarized-s-base3 "#fdf6e3" - - ;; Solarized accented colors - +solarized-yellow "#b58900" - +solarized-orange "#cb4b16" - +solarized-red "#dc322f" - +solarized-magenta "#d33682" - +solarized-violet "#6c71c4" - +solarized-blue "#268bd2" - +solarized-cyan "#2aa198" - +solarized-green "#859900" - - ;; Darker and lighter accented colors - ;; Only use these in exceptional circumstances! - +solarized-yellow-d "#7B6000" - +solarized-yellow-l "#DEB542" - +solarized-orange-d "#8B2C02" - +solarized-orange-l "#F2804F" - +solarized-red-d "#990A1B" - +solarized-red-l "#FF6E64" - +solarized-magenta-d "#93115C" - +solarized-magenta-l "#F771AC" - +solarized-violet-d "#3F4D91" - +solarized-violet-l "#9EA0E5" - +solarized-blue-d "#00629D" - +solarized-blue-l "#69B7F0" - +solarized-cyan-d "#00736F" - +solarized-cyan-l "#69CABF" - +solarized-green-d "#546E00" - +solarized-green-l "#B4C342") - -(defcustom theme-overrides nil - "Association list of override faces to set for different custom themes.") - -(defadvice load-theme (after theme-set-overrides activate) - (dolist (theme-settings theme-overrides) - (let ((theme (car theme-settings)) - (faces (cadr theme-settings))) - (if (member theme custom-enabled-themes) - (progn - (dolist (face faces) - (custom-theme-set-faces theme face))))))) - -(defun alist-set (alist-symbol key value) - "Set VALUE of a KEY in ALIST-SYMBOL." - (set alist-symbol (cons (list key value) (assq-delete-all key (eval alist-symbol))))) - -(comment - (custom-theme-set-faces 'grfn-solarized-light - `(font-lock-doc-face - ((t (:foreground ,+solarized-s-base1))))) - -+solarized-s-base1 -(custom-theme-) - (custom-face-get-current-spec 'font-lock-doc-face) - - ) - -(alist-set 'theme-overrides 'grfn-solarized-light - `((font-lock-doc-face ((t (:foreground ,+solarized-s-base1)))) - (font-lock-preprocessor-face ((t (:foreground ,+solarized-red)))) - (font-lock-keyword-face ((t (:foreground ,+solarized-green :bold nil)))) - (font-lock-builtin-face ((t (:foreground ,+solarized-s-base01 - :bold t)))) - - (elixir-attribute-face ((t (:foreground ,+solarized-blue)))) - (elixir-atom-face ((t (:foreground ,+solarized-cyan)))) - (linum ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1)))) - (line-number ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1)))) - (line-number-current-line ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1)))) - - (haskell-operator-face ((t (:foreground ,+solarized-green)))) - (haskell-keyword-face ((t (:foreground ,+solarized-cyan)))) - - (org-drawer ((t (:foreground ,+solarized-s-base1 - :bold t)))))) - -(setq solarized-use-variable-pitch nil - solarized-scale-org-headlines nil - solarized-use-less-bold t) - -(add-to-list 'custom-theme-load-path "~/.doom.d/themes") -(load-theme 'grfn-solarized-light t) - -(defface haskell-import-face `((t (:foreground ,+solarized-magenta))) "") - -(setq doom-theme 'grfn-solarized-light) -; (setq doom-theme 'doom-solarized-light) - -(add-hook! doom-post-init - (set-face-attribute 'bold nil :weight 'ultra-light) - (set-face-bold 'bold nil) - (enable-theme 'grfn-solarized-light)) - -(defun rx-words (&rest words) - (rx-to-string - `(and symbol-start (group (or ,@words)) symbol-end))) - -(font-lock-add-keywords - 'elixir-mode - `((,(rx-words "def" - "defp" - "test" - "describe" - "property" - "defrecord" - "defmodule" - "defstruct" - "defdelegate" - "defprotocol" - "defimpl" - "use" - "import" - "alias" - "require" - "assert" - "refute" - "assert_raise") - . - 'font-lock-preprocessor-face))) - -(font-lock-add-keywords - 'elixir-mode - `((,(rx-words "def" - "defp" - "test" - "describe" - "property" - "defrecord" - "defmodule" - "defstruct" - "defdelegate" - "use" - "import" - "alias" - "require" - "assert" - "refute" - "assert_raise") - . - 'font-lock-preprocessor-face))) - -(font-lock-add-keywords - 'haskell-mode - `((,(rx-words "import") . 'haskell-import-face))) - -;; (font-lock-add-keywords -;; 'haskell-mode -;; `((,(rx "-- |") . 'haskell-keyword-face))) - - -;; (load-file (let ((coding-system-for-read 'utf-8)) -;; (shell-command-to-string "agda-mode locate"))) - -(defvar +grfn-dir (file-name-directory load-file-name)) -(defvar +grfn-snippets-dir (expand-file-name "snippets/" +grfn-dir)) - -;; -(load! "+bindings") -(load! "+commands") -(load! "cpp") - - -(add-to-list 'load-path "/home/grfn/code/org-tracker") -(require 'org-tracker) -(use-package! org-tracker - :hook (org-mode . org-tracker-mode) - :config - (setq org-tracker-state-alist '(("INBOX" . "Triage") - ("BACKLOG" . "Backlog") - ("TODO" . "Todo") - ("ACTIVE" . "In Progress") - ("PR" . "Code Review") - ("DONE" . "Done") - ("CANCELLED" . "Canceled")) - org-tracker-username "griffin@readyset.io" - org-tracker-claim-ticket-on-status-update '("ACTIVE" "PR" "DONE") - org-tracker-create-stories-with-labels 'existing) - - (defun org-tracker-headlines-from-assigned-to-me (level) - (interactive "*nLevel: ") - (funcall-interactively - #'org-tracker-headlines-from-search - level - "assignee = currentUser() and statusCategory = 2"))) - -(load! "+private") - -(require 'dash) - -(use-package! predd) - - -;; -;; Global config -;; - -(setq doom-modeline-buffer-file-name-style 'relative-to-project - doom-modeline-modal-icon nil - doom-modeline-github t) - -;; -;; Modules -;; - -(after! smartparens - ;; Auto-close more conservatively and expand braces on RET - (let ((unless-list '(sp-point-before-word-p - sp-point-after-word-p - sp-point-before-same-p))) - (sp-pair "'" nil :unless unless-list) - (sp-pair "\"" nil :unless unless-list)) - (sp-pair "{" nil :post-handlers '(("||\n[i]" "RET") ("| " " ")) - :unless '(sp-point-before-word-p sp-point-before-same-p)) - (sp-pair "(" nil :post-handlers '(("||\n[i]" "RET") ("| " " ")) - :unless '(sp-point-before-word-p sp-point-before-same-p)) - (sp-pair "[" nil :post-handlers '(("| " " ")) - :unless '(sp-point-before-word-p sp-point-before-same-p))) - -;; feature/snippets -(after! yasnippet - ;; Don't use default snippets, use mine. - (setq yas-snippet-dirs - (append (list '+grfn-snippets-dir) - (delq 'yas-installed-snippets-dir yas-snippet-dirs)))) - -(after! company - (setq company-idle-delay 0.2 - company-minimum-prefix-length 1)) - -(setq doom-modeline-height 12) - - - -;; Should really figure out which of these is correct, eventually - -(setq +solarized-s-base03 "#002b36" - +solarized-s-base02 "#073642" - ;; emphasized content - +solarized-s-base01 "#586e75" - ;; primary content - +solarized-s-base00 "#657b83" - +solarized-s-base0 "#839496" - ;; comments - +solarized-s-base1 "#93a1a1" - ;; background highlight light - +solarized-s-base2 "#eee8d5" - ;; background light - +solarized-s-base3 "#fdf6e3" - - ;; Solarized accented colors - +solarized-yellow "#b58900" - +solarized-orange "#cb4b16" - +solarized-red "#dc322f" - +solarized-magenta "#d33682" - +solarized-violet "#6c71c4" - +solarized-blue "#268bd2" - +solarized-cyan "#2aa198" - +solarized-green "#859900" - - ;; Darker and lighter accented colors - ;; Only use these in exceptional circumstances! - +solarized-yellow-d "#7B6000" - +solarized-yellow-l "#DEB542" - +solarized-orange-d "#8B2C02" - +solarized-orange-l "#F2804F" - +solarized-red-d "#990A1B" - +solarized-red-l "#FF6E64" - +solarized-magenta-d "#93115C" - +solarized-magenta-l "#F771AC" - +solarized-violet-d "#3F4D91" - +solarized-violet-l "#9EA0E5" - +solarized-blue-d "#00629D" - +solarized-blue-l "#69B7F0" - +solarized-cyan-d "#00736F" - +solarized-cyan-l "#69CABF" - +solarized-green-d "#546E00" - +solarized-green-l "#B4C342") - -(set-cursor-color +solarized-s-base02) - -(after! doom-theme - (set-face-foreground 'font-lock-doc-face +solarized-s-base1) - (set-face-foreground 'org-block +solarized-s-base00) - (set-face-foreground 'slack-message-output-header +solarized-s-base01) - (set-face-attribute 'slack-message-output-header nil :underline nil) - (set-face-attribute 'slack-message-output-text nil :height 1.0) - (set-face-attribute 'caml-types-expr-face - nil - :background +solarized-s-base2)) - -(after! solarized-theme - (set-face-foreground 'font-lock-doc-face +solarized-s-base1) - (set-face-foreground 'org-block +solarized-s-base00) - - (set-face-foreground 'slack-message-output-header +solarized-s-base01) - (set-face-attribute 'slack-message-output-header nil :underline nil) - (set-face-attribute 'slack-message-output-text nil :height 1.0) - ) - -(after! evil - (setq evil-shift-width 2)) - -(after! org - (load! "org-query") - (load! "org-config")) - -(after! magit - (setq git-commit-summary-max-length 50)) - -(after! ivy - ;; (setq ivy-re-builders-alist - ;; '((t . ivy--regex-fuzzy))) - ) - -(add-hook 'before-save-hook 'delete-trailing-whitespace) - -(after! paxedit - (add-hook! emacs-lisp-mode #'paxedit-mode) - (add-hook! clojure-mode #'paxedit-mode) - (add-hook! common-lisp-mode #'paxedit-mode)) - -(require 'haskell) - -(let ((m-symbols - '(("`mappend`" . "⊕") - ("<>" . "⊕") - ("`elem`" . "∈") - ("`notElem`" . "∉")))) - (dolist (item m-symbols) (add-to-list 'haskell-font-lock-symbols-alist item))) - -(setq haskell-font-lock-symbols t) - - -(add-hook! haskell-mode - ;; (intero-mode) - (lsp-mode) - ;; (flycheck-add-next-checker - ;; 'intero - ;; 'haskell-hlint) - (set-fill-column 80) - (setq evil-shift-width 2)) - -(auth-source-pass-enable) - -(require 'fill-column-indicator) -;;; * Column Marker -(defun sanityinc/fci-enabled-p () (symbol-value 'fci-mode)) - -(defvar sanityinc/fci-mode-suppressed nil) -(make-variable-buffer-local 'sanityinc/fci-mode-suppressed) - -(defadvice popup-create (before suppress-fci-mode activate) - "Suspend fci-mode while popups are visible" - (let ((fci-enabled (sanityinc/fci-enabled-p))) - (when fci-enabled - (setq sanityinc/fci-mode-suppressed fci-enabled) - (turn-off-fci-mode)))) - -(defadvice popup-delete (after restore-fci-mode activate) - "Restore fci-mode when all popups have closed" - (when (and sanityinc/fci-mode-suppressed - (null popup-instances)) - (setq sanityinc/fci-mode-suppressed nil) - (turn-on-fci-mode))) - - -;;; Javascript - -(require 'smartparens) - -(setq js-indent-level 2) - -(require 'prettier-js) -(after! prettier-js - (add-hook! rjsx-mode #'prettier-js-mode) - (add-hook! js2-mode #'prettier-js-mode) - (add-hook! json-mode #'prettier-js-mode) - (add-hook! css-mode #'prettier-js-mode)) - -(remove-hook 'js2-mode-hook 'tide-setup t) - -;; Set this to the mode you use, I use rjsx-mode -(add-hook 'rjsx-mode-hook #'flow/set-flow-executable t) - - -;; Auto-format Haskell on save, with a combination of hindent + brittany - -; (define-minor-mode brittany-haskell-mode -; :init-value nil -; :group 'haskell -; :lighter "Brittany-Haskell" -; :keymap '() -; ) - - -(require 'alert) -(setq alert-default-style 'libnotify) - -;; (setq slack-buffer-function #'switch-to-buffer) - -(setq projectile-test-suffix-function - (lambda (project-type) - (case project-type - ('haskell-stack "Test") - ('npm ".test") - (otherwise (projectile-test-suffix project-type))))) - -(setq projectile-create-missing-test-files 't) - -(setq grfn/tracker-refs-re - (rx line-start - (or "Refs" "Fixes") - ": " - (one-or-more graph) - line-end)) - -(defun grfn/add-tracker-reference-to-commit-message () - (interactive) - (when-let* ((ticket-id (grfn/org-clocked-in-ticket-id))) - (save-excursion - (save-match-data - (goto-char (point-min)) - ;; Don't add one if we've already got one - (unless (search-forward-regexp grfn/tracker-refs-re nil t) - (or - (and - (search-forward-regexp (rx line-start "Change-Id:") nil t) - (forward-line -1)) - (and - (search-forward-regexp (rx line-start "# Please enter") nil t) - (forward-line -2))) - (insert (format "\nRefs: %s" ticket-id))))))) - -(defun grfn/switch-tracker-refs-fixes () - (interactive) - (save-excursion - (save-match-data - (if (not (search-forward-regexp grfn/tracker-refs-re nil t)) - (message "Could not find reference to ticket") - (goto-char (point-at-bol)) - (save-restriction - (narrow-to-region (point-at-bol) - (point-at-eol)) - (or - (and (search-forward "Refs" nil t) - (replace-match "Fixes")) - (and (search-forward "Fixes" nil t) - (replace-match "Refs")))))))) - -(after! magit - (map! :map magit-mode-map - ;; :n "] ]" #'magit-section-forward - ;; :n "[ [" #'magit-section-backward - ) - - (transient-define-suffix magit-commit-wip () - (interactive) - (magit-commit-create '("-m" "wip"))) - - (transient-append-suffix - #'magit-commit - ["c"] - (list "W" "Commit WIP" #'magit-commit-wip)) - - (transient-define-suffix magit-reset-head-back () - (interactive) - (magit-reset-mixed "HEAD~")) - - (transient-define-suffix magit-reset-head-previous () - (interactive) - (magit-reset-mixed "HEAD@{1}")) - - (transient-append-suffix - #'magit-reset - ["f"] - (list "b" "Reset HEAD~" #'magit-reset-head-back)) - (transient-append-suffix - #'magit-reset - ["f"] - (list "o" "Reset HEAD@{1}" #'magit-reset-head-previous)) - - (defun magit-read-org-tracker-branch-name () - (when-let ((issue-id (org-tracker-clocked-in-issue-id))) - (let ((desc - (magit-read-string-ns - (format "Issue description (to go after gs/%s/)" - issue-id)))) - (format "gs/%s/%s" issue-id desc)))) - - (defun magit-read-org-tracker-branch-args () - (if-let ((issue-id (org-tracker-clocked-in-issue-id))) - (let ((start-point (magit-read-starting-point - "Create and checkout branch for Tracker issue" - nil - "origin/master"))) - (if (magit-rev-verify start-point) - (when-let ((desc (magit-read-org-tracker-branch-name))) - (list desc start-point)) - (user-error "Not a valid starting point: %s" choice))) - (user-error "No currently clocked-in tracker issue"))) - - (transient-define-suffix magit-checkout-org-tracker-branch (branch start-point) - (interactive (magit-read-org-tracker-branch-args)) - (magit-branch-and-checkout branch start-point)) - - (transient-define-suffix magit-rename-org-tracker-branch (old new) - (interactive - (let ((branch (magit-read-local-branch "Rename branch"))) - (list branch (magit-read-org-tracker-branch-name)))) - (when (and old new) - (magit-branch-rename old new))) - - (transient-append-suffix - #'magit-branch - ["c"] - (list "C" "Checkout Tracker branch" #'magit-checkout-org-tracker-branch)) - (transient-append-suffix - #'magit-branch - ["c"] - (list "M" "Rename branch to Tracker ticket" #'magit-rename-org-tracker-branch)) - - ) - -(add-hook 'git-commit-setup-hook #'grfn/add-tracker-reference-to-commit-message) -(map! (:map git-commit-mode-map - "C-c C-f" #'grfn/switch-tracker-refs-fixes)) - -;; (defun grfn/split-window-more-sensibly (&optional window) -;; (let ((window (or window (selected-window)))) -;; (or (and (window-splittable-p window) -;; ;; Split window vertically. -;; (with-selected-window window -;; (split-window-right))) -;; (and (window-splittable-p window t) -;; ;; Split window horizontally. -;; (with-selected-window window -;; (split-window-right))) -;; (and (eq window (frame-root-window (window-frame window))) -;; (not (window-minibuffer-p window)) -;; ;; If WINDOW is the only window on its frame and is not the -;; ;; minibuffer window, try to split it vertically disregarding -;; ;; the value of `split-height-threshold'. -;; (let ((split-height-threshold 0)) -;; (when (window-splittable-p window) -;; (with-selected-window window -;; (split-window-below)))))))) - -(use-package! lsp-mode - :after (:any haskell-mode) - :config - (setq lsp-response-timeout 60) - :hook - (haskell-mode . lsp-mode)) - -(use-package! lsp-ui - :after lsp-mode - :config - (defun +grfn/lsp-ui-doc-frame-hook (frame window) - (set-frame-font (if doom-big-font-mode doom-big-font doom-font) - nil (list frame))) - (setq lsp-ui-flycheck-enable t - lsp-ui-doc-header nil - lsp-ui-doc-position 'top - lsp-ui-doc-alignment 'window - lsp-ui-doc-frame-hook '+grfn/lsp-ui-doc-frame-hook - lsp-ui-doc-max-width 150 - lsp-ui-doc-max-height 13) - (setq imenu-auto-rescan t) - (set-face-background 'lsp-ui-doc-background +solarized-s-base2) - (set-face-background 'lsp-face-highlight-read +solarized-s-base2) - (set-face-background 'lsp-face-highlight-write +solarized-s-base2) - :hook - (lsp-mode . lsp-ui-mode) - (lsp-ui-mode . flycheck-mode)) - -(use-package! company-lsp - :after (lsp-mode lsp-ui) - :config - (add-to-list #'company-backends #'company-lsp) - (setq company-lsp-async t)) - -(defun +grfn/haskell-mode-setup () - (interactive) - (flymake-mode -1) - (add-to-list 'flycheck-disabled-checkers 'haskell-ghc) - - (flycheck-remove-next-checker 'lsp 'haskell-ghc) - (flycheck-add-next-checker 'lsp '(warning . haskell-hlint)) - - ;; If there’s a 'hie.sh' defined locally by a project - ;; (e.g. to run HIE in a nix-shell), use it… - (when-let ((project-dir (locate-dominating-file default-directory "hie.sh"))) - (cl-flet - ((which (cmd) - (s-trim - (shell-command-to-string - (concat - "nix-shell " - (expand-file-name "shell.nix" project-dir) - " --run \"which " cmd "\" 2>/dev/null"))))) - (setq-local - lsp-haskell-process-path-hie (expand-file-name "hie.sh" project-dir) - haskell-hoogle-command (which "hoogle")))) - ;; … and only then setup the LSP. - (lsp)) - -(defun never-flymake-mode (orig &rest args) - (when (and (bound-and-true-p flymake-mode)) - (funcall orig 0) - (message "disabled flymake-mode"))) -(advice-add #'flymake-mode :around #'never-flymake-mode) - -(defun +grfn/wrap-lsp-haskell-process (argv) - (let* ((project-dir (locate-dominating-file - (buffer-file-name) - "hie.yaml")) - (shell-dot-nix (expand-file-name "shell.nix" project-dir))) - ;; (when (string-equal default-directory "/home/grfn/code/depot") - ;; (debug)) - (message "%s %s %s %s" - (buffer-file-name) - default-directory - project-dir - shell-dot-nix) - (if (file-exists-p shell-dot-nix) - `("bash" "-c" - ,(format "cd %s && nix-shell %s --run '%s'" - project-dir - shell-dot-nix - (s-join " " argv))) - argv))) - -(use-package! lsp-haskell - :after (lsp-mode lsp-ui haskell-mode) - ;; :hook - ;; (haskell-mode . lsp-haskell-enable) - :config - (setq lsp-haskell-process-path-hie "haskell-language-server-wrapper" - lsp-haskell-process-args-hie - '("-d" "-l" "/tmp/hie.log" "+RTS" "-M4G" "-H1G" "-K4G" "-A16M" "-RTS") - lsp-haskell-process-wrapper-function - #'+grfn/wrap-lsp-haskell-process) - (add-hook 'haskell-mode-hook #'+grfn/haskell-mode-setup 't)) - -(use-package! lsp-imenu - :after (lsp-mode lsp-ui) - :hook - (lsp-after-open . lsp-enable-imenu)) - -;; (use-package! counsel-etags -;; :ensure t -;; :init -;; (add-hook 'haskell-mode-hook -;; (lambda () -;; (add-hook 'after-save-hook -;; 'counsel-etags-virtual-update-tags 'append 'local))) -;; :config -;; (setq counsel-etags-update-interval 60) -;; ;; (push "build" counsel-etags-ignore-directories) -;; ) - -;; (use-package! evil-magit -;; :after (magit)) - -(use-package! writeroom-mode) - -(use-package! graphql-mode) - - -(require 'whitespace) -(setq whitespace-style '(face lines-tail)) -(global-whitespace-mode t) -(add-hook 'org-mode-hook (lambda () (whitespace-mode -1)) t) - -(set-face-foreground 'whitespace-line +solarized-red) -(set-face-attribute 'whitespace-line nil :underline 't) - -;; (set-face-background 'ivy-posframe +solarized-s-base3) -;; (set-face-foreground 'ivy-posframe +solarized-s-base01) - -(let ((base03 "#002b36") - (base02 "#073642") - (base01 "#586e75") - (base00 "#657b83") - (base0 "#839496") - (base1 "#93a1a1") - (base2 "#eee8d5") - (base3 "#fdf6e3") - (yellow "#b58900") - (orange "#cb4b16") - (red "#dc322f") - (magenta "#d33682") - (violet "#6c71c4") - (blue "#268bd2") - (cyan "#2aa198") - (green "#859900")) - (custom-set-faces - `(agda2-highlight-keyword-face ((t (:foreground ,green)))) - `(agda2-highlight-string-face ((t (:foreground ,cyan)))) - `(agda2-highlight-number-face ((t (:foreground ,violet)))) - `(agda2-highlight-symbol-face ((((background ,base3)) (:foreground ,base01)))) - `(agda2-highlight-primitive-type-face ((t (:foreground ,blue)))) - `(agda2-highlight-bound-variable-face ((t nil))) - `(agda2-highlight-inductive-constructor-face ((t (:foreground ,green)))) - `(agda2-highlight-coinductive-constructor-face ((t (:foreground ,yellow)))) - `(agda2-highlight-datatype-face ((t (:foreground ,blue)))) - `(agda2-highlight-field-face ((t (:foreground ,red)))) - `(agda2-highlight-function-face ((t (:foreground ,blue)))) - `(agda2-highlight-module-face ((t (:foreground ,yellow)))) - `(agda2-highlight-postulate-face ((t (:foreground ,blue)))) - `(agda2-highlight-primitive-face ((t (:foreground ,blue)))) - `(agda2-highlight-record-face ((t (:foreground ,blue)))) - `(agda2-highlight-dotted-face ((t nil))) - `(agda2-highlight-operator-face ((t nil))) - `(agda2-highlight-error-face ((t (:foreground ,red :underline t)))) - `(agda2-highlight-unsolved-meta-face ((t (:background ,base2)))) - `(agda2-highlight-unsolved-constraint-face ((t (:background ,base2)))) - `(agda2-highlight-termination-problem-face ((t (:background ,orange :foreground ,base03)))) - `(agda2-highlight-incomplete-pattern-face ((t (:background ,orange :foreground ,base03)))) - `(agda2-highlight-typechecks-face ((t (:background ,cyan :foreground ,base03)))))) - - -(after! cider - (setq cider-prompt-for-symbol nil - cider-font-lock-dynamically 't - cider-save-file-on-load 't) - ) - -(comment - (setq elt (+org-clocked-in-element)) - - (eq 'headline (car elt)) - (plist-get (cadr elt) :raw-value) - ) - -(defun +org-headline-title (headline) - (when (eq 'headline (car elt)) - (plist-get (cadr elt) :raw-value))) - -;; (setq +ligatures-extra-symbols -;; (append +ligatures-extra-symbols -;; '(:equal "≡" -;; :not-equal "≠" -;; :is "≣" -;; :isnt "≢" -;; :lte "≤" -;; :gte "≥" -;; :subseteq "⊆" -;; ))) - -;; (after! python -;; (set-pretty-symbols! 'python-mode :merge t -;; :equal "==" -;; :not-equal "!=" -;; :lte "<=" -;; :gte ">=" -;; :is "is" -;; :isnt "is not" -;; :subseteq "issubset" - -;; ;; doom builtins - -;; ;; Functional -;; :def "def" -;; :lambda "lambda" -;; ;; Types -;; :null "None" -;; :true "True" :false "False" -;; :int "int" :str "str" -;; :float "float" -;; :bool "bool" -;; :tuple "tuple" -;; ;; Flow -;; :not "not" -;; :in "in" :not-in "not in" -;; :and "and" :or "or" -;; :for "for" -;; :return "return" :yield "yield")) - -(use-package! sqlup-mode - :hook - (sql-mode-hook . sqlup-mode) - (sql-interactive-mode-hook . sqlup-mode)) - -(use-package! emacsql) -(use-package! emacsql-psql - :after (emacsql)) - -(use-package! pyimport - :after (python)) - -(use-package! blacken - :after (python) - :init - (add-hook #'python-mode-hook #'blacken-mode) - :config - (setq blacken-only-if-project-is-blackened t - blacken-allow-py36 t - blacken-line-length 100)) - -(after! python - (defun +python-setup () - (setq-local fill-column 100 - whitespace-line-column 100 - flycheck-disabled-checkers '(python-flake8) - flycheck-checker 'python-pylint)) - - (add-hook #'python-mode-hook #'+python-setup) - (add-hook #'python-mode-hook #'lsp) - (remove-hook #'python-mode-hook #'pipenv-mode)) - -; (use-package! w3m -; :config -; (setq browse-url-browser-function -; `(("^https://app.clubhouse.io.*" . browse-url-firefox) -; ("^https://github.com.*" . browse-url-firefox) -; (".*" . browse-url-firefox)))) - -(use-package! ob-http - :config - (add-to-list 'org-babel-load-languages '(http . t))) - -;; (use-package! ob-ipython -;; :after (pyimport) -;; :config -;; (add-to-list 'org-babel-load-languages '(ipython . t)) -;; (setq ob-ipython-command - ;; "/home/griffin/code/urb/ciml-video-classifier/bin/jupyter")) - -(use-package! counsel-spotify) - -(after! counsel - (map! [remap counsel-org-capture] #'org-capture - [remap org-capture] #'org-capture)) - -(remove-hook 'doom-first-input-hook #'evil-snipe-mode) - -(use-package! rainbow-mode) - -(use-package! org-alert - :disabled t - :config - (org-alert-enable) - (setq alert-default-style 'libnotify - org-alert-headline-title "org")) - -(use-package! ob-async) - -(use-package! org-recent-headings - :config - (map! :n "SPC n r" #'org-recent-headings-ivy)) - -(use-package! org-sticky-header - :after (org) - :hook (org-mode-hook . org-sticky-header-mode) - :config - (setq-default org-sticky-header-heading-star "●")) - -(enable-theme 'grfn-solarized-light) - -;;; this needs to be *after the theme*, or else I get no agenda items. -;;; whuuu?? -(load! "org-config") - - -;;; word-char -(add-hook! prog-mode - (modify-syntax-entry ?_ "w")) - -(add-hook! lisp-mode - (modify-syntax-entry ?- "w")) - -(after! flycheck - (put 'flycheck-python-pylint-executable 'safe-local-variable (lambda (_) t)) - (setq flycheck-error-list-minimum-level 'warn - flycheck-navigation-minimum-level 'warn)) - -(defvar alembic-command "alembic" - "Command to execute when running alembic") - -(defvar alembic-dir-fun (lambda () default-directory) - "Reference to a function whose return value will be used as the directory to - run Alembic in") - -(put 'alembic-command 'safe-local-variable (lambda (_) t)) -(put 'alembic-dir-fun 'safe-local-variable (lambda (_) t)) - -(defun make-alembic-command (args) - (if (functionp alembic-command) - (funcall alembic-command args) - (concat alembic-command " " args))) - -(defun +grfn/extract-alembic-migration-name (output) - (unless (string-match (rx (0+ anything) "Generating " - (group (one-or-more (not (syntax whitespace)))) - " ..." (one-or-more (syntax whitespace)) "done" - (0+ anything)) - output) - (user-error "Error: %s" output)) - (match-string-no-properties 1 output)) - -(defun -run-alembic (args) - (let* ((default-directory (funcall alembic-dir-fun)) - (command (make-alembic-command args)) - ;; (format "nix-shell --run 'alembic %s'" args) - ;; (format "%s %s" alembic-command args) - (res - (with-temp-buffer - (cons - (shell-command command t) - (s-replace-regexp - "^.*Nix search path entry.*$" "" - (buffer-string))))) - (exit-code (car res)) - (out (cdr res))) - ;; (if (= 0 exit-code) - ;; out - ;; (error "Error running %s: %s" command out)) - out - )) - -(comment - --exit-code - --bs - ) - -(defun run-alembic (args) - (interactive "sAlembic command: ") - (message "%s" (-run-alembic args))) - -(defun generate-alembic-migration (msg &rest args) - (interactive "sMessage: ") - (-> - (format "revision %s -m \"%s\"" - (s-join " " args) - msg) - (-run-alembic) - (+grfn/extract-alembic-migration-name) - (find-file-other-window))) - -(cl-defun alembic-upgrade (&optional revision &key namespace) - (interactive "sRevision: ") - (let ((default-directory (funcall alembic-dir-fun))) - (run-alembic (format "%s upgrade %s" - (if namespace (concat "-n " namespace) "") - (or revision "head"))))) - -(defun alembic-downgrade (revision) - (interactive "sRevision: ") - (let ((default-directory (funcall alembic-dir-fun))) - (run-alembic (format "downgrade %s" (or revision "head"))))) - -(use-package! gnuplot) -(use-package! gnuplot-mode :after gnuplot) -(use-package! string-inflection) - -(after! anaconda-mode - ;; (set-company-backend! 'anaconda-mode #'company-yasnippet) - ) - -;; (add-hook! python-mode -;; (capf)) - -(cl-defstruct pull-request url number title author repository) - -(defun grfn/num-inbox-items () - (length (org-elements-agenda-match "inbox" t))) - -(use-package! dhall-mode - :mode "\\.dhall\\'") - -(use-package! github-review - :after forge) - -(after! forge - (set-popup-rule! - "^\\*forge" - :size 0.75)) - -(defun grfn/org-add-db-connection-params () - (interactive) - (ivy-read - "DB to connect to: " - (-map (lambda (opts) - (propertize (symbol-name (car opts)) - 'header-args (cdr opts))) - db-connection-param-options) - :require-match t - :action - (lambda (opt) - (let ((header-args (get-text-property 0 'header-args opt))) - (org-set-property "header-args" header-args))))) - -(use-package! kubernetes - :commands (kubernetes-overview)) - -(use-package! k8s-mode - :hook (k8s-mode . yas-minor-mode)) - -(use-package! sx) - -;; (use-package! nix-update -;; :config -;; (map! (:map nix-mode-map -;; (:leader -;; :desc "Update fetcher" :nv #'nix-update-fetch)))) - - -(after! lsp-haskell - (lsp-register-client - (make-lsp--client - :new-connection (lsp-stdio-connection (lambda () (lsp-haskell--hie-command))) - :major-modes '(haskell-mode) - :server-id 'hie - ;; :multi-root t - ;; :initialization-options 'lsp-haskell--make-init-options - ) - ) - ) - -(solaire-global-mode -1) - -(use-package! wsd-mode) - -(use-package! metal-mercury-mode) -(use-package! flycheck-mercury - :after (metal-mercury-mode flycheck-mercury)) - -(use-package! direnv - :config (direnv-mode)) - -(after! erc - ;; (setq erc-autojoin-channels-alist '(("freenode.net" "#nixos" "#haskell" "##tvl"))) - ) - -(defun evil-disable-insert-state-bindings () - evil-disable-insert-state-bindings) - -;; (use-package! terraform-mode) -;; (use-package! company-terraform -;; :after terraform-mode -;; :config (company-terraform-init)) - -(use-package! znc - :config - (setq znc-servers - '(("znc.gws.fyi" 5000 t - ((freenode "glittershark" "Ompquy")))))) - -(use-package! jsonnet-mode - :config - (map! - (:map jsonnet-mode-map - (:n "g SPC" #'jsonnet-eval-buffer)))) - -(add-to-list 'safe-local-variable-values - '(truncate-lines . t)) - -(set-popup-rule! - "^\\*gud-" - :quit nil) - -(setq elcord-editor-icon "emacs_icon") - -;;; ocaml - -(after! merlin-mode - (set-face-attribute - 'caml-types-expr-face - nil - :background +solarized-s-base2) - (add-hook! merlin-mode - (setq whitespace-line-column 90))) - -(use-package! dune-format - :hook (dune-mode . dune-format-on-save-mode)) diff --git a/users/aspen/emacs.d/cpp.el b/users/aspen/emacs.d/cpp.el deleted file mode 100644 index 6068736ec..000000000 --- a/users/aspen/emacs.d/cpp.el +++ /dev/null @@ -1,39 +0,0 @@ -;;; -*- lexical-binding: t; -*- - - -(load! "google-c-style") - -(after! flycheck - (add-to-list 'flycheck-disabled-checkers 'c/c++-gcc) - (add-to-list 'flycheck-disabled-checkers 'c/c++-clang)) - -(defun +aspen/cpp-setup () - (when (s-starts-with? - "/home/aspen/code/depot/third_party/nix" - (buffer-file-name)) - (setq lsp-clients-clangd-executable "/home/aspen/code/depot/users/aspen/emacs.d/nix-clangd.sh" - lsp-clients-clangd-args nil) - (google-set-c-style) - (lsp) - (add-to-list 'flycheck-disabled-checkers 'c/c++-gcc) - (add-to-list 'flycheck-disabled-checkers 'c/c++-clang))) - -(add-hook 'c++-mode-hook #'+aspen/cpp-setup) - -(use-package! protobuf-mode) - -(use-package! clang-format+ - :config - (add-hook 'c-mode-common-hook #'clang-format+-mode)) - -(map! - (:map c++-mode-map - :leader - (:n "/ i" #'counsel-semantic-or-imenu))) - -(comment - (setq - lsp-clients-clangd-executable - "/home/aspen/code/depot/third_party/nix/clangd.sh" - lsp-clients-clangd-args nil) - ) diff --git a/users/aspen/emacs.d/email.el b/users/aspen/emacs.d/email.el deleted file mode 100644 index 70360d007..000000000 --- a/users/aspen/emacs.d/email.el +++ /dev/null @@ -1,53 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(after! notmuch - (setq notmuch-saved-searches - '((:name "inbox" :query "tag:inbox tag:important not tag:trash" :key "i") - (:name "flagged" :query "tag:flagged" :key "f") - (:name "sent" :query "tag:sent" :key "s") - (:name "drafts" :query "tag:draft" :key "d") - - (:name "work" :query "tag:inbox and tag:important and path:work/**" - :key "w") - (:name "personal" :query "tag:inbox and tag:important and path:personal/**" - :key "p")) - message-send-mail-function 'message-send-mail-with-sendmail - message-sendmail-f-is-evil 't - message-sendmail-envelope-from 'header - message-sendmail-extra-arguments '("--read-envelope-from")) - - (add-hook! notmuch-message-mode-hook #'notmuch-company-setup)) - -(setq notmuch-saved-searches - '((:name "inbox" :query "tag:inbox tag:important not tag:trash" :key "i") - (:name "flagged" :query "tag:flagged" :key "f") - (:name "sent" :query "tag:sent" :key "s") - (:name "drafts" :query "tag:draft" :key "d") - - (:name "work" :query "tag:inbox and tag:important and path:work/**" - :key "w") - (:name "personal" :query "tag:inbox and tag:important and path:personal/**" - :key "p")) - message-send-mail-function 'message-send-mail-with-sendmail - message-sendmail-f-is-evil 't - message-sendmail-envelope-from 'header - message-sendmail-extra-arguments '("--read-envelope-from")) - -(set-popup-rule! "^\\*notmuch-saved-search-" - :ignore t) - -(set-popup-rule! (lambda (_ action) - (eq (car action) - 'display-buffer-same-window)) - :ignore t) - -(defun apply-thread-patchset (repo branch) - (interactive "Dgit repo: \nsnew branch name: ") - (let ((tid notmuch-show-thread-id) - (tmp "/tmp/notmuch-patchset")) - (shell-command (format "notmuch-extract-patch %s > %s && ( cd %s && git checkout -b %s && git am %s )" - (shell-quote-argument tid) - (shell-quote-argument tmp) - (shell-quote-argument (expand-file-name repo)) - (shell-quote-argument branch) - (shell-quote-argument tmp))))) diff --git a/users/aspen/emacs.d/github-org.el b/users/aspen/emacs.d/github-org.el deleted file mode 100644 index f4f9d2e37..000000000 --- a/users/aspen/emacs.d/github-org.el +++ /dev/null @@ -1,99 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(require 'ghub) - -(defun grfn/alist->plist (alist) - (->> alist - (-mapcat (lambda (pair) - (list (intern (concat ":" (symbol-name (car pair)))) - (cdr pair)))))) - -;;; - -(cl-defstruct pull-request url number title author repository) - -(defun grfn/query-pulls (query) - (let ((resp (ghub-graphql "query reviewRequests($query: String!) { - reviewRequests: search( - type:ISSUE, - query: $query, - first: 100 - ) { - issueCount - nodes { - ... on PullRequest { - url - number - title - author { - login - ... on User { name } - } - repository { - name - owner { login } - } - } - } - } - }" `((query . ,query))))) - (->> resp - (alist-get 'data) - (alist-get 'reviewRequests) - (alist-get 'nodes) - (-map - (lambda (pr) - (apply - #'make-pull-request - (grfn/alist->plist pr))))))) - -(defun grfn/requested-changes ()) - -(defun grfn/pull-request->org-headline (format-string level pr) - (check-type format-string string) - (check-type level integer) - (check-type pr pull-request) - (s-format (concat (make-string level ?*) " " format-string) - 'aget - `((author . ,(or (->> pr (pull-request-author) (alist-get 'name)) - "no author")) - (owner . ,(->> pr (pull-request-repository) - (alist-get 'owner) - (alist-get 'login))) - (repo . ,(->> pr (pull-request-repository) (alist-get 'name))) - (pr-link . ,(org-make-link-string - (pull-request-url pr) - (pull-request-title pr))) - (today . ,(format-time-string "%Y-%m-%d %a"))))) - -(defun grfn/org-headlines-from-review-requests (level) - "Create org-mode headlines at LEVEL from all review-requested PRs on Github" - (interactive "*nLevel: ") - (let* ((prs (grfn/query-pulls - "is:open is:pr review-requested:glittershark archived:false")) - (text (mapconcat - (apply-partially - #'grfn/pull-request->org-headline - "TODO Review ${author}'s PR on ${owner}/${repo}: ${pr-link} :pr: -SCHEDULED: <${today}>" - level) prs "\n"))) - (save-mark-and-excursion - (insert text)) - (org-align-tags 't))) - -(defun grfn/org-headlines-from-requested-changes (level) - "Create org-mode headlines at LEVEL from all PRs with changes requested - on Github" - (interactive "*nLevel: ") - (let* ((prs (grfn/query-pulls - (concat "is:pr is:open author:glittershark archived:false " - "sort:updated-desc review:changes-requested"))) - (text (mapconcat - (apply-partially - #'grfn/pull-request->org-headline - "TODO Address review comments on ${pr-link} :pr: -SCHEDULED: <${today}>" - level) prs "\n"))) - (save-mark-and-excursion - (insert text)) - (org-align-tags 't))) diff --git a/users/aspen/emacs.d/google-c-style.el b/users/aspen/emacs.d/google-c-style.el deleted file mode 100644 index 9bb12c61a..000000000 --- a/users/aspen/emacs.d/google-c-style.el +++ /dev/null @@ -1,151 +0,0 @@ -;;; google-c-style.el --- Google's C/C++ style for c-mode - -;; Keywords: c, tools - -;; google-c-style.el is Copyright (C) 2008 Google Inc. All Rights Reserved. -;; -;; It is free software; you can redistribute it and/or modify it under the -;; terms of either: -;; -;; a) the GNU General Public License as published by the Free Software -;; Foundation; either version 1, or (at your option) any later version, or -;; -;; b) the "Artistic License". - -;;; Commentary: - -;; Provides the google C/C++ coding style. You may wish to add -;; `google-set-c-style' to your `c-mode-common-hook' after requiring this -;; file. For example: -;; -;; (add-hook 'c-mode-common-hook 'google-set-c-style) -;; -;; If you want the RETURN key to go to the next line and space over -;; to the right place, add this to your .emacs right after the load-file: -;; -;; (add-hook 'c-mode-common-hook 'google-make-newline-indent) - -;;; Code: - -;; For some reason 1) c-backward-syntactic-ws is a macro and 2) under Emacs 22 -;; bytecode cannot call (unexpanded) macros at run time: -(eval-when-compile (require 'cc-defs)) - -;; Wrapper function needed for Emacs 21 and XEmacs (Emacs 22 offers the more -;; elegant solution of composing a list of lineup functions or quantities with -;; operators such as "add") -(defun google-c-lineup-expression-plus-4 (langelem) - "Indents to the beginning of the current C expression plus 4 spaces. - -This implements title \"Function Declarations and Definitions\" -of the Google C++ Style Guide for the case where the previous -line ends with an open parenthese. - -\"Current C expression\", as per the Google Style Guide and as -clarified by subsequent discussions, means the whole expression -regardless of the number of nested parentheses, but excluding -non-expression material such as \"if(\" and \"for(\" control -structures. - -Suitable for inclusion in `c-offsets-alist'." - (save-excursion - (back-to-indentation) - ;; Go to beginning of *previous* line: - (c-backward-syntactic-ws) - (back-to-indentation) - (cond - ;; We are making a reasonable assumption that if there is a control - ;; structure to indent past, it has to be at the beginning of the line. - ((looking-at "\\(\\(if\\|for\\|while\\)\\s *(\\)") - (goto-char (match-end 1))) - ;; For constructor initializer lists, the reference point for line-up is - ;; the token after the initial colon. - ((looking-at ":\\s *") - (goto-char (match-end 0)))) - (vector (+ 4 (current-column))))) - -;;;###autoload -(defconst google-c-style - `((c-recognize-knr-p . nil) - (c-enable-xemacs-performance-kludge-p . t) ; speed up indentation in XEmacs - (c-basic-offset . 2) - (indent-tabs-mode . nil) - (c-comment-only-line-offset . 0) - (c-hanging-braces-alist . ((defun-open after) - (defun-close before after) - (class-open after) - (class-close before after) - (inexpr-class-open after) - (inexpr-class-close before) - (namespace-open after) - (inline-open after) - (inline-close before after) - (block-open after) - (block-close . c-snug-do-while) - (extern-lang-open after) - (extern-lang-close after) - (statement-case-open after) - (substatement-open after))) - (c-hanging-colons-alist . ((case-label) - (label after) - (access-label after) - (member-init-intro before) - (inher-intro))) - (c-hanging-semi&comma-criteria - . (c-semi&comma-no-newlines-for-oneline-inliners - c-semi&comma-inside-parenlist - c-semi&comma-no-newlines-before-nonblanks)) - (c-indent-comments-syntactically-p . t) - (comment-column . 40) - (c-indent-comment-alist . ((other . (space . 2)))) - (c-cleanup-list . (brace-else-brace - brace-elseif-brace - brace-catch-brace - empty-defun-braces - defun-close-semi - list-close-comma - scope-operator)) - (c-offsets-alist . ((arglist-intro google-c-lineup-expression-plus-4) - (func-decl-cont . ++) - (member-init-intro . ++) - (inher-intro . ++) - (comment-intro . 0) - (arglist-close . c-lineup-arglist) - (topmost-intro . 0) - (block-open . 0) - (inline-open . 0) - (substatement-open . 0) - (statement-cont - . - (,(when (fboundp 'c-no-indent-after-java-annotations) - 'c-no-indent-after-java-annotations) - ,(when (fboundp 'c-lineup-assignments) - 'c-lineup-assignments) - ++)) - (label . /) - (case-label . +) - (statement-case-open . +) - (statement-case-intro . +) ; case w/o { - (access-label . /) - (innamespace . 0)))) - "Google C/C++ Programming Style.") - -;;;###autoload -(defun google-set-c-style () - "Set the current buffer's c-style to Google C/C++ Programming - Style. Meant to be added to `c-mode-common-hook'." - (interactive) - (make-local-variable 'c-tab-always-indent) - (setq c-tab-always-indent t) - (c-add-style "Google" google-c-style t)) - -;;;###autoload -(defun google-make-newline-indent () - "Sets up preferred newline behavior. Not set by default. Meant - to be added to `c-mode-common-hook'." - (interactive) - (define-key c-mode-base-map "\C-m" 'newline-and-indent) - (define-key c-mode-base-map [ret] 'newline-and-indent)) - -(provide 'google-c-style) -;;; google-c-style.el ends here diff --git a/users/aspen/emacs.d/grid.el b/users/aspen/emacs.d/grid.el deleted file mode 100644 index 75776a38c..000000000 --- a/users/aspen/emacs.d/grid.el +++ /dev/null @@ -1,128 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(require 's) - -(defun grfn/all-match-groups (s) - (loop for n from 1 - for x = (match-string n s) - while x - collect x)) - -(defun projectile-grid-ff (path &optional ask) - "Call `find-file' function on PATH when it is not nil and the file exists. -If file does not exist and ASK in not nil it will ask user to proceed." - (if (or (and path (file-exists-p path)) - (and ask (yes-or-no-p - (s-lex-format - "File does not exists. Create a new buffer ${path} ?")))) - (find-file path))) - -(defun projectile-grid-goto-file (filepath &optional ask) - "Find FILEPATH after expanding root. ASK is passed straight to `projectile-grid-ff'." - (projectile-grid-ff (projectile-expand-root filepath) ask)) - -(defun projectile-grid-choices (ds) - "Uses `projectile-dir-files' function to find files in directories. -The DIRS is list of lists consisting of a directory path and regexp to filter files from that directory. -Optional third element can be present in the DS list. The third element will be a prefix to be placed before -the filename in the resulting choice. -Returns a hash table with keys being short names (choices) and values being relative paths to the files." - (loop with hash = (make-hash-table :test 'equal) - for (dir re prefix) in ds do - (loop for file in (projectile-dir-files (projectile-expand-root dir)) do - (when (string-match re file) - (puthash - (concat (or prefix "") - (s-join "/" (grfn/all-match-groups file))) - (concat dir file) - hash))) - finally return hash)) - -(defmacro projectile-grid-find-resource (prompt dirs &optional newfile-template) - "Presents files from DIRS with PROMPT to the user using `projectile-completing-read'. -If users chooses a non existant file and NEWFILE-TEMPLATE is not nil -it will use that variable to interpolate the name for the new file. -NEWFILE-TEMPLATE will be the argument for `s-lex-format'. -The bound variable is \"filename\"." - `(lexical-let ((choices (projectile-grid-choices ,dirs))) - (projectile-completing-read - ,prompt - (hash-table-keys choices) - :action - (lambda (c) - (let* ((filepath (gethash c choices)) - (filename c)) ;; so `s-lex-format' can interpolate FILENAME - (if filepath - (projectile-grid-goto-file filepath) - (when-let ((newfile-template ,newfile-template)) - (projectile-grid-goto-file - (funcall newfile-template filepath) - ;; (cond - ;; ((functionp newfile-template) (funcall newfile-template filepath)) - ;; ((stringp newfile-template) (s-lex-format newfile-template))) - t)))))))) - -(defun projectile-grid-find-model () - "Find a model." - (interactive) - (projectile-grid-find-resource - "model: " - '(("python/urbint_lib/models/" - "\\(.+\\)\\.py$") - ("python/urbint_lib/" - "\\(.+\\)/models/\\(.+\\).py$")) - (lambda (filename) - (pcase (s-split "/" filename) - (`(,model) - (s-lex-format "python/urbint_lib/models/${model}.py")) - (`(,app ,model) - (s-lex-format "python/urbint_lib/${app}/models/${model}.py")))))) - -(defun projectile-grid-find-repository () - "Find a repository." - (interactive) - (projectile-grid-find-resource - "repository: " - '(("python/urbint_lib/repositories/" - "\\(.+\\)\\.py$") - ("python/urbint_lib/" - "\\(.+\\)/repositories/\\(.+\\).py$")) - (lambda (filename) - (pcase (s-split "/" filename) - (`(,repository) - (s-lex-format "python/urbint_lib/repositories/${repository}.py")) - (`(,app ,repository) - (s-lex-format "python/urbint_lib/${app}/repositories/${repository}.py")))))) - -(defun projectile-grid-find-controller () - "Find a controller." - (interactive) - (projectile-grid-find-resource - "controller: " - '(("backend/src/grid/api/controllers/" - "\\(.+\\)\\.py$") - ("backend/src/grid/api/apps/" - "\\(.+\\)/controllers/\\(.+\\).py$")) - (lambda (filename) - (pcase (s-split "/" filename) - (`(,controller) - (s-lex-format "backend/src/grid/api/controllers/${controller}.py")) - (`(,app ,controller) - (s-lex-format "backend/src/grid/api/apps/${app}/controllers/${controller}.py")))))) - -(setq projectile-grid-mode-map - (let ((map (make-keymap))) - (map! - (:map map - (:leader - (:desc "Edit..." :prefix "e" - :desc "Model" :n "m" #'projectile-grid-find-model - :desc "Controller" :n "c" #'projectile-grid-find-controller - :desc "Repository" :n "r" #'projectile-grid-find-repository)))) - map)) - -(define-minor-mode projectile-grid-mode - "Minor mode for finding files in GRID" - :init-value nil - :lighter " GRID" - :keymap projectile-grid-mode-map) diff --git a/users/aspen/emacs.d/init.el b/users/aspen/emacs.d/init.el deleted file mode 100644 index 46530ab95..000000000 --- a/users/aspen/emacs.d/init.el +++ /dev/null @@ -1,175 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(defvar native-comp-deferred-compilation-deny-list nil) - -(doom! :completion - company ; the ultimate code completion backend - (ivy +fuzzy - +prescient) ; a search engine for love and life - - :ui - ;;deft ; notational velocity for Emacs - doom ; what makes DOOM look the way it does - ;doom-dashboard ; a nifty splash screen for Emacs - doom-quit ; DOOM quit-message prompts when you quit Emacs - ;fill-column ; a `fill-column' indicator - hl-todo ; highlight TODO/FIXME/NOTE tags - ;;indent-guides ; highlighted indent columns - modeline ; snazzy, Atom-inspired modeline, plus API - nav-flash ; blink the current line after jumping - ;;neotree ; a project drawer, like NERDTree for vim - ophints ; highlight the region an operation acts on - (popup ; tame sudden yet inevitable temporary windows - +all ; catch all popups that start with an asterix - +defaults) ; default popup rules - ;; ligatures ; replace bits of code with pretty symbols - ;; tabbar ; FIXME an (incomplete) tab bar for Emacs - ;; treemacs ; a project drawer, like neotree but cooler - unicode ; extended unicode support for various languages - vc-gutter ; vcs diff in the fringe - vi-tilde-fringe ; fringe tildes to mark beyond EOB - ;;window-select ; visually switch windows - workspaces ; tab emulation, persistence & separate workspaces - - :editor - (evil +everywhere); come to the dark side, we have cookies - file-templates ; auto-snippets for empty files - fold ; (nigh) universal code folding - ;;(format +onsave) ; automated prettiness - ;;god ; run Emacs commands without modifier keys - ;;lispy ; vim for lisp, for people who dont like vim - ;;multiple-cursors ; editing in many places at once - ;;objed ; text object editing for the innocent - ;;parinfer ; turn lisp into python, sort of - ;;rotate-text ; cycle region at point between text candidates - snippets ; my elves. They type so I don't have to - word-wrap - - :emacs - dired ; making dired pretty [functional] - electric ; smarter, keyword-based electric-indent - ;;eshell ; a consistent, cross-platform shell (WIP) - ;;term ; terminals in Emacs - (undo +tree) - vc ; version-control and Emacs, sitting in a tree - - :tools - ;;ansible - ;;debugger ; FIXME stepping through code, to help you add bugs - ;;direnv - docker - ;;editorconfig ; let someone else argue about tabs vs spaces - ;; ein ; tame Jupyter notebooks with emacs - (eval +overlay) ; run code, run (also, repls) - gist ; interacting with github gists - (lookup ; helps you navigate your code and documentation - +docsets) ; ...or in Dash docsets locally - lsp - ;;macos ; MacOS-specific commands - magit ; a git porcelain for Emacs - make ; run make tasks from Emacs - pass ; password manager for nerds - pdf ; pdf enhancements - ;;prodigy ; FIXME managing external services & code builders - ;;rgb ; creating color strings - ;;terraform ; infrastructure as code - ;;tmux ; an API for interacting with tmux - tree-sitter ; syntax and parsing, sitting in a tree... - ;;upload ; map local to remote projects via ssh/ftp - ;;wakatime - ;;vterm ; another terminals in Emacs - - :checkers - syntax ; tasing you for every semicolon you forget - ; spell ; tasing you for misspelling mispelling - - :lang - agda ; types of types of types of types... - ;;assembly ; assembly for fun or debugging - cc ; C/C++/Obj-C madness - clojure ; java with a lisp - common-lisp ; if you've seen one lisp, you've seen them all - ; coq ; proofs-as-programs - ;;crystal ; ruby at the speed of c - ;;csharp ; unity, .NET, and mono shenanigans - data ; config/data formats - erlang ; an elegant language for a more civilized age - elixir ; erlang done right - ;;elm ; care for a cup of TEA? - emacs-lisp ; drown in parentheses - ;;ess ; emacs speaks statistics - ;;go ; the hipster dialect - ;; (haskell +intero) ; a language that's lazier than I am - haskell ; a language that's lazier than I am - ;;hy ; readability of scheme w/ speed of python - ;; idris ; - ;;(java +meghanada) ; the poster child for carpal tunnel syndrome - javascript ; all(hope(abandon(ye(who(enter(here)))))) - julia ; a better, faster MATLAB - ;;kotlin ; a better, slicker Java(Script) - latex ; writing papers in Emacs has never been so fun - ;;ledger ; an accounting system in Emacs - lua ; one-based indices? one-based indices - markdown ; writing docs for people to ignore - ;;nim ; python + lisp at the speed of c - nix ; I hereby declare "nix geht mehr!" - ocaml ; an objective camel - (org ; organize your plain life in plain text - +dragndrop ; drag & drop files/images into org buffers - +attach ; custom attachment system - +babel ; running code in org - +capture ; org-capture in and outside of Emacs - +export ; Exporting org to whatever you want - ;; +habit ; Keep track of your habits - +present ; Emacs for presentations - +pretty - +brain - +protocol) ; Support for org-protocol:// links - ;;perl ; write code no one else can comprehend - ;;php ; perl's insecure younger brother - ;;plantuml ; diagrams for confusing people more - purescript ; javascript, but functional - (python +lsp) ; beautiful is better than ugly - ;;qt ; the 'cutest' gui framework ever - racket ; a DSL for DSLs - rest ; Emacs as a REST client - ;;ruby ; 1.step do {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} - (rust +tree-sitter) ; Fe2O3.unwrap().unwrap().unwrap().unwrap() - ;;scala ; java, but good - (sh +fish) ; she sells (ba|z|fi)sh shells on the C xor - ;;solidity ; do you need a blockchain? No. - ;;swift ; who asked for emoji variables? - ;;terra ; Earth and Moon in alignment for performance. - ;;web ; the tubes - ;;vala ; GObjective-C - zig - - ;; Applications are complex and opinionated modules that transform Emacs - ;; toward a specific purpose. They may have additional dependencies and - ;; should be loaded late. - :app - ;;(email +gmail) ; emacs as an email client - irc ; how neckbeards socialize - ;;(rss +org) ; emacs as an RSS reader - twitter ; twitter client https://twitter.com/vnought - ;;(write ; emacs as a word processor (latex + org + markdown) - ;; +wordnut ; wordnet (wn) search - ;; +langtool) ; a proofreader (grammar/style check) for Emacs - - :email - ;; (mu4e +gmail) - notmuch - - :collab - ;;floobits ; peer programming for a price - ;;impatient-mode ; show off code over HTTP - - :config - ;; For literate config users. This will tangle+compile a config.org - ;; literate config in your `doom-private-dir' whenever it changes. - ;;literate - - ;; The default module sets reasonable defaults for Emacs. It also - ;; provides a Spacemacs-inspired keybinding scheme and a smartparens - ;; config. Use it as a reference for your own modules. - (default +bindings +smartparens)) diff --git a/users/aspen/emacs.d/irc.el b/users/aspen/emacs.d/irc.el deleted file mode 100644 index 117869599..000000000 --- a/users/aspen/emacs.d/irc.el +++ /dev/null @@ -1,131 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(require 'erc) -(require 'alert) - -(defvar irc-servers - '("hackint" - "libera")) - -(defun irc-connect (server) - (interactive - (list (ivy-read "Server: " irc-servers))) - (let ((pw (s-trim (shell-command-to-string - (format "pass irccloud/%s" server)))) - (gnutls-verify-error nil)) - (erc-tls :server "bnc.irccloud.com" - :port 6697 - :nick "grfn" - :password (concat "bnc@" - (s-trim (shell-command-to-string "hostname")) - ":" - pw)))) - - -(defgroup erc-alert nil - "Alert me using alert.el for important ERC messages" - :group 'erc) - -(defcustom erc-noise-regexp - "\\(Logging in:\\|Signing off\\|You're now away\\|Welcome back\\)" - "This regexp matches unwanted noise." - :type 'regexp - :group 'erc) - -(setq tvl-enabled? t) - -(defun disable-tvl-notifications () - (interactive) - (setq tvl-enabled? nil)) - -(defun enable-tvl-notifications () - (interactive) - (setq tvl-enabled? t)) - -(defun erc-alert-important-p (info) - (let ((message (plist-get info :message)) - (erc-message (-> info (plist-get :data) (plist-get :message))) - (erc-channel (-> info (plist-get :data) (plist-get :channel)))) - (and erc-message - (not (or (string-match "^\\** *Users on #" message) - (string-match erc-noise-regexp - message))) - (or (and tvl-enabled? - (string-equal erc-channel "#tvl")) - (string-match "grfn" message))))) - -(comment - last-info - erc-noise-regexp - (setq tvl-enabled? nil) - ) - -(defun my-erc-hook (&optional match-type nick message) - "Shows a notification, when user's nick was mentioned. -If the buffer is currently not visible, makes it sticky." - (setq last-message message) - (if (or (null match-type) (not (eq match-type 'fool))) - (let (alert-log-messages) - (alert (or message (buffer-string)) - :severity (if (string-match "grfn" (or message "")) - 'high 'low) - :title (or nick (buffer-name)) - :data `(:message ,(or message (buffer-string)) - :channel ,(or nick (buffer-name))))))) - -(add-hook 'erc-text-matched-hook 'my-erc-hook) -(add-hook 'erc-insert-modify-hook 'my-erc-hook) - -(defun my-erc-define-alerts (&rest ignore) - ;; Unless the user has recently typed in the ERC buffer, highlight the fringe - (alert-add-rule - :status '(buried visible idle) - :severity '(moderate high urgent) - :mode 'erc-mode - :predicate - #'(lambda (info) - (and (not (eq (current-buffer) (plist-get info :buffer))) - (string-match "grfn:" (plist-get info :message)))) - :persistent - #'(lambda (info) - ;; If the buffer is buried, or the user has been idle for - ;; `alert-reveal-idle-time' seconds, make this alert - ;; persistent. Normally, alerts become persistent after - ;; `alert-persist-idle-time' seconds. - (memq (plist-get info :status) '(buried idle))) - :style 'message - :continue t) - - (alert-add-rule - :status 'buried - :mode 'erc-mode - :predicate #'erc-alert-important-p - :style 'libnotify - :append t) - - (alert-add-rule - :status 'buried - :mode 'erc-mode - :predicate #'erc-alert-important-p - :style 'message - :append t) - - (alert-add-rule - :mode 'erc-mode - :predicate #'erc-alert-important-p - :style 'log - :append t) - - (alert-add-rule :mode 'erc-mode :style 'ignore :append t)) - -(add-hook 'erc-connect-pre-hook 'my-erc-define-alerts) - -(defun fix-irc-message (msg) - (let ((msg (s-trim msg))) - (if (string-equal msg ":q") "" msg))) - -(advice-add #'erc-user-input :filter-return #'fix-irc-message) - -(comment - (my-erc-define-alerts) - ) diff --git a/users/aspen/emacs.d/lisp.el b/users/aspen/emacs.d/lisp.el deleted file mode 100644 index c45cc7e6e..000000000 --- a/users/aspen/emacs.d/lisp.el +++ /dev/null @@ -1,38 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(defun grfn/sly-panettone () - (interactive) - (sly - (concat - (s-trim - (shell-command-to-string - "nix-build -o sbcl -E 'with import ~/code/depot {}; nix.buildLisp.sbclWith [web.panettone]'")) - "/bin/sbcl"))) - -(defun grfn/setup-lisp () - (interactive) - (unless paxedit-mode (paxedit-mode 1)) - (rainbow-delimiters-mode) - (flycheck-mode -1)) - -(add-hook 'common-lisp-lisp-mode-hook #'grfn/setup-lisp) - -(defun sly-run-tests () - (interactive) - ;; TODO: handle other test frameworks - (let ((orig-window (get-buffer-window))) - (sly-eval '(fiveam:run!)) - (funcall-interactively #'sly-mrepl-sync) - (select-window orig-window))) - -(map! - (:map sly-mode-map - :n "g \\" #'sly-mrepl-sync - :n "g d" #'sly-edit-definition - :n "K" #'sly-documentation - :n "g SPC" #'sly-compile-and-load-file - :n "g RET" #'sly-run-tests) - - (:map sly-mrepl-mode-map - "C-k" #'sly-mrepl-previous-prompt - "C-r" #'isearch-backward)) diff --git a/users/aspen/emacs.d/nix-clangd.sh b/users/aspen/emacs.d/nix-clangd.sh deleted file mode 100755 index 16f6252d8..000000000 --- a/users/aspen/emacs.d/nix-clangd.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -CLANGD_FLAGS=--compile-commands-dir=/home/grfn/builds/tvix \ - nix-shell /home/grfn/code/depot \ - -A third_party.nix \ - --run nix-clangd diff --git a/users/aspen/emacs.d/nix.el b/users/aspen/emacs.d/nix.el deleted file mode 100644 index ec5b474af..000000000 --- a/users/aspen/emacs.d/nix.el +++ /dev/null @@ -1,30 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(defun nix-buffer-type () - "Returns: - -'home-manager, if the current buffer is a home-manager module -'nixos, if the current buffer is a nixos module -nil, if none of the above are the case" - (when buffer-file-name - (pcase buffer-file-name - ((rx (0+ nonl) "system/home" (0+ nonl) ".nix" eos) - 'home-manager) - ((rx (0+ nonl) "system/system" (0+ nonl) ".nix" eos) - 'nixos)))) - -(defun set-nix-compile-command () - "Set the compile command for the current buffer based on the type of nix -buffer it is, per `nix-buffer-type'" - (interactive) - (when-let ((btype (nix-buffer-type))) - (setq-local - compile-command - (case btype - ('home-manager "home-manager switch") - ('nixos "sudo nixos-rebuild switch"))))) - -(add-hook 'nix-mode-hook #'set-nix-compile-command) - -(map! (:map nix-mode-map - (:n "g SPC" #'compile))) diff --git a/users/aspen/emacs.d/org-alerts.el b/users/aspen/emacs.d/org-alerts.el deleted file mode 100644 index 8e6c3e041..000000000 --- a/users/aspen/emacs.d/org-alerts.el +++ /dev/null @@ -1,188 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -;;; Commentary: - -;;; Code: - -(require 's) -(require 'dash) -(require 'alert) -(require 'org-agenda) - - -(defvar grfn/org-alert-interval 300 - "Interval in seconds to recheck and display deadlines.") - - -(defvar grfn/org-alert-notification-title "*org*" - "Title to be sent with notify-send.") - -(defvar grfn/org-alert-headline-regexp "\\(Sched.+:.+\\|Deadline:.+\\)" - "Regexp for headlines to search in agenda buffer.") - -(defun grfn/org-alert--strip-prefix (headline) - "Remove the scheduled/deadline prefix from HEADLINE." - (replace-regexp-in-string ".*:\s+" "" headline)) - - -(defun grfn/org-alert--unique-headlines (regexp agenda) - "Return unique headlines from the results of REGEXP in AGENDA." - (let ((matches (-distinct (-flatten (s-match-strings-all regexp agenda))))) - (--map (grfn/org-alert--strip-prefix it) matches))) - - -(defun grfn/org-alert--get-headlines () - "Return the current org agenda as text only." - (with-temp-buffer - (let ((org-agenda-sticky nil) - (org-agenda-buffer-tmp-name (buffer-name))) - (ignore-errors (org-agenda-list nil "TODAY" 1)) - (grfn/org-alert--unique-headlines - grfn/org-alert-headline-regexp - (buffer-substring-no-properties (point-min) (point-max)))))) - -(defun grfn/parse-range-string (str) - (when - (string-match (rx (group (repeat 2 (any digit)) - ":" - (repeat 2 (any digit))) - (optional - (and - "-" - (group (repeat 2 (any digit)) - ":" - (repeat 2 (any digit)))))) - str) - (list - (org-read-date nil t - (match-string 1 str)) - (when-let ((et (match-string 2 str))) (org-read-date nil t et))))) - -(defun grfn/start-time-from-range-string (str) - (pcase-let ((`(,start-time . _) (grfn/parse-range-string str))) - start-time)) - -(comment - (org-agenda-list nil "TODAY" 1) - - (grfn/org-alert--get-headlines) - (setq --src - (with-temp-buffer - (let ((org-agenda-sticky nil) - (org-agenda-buffer-tmp-name (buffer-name))) - (ignore-errors (org-agenda-list nil "TODAY" 1)) - (buffer-substring-no-properties (point-min) (point-max))))) - - (setq --entries - (with-temp-buffer - (let ((inhibit-redisplay t) - (org-agenda-sticky nil) - (org-agenda-buffer-tmp-name (buffer-name)) - (org-agenda-buffer-name (buffer-name)) - (org-agenda-buffer (current-buffer))) - (org-agenda-get-day-entries - (cadr (org-agenda-files nil 'ifmode)) - (calendar-gregorian-from-absolute - (time-to-days (org-read-date nil t "TODAY"))))))) - - (loop for k in (text-properties-at 0 (car --entries)) - by #'cddr - collect k) - - (--map (substring-no-properties (get-text-property 0 'txt it)) --entries) - (--map (get-text-property 0 'time it) --entries) - (current-time) - - (format-time-string "%R" (org-read-date nil t "10:00-11:00")) - - (grfn/start-time-from-range-string "10:00") - - (current-time-string (org-read-date nil t "10:00-11:00")) - - (todo-state - org-habit-p - priority - warntime - ts-date - date - type - org-hd-marker - org-marker - face - undone-face - help-echo - mouse-face - done-face - org-complex-heading-regexp - org-todo-regexp - org-not-done-regexp - dotime - format - extra - time - level - txt - breadcrumbs - duration - time-of-day - org-lowest-priority - org-highest-priority - tags - org-category) - - (propertize) - - --src - ) - - -(defun grfn/org-alert--headline-complete? (headline) - "Return whether HEADLINE has been completed." - (--any? (s-starts-with? it headline) org-done-keywords-for-agenda)) - - -(defun grfn/org-alert--filter-active (deadlines) - "Remove any completed headings from the provided DEADLINES." - (-remove 'grfn/org-alert--headline-complete? deadlines)) - - -(defun grfn/org-alert--strip-states (deadlines) - "Remove the todo states from DEADLINES." - (--map (s-trim (s-chop-prefixes org-todo-keywords-for-agenda it)) deadlines)) - - -(defun grfn/org-alert-check () - "Check for active, due deadlines and initiate notifications." - (interactive) - ;; avoid interrupting current command. - (unless (minibufferp) - (save-window-excursion - (save-excursion - (save-restriction - (let ((active (grfn/org-alert--filter-active (grfn/org-alert--get-headlines)))) - (dolist (dl (grfn/org-alert--strip-states active)) - (alert dl :title grfn/org-alert-notification-title)))))) - (when (get-buffer org-agenda-buffer-name) - (ignore-errors - (with-current-buffer org-agenda-buffer-name - (org-agenda-redo t)))))) - - -(defun grfn/org-alert-enable () - "Enable the notification timer. Cancels existing timer if running." - (interactive) - (grfn/org-alert-disable) - (run-at-time 0 grfn/org-alert-interval 'grfn/org-alert-check)) - - -(defun grfn/org-alert-disable () - "Cancel the running notification timer." - (interactive) - (dolist (timer timer-list) - (if (eq (elt timer 5) 'grfn/org-alert-check) - (cancel-timer timer)))) - - - -(provide 'grfn/org-alert) -;;; grfn/org-alert.el ends here diff --git a/users/aspen/emacs.d/org-config.el b/users/aspen/emacs.d/org-config.el deleted file mode 100644 index b8d88d319..000000000 --- a/users/aspen/emacs.d/org-config.el +++ /dev/null @@ -1,191 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(defun +aspen/org-setup () - (setq-local truncate-lines -1) - (display-line-numbers-mode -1) - (line-number-mode -1)) - -(add-hook 'org-mode-hook #'+aspen/org-setup) - -(defun notes-file (f) - (concat org-directory (if (string-prefix-p "/" f) "" "/") f)) - -(defun aspen/org-project-tag->key (tag) - (s-replace-regexp "^project__" "" tag)) - -(defun aspen/org-project-tag->name (tag) - (s-titleized-words - (s-join " " (s-split "_" (aspen/org-project-tag->key tag))))) - -(defun aspen/org-project-tag->keys (tag) - (s-join "" (cons "p" - (-map (lambda (s) (substring-no-properties s 0 1)) - (s-split "_" (aspen/org-project-tag->key tag)))))) - -(defun aspen/org-projects->agenda-commands (project-tags) - (loop for tag in project-tags - collect `(,(aspen/org-project-tag->keys tag) - ,(aspen/org-project-tag->name tag) - tags-todo - ,tag))) - -(defun aspen/org-projects () - (loop for (tag) in - (org-global-tags-completion-table - (directory-files-recursively "~/notes" "\\.org$")) - when (s-starts-with-p "project__" tag) - collect tag)) - -(comment - (aspen/org-projects->agenda-commands (aspen/org-projects)) - ) - -(setq - org-directory (expand-file-name "~/notes") - +org-dir (expand-file-name "~/notes") - org-default-notes-file (concat org-directory "/inbox.org") - +org-default-todo-file (concat org-directory "/inbox.org") - org-agenda-files (directory-files-recursively - "~/notes" "\\.org$") - org-refile-targets '((org-agenda-files :maxlevel . 3)) - org-outline-path-complete-in-steps nil - org-refile-use-outline-path t - org-file-apps `((auto-mode . emacs) - (,(rx (or (and "." (optional "x") (optional "htm") (optional "l") buffer-end) - (and buffer-start "http" (optional "s") "://"))) - . "firefox %s") - (,(rx ".pdf" buffer-end) . "apvlv %s") - (,(rx "." (or "png" - "jpg" - "jpeg" - "gif" - "tif" - "tiff") - buffer-end) - . "feh %s")) - org-log-done 'time - org-archive-location "~/notes/trash::* From %s" - org-cycle-separator-lines 2 - org-hidden-keywords '(title) - org-tags-column -130 - org-ellipsis "…" - org-imenu-depth 9 - org-capture-templates - `(("t" "Todo" entry - (file +org-default-todo-file) - "* TODO %?\n%i" - :kill-buffer t) - - ("m" "Email" entry - (file +org-default-todo-file) - "* TODO [[%L][%:subject]] :email:\n%i") - - ("n" "Notes" entry - (file +org-default-todo-file) - "* %U %?\n%i" - :prepend t - :kill-buffer t) - - ("c" "Task note" entry - (clock) - "* %U %?\n%i[%l[Context]]\n" - :kill-buffer t - :unnarrowed t) - - ("p" "Projects") - ("px" "Xanthous" entry - (file+headline ,(notes-file "xanthous.org") "Backlog") - "* TODO %?\nContext %a\nIn task: %K") - ("pt" "Tvix" entry - (file+headline ,(notes-file "tvix.org") "Tvix TODO") - "* TODO %?\nContext %a\nIn task: %K") - ("pw" "Windtunnel" entry - (file+headline ,(notes-file "windtunnel.org") "Inbox") - "* TODO %i%?\nContext: %a\nIn task: %K") - ) - - org-capture-templates-contexts - `(("px" ((in-file . "/home/aspen/code/depot/users/aspen/xanthous/.*"))) - ("e" ((in-mode . "notmuch-show-mode")))) - - org-deadline-warning-days 1 - org-agenda-skip-scheduled-if-deadline-is-shown 'todo - org-todo-keywords '((sequence "TODO(t)" "ACTIVE(a)" "|" "DONE(d)" "RUNNING(r)") - (sequence "NEXT(n)" "WAITING(w)" "LATER(l)" "|" "CANCELLED(c)")) - org-agenda-custom-commands - `(("i" "Inbox" tags "inbox") - ("r" "Running jobs" todo "RUNNING") - ("w" "@Work" tags-todo "@work") - ("n" . "Next...") - ("nw" "Next @Work" tags-todo "@work&next") - ("nt" "Next tooling" tags-todo "tooling") - - ("p" . "Project...") - ,@(aspen/org-projects->agenda-commands (aspen/org-projects))) - - org-agenda-dim-blocked-tasks nil - org-enforce-todo-dependencies nil - - org-babel-clojure-backend 'cider) - -(defun +aspen/insert-work-template () - (interactive) - (goto-char (point-min)) - (forward-line) - (insert "#+TODO: TODO(t) NEXT(n) ACTIVE(a) | DONE(d) PR(p) RUNNING(r) TESTING(D) -#+TODO: BLOCKED(b) BACKLOG(l) PROPOSED(o) | CANCELLED(c) -#+FILETAGS: @work -#+FILETAGS: @work -#+PROPERTY: Effort_ALL 0 4:00 8:00 12:00 20:00 32:00 -#+PROPERTY: ESTIMATE_ALL 0 1 2 3 5 8 -#+PROPERTY: STORY-TYPE_ALL Feature Bug Chore -#+PROPERTY: NOBLOCKING t -#+COLUMNS: %TODO %40ITEM(Task) %17EFFORT(Estimated){:} %CLOCKSUM(Time Spent) %17STORY-TYPE(Type) %TAGS")) - -(defun +aspen/insert-org-template () - (interactive) - (pcase (buffer-file-name) - ((s-contains "/work/") (+aspen/insert-work-template)))) - -;;; TODO: this doesn't work? -(define-auto-insert "\\.org?$" #'aspen/insert-org-template t) - -(defun forge--post-submit-around---link-pr-to-org-item - (orig) - (let ((cb (funcall orig))) - (lambda (value headers status req) - (prog1 (funcall cb value headers status req) - (aspen/at-org-clocked-in-item - (let ((url (alist-get 'html_url value)) - (number (alist-get 'number value))) - (org-set-property - "pull-request" - (org-make-link-string - url - (format "%s/%s/%d" - (->> value - (alist-get 'base) - (alist-get 'repo) - (alist-get 'name)) - (->> value - (alist-get 'base) - (alist-get 'repo) - (alist-get 'owner) - (alist-get 'login)) - number))))))))) - -(advice-add - #'forge--post-submit-callback - :around #'forge--post-submit-around---link-pr-to-org-item) - -(set-face-foreground 'org-block +solarized-s-base00) -(setq whitespace-global-modes '(not org-mode magit-mode vterm-mode)) -(setf (alist-get 'file org-link-frame-setup) 'find-file-other-window) -(set-face-foreground 'org-block +solarized-s-base00) - -;; (add-hook! org-mode -;; (set-company-backend! 'org-mode -;; '(:separate company-ob-postgresql -;; company-dabbrev -;; company-yasnippet -;; company-ispell))) diff --git a/users/aspen/emacs.d/org-gcal.el b/users/aspen/emacs.d/org-gcal.el deleted file mode 100644 index 3e315c5e6..000000000 --- a/users/aspen/emacs.d/org-gcal.el +++ /dev/null @@ -1,181 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(require 'aio) -(require 'parse-time) - -(setq-local lexical-binding t) -(setq plstore-cache-passphrase-for-symmetric-encryption t) - -(defvar gcal-client-id) -(defvar gcal-client-secret) - -(defvar google-calendar-readonly-scope - "https://www.googleapis.com/auth/calendar.readonly") - -(defvar events-file "/home/grfn/notes/events.org") - -(defun google--get-token (scope client-id client-secret) - (oauth2-auth-and-store - "https://accounts.google.com/o/oauth2/v2/auth" - "https://oauth2.googleapis.com/token" - scope - client-id - client-secret)) - -(cl-defun google--request (url &key method params scope) - (let ((p (aio-promise)) - (auth-token (google--get-token scope gcal-client-id gcal-client-secret))) - (oauth2-refresh-access auth-token) - (oauth2-url-retrieve - auth-token - url - (lambda (&rest _) - (goto-char (point-min)) - (re-search-forward "^$") - (let ((resp (json-parse-buffer :object-type 'alist))) - (aio-resolve p (lambda () resp)))) - nil - (or method "GET") - params) - p)) - -(cl-defun list-events (&key min-time max-time) - (google--request - (concat - "https://www.googleapis.com/calendar/v3/calendars/griffin@urbint.com/events" - "?timeMin=" (format-time-string "%Y-%m-%dT%T%z" min-time) - "&timeMax=" (format-time-string "%Y-%m-%dT%T%z" max-time)) - :scope google-calendar-readonly-scope)) - - -(defun last-week-events () - (list-events :min-time (time-subtract - (current-time) - (seconds-to-time - (* 60 60 24 7))) - :max-time (current-time))) - -(defun next-week-events () - (list-events :min-time (current-time) - :max-time (time-add - (current-time) - (seconds-to-time - (* 60 60 24 7))))) - -(defun attending-event? (event) - (let* ((attendees (append (alist-get 'attendees event) nil)) - (self (--find (alist-get 'self it) attendees))) - (equal "accepted" (alist-get 'responseStatus self)))) - -(defun event->org-headline (event level) - (cl-flet ((make-time - (key) - (when-let ((raw-time (->> event (alist-get key) (alist-get 'dateTime)))) - (format-time-string - (org-time-stamp-format t) - (parse-iso8601-time-string raw-time))))) - (if-let ((start-time (make-time 'start)) - (end-time (make-time 'end))) - (s-format - "${headline} [[${htmlLink}][${summary}]] :event: -${startTime}--${endTime} -:PROPERTIES: -${location-prop} -:EVENT: ${htmlLink} -:END: - -${description}" - (function - (lambda (k m) - (or (alist-get (intern k) m) - (format "key not found: %s" k)))) - (append - event - `((headline . ,(make-string level ?*)) - (startTime . ,start-time) - (endTime . ,end-time) - (location-prop - . ,(if-let ((location (alist-get 'location event))) - (s-lex-format ":LOCATION: ${location}") - ""))))) - ""))) - -(comment - (alist-get 'foo nil) - ) - -(defun write-events (events) - (with-current-buffer (find-file-noselect events-file) - (save-mark-and-excursion - (save-restriction - (widen) - (erase-buffer) - (goto-char (point-min)) - (insert "#+TITLE: Events") - (newline) (newline) - (prog1 - (loop for event in (append events nil) - when (attending-event? event) - do - (insert (event->org-headline event 1)) - (newline) - sum 1) - (org-align-tags t)))))) - -(defun +grfn/sync-events () - (interactive) - (let* ((events (alist-get 'items (aio-wait-for (next-week-events)))) - (num-written (write-events events))) - (message "Successfully wrote %d events" num-written))) - -(comment - ((kind . "calendar#event") - (etag . "\"3174776941020000\"") - (id . "SNIP") - (status . "confirmed") - (htmlLink . "https://www.google.com/calendar/event?eid=SNIP") - (created . "2020-04-01T13:30:09.000Z") - (updated . "2020-04-20T13:14:30.510Z") - (summary . "SNIP") - (description . "SNIP") - (location . "SNIP") - (creator - (email . "griffin@urbint.com") - (self . t)) - (organizer - (email . "griffin@urbint.com") - (self . t)) - (start - (dateTime . "2020-04-01T12:00:00-04:00") - (timeZone . "America/New_York")) - (end - (dateTime . "2020-04-01T12:30:00-04:00") - (timeZone . "America/New_York")) - (recurrence . - ["RRULE:FREQ=WEEKLY;UNTIL=20200408T035959Z;BYDAY=WE"]) - (iCalUID . "SNIP") - (sequence . 0) - (attendees . - [((email . "griffin@urbint.com") - (organizer . t) - (self . t) - (responseStatus . "accepted")) - ((email . "SNIP") - (displayName . "SNIP") - (responseStatus . "needsAction"))]) - (extendedProperties - (private - (origRecurringId . "309q48kc1dihsvbi13pnlimb5a")) - (shared - (origRecurringId . "309q48kc1dihsvbi13pnlimb5a"))) - (reminders - (useDefault . t))) - - (require 'icalendar) - - (icalendar--convert-recurring-to-diary - nil - "RRULE:FREQ=WEEKLY;UNTIL=20200408T035959Z;BYDAY=WE" - ) - - ) diff --git a/users/aspen/emacs.d/org-query.el b/users/aspen/emacs.d/org-query.el deleted file mode 100644 index 9d3b3358a..000000000 --- a/users/aspen/emacs.d/org-query.el +++ /dev/null @@ -1,143 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(require 'org) -(require 'org-agenda) -(require 'inflections) - -(defun grfn/org-text-element->string (elt) - (cond - ((stringp elt) elt) - ((and (consp elt) - (symbolp (car elt))) - (-> elt (caddr) (grfn/org-text-element->string) (s-trim) (concat " "))))) - -(defun grfn/org-element-title (elt) - (let ((title (org-element-property :title elt))) - (cond - ((stringp title) title) - ((listp title) - (->> title - (mapcar #'grfn/org-text-element->string) - (s-join "") - (s-trim)))))) - -(defun grfn/org-agenda-entry->element (agenda-entry) - ;; ??? - ()) - -(defun org-elements-agenda-match (match &optional todo-only) - (setq match - (propertize match 'inherited t)) - (with-temp-buffer - (let ((inhibit-redisplay (not debug-on-error)) - (org-agenda-sticky nil) - (org-agenda-buffer-tmp-name (buffer-name)) - (org-agenda-buffer-name (buffer-name)) - (org-agenda-buffer (current-buffer)) - (matcher (org-make-tags-matcher match)) - result) - (org-agenda-prepare (concat "TAGS " match)) - (setq match (car matcher) - matcher (cdr matcher)) - (dolist (file (org-agenda-files nil 'ifmode) - result) - (catch 'nextfile - (org-check-agenda-file file) - (when-let ((buffer (if (file-exists-p file) - (org-get-agenda-file-buffer file) - (error "No such file %s" file)))) - (with-current-buffer buffer - (unless (derived-mode-p 'org-mode) - (error "Agenda file %s is not in Org mode" file)) - (save-excursion - (save-restriction - (if (eq buffer org-agenda-restrict) - (narrow-to-region org-agenda-restrict-begin - org-agenda-restrict-end) - (widen)) - (setq result - (append result (org-scan-tags - 'agenda - matcher - todo-only)))))))))))) - -(defun grfn/num-inbox-items () - (length (org-elements-agenda-match "inbox" t))) - -(defun grfn/num-inbox-items-message () - (let ((n (grfn/num-inbox-items))) - (if (zerop n) "" - (format "%d %s" - n - (if (= 1 n) "item" "items"))))) - -(defmacro grfn/at-org-clocked-in-item (&rest body) - `(when (org-clocking-p) - (let ((m org-clock-marker)) - (with-current-buffer (marker-buffer m) - (save-mark-and-excursion - (goto-char m) - (org-back-to-heading t) - ,@body))))) - -(defun grfn/org-element-clocked-in-task () - (grfn/at-org-clocked-in-item - (org-element-at-point))) - -(comment - (grfn/org-element-clocked-in-task) - (org-element-property :title (grfn/org-element-clocked-in-task)) - ) - -(defun grfn/minutes->hours:minutes (minutes) - (format "%d:%02d" - (floor (/ minutes 60)) - (mod minutes 60))) - -(comment - (grfn/minutes->hours:minutes 1) ; => "0:01" - (grfn/minutes->hours:minutes 15) ; => "0:15" - (grfn/minutes->hours:minutes 130) ; => "2:10" - ) - -(defun grfn/org-current-clocked-in-task-message () - (if (org-clocking-p) - (format "(%s) [%s]" - (->> (grfn/org-element-clocked-in-task) - (grfn/org-element-title) - (substring-no-properties) - (s-trim)) - (grfn/minutes->hours:minutes - (org-clock-get-clocked-time))) - "")) - -(comment - (grfn/org-current-clocked-in-task-message) - ) - -(cl-defgeneric grfn/org-tracker-ticket-id-label (backend elt) - (org-tracker-backend/extract-issue-id backend elt)) -(cl-defmethod grfn/org-tracker-ticket-id-label - ((backend org-tracker-linear-backend) elt) - (when-let* ((link (plist-get elt :LINEAR-KEY))) - (string-match - (rx "[[" (one-or-more anything) "]" - "[" (group (one-or-more anything)) "]]") - link) - (match-string 1 link))) - -(defun grfn/org-clocked-in-ticket-id () - (grfn/at-org-clocked-in-item - (when-let* ((backend (org-tracker-current-backend t))) - (grfn/org-tracker-ticket-id-label - backend - (cadr (org-element-at-point)))))) - -(comment - (grfn/at-org-clocked-in-item - (org-tracker-backend/extract-issue-id - (org-tracker-current-backend) - (cadr (org-element-at-point)))) - - (grfn/org-clocked-in-ticket-id) - ) diff --git a/users/aspen/emacs.d/packages.el b/users/aspen/emacs.d/packages.el deleted file mode 100644 index 15a3843f4..000000000 --- a/users/aspen/emacs.d/packages.el +++ /dev/null @@ -1,154 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; private/grfn/packages.el - -(package! moody) - -;; Editor -(package! solarized-theme) -(package! fill-column-indicator) -(package! flx) -(package! general - :recipe (:host github :repo "noctuid/general.el")) -(package! fill-column-indicator) -(package! writeroom-mode) -(package! dash) -(package! w3m) -(package! rainbow-mode) -(package! string-inflection) - -;;; Org -(package! org-tracker - :recipe (:host file - :local-repo "~/code/org-tracker")) -(package! jiralib2) -(package! org-alert) -(package! ob-http) -(package! ob-ipython) -(package! ob-async) -(package! org-recent-headings) -(package! org-sticky-header) -(package! gnuplot) -(package! gnuplot-mode) -(package! org-d20) - -;; Presentation -(package! epresent) -(package! org-tree-slide) -(package! ox-reveal) - -;; Slack etc -(package! slack) -(package! alert) - -;; Git -(package! evil-magit) -(package! marshal) -(package! forge) -(package! - github-review - :recipe - (:host github - :repo "charignon/github-review" - :files ("github-review.el"))) - -;; Elisp -(package! dash) -(package! dash-functional) -(package! s) -(package! request) -(package! predd - :recipe (:host github :repo "skeeto/predd")) -(package! aio) - -;; Haskell -(package! lsp-haskell) -(package! counsel-etags) - -;;; LSP -(package! lsp-mode) -(package! lsp-ui :recipe (:host github :repo "emacs-lsp/lsp-ui")) -(package! company-lsp) -(package! lsp-treemacs) - -;; Rust -;; (package! rustic :disable t) -;; (package! racer :disable t) -(package! cargo) - -;; Lisp -(package! paxedit) - -;; Javascript -(package! flow-minor-mode) -(package! flycheck-flow) -(package! company-flow) -(package! prettier-js) - -;; GraphQL -(package! graphql-mode) - -;; Haskell -(package! lsp-mode) -(package! lsp-ui) -(package! lsp-haskell) -(package! company-lsp) -;; (package! lsp-imenu) - -;; Clojure -(package! flycheck-clojure) - -;; SQL -(package! sqlup-mode) -(package! emacsql) -(package! emacsql-psql) - -;;; Python -(package! pyimport) -;; (package! yapfify) -(package! blacken) - - -;;; Desktop interaction -(package! counsel-spotify) - -;;; Dhall -(package! dhall-mode) - -;;; Kubernetes -(package! kubernetes) -(package! kubernetes-evil) -(package! k8s-mode) - -;;; Stack Exchange -(package! sx) - -;;; Nix -(package! nix-update - :recipe (:host github - :repo "glittershark/nix-update-el")) -(package! direnv) - -;;; Sequence diagrams -(package! wsd-mode - :recipe (:host github - :repo "josteink/wsd-mode")) - -;;; logic? -(package! metal-mercury-mode - :recipe (:host github - :repo "ahungry/metal-mercury-mode")) -(package! flycheck-mercury) - -(package! terraform-mode) -(package! company-terraform) - -(package! jsonnet-mode) - -;;; -(package! znc - :recipe (:host github - :repo "sshirokov/ZNC.el")) - -;;; cpp -(package! protobuf-mode) -(package! clang-format+) diff --git a/users/aspen/emacs.d/rust.el b/users/aspen/emacs.d/rust.el deleted file mode 100644 index 9988d16a5..000000000 --- a/users/aspen/emacs.d/rust.el +++ /dev/null @@ -1,42 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(add-to-list 'auto-mode-alist '("\\.rs$" . rust-mode)) - -(defun grfn/rust-setup () - (interactive) - - (direnv--maybe-update-environment) - - (+evil-embrace-angle-bracket-modes-hook-h) - - ;; (setq lsp-rust-server 'rust-analyzer) - (setq-local whitespace-line-column 100 - fill-column 100) - ;; (setq rust-format-show-buffer nil) - (setq lsp-rust-analyzer-import-merge-behaviour "last" - lsp-rust-analyzer-cargo-watch-command "clippy" - lsp-rust-analyzer-cargo-watch-args ["--target-dir" "/home/grfn/code/readyset/readyset/target/rust-analyzer"] - rustic-format-trigger 'on-save - lsp-ui-doc-enable t) - ;; (rust-enable-format-on-save) - (lsp)) - -(add-hook 'rust-mode-hook #'grfn/rust-setup) - -(map! - (:map rust-mode-map - :n "g RET" #'lsp-rust-analyzer-run - :n "g R" #'lsp-find-references - :n "g d" #'lsp-find-definition - :n "g Y" #'lsp-goto-type-definition - (:localleader - "m" #'lsp-rust-analyzer-expand-macro))) - -(comment - (flycheck-get-next-checkers 'lsp) - (flycheck-add-next-checker) - (flycheck-get-next-checkers 'lsp) - ) - -(set-company-backend! 'rust-mode - '(:separate company-capf company-yasnippet)) diff --git a/users/aspen/emacs.d/show-matching-paren.el b/users/aspen/emacs.d/show-matching-paren.el deleted file mode 100644 index ab65a912a..000000000 --- a/users/aspen/emacs.d/show-matching-paren.el +++ /dev/null @@ -1,61 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -;;; https://with-emacs.com/posts/ui-hacks/show-matching-lines-when-parentheses-go-off-screen/ - -;; we will call `blink-matching-open` ourselves... -(remove-hook 'post-self-insert-hook - #'blink-paren-post-self-insert-function) -;; this still needs to be set for `blink-matching-open` to work -(setq blink-matching-paren 'show) - -(let ((ov nil)) ; keep track of the overlay - (advice-add - #'show-paren-function - :after - (defun show-paren--off-screen+ (&rest _args) - "Display matching line for off-screen paren." - (when (overlayp ov) - (delete-overlay ov)) - ;; check if it's appropriate to show match info, - ;; see `blink-paren-post-self-insert-function' - (when (and (overlay-buffer show-paren--overlay) - (not (or cursor-in-echo-area - executing-kbd-macro - noninteractive - (minibufferp) - this-command)) - (and (not (bobp)) - (memq (char-syntax (char-before)) '(?\) ?\$))) - (= 1 (logand 1 (- (point) - (save-excursion - (forward-char -1) - (skip-syntax-backward "/\\") - (point)))))) - ;; rebind `minibuffer-message' called by - ;; `blink-matching-open' to handle the overlay display - (cl-letf (((symbol-function #'minibuffer-message) - (lambda (msg &rest args) - (let ((msg (apply #'format-message msg args))) - (setq ov (display-line-overlay+ - (window-start) msg )))))) - (blink-matching-open)))))) - -(defun display-line-overlay+ (pos str &optional face) - "Display line at POS as STR with FACE. - -FACE defaults to inheriting from default and highlight." - (let ((ol (save-excursion - (goto-char pos) - (make-overlay (line-beginning-position) - (line-end-position))))) - (overlay-put ol 'display str) - (overlay-put ol 'face - (or face '(:inherit default :inherit highlight))) - ol)) - -(setq show-paren-style 'paren - show-paren-delay 0.03 - show-paren-highlight-openparen t - show-paren-when-point-inside-paren nil - show-paren-when-point-in-periphery t) -(show-paren-mode 1) diff --git a/users/aspen/emacs.d/slack-snippets.el b/users/aspen/emacs.d/slack-snippets.el deleted file mode 100644 index b5bd4db74..000000000 --- a/users/aspen/emacs.d/slack-snippets.el +++ /dev/null @@ -1,227 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(require 'dash) -(require 'dash-functional) -(require 'request) - -;;; -;;; Configuration -;;; - -(defvar slack/token nil - "Legacy (https://api.slack.com/custom-integrations/legacy-tokens) access token") - -(defvar slack/include-public-channels 't - "Whether or not to inclue public channels in the list of conversations") - -(defvar slack/include-private-channels 't - "Whether or not to inclue public channels in the list of conversations") - -(defvar slack/include-im 't - "Whether or not to inclue IMs (private messages) in the list of conversations") - -(defvar slack/include-mpim nil - "Whether or not to inclue multi-person IMs (multi-person private messages) in - the list of conversations") - -;;; -;;; Utilities -;;; - -(defmacro comment (&rest _body) - "Comment out one or more s-expressions" - nil) - -(defun ->list (vec) (append vec nil)) - -(defun json-truthy? (x) (and x (not (equal :json-false x)))) - -;;; -;;; Generic API integration -;;; - -(defvar slack/base-url "https://slack.com/api") - -(defun slack/get (path params &optional callback) - "params is an alist of query parameters" - (let* ((params-callback (if (functionp params) `(() . ,params) (cons params callback))) - (params (car params-callback)) (callback (cdr params-callback)) - (params (append `(("token" . ,slack/token)) params)) - (url (concat (file-name-as-directory slack/base-url) path))) - (request url - :type "GET" - :params params - :parser 'json-read - :success (cl-function - (lambda (&key data &allow-other-keys) - (funcall callback data)))))) - -(defun slack/post (path params &optional callback) - (let* ((params-callback (if (functionp params) `(() . ,params) (cons params callback))) - (params (car params-callback)) (callback (cdr params-callback)) - (url (concat (file-name-as-directory slack/base-url) path))) - (request url - :type "POST" - :data (json-encode params) - :headers `(("Content-Type" . "application/json") - ("Authorization" . ,(format "Bearer %s" slack/token))) - :success (cl-function - (lambda (&key data &allow-other-keys) - (funcall callback data)))))) - - -;;; -;;; Specific API endpoints -;;; - -;; Users - -(defun slack/users (cb) - "Returns users as (id . name) pairs" - (slack/get - "users.list" - (lambda (data) - (->> data - (assoc-default 'members) - ->list - (-map (lambda (user) - (cons (assoc-default 'id user) - (assoc-default 'real_name user)))) - (-filter #'cdr) - (funcall cb))))) - -(comment - (slack/get - "users.list" - (lambda (data) (setq response-data data))) - - (slack/users (lambda (data) (setq --users data))) - - ) - -;; Conversations - -(defun slack/conversation-types () - (->> - (list (when slack/include-public-channels "public_channel") - (when slack/include-private-channels "private_channel") - (when slack/include-im "im") - (when slack/include-mpim "mpim")) - (-filter #'identity) - (s-join ","))) - -(defun channel-label (chan users-alist) - (cond - ((json-truthy? (assoc-default 'is_channel chan)) - (format "#%s" (assoc-default 'name chan))) - ((json-truthy? (assoc-default 'is_im chan)) - (let ((user-id (assoc-default 'user chan))) - (format "Private message with %s" (assoc-default user-id users-alist)))) - ((json-truthy? (assoc-default 'is_mpim chan)) - (->> chan - (assoc-default 'purpose) - (assoc-default 'value))))) - -(defun slack/conversations (cb) - "Calls `cb' with (id . '((label . \"label\") '(topic . \"topic\") '(purpose . \"purpose\"))) pairs" - (slack/get - "conversations.list" - `(("types" . ,(slack/conversation-types)) - ("exclude-archived" . "true")) - (lambda (data) - (setq --data data) - (slack/users - (lambda (users) - (->> data - (assoc-default 'channels) - ->list - (-map - (lambda (chan) - (cons (assoc-default 'id chan) - `((label . ,(channel-label chan users)) - (topic . ,(->> chan - (assoc-default 'topic) - (assoc-default 'value))) - (purpose . ,(->> chan - (assoc-default 'purpose) - (assoc-default 'value))))))) - (funcall cb))))))) - -(comment - (slack/get - "conversations.list" - '(("types" . "public_channel,private_channel,im,mpim")) - (lambda (data) (setq response-data data))) - - (slack/get - "conversations.list" - '(("types" . "im")) - (lambda (data) (setq response-data data))) - - (slack/conversations - (lambda (convos) (setq --conversations convos))) - - ) - -;; Messages - -(cl-defun slack/post-message - (&key text channel-id (on-success #'identity)) - (slack/post "chat.postMessage" - `((text . ,text) - (channel . ,channel-id) - (as_user . t)) - on-success)) - -(comment - - (slack/post-message - :text "hi slackbot" - :channel-id slackbot-channel-id - :on-success (lambda (data) (setq resp data))) - - ) - -;;; -;;; Posting code snippets to slack -;;; - -(defun prompt-for-channel (cb) - (slack/conversations - (lambda (conversations) - (ivy-read - "Select channel: " - ;; TODO want to potentially use purpose / topic stuff here - (->> conversations - (-filter (lambda (c) (assoc-default 'label (cdr c)))) - (-map (lambda (chan) (let ((label (assoc-default 'label (cdr chan))) - (id (car chan))) - (propertize label 'channel-id id))))) - :history 'slack/channel-history - :action (lambda (selected) - (let ((channel-id (get-text-property 0 'channel-id selected))) - (funcall cb channel-id) - (message "Sent message to %s" selected)))))) - nil) - -(comment - (prompt-for-channel #'message) - (->> --convos - (-filter (lambda (c) (assoc-default 'label (cdr c)))) - (-map (lambda (chan) (let ((label (assoc-default 'label (cdr chan))) - (id (car chan))) - (propertize label 'channel-id id))))) - - (->> --convos (car) (cdr) (assoc-default 'label)) - ) - -(defun slack-send-code-snippet (&optional snippet-text) - (interactive - (list (buffer-substring-no-properties (mark) (point)))) - (prompt-for-channel - (lambda (channel-id) - (slack/post-message - :text (format "```\n%s```" snippet-text) - :channel-id channel-id)))) - -(provide 'slack-snippets) diff --git a/users/aspen/emacs.d/slack.el b/users/aspen/emacs.d/slack.el deleted file mode 100644 index 54d3b40b0..000000000 --- a/users/aspen/emacs.d/slack.el +++ /dev/null @@ -1,24 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(after! slack - (set-face-foreground 'slack-message-output-header +solarized-s-base01) - (set-face-attribute 'slack-message-output-header nil :underline nil) - (set-face-attribute 'slack-message-output-text nil :height 1.0)) - -(require 'slack) -(setq slack-buffer-emojify 't - slack-prefer-current-team 't - slack-thread-also-send-to-room nil) - -(set-popup-rule! "^\\*Slack" - :quit nil - :select t - :side 'bottom - :ttl nil - :size 0.5) - -(add-hook #'slack-message-buffer-mode-hook - (lambda () (toggle-truncate-lines -1))) - -(map! (:map slack-message-buffer-mode-map - :n "q" #'delete-window)) diff --git a/users/aspen/emacs.d/snippets/haskell-mode/annotation b/users/aspen/emacs.d/snippets/haskell-mode/annotation deleted file mode 100644 index 8a2854d75..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/annotation +++ /dev/null @@ -1,5 +0,0 @@ -# key: ann -# name: annotation -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# ANN ${1:module} ("${2:HLint: ignore ${3:Reduce duplication}}" :: String) #-} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/benchmark-module b/users/aspen/emacs.d/snippets/haskell-mode/benchmark-module deleted file mode 100644 index cbb1646e4..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/benchmark-module +++ /dev/null @@ -1,26 +0,0 @@ -# key: bench -# name: benchmark-module -# expand-env: ((yas-indent-line (quote fixed))) -# -- --------------------------------------------------------------------------------- -module ${1:`(if (not buffer-file-name) "Module" - (let ((name (file-name-sans-extension (buffer-file-name))) - (case-fold-search nil)) - (if (cl-search "bench/" name) - (replace-regexp-in-string "/" "." - (replace-regexp-in-string "^\/[^A-Z]*" "" - (car (last (split-string name "src"))))) - (file-name-nondirectory name))))`} ( benchmark, main ) where --------------------------------------------------------------------------------- -import Bench.Prelude --------------------------------------------------------------------------------- -import ${1:$(s-chop-suffix "Bench" yas-text)} --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain [benchmark] - --------------------------------------------------------------------------------- - -benchmark :: Benchmark -benchmark = bgroup "${1:$(->> yas-text (s-chop-suffix "Bench") (s-split ".") -last-item)}" [bench "something dumb" $ nf (1 +) (1 :: Int)] diff --git a/users/aspen/emacs.d/snippets/haskell-mode/header b/users/aspen/emacs.d/snippets/haskell-mode/header deleted file mode 100644 index fdd8250d8..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/header +++ /dev/null @@ -1,5 +0,0 @@ -# key: hh -# name: header -# expand-env: ((yas-indent-line 'fixed)) -# -- ---------------------------------------------------------------------------------$2 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/hedgehog-generator b/users/aspen/emacs.d/snippets/haskell-mode/hedgehog-generator deleted file mode 100644 index 68863f705..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/hedgehog-generator +++ /dev/null @@ -1,8 +0,0 @@ -# key: gen -# name: Hedgehog Generator -# expand-env: ((yas-indent-line (quote fixed))) -# -- -gen${1:Foo} :: Gen $1 -gen$1 = do - $2 - pure $1{..} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/hedgehog-property b/users/aspen/emacs.d/snippets/haskell-mode/hedgehog-property deleted file mode 100644 index bf39a2a3e..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/hedgehog-property +++ /dev/null @@ -1,9 +0,0 @@ -# -*- mode: snippet -*- -# name: Hedgehog Property -# key: hprop -# expand-env: ((yas-indent-line 'fixed)) -# -- -hprop_${1:somethingIsAlwaysTrue} :: Property -hprop_$1 = property $ do - ${2:x} <- forAll ${3:Gen.int $ Range.linear 1 100} - ${4:x === x} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/hlint b/users/aspen/emacs.d/snippets/haskell-mode/hlint deleted file mode 100644 index f25a9b8d4..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/hlint +++ /dev/null @@ -1,8 +0,0 @@ -# -*- mode: snippet -*- -# name: hlint -# uuid: hlint -# expand-env: ((yas-indent-line 'fixed)) -# key: hlint -# condition: t -# -- -{-# ANN module ("Hlint: ignore $1" :: String) #- } \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/import-i b/users/aspen/emacs.d/snippets/haskell-mode/import-i deleted file mode 100644 index 4a7fca2c2..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/import-i +++ /dev/null @@ -1,4 +0,0 @@ -# key: i -# name: import-i -# -- -import ${1:Prelude} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/inl b/users/aspen/emacs.d/snippets/haskell-mode/inl deleted file mode 100644 index 6e17b83d7..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/inl +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: inl -# key: inl -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# INLINE $1 #-} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/inline b/users/aspen/emacs.d/snippets/haskell-mode/inline deleted file mode 100644 index 1beafbe50..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/inline +++ /dev/null @@ -1,5 +0,0 @@ -# key: inline -# name: inline -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# INLINE $1 #-} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/language pragma b/users/aspen/emacs.d/snippets/haskell-mode/language pragma deleted file mode 100644 index 6f84720f4..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/language pragma +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: language pragma -# key: lang -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# LANGUAGE $1 #-} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/lens.field b/users/aspen/emacs.d/snippets/haskell-mode/lens.field deleted file mode 100644 index b22ea3d2e..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/lens.field +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: lens.field -# key: lens -# expand-env: ((yas-indent-line 'fixed)) -# -- -${1:field} :: Lens' ${2:Source} ${3:Target} -$1 = lens _${4:sourceField} $ \\${2:$(-> yas-text s-word-initials s-downcase)} ${4:$(-> yas-text s-word-initials s-downcase)} -> ${2:$(-> yas-text s-word-initials s-downcase)} { _$4 = ${4:$(-> yas-text s-word-initials s-downcase)} } \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/module b/users/aspen/emacs.d/snippets/haskell-mode/module deleted file mode 100644 index 4554d33f9..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/module +++ /dev/null @@ -1,32 +0,0 @@ -# -*- mode: snippet -*- -# key: module -# name: module -# condition: (= (length "module") (current-column)) -# expand-env: ((yas-indent-line 'fixed)) -# contributor: Luke Hoersten -# -- --------------------------------------------------------------------------------- --- | --- Module : $1 --- Description : $2 --- Maintainer : Griffin Smith --- Maturity : ${3:Draft, Usable, Maintained, OR MatureAF} --- --- $4 --------------------------------------------------------------------------------- -module ${1:`(if (not buffer-file-name) "Module" - (let ((name (file-name-sans-extension (buffer-file-name))) - (case-fold-search nil)) - (if (or (cl-search "src/" name) - (cl-search "test/" name)) - (replace-regexp-in-string "/" "." - (replace-regexp-in-string "^\/[^A-Z]*" "" - (car (last (split-string name "src"))))) - (file-name-nondirectory name))))`} - ( - ) where --------------------------------------------------------------------------------- -import Prelude --------------------------------------------------------------------------------- - -$0 diff --git a/users/aspen/emacs.d/snippets/haskell-mode/shut up, hlint b/users/aspen/emacs.d/snippets/haskell-mode/shut up, hlint deleted file mode 100644 index fccff1d66..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/shut up, hlint +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: shut up, hlint -# key: dupl -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/test-group b/users/aspen/emacs.d/snippets/haskell-mode/test-group deleted file mode 100644 index bf6a66f8a..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/test-group +++ /dev/null @@ -1,9 +0,0 @@ -# -*- mode: snippet -*- -# name: test-group -# uuid: test-group -# key: testGroup -# condition: t -# -- -testGroup "${1:name}" -[ $0 -] \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/test-module b/users/aspen/emacs.d/snippets/haskell-mode/test-module deleted file mode 100644 index 036b0ae99..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/test-module +++ /dev/null @@ -1,27 +0,0 @@ -# -*- mode: snippet -*- -# name: test-module -# key: test -# expand-env: ((yas-indent-line 'fixed)) -# -- --------------------------------------------------------------------------------- -module ${1:`(if (not buffer-file-name) "Module" - (let ((name (file-name-sans-extension (buffer-file-name))) - (case-fold-search nil)) - (if (cl-search "test/" name) - (replace-regexp-in-string "/" "." - (replace-regexp-in-string "^\/[^A-Z]*" "" - (car (last (split-string name "src"))))) - (file-name-nondirectory name))))`} (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import ${1:$(s-chop-suffix "Spec" yas-text)} --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "$1" - [ $0 - ] \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/haskell-mode/undefined b/users/aspen/emacs.d/snippets/haskell-mode/undefined deleted file mode 100644 index 7bcd99b57..000000000 --- a/users/aspen/emacs.d/snippets/haskell-mode/undefined +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: undefined -# key: u -# expand-env: ((yas-indent-line 'fixed) (yas-wrap-around-region 'nil)) -# -- -undefined$1 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/action-type b/users/aspen/emacs.d/snippets/js2-mode/action-type deleted file mode 100644 index ef8d1a386..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/action-type +++ /dev/null @@ -1,4 +0,0 @@ -# key: at -# name: action-type -# -- -export const ${1:FOO_BAR$(->> yas-text s-upcase (s-replace-all '(("-" . "_") (" " . "_"))))}: '${3:ns}/${1:$(-> yas-text s-dashed-words)}' = '$3/${1:$(-> yas-text s-dashed-words)}'$5 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/before b/users/aspen/emacs.d/snippets/js2-mode/before deleted file mode 100644 index 4569b6583..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/before +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: before -# key: bef -# -- -before(function() { - $1 -}) diff --git a/users/aspen/emacs.d/snippets/js2-mode/context b/users/aspen/emacs.d/snippets/js2-mode/context deleted file mode 100644 index d83809f3c..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/context +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: context -# key: context -# -- -context('$1', function() { - $2 -}) diff --git a/users/aspen/emacs.d/snippets/js2-mode/describe b/users/aspen/emacs.d/snippets/js2-mode/describe deleted file mode 100644 index bd0198181..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/describe +++ /dev/null @@ -1,6 +0,0 @@ -# key: desc -# name: describe -# -- -describe('$1', () => { - $2 -}) \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/expect b/users/aspen/emacs.d/snippets/js2-mode/expect deleted file mode 100644 index eba41ef33..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/expect +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: expect -# key: ex -# -- -expect($1).$2 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/function b/users/aspen/emacs.d/snippets/js2-mode/function deleted file mode 100644 index b423044b4..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/function +++ /dev/null @@ -1,6 +0,0 @@ -# key: f -# name: function -# -- -function $1($2) { - $3 -} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/header b/users/aspen/emacs.d/snippets/js2-mode/header deleted file mode 100644 index 3e303764c..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/header +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: header -# key: hh -# expand-env: ((yas-indent-line 'fixed)) -# -- -//////////////////////////////////////////////////////////////////////////////// diff --git a/users/aspen/emacs.d/snippets/js2-mode/it b/users/aspen/emacs.d/snippets/js2-mode/it deleted file mode 100644 index a451cfc08..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/it +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: it -# key: it -# -- -it('$1', () => { - $2 -}) \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/it-pending b/users/aspen/emacs.d/snippets/js2-mode/it-pending deleted file mode 100644 index 00da312e1..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/it-pending +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: it-pending -# key: xi -# -- -it('$1')$0 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/module b/users/aspen/emacs.d/snippets/js2-mode/module deleted file mode 100644 index dc79819d8..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/module +++ /dev/null @@ -1,12 +0,0 @@ -# key: module -# name: module -# expand-env: ((yas-indent-line (quote fixed))) -# condition: (= (length "module") (current-column)) -# -- -/** - * @fileOverview $1 - * @name ${2:`(file-name-nondirectory (buffer-file-name))`} - * @author Griffin Smith - * @license Proprietary - */ -$3 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/record b/users/aspen/emacs.d/snippets/js2-mode/record deleted file mode 100644 index 0bb0f0243..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/record +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: record -# key: rec -# -- -export default class $1 extends Record({ - $2 -}) {} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/js2-mode/test b/users/aspen/emacs.d/snippets/js2-mode/test deleted file mode 100644 index 938d490a7..000000000 --- a/users/aspen/emacs.d/snippets/js2-mode/test +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: test -# key: test -# -- -test('$1', () => { - $2 -}) \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/nix-mode/fetchFromGitHub b/users/aspen/emacs.d/snippets/nix-mode/fetchFromGitHub deleted file mode 100644 index d2447e4b5..000000000 --- a/users/aspen/emacs.d/snippets/nix-mode/fetchFromGitHub +++ /dev/null @@ -1,12 +0,0 @@ -# -*- mode: snippet -*- -# name: fetchFromGitHub -# uuid: fetchFromGitHub -# key: fetchFromGitHub -# condition: t -# -- -fetchFromGitHub { - owner = "$1"; - repo = "$2"; - rev = "$3"; - sha256 = "0000000000000000000000000000000000000000000000000000"; -} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/nix-mode/pythonPackage b/users/aspen/emacs.d/snippets/nix-mode/pythonPackage deleted file mode 100644 index 0a74c21e1..000000000 --- a/users/aspen/emacs.d/snippets/nix-mode/pythonPackage +++ /dev/null @@ -1,16 +0,0 @@ -# key: pypkg -# name: pythonPackage -# condition: t -# -- -${1:pname} = buildPythonPackage rec { - name = "\${pname}-\${version}"; - pname = "$1"; - version = "${2:1.0.0}"; - src = fetchPypi { - inherit pname version; - sha256 = "0000000000000000000000000000000000000000000000000000"; - }; - propagatedBuildInputs = with pythonSelf; [ - $3 - ]; -}; \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/nix-mode/sha256 b/users/aspen/emacs.d/snippets/nix-mode/sha256 deleted file mode 100644 index bc640e5ab..000000000 --- a/users/aspen/emacs.d/snippets/nix-mode/sha256 +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: sha256 -# uuid: sha256 -# key: sha256 -# condition: t -# -- -sha256 = "0000000000000000000000000000000000000000000000000000"; \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/org-mode/SQL source block b/users/aspen/emacs.d/snippets/org-mode/SQL source block deleted file mode 100644 index b5d43fd6b..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/SQL source block +++ /dev/null @@ -1,6 +0,0 @@ -# key: sql -# name: SQL source block -# -- -#+BEGIN_SRC sql ${1::async} -$2 -#+END_SRC diff --git a/users/aspen/emacs.d/snippets/org-mode/combat b/users/aspen/emacs.d/snippets/org-mode/combat deleted file mode 100644 index b4db0f433..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/combat +++ /dev/null @@ -1,13 +0,0 @@ -# -*- mode: snippet -*- -# name: combat -# uuid: combat -# key: combat -# condition: t -# -- -| | initiative | max hp | current hp | status | | -|-------------+------------+--------+------------+--------+------| -| Barty Barty | | | | | <--- | -| Hectoroth | | | | | | -| Xanadu | | | | | | -| Aurora | | | | | | -| EFB | | | | | | \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/org-mode/date b/users/aspen/emacs.d/snippets/org-mode/date deleted file mode 100644 index 297529cda..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/date +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# key: date -# name: date.org -# -- -[`(format-time-string "%Y-%m-%d")`]$0 diff --git a/users/aspen/emacs.d/snippets/org-mode/date-time b/users/aspen/emacs.d/snippets/org-mode/date-time deleted file mode 100644 index fde469276..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/date-time +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: date-time -# key: dt -# -- -[`(format-time-string "%Y-%m-%d %H:%m:%S")`] \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/org-mode/description b/users/aspen/emacs.d/snippets/org-mode/description deleted file mode 100644 index a43bc95cc..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/description +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: description -# key: desc -# -- -:DESCRIPTION: -$1 -:END: diff --git a/users/aspen/emacs.d/snippets/org-mode/nologdone b/users/aspen/emacs.d/snippets/org-mode/nologdone deleted file mode 100644 index e5be85d6b..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/nologdone +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: nologdone -# key: nologdone -# -- -#+STARTUP: nologdone$0 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/org-mode/python source block b/users/aspen/emacs.d/snippets/org-mode/python source block deleted file mode 100644 index 247ae51b0..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/python source block +++ /dev/null @@ -1,6 +0,0 @@ -# key: py -# name: Python source block -# -- -#+BEGIN_SRC python -$0 -#+END_SRC \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/org-mode/reveal b/users/aspen/emacs.d/snippets/org-mode/reveal deleted file mode 100644 index 1bdbdfa5d..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/reveal +++ /dev/null @@ -1,6 +0,0 @@ -# key: reveal -# name: reveal -# condition: t -# -- -#+ATTR_REVEAL: :frag ${1:roll-in} -$0 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/org-mode/transaction b/users/aspen/emacs.d/snippets/org-mode/transaction deleted file mode 100644 index 37f2dd31c..000000000 --- a/users/aspen/emacs.d/snippets/org-mode/transaction +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: transaction -# key: begin -# -- -BEGIN; -$0 -ROLLBACK; \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/prolog-mode/use-module b/users/aspen/emacs.d/snippets/prolog-mode/use-module deleted file mode 100644 index 75fd19b64..000000000 --- a/users/aspen/emacs.d/snippets/prolog-mode/use-module +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: use-module -# uuid: use-module -# key: use -# condition: t -# -- -:- use_module(${1:library($2)}${3:, [$4]}). \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/python-mode/add_column b/users/aspen/emacs.d/snippets/python-mode/add_column deleted file mode 100644 index 47e83850d..000000000 --- a/users/aspen/emacs.d/snippets/python-mode/add_column +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: add_column -# key: op.add_column -# -- -op.add_column('${1:table}', sa.Column('${2:name}', sa.${3:String()}))$0 diff --git a/users/aspen/emacs.d/snippets/python-mode/decorate b/users/aspen/emacs.d/snippets/python-mode/decorate deleted file mode 100644 index 4f9674857..000000000 --- a/users/aspen/emacs.d/snippets/python-mode/decorate +++ /dev/null @@ -1,15 +0,0 @@ -# -*- mode: snippet -*- -# name: decorate -# uuid: decorate -# key: decorate -# condition: t -# -- -def wrap(inner): - @wraps(inner) - def wrapped(*args, **kwargs): - ret = inner(*args, **kwargs) - return ret - - return wrapped - -return wrap \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/python-mode/dunder b/users/aspen/emacs.d/snippets/python-mode/dunder deleted file mode 100644 index 71d99dddc..000000000 --- a/users/aspen/emacs.d/snippets/python-mode/dunder +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: dunder -# uuid: dunder -# key: du -# condition: t -# -- -__$1__$0 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/python-mode/name b/users/aspen/emacs.d/snippets/python-mode/name deleted file mode 100644 index 1495cc91d..000000000 --- a/users/aspen/emacs.d/snippets/python-mode/name +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: name -# uuid: name -# key: name -# condition: t -# -- -__name__ \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/python-mode/op.get_bind.execute b/users/aspen/emacs.d/snippets/python-mode/op.get_bind.execute deleted file mode 100644 index aba801c6b..000000000 --- a/users/aspen/emacs.d/snippets/python-mode/op.get_bind.execute +++ /dev/null @@ -1,7 +0,0 @@ -# key: exec -# name: op.get_bind.execute -# -- -op.get_bind().execute( - """ - `(progn (sqlup-mode) "")`$1 - """) diff --git a/users/aspen/emacs.d/snippets/python-mode/pdb b/users/aspen/emacs.d/snippets/python-mode/pdb deleted file mode 100644 index 41c6f87cb..000000000 --- a/users/aspen/emacs.d/snippets/python-mode/pdb +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: pdb -# uuid: pdb -# key: pdb -# condition: t -# -- -import pdb; pdb.set_trace() \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/rust-mode/#[macro_use] b/users/aspen/emacs.d/snippets/rust-mode/#[macro_use] deleted file mode 100644 index fea942a33..000000000 --- a/users/aspen/emacs.d/snippets/rust-mode/#[macro_use] +++ /dev/null @@ -1,5 +0,0 @@ -# key: macro_use -# name: #[macro_use] -# -- -#[macro_use] -${1:extern crate} ${2:something};$0 diff --git a/users/aspen/emacs.d/snippets/rust-mode/async test b/users/aspen/emacs.d/snippets/rust-mode/async test deleted file mode 100644 index 2352d7b56..000000000 --- a/users/aspen/emacs.d/snippets/rust-mode/async test +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: snippet -*- -# name: async test -# uuid: atest -# key: atest -# condition: t -# -- -#[tokio::test${1:(flavor = "multi_thread")}] -async fn ${2:test_name}() { - `%`$0 -} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/rust-mode/benchmark b/users/aspen/emacs.d/snippets/rust-mode/benchmark deleted file mode 100644 index 9ec430753..000000000 --- a/users/aspen/emacs.d/snippets/rust-mode/benchmark +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: snippet -*- -# name: benchmark -# uuid: benchmark -# key: bench -# condition: t -# -- -#[bench] -fn ${1:benchmark_name}(b: &mut Bencher) { - `%`b.iter(|| $0); -} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/rust-mode/proptest b/users/aspen/emacs.d/snippets/rust-mode/proptest deleted file mode 100644 index be12af491..000000000 --- a/users/aspen/emacs.d/snippets/rust-mode/proptest +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: snippet -*- -# name: proptest -# uuid: proptest -# key: proptest -# condition: t -# -- -#[proptest] -fn ${1:test_name}($2) { - `%`$0 -} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/rust-mode/test-module b/users/aspen/emacs.d/snippets/rust-mode/test-module deleted file mode 100644 index bfa2ca2d1..000000000 --- a/users/aspen/emacs.d/snippets/rust-mode/test-module +++ /dev/null @@ -1,11 +0,0 @@ -# -*- mode: snippet -*- -# name: test-module -# uuid: test-module -# key: tmod -# condition: t -# -- -mod $1 { - use super::*; - - $0 -} \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/rust-mode/tests b/users/aspen/emacs.d/snippets/rust-mode/tests deleted file mode 100644 index 0a476ab58..000000000 --- a/users/aspen/emacs.d/snippets/rust-mode/tests +++ /dev/null @@ -1,9 +0,0 @@ -# key: tests -# name: test module -# -- -#[cfg(test)] -mod ${1:tests} { - use super::*; - - $0 -} diff --git a/users/aspen/emacs.d/snippets/snippet-mode/indent b/users/aspen/emacs.d/snippets/snippet-mode/indent deleted file mode 100644 index d38ffceaf..000000000 --- a/users/aspen/emacs.d/snippets/snippet-mode/indent +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: indent -# key: indent -# -- -# expand-env: ((yas-indent-line 'fixed)) \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/sql-mode/count(*) group by b/users/aspen/emacs.d/snippets/sql-mode/count(*) group by deleted file mode 100644 index 6acc46ff3..000000000 --- a/users/aspen/emacs.d/snippets/sql-mode/count(*) group by +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: count(*) group by -# key: countby -# -- -SELECT count(*), ${1:column} FROM ${2:table} GROUP BY $1; diff --git a/users/aspen/emacs.d/snippets/terraform-mode/variable b/users/aspen/emacs.d/snippets/terraform-mode/variable deleted file mode 100644 index 14822f1a0..000000000 --- a/users/aspen/emacs.d/snippets/terraform-mode/variable +++ /dev/null @@ -1,11 +0,0 @@ -# -*- mode: snippet -*- -# name: variable -# uuid: variable -# key: var -# condition: t -# -- -variable "${1:name}" { - type = ${2:string} - ${3:default = ${4:default}} -} -$0 \ No newline at end of file diff --git a/users/aspen/emacs.d/snippets/text-mode/date b/users/aspen/emacs.d/snippets/text-mode/date deleted file mode 100644 index 7b9431147..000000000 --- a/users/aspen/emacs.d/snippets/text-mode/date +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -# name: date -# key: date -# -- -`(format-time-string "%Y-%m-%d")`$0 \ No newline at end of file diff --git a/users/aspen/emacs.d/splitjoin.el b/users/aspen/emacs.d/splitjoin.el deleted file mode 100644 index dbc9704d7..000000000 --- a/users/aspen/emacs.d/splitjoin.el +++ /dev/null @@ -1,192 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(require 'dash) -(load! "utils") - -;;; -;;; Vars -;;; - -(defvar +splitjoin/split-callbacks '() - "Alist mapping major mode symbol names to lists of split callbacks") - -(defvar +splitjoin/join-callbacks '() - "Alist mapping major mode symbol names to lists of join callbacks") - - - -;;; -;;; Definition macros -;;; - -(defmacro +splitjoin/defsplit (mode name &rest body) - `(setf - (alist-get ',name (alist-get ,mode +splitjoin/split-callbacks)) - (λ! () ,@body))) - -(defmacro +splitjoin/defjoin (mode name &rest body) - `(setf - (alist-get ',name (alist-get ,mode +splitjoin/join-callbacks)) - (λ! () ,@body))) - -;;; -;;; Commands -;;; - -(defun +splitjoin/split () - (interactive) - (when-let (callbacks (->> +splitjoin/split-callbacks - (alist-get major-mode) - (-map #'cdr))) - (find-if #'funcall callbacks))) - -(defun +splitjoin/join () - (interactive) - (when-let (callbacks (->> +splitjoin/join-callbacks - (alist-get major-mode) - (-map #'cdr))) - (find-if #'funcall callbacks))) - - -;;; -;;; Splits and joins -;;; TODO: this should probably go in a file-per-language -;;; - -(+splitjoin/defjoin - 'elixir-mode - join-do - (let* ((function-pattern (rx (and (zero-or-more whitespace) - "do" - (zero-or-more whitespace) - (optional (and "#" (zero-or-more anything))) - eol))) - (end-pattern (rx bol - (zero-or-more whitespace) - "end" - (zero-or-more whitespace) - eol)) - (else-pattern (rx bol - (zero-or-more whitespace) - "else" - (zero-or-more whitespace) - eol)) - (lineno (line-number-at-pos)) - (line (thing-at-point 'line t))) - (when-let ((do-start-pos (string-match function-pattern line))) - (cond - ((string-match-p end-pattern (get-line (inc lineno))) - (modify-then-indent - (goto-line-char do-start-pos) - (insert ",") - (goto-char (line-end-position)) - (insert ": nil") - (line-move 1) - (delete-line)) - t) - - ((string-match-p end-pattern (get-line (+ 2 lineno))) - (modify-then-indent - (goto-line-char do-start-pos) - (insert ",") - (goto-char (line-end-position)) - (insert ":") - (join-line t) - (line-move 1) - (delete-line)) - t) - - ((and (string-match-p else-pattern (get-line (+ 2 lineno))) - (string-match-p end-pattern (get-line (+ 4 lineno)))) - (modify-then-indent - (goto-line-char do-start-pos) - (insert ",") - (goto-char (line-end-position)) - (insert ":") - (join-line t) - (goto-eol) - (insert ",") - (join-line t) - (goto-eol) - (insert ":") - (join-line t) - (line-move 1) - (delete-line)) - t))))) - -(comment - (string-match (rx (and bol - "if " - (one-or-more anything) - "," - (zero-or-more whitespace) - "do:" - (one-or-more anything) - "," - (zero-or-more whitespace) - "else:" - (one-or-more anything))) - "if 1, do: nil, else: nil") - - ) - -(+splitjoin/defsplit - 'elixir-mode - split-do-with-optional-else - (let* ((if-with-else-pattern (rx (and bol - (one-or-more anything) - "," - (zero-or-more whitespace) - "do:" - (one-or-more anything) - (optional - "," - (zero-or-more whitespace) - "else:" - (one-or-more anything))))) - (current-line (get-line))) - (when (string-match if-with-else-pattern current-line) - (modify-then-indent - (assert (goto-regex-on-line ",[[:space:]]*do:")) - (delete-char 1) - (assert (goto-regex-on-line ":")) - (delete-char 1) - (insert "\n") - (when (goto-regex-on-line-r ",[[:space:]]*else:") - (delete-char 1) - (insert "\n") - (assert (goto-regex-on-line ":")) - (delete-char 1) - (insert "\n")) - (goto-eol) - (insert "\nend")) - t))) - -(comment - (+splitjoin/defsplit 'elixir-mode split-def - (let ((function-pattern (rx (and "," - (zero-or-more whitespace) - "do:"))) - (line (thing-at-point 'line t))) - (when-let (idx (string-match function-pattern line)) - (let ((beg (line-beginning-position)) - (orig-line-char (- (point) (line-beginning-position)))) - (save-mark-and-excursion - (goto-line-char idx) - (delete-char 1) - (goto-line-char (string-match ":" (thing-at-point 'line t))) - (delete-char 1) - (insert "\n") - (goto-eol) - (insert "\n") - (insert "end") - (evil-indent beg (+ (line-end-position) 1)))) - (goto-line-char orig-line-char) - t)))) - -(+splitjoin/defjoin - 'elixir-mode - join-if-with-else - (let* ((current-line (thing-at-point 'line))))) - -(provide 'splitjoin) diff --git a/users/aspen/emacs.d/sql-strings.el b/users/aspen/emacs.d/sql-strings.el deleted file mode 100644 index eef397a24..000000000 --- a/users/aspen/emacs.d/sql-strings.el +++ /dev/null @@ -1,75 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -;;; https://www.emacswiki.org/emacs/StringAtPoint -(defun ourcomments-string-or-comment-bounds-1 (what) - (save-restriction - (widen) - (let* ((here (point)) - ;; Fix-me: when on end-point, how to handle that and which should be last hit point? - (state (parse-partial-sexp (point-min) (1+ here))) - (type (if (nth 3 state) - 'string - (if (nth 4 state) - 'comment))) - (start (when type (nth 8 state))) - end) - (unless start - (setq state (parse-partial-sexp (point-min) here)) - (setq type (if (nth 3 state) - 'string - (if (nth 4 state) - 'comment))) - (setq start (when type (nth 8 state)))) - (unless (or (not what) - (eq what type)) - (setq start nil)) - (if (not start) - (progn - (goto-char here) - nil) - (setq state (parse-partial-sexp (1+ start) (point-max) - nil nil state 'syntax-table)) - (setq end (point)) - (goto-char here) - (cons start end))))) - -(defun ourcomments-bounds-of-string-at-point () - "Return bounds of string at point if any." - (ourcomments-string-or-comment-bounds-1 'string)) - -(put 'string 'bounds-of-thing-at-point 'ourcomments-bounds-of-string-at-point) - -(defun -sanitize-sql-string (str) - (->> str - (downcase) - (s-trim) - (replace-regexp-in-string - (rx (or (and string-start (or "\"\"\"" - "\"")) - (and (or "\"\"\"" - "\"") - string-end))) - "") - (s-trim))) - -(defun sql-string-p (str) - "Returns 't if STR looks like a string literal for a SQL statement" - (setq str (-sanitize-sql-string str)) - (or (s-starts-with? "select" str))) - -;;; tests - -(require 'ert) - -(ert-deftest sanitize-sql-string-test () - (should (string-equal "select * from foo;" - (-sanitize-sql-string - "\"\"\"SELECT * FROM foo;\n\n\"\"\"")))) - -(ert-deftest test-sql-string-p () - (dolist (str '("SELECT * FROM foo;" - "select * from foo;")) - (should (sql-string-p str))) - - (dolist (str '("not a QUERY")) - (should-not (sql-string-p str)))) diff --git a/users/aspen/emacs.d/terraform.el b/users/aspen/emacs.d/terraform.el deleted file mode 100644 index 2d69c9bad..000000000 --- a/users/aspen/emacs.d/terraform.el +++ /dev/null @@ -1,31 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(add-hook 'terraform-mode-hook #'terraform-format-on-save-mode) - -(defun packer-format-buffer () - (interactive) - (let ((buf (get-buffer-create "*packer-fmt*"))) - (if (zerop (call-process-region (point-min) (point-max) - "packer" nil buf nil "fmt" "-")) - (let ((point (point)) - (window-start (window-start))) - (erase-buffer) - (insert-buffer-substring buf) - (goto-char point) - (set-window-start nil window-start)) - (message "packer fmt failed: %s" (with-current-buffer buf (buffer-string)))) - (kill-buffer buf))) - -(define-minor-mode packer-format-on-save-mode - "Run packer-format-buffer before saving the current buffer" - :lighter nil - (if packer-format-on-save-mode - (add-hook 'before-save-hook #'packer-format-buffer nil t) - (remove-hook 'before-save-hook #'packer-format-buffer t))) - -(defun maybe-init-packer () - (interactive) - (when (s-ends-with-p ".pkr" (file-name-base (buffer-file-name))) - (packer-format-on-save-mode))) - -(add-hook 'hcl-mode-hook #'maybe-init-packer) diff --git a/users/aspen/emacs.d/tests/splitjoin_test.el b/users/aspen/emacs.d/tests/splitjoin_test.el deleted file mode 100644 index 6495a1a59..000000000 --- a/users/aspen/emacs.d/tests/splitjoin_test.el +++ /dev/null @@ -1,68 +0,0 @@ -;;; private/grfn/tests/splitjoin_test.el -*- lexical-binding: t; -*- - -(require 'ert) -;; (load! 'splitjoin) -;; (load! 'utils) -; (require 'splitjoin) - -;;; Helpers - -(defvar *test-buffer* nil) -(make-variable-buffer-local '*test-buffer*) - -(defun test-buffer () - (when (not *test-buffer*) - (setq *test-buffer* (get-buffer-create "test-buffer"))) - *test-buffer*) - -(defmacro with-test-buffer (&rest body) - `(with-current-buffer (test-buffer) - ,@body)) - -(defun set-test-buffer-mode (mode) - (let ((mode (if (functionp mode) mode - (-> mode symbol-name (concat "-mode") intern)))) - (assert (functionp mode)) - (with-test-buffer (funcall mode)))) - -(defmacro set-test-buffer-contents (contents) - (with-test-buffer - (erase-buffer) - (insert contents))) - -(defun test-buffer-contents () - (with-test-buffer (substring-no-properties (buffer-string)))) - -(defmacro assert-test-buffer-contents (expected-contents) - `(should (equal (string-trim (test-buffer-contents)) - (string-trim ,expected-contents)))) - -(defmacro should-join-to (mode original-contents expected-contents) - `(progn - (set-test-buffer-mode ,mode) - (set-test-buffer-contents ,original-contents) - (with-test-buffer (+splitjoin/join)) - (assert-test-buffer-contents ,expected-contents))) - -(defmacro should-split-to (mode original-contents expected-contents) - `(progn - (set-test-buffer-mode ,mode) - (set-test-buffer-contents ,original-contents) - (with-test-buffer (+splitjoin/split)) - (assert-test-buffer-contents ,expected-contents))) - -(defmacro should-splitjoin (mode joined-contents split-contents) - `(progn - (should-split-to ,mode ,joined-contents ,split-contents) - (should-join-to ,mode ,split-contents ,joined-contents))) - -;;; Tests - -;; Elixir -(ert-deftest elixir-if-splitjoin-test () - (should-splitjoin 'elixir - "if predicate?(), do: result" - "if predicate?() do - result -end")) - diff --git a/users/aspen/emacs.d/themes/grfn-solarized-light-theme.el b/users/aspen/emacs.d/themes/grfn-solarized-light-theme.el deleted file mode 100644 index ae00b6b5f..000000000 --- a/users/aspen/emacs.d/themes/grfn-solarized-light-theme.el +++ /dev/null @@ -1,115 +0,0 @@ -(require 'solarized) -(eval-when-compile - (require 'solarized-palettes)) - -;; (defun grfn-solarized-theme () -;; (custom-theme-set-faces -;; theme-name -;; `(font-lock-doc-face ((,class (:foreground ,s-base1)))) -;; `(font-lock-preprocessor-face ((,class (:foreground ,red)))) -;; `(font-lock-keyword-face ((,class (:foreground ,green)))) - -;; `(elixir-attribute-face ((,class (:foreground ,blue)))) -;; `(elixir-atom-face ((,class (:foreground ,cyan)))))) - -(setq +solarized-s-base03 "#002b36" - +solarized-s-base02 "#073642" - ;; emphasized content - +solarized-s-base01 "#586e75" - ;; primary content - +solarized-s-base00 "#657b83" - +solarized-s-base0 "#839496" - ;; comments - +solarized-s-base1 "#93a1a1" - ;; background highlight light - +solarized-s-base2 "#eee8d5" - ;; background light - +solarized-s-base3 "#fdf6e3" - - ;; Solarized accented colors - +solarized-yellow "#b58900" - +solarized-orange "#cb4b16" - +solarized-red "#dc322f" - +solarized-magenta "#d33682" - +solarized-violet "#6c71c4" - +solarized-blue "#268bd2" - +solarized-cyan "#2aa198" - +solarized-green "#859900" - - ;; Darker and lighter accented colors - ;; Only use these in exceptional circumstances! - +solarized-yellow-d "#7B6000" - +solarized-yellow-l "#DEB542" - +solarized-orange-d "#8B2C02" - +solarized-orange-l "#F2804F" - +solarized-red-d "#990A1B" - +solarized-red-l "#FF6E64" - +solarized-magenta-d "#93115C" - +solarized-magenta-l "#F771AC" - +solarized-violet-d "#3F4D91" - +solarized-violet-l "#9EA0E5" - +solarized-blue-d "#00629D" - +solarized-blue-l "#69B7F0" - +solarized-cyan-d "#00736F" - +solarized-cyan-l "#69CABF" - +solarized-green-d "#546E00" - +solarized-green-l "#B4C342") - - -(deftheme grfn-solarized-light "The light variant of Griffin's solarized theme") - -(setq grfn-solarized-faces - '("Griffin's solarized theme customization" - (custom-theme-set-faces - theme-name - `(font-lock-doc-face ((t (:foreground ,+solarized-s-base1)))) - `(font-lock-preprocessor-face ((t (:foreground ,+solarized-red)))) - `(font-lock-keyword-face ((t (:foreground ,+solarized-green)))) - - `(elixir-attribute-face ((t (:foreground ,+solarized-blue)))) - `(elixir-atom-face ((t (:foreground ,+solarized-cyan)))) - `(agda2-highlight-keyword-face ((t (:foreground ,green)))) - `(agda2-highlight-string-face ((t (:foreground ,cyan)))) - `(agda2-highlight-number-face ((t (:foreground ,violet)))) - `(agda2-highlight-symbol-face ((((background ,base3)) (:foreground ,base01)))) - `(agda2-highlight-primitive-type-face ((t (:foreground ,blue)))) - `(agda2-highlight-bound-variable-face ((t nil))) - `(agda2-highlight-inductive-constructor-face ((t (:foreground ,green)))) - `(agda2-highlight-coinductive-constructor-face ((t (:foreground ,yellow)))) - `(agda2-highlight-datatype-face ((t (:foreground ,blue)))) - `(agda2-highlight-field-face ((t (:foreground ,red)))) - `(agda2-highlight-function-face ((t (:foreground ,blue)))) - `(agda2-highlight-module-face ((t (:foreground ,yellow)))) - `(agda2-highlight-postulate-face ((t (:foreground ,blue)))) - `(agda2-highlight-primitive-face ((t (:foreground ,blue)))) - `(agda2-highlight-record-face ((t (:foreground ,blue)))) - `(agda2-highlight-dotted-face ((t nil))) - `(agda2-highlight-operator-face ((t nil))) - `(agda2-highlight-error-face ((t (:foreground ,red :underline t)))) - `(agda2-highlight-unsolved-meta-face ((t (:background ,base2)))) - `(agda2-highlight-unsolved-constraint-face ((t (:background ,base2)))) - `(agda2-highlight-termination-problem-face ((t (:background ,orange :foreground ,base03)))) - `(agda2-highlight-incomplete-pattern-face ((t (:background ,orange :foreground ,base03)))) - `(agda2-highlight-typechecks-face ((t (:background ,cyan :foreground ,base03)))) - - `(font-lock-doc-face ((t (:foreground ,+solarized-s-base1)))) - `(font-lock-preprocessor-face ((t (:foreground ,+solarized-red)))) - `(font-lock-keyword-face ((t (:foreground ,+solarized-green :bold nil)))) - `(font-lock-builtin-face ((t (:foreground ,+solarized-s-base01 - :bold t)))) - - `(elixir-attribute-face ((t (:foreground ,+solarized-blue)))) - `(elixir-atom-face ((t (:foreground ,+solarized-cyan)))) - `(linum ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1)))) - `(line-number ((t (:background ,+solarized-s-base2 :foreground ,+solarized-s-base1)))) - - `(haskell-operator-face ((t (:foreground ,+solarized-green)))) - `(haskell-keyword-face ((t (:foreground ,+solarized-cyan)))) - - `(org-drawer ((t (:foreground ,+solarized-s-base1 - :bold t))))))) - -(solarized-with-color-variables - 'light 'grfn-solarized-light solarized-light-color-palette-alist) - -(provide-theme 'grfn-solarized-light) diff --git a/users/aspen/emacs.d/utils.el b/users/aspen/emacs.d/utils.el deleted file mode 100644 index 21192753a..000000000 --- a/users/aspen/emacs.d/utils.el +++ /dev/null @@ -1,114 +0,0 @@ -;;; -*- lexical-binding: t; -*- - - -;; Elisp Extras - -(defmacro comment (&rest _body) - "Comment out one or more s-expressions" - nil) - -(defun inc (x) "Returns x + 1" (+ 1 x)) -(defun dec (x) "Returns x - 1" (- x 1)) - -(defun average (ns) - "Arithmetic mean of xs" - (if (null ns) nil - (/ (apply #'+ ns) - (length ns)))) - -(comment - (average (list 1 2 3 4)) - ) - -;; -;; Text editing utils -;; - -;; Reading strings - -(defun get-char (&optional point) - "Get the character at the given `point' (defaulting to the current point), -without properties" - (let ((point (or point (point)))) - (buffer-substring-no-properties point (+ 1 point)))) - -(defun get-line (&optional lineno) - "Read the line number `lineno', or the current line if `lineno' is nil, and -return it as a string stripped of all text properties" - (let ((current-line (line-number-at-pos))) - (if (or (not lineno) - (= current-line lineno)) - (thing-at-point 'line t) - (save-mark-and-excursion - (line-move (- lineno (line-number-at-pos))) - (thing-at-point 'line t))))) - -(defun get-line-point () - "Get the position in the current line of the point" - (- (point) (line-beginning-position))) - -;; Moving in the file - -(defun goto-line-char (pt) - "Moves the point to the given position expressed as an offset from the start -of the line" - (goto-char (+ (line-beginning-position) pt))) - -(defun goto-eol () - "Moves to the end of the current line" - (goto-char (line-end-position))) - -(defun goto-regex-on-line (regex) - "Moves the point to the first occurrence of `regex' on the current line. -Returns nil if the regex did not match, non-nil otherwise" - (when-let ((current-line (get-line)) - (line-char (string-match regex current-line))) - (goto-line-char line-char))) - -(defun goto-regex-on-line-r (regex) - "Moves the point to the *last* occurrence of `regex' on the current line. -Returns nil if the regex did not match, non-nil otherwise" - (when-let ((current-line (get-line)) - (modified-regex (concat ".*\\(" regex "\\)")) - (_ (string-match modified-regex current-line)) - (match-start (match-beginning 1))) - (goto-line-char match-start))) - -(comment - (progn - (string-match (rx (and (zero-or-more anything) - (group "foo" "foo"))) - "foofoofoo") - (match-beginning 1))) - -;; Changing file contents - -(defun delete-line () - "Remove the line at the current point" - (delete-region (line-beginning-position) - (inc (line-end-position)))) - -(defmacro modify-then-indent (&rest body) - "Modify text in the buffer according to body, then re-indent from where the - cursor started to where the cursor ended up, then return the cursor to where - it started." - `(let ((beg (line-beginning-position)) - (orig-line-char (- (point) (line-beginning-position)))) - (atomic-change-group - (save-mark-and-excursion - ,@body - (evil-indent beg (+ (line-end-position) 1)))) - (goto-line-char orig-line-char))) - -(pcase-defmacro s-starts-with (prefix) - `(pred (s-starts-with-p ,prefix))) - -(pcase-defmacro s-contains (needle &optional ignore-case) - `(pred (s-contains-p ,needle - ,@(when ignore-case (list ignore-case))))) - -(comment - (pcase "foo" - ((s-contains "bar") 1) - ((s-contains "o") 2)) - ) diff --git a/users/aspen/emacs.d/vterm.el b/users/aspen/emacs.d/vterm.el deleted file mode 100644 index a7fdea46d..000000000 --- a/users/aspen/emacs.d/vterm.el +++ /dev/null @@ -1,24 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -(defun require-vterm () - (add-to-list - 'load-path - (concat - (s-trim - (shell-command-to-string - "nix-build --no-out-link ~/code/depot -A third_party.emacs.vterm")) - "/share/emacs/site-lisp/elpa/vterm-20200515.1412")) - (require 'vterm)) - -(defun +grfn/vterm-setup () - (hide-mode-line-mode) - (setq-local evil-collection-vterm-send-escape-to-vterm-p t)) - -(add-hook 'vterm-mode-hook #'+grfn/vterm-setup) - -(map! (:map vterm-mode-map - "" #'evil-normal-state)) - -(comment - (require-vterm) - ) diff --git a/users/aspen/emacs/.gitignore b/users/aspen/emacs/.gitignore deleted file mode 100644 index f5236c123..000000000 --- a/users/aspen/emacs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -custom.el -config.el diff --git a/users/aspen/emacs/config.org b/users/aspen/emacs/config.org deleted file mode 100644 index 11ea92bc0..000000000 --- a/users/aspen/emacs/config.org +++ /dev/null @@ -1,1667 +0,0 @@ -# Local variables: -# lexical-binding: t -# eval: (paxedit-mode 1) -# eval: (display-line-numbers-mode 1) -# eval: (flyspell-mode -1) -# eval: (org-config-mode 1) -# End: - -#+title: Emacs Config - -#+begin_src emacs-lisp -;; -*- lexical-binding: t; -*- -#+end_src - -* Utils -#+begin_src emacs-lisp -(use-package! dash) -#+end_src - -** Elisp extras - -#+begin_src emacs-lisp -(defmacro comment (&rest _body) - "Comment out one or more s-expressions" - nil) - -(defun inc (x) "Returns x + 1" (+ 1 x)) -(defun dec (x) "Returns x - 1" (- x 1)) - -(defun average (ns) - "Arithmetic mean of xs" - (if (null ns) nil - (/ (apply #'+ ns) - (length ns)))) - -(defun alist-set (alist-symbol key value) - "Set VALUE of a KEY in ALIST-SYMBOL." - (set alist-symbol (cons (list key value) (assq-delete-all key (eval alist-symbol))))) - -(defun rx-words (&rest words) - (rx-to-string - `(and symbol-start (group (or ,@words)) symbol-end))) -#+end_src - -#+RESULTS: -: rx-words - -#+begin_src elisp :tangle no :results example -(average (list 1 2 3 4)) -#+end_src - -#+RESULTS: -: 2 - -** Text editing utils -*** Reading strings -#+begin_src emacs-lisp -(defun get-char (&optional point) - "Get the character at the given `point' (defaulting to the current point), -without properties" - (let ((point (or point (point)))) - (buffer-substring-no-properties point (+ 1 point)))) - -(defun get-line (&optional lineno) - "Read the line number `lineno', or the current line if `lineno' is nil, and -return it as a string stripped of all text properties" - (let ((current-line (line-number-at-pos))) - (if (or (not lineno) - (= current-line lineno)) - (thing-at-point 'line t) - (save-mark-and-excursion - (line-move (- lineno (line-number-at-pos))) - (thing-at-point 'line t))))) - -(defun get-line-point () - "Get the position in the current line of the point" - (- (point) (line-beginning-position))) - -;; Moving in the file - -(defun goto-line-char (pt) - "Moves the point to the given position expressed as an offset from the start -of the line" - (goto-char (+ (line-beginning-position) pt))) - -(defun goto-eol () - "Moves to the end of the current line" - (goto-char (line-end-position))) - -(defun goto-regex-on-line (regex) - "Moves the point to the first occurrence of `regex' on the current line. -Returns nil if the regex did not match, non-nil otherwise" - (when-let ((current-line (get-line)) - (line-char (string-match regex current-line))) - (goto-line-char line-char))) - -(defun goto-regex-on-line-r (regex) - "Moves the point to the *last* occurrence of `regex' on the current line. -Returns nil if the regex did not match, non-nil otherwise" - (when-let ((current-line (get-line)) - (modified-regex (concat ".*\\(" regex "\\)")) - (_ (string-match modified-regex current-line)) - (match-start (match-beginning 1))) - (goto-line-char match-start))) -#+end_src - -#+begin_src elisp :tangle no -(progn - (string-match (rx (and (zero-or-more anything) - (group "foo" "foo"))) - "foofoofoo") - (match-beginning 1)) -#+end_src - -#+RESULTS: -: 3 -*** Changing file contents -#+begin_src emacs-lisp -(defmacro saving-excursion (&rest body) - `(λ! () (save-excursion ,@body))) - -(defun delete-line () - "Remove the line at the current point" - (delete-region (line-beginning-position) - (inc (line-end-position)))) - -(defmacro modify-then-indent (&rest body) - "Modify text in the buffer according to body, then re-indent from where the - cursor started to where the cursor ended up, then return the cursor to where - it started." - `(let ((beg (line-beginning-position)) - (orig-line-char (- (point) (line-beginning-position)))) - (atomic-change-group - (save-mark-and-excursion - ,@body - (evil-indent beg (+ (line-end-position) 1)))) - (goto-line-char orig-line-char))) - -(pcase-defmacro s-starts-with (prefix) - `(pred (s-starts-with-p ,prefix))) - -(pcase-defmacro s-contains (needle &optional ignore-case) - `(pred (s-contains-p ,needle - ,@(when ignore-case (list ignore-case))))) -#+end_src - -#+RESULTS: -: s-contains--pcase-macroexpander - -#+begin_src elisp :tangle no -(pcase "foo" - ((s-contains "bar") 1) - ((s-contains "o") 2)) -#+end_src - -#+RESULTS: -: 2 - -** Evil utils -#+begin_src emacs-lisp -(defmacro define-move-and-insert - (name &rest body) - `(defun ,name (count &optional vcount skip-empty-lines) - ;; Following interactive form taken from the source for `evil-insert' - (interactive - (list (prefix-numeric-value current-prefix-arg) - (and (evil-visual-state-p) - (memq (evil-visual-type) '(line block)) - (save-excursion - (let ((m (mark))) - ;; go to upper-left corner temporarily so - ;; `count-lines' yields accurate results - (evil-visual-rotate 'upper-left) - (prog1 (count-lines evil-visual-beginning evil-visual-end) - (set-mark m))))) - (evil-visual-state-p))) - (atomic-change-group - ,@body - (evil-insert count vcount skip-empty-lines)))) -#+end_src - -#+RESULTS: -: define-move-and-insert - -* Name and email -#+begin_src emacs-lisp -(setq user-full-name "Aspen Smith" - user-mail-address "root@gws.fyi") -#+end_src - -#+RESULTS: -: root@gws.fyi - -* Visual style -#+begin_src emacs-lisp -(let ((font-family (pcase system-type - ('darwin "MesloLGSDZ NF") - ('gnu/linux "Meslo LGSDZ Nerd Font")))) - (setq doom-font (font-spec :family font-family :height 140) - doom-big-font (font-spec :family font-family :size 24) - doom-big-font-increment 5 - doom-variable-pitch-font (font-spec :family font-family) - doom-theme 'doom-solarized-light)) - -(setq display-line-numbers-type t) - -(setq doom-modeline-buffer-file-name-style 'relative-to-project - doom-modeline-modal-icon nil - doom-modeline-github t - doom-modeline-height 12) -#+end_src - -#+RESULTS: -: 12 - -#+begin_src emacs-lisp -(setq whitespace-style '(face lines-tail)) -(global-whitespace-mode t) -(add-hook 'org-mode-hook (lambda () (whitespace-mode -1)) t) -#+end_src - -#+RESULTS: -| er/add-org-mode-expansions | (closure ((hook . org-mode-hook)) (&rest _) (progn (let ((tail '(after-change-major-mode-hook))) (while tail (let ((hook (car tail))) (let ((tail (list #'(lambda (&rest _) (if (derived-mode-p 'org-mode) (progn (setq tab-width 8))))))) (while tail (let ((func (car tail))) (add-hook hook func nil t) (setq tail (cdr tail))))) (setq tail (cdr tail)))))) (add-hook 'save-place-after-find-file-hook #'+org-make-last-point-visible-h nil t)) | +lookup--init-org-mode-handlers-h | (closure (t) (&rest _) (add-hook 'before-save-hook 'org-encrypt-entries nil t)) | #[0 \300\301\302\303\304$\207 [add-hook change-major-mode-hook org-fold-show-all append local] 5] | #[0 \301\211\207 [imenu-create-index-function org-imenu-get-tree] 2] | doom-disable-show-paren-mode-h | doom-disable-show-trailing-whitespace-h | org-appear-mode | org-fancy-priorities-mode | org-superstar-mode | evil-org-mode | org-eldoc-load | toc-org-enable | #[0 \300\301\302\303\304$\207 [add-hook change-major-mode-hook org-babel-show-result-all append local] 5] | org-babel-result-hide-spec | org-babel-hide-all-hashes | flyspell-mode | embrace-org-mode-hook | +corfu-add-cape-elisp-block-h | +literate-enable-recompile-h | (lambda nil (whitespace-mode -1)) | - -** Theme -[[https://davidjohnstone.net/lch-lab-colour-gradient-picker][LAB colour gradient picker]] is a good tool for trying to find "halfway points" between two colours - -*** Variables -#+begin_src elisp :tangle no -(rainbow-mode) -#+end_src - -#+RESULTS: -: t - -#+name: solarized-vars -#+begin_src emacs-lisp -(setq +solarized-s-base03 "#002b36" - +solarized-s-base02 "#073642" - ;; emphasized content - +solarized-s-base01 "#586e75" - ;; primary content - +solarized-s-base00 "#657b83" - +solarized-s-base0 "#839496" - ;; comments - +solarized-s-base1 "#93a1a1" - ;; background highlight light - +solarized-s-base2 "#eee8d5" - ;; background light - +solarized-s-base3 "#fdf6e3" - - +solarized-halfway-highlight "#f5efdc" - - ;; Solarized accented colors - +solarized-yellow "#b58900" - +solarized-orange "#cb4b16" - +solarized-red "#dc322f" - +solarized-magenta "#d33682" - +solarized-violet "#6c71c4" - +solarized-blue "#268bd2" - +solarized-cyan "#2aa198" - +solarized-green "#859900" - - ;; Darker and lighter accented colors - ;; Only use these in exceptional circumstances! - +solarized-yellow-d "#7B6000" - +solarized-yellow-l "#DEB542" - +solarized-orange-d "#8B2C02" - +solarized-orange-l "#F2804F" - +solarized-red-d "#990A1B" - +solarized-red-l "#FF6E64" - +solarized-magenta-d "#93115C" - +solarized-magenta-l "#F771AC" - +solarized-violet-d "#3F4D91" - +solarized-violet-l "#9EA0E5" - +solarized-blue-d "#00629D" - +solarized-blue-l "#69B7F0" - +solarized-cyan-d "#00736F" - +solarized-cyan-l "#69CABF" - +solarized-green-d "#546E00" - +solarized-green-l "#B4C342") -#+end_src - -#+RESULTS: solarized-vars -: #B4C342 - -*** Overrides - -#+name: overrides-for-solarized-light -#+begin_src emacs-lisp -(custom-set-faces! - `(cursor :background ,+solarized-s-base00) - `(font-lock-doc-face :foreground ,+solarized-s-base1) - `(font-lock-preprocessor-face :foreground ,+solarized-red :bold nil) - `(font-lock-keyword-face :foreground ,+solarized-green :bold nil) - `(font-lock-builtin-face :foreground ,+solarized-s-base01 :bold t) - `(font-lock-function-name-face :foreground ,+solarized-blue) - `(font-lock-constant-face :foreground ,+solarized-blue) - `(font-lock-type-face :italic nil) - `(highlight-numbers-number :bold nil) - `(highlight :background ,+solarized-s-base2) - `(solaire-hl-line-face :background ,+solarized-halfway-highlight) - `(hl-line :background ,+solarized-s-base2) - - `(linum :background ,+solarized-s-base2 :foreground ,+solarized-s-base1) - `(line-number :background ,+solarized-s-base2 :foreground ,+solarized-s-base1) - `(line-number-current-line :background ,+solarized-s-base2 :foreground ,+solarized-s-base1) - `(fringe :background ,+solarized-s-base2) - - `(whitespace-line :foreground ,+solarized-red :underline t) - - `(haskell-operator-face :foreground ,+solarized-green) - `(haskell-keyword-face :foreground ,+solarized-cyan) - - `(magit-branch-local :foreground ,+solarized-blue :bold t) - `(magit-branch-remote :foreground ,+solarized-green :bold t) - `(magit-branch-remote-head :foreground ,+solarized-green :bold t :box t) - `(magit-branch-current :box t :bold t) - `(magit-header-line :background nil :foreground ,+solarized-yellow :bold t :box nil) - `(diff-refine-added :foreground "#dbdb9c" :background "#5b6e35" :bold nil) - `(magit-diff-added-highlight :foreground "#657827" :background "#efeac7" :bold nil) - `(diff-refine-removed :background "#8e433d" :foreground "#ffb9a1" :bold nil) - `(magit-diff-removed-highlight :foreground "#a33c35" :background "#ffdec8" :bold nil) - `(magit-diff-hunk-heading :background "#f8e8c6" :foreground "#876d26" :bold nil) - `(magit-diff-hunk-heading-highlight :background "#f1d49b" :foreground "#766634" :bold nil) - `(magit-section-heading :foreground "#b58900") - `(magit-filename :foreground ,+solarized-s-base00) - `(magit-diff-context-highlight :background ,+solarized-halfway-highlight) - - `(transient-delimiter :foreground ,+solarized-s-base1) - `(transient-inapt-suffix :foreground ,+solarized-s-base1) - `(transient-inactive-value :foreground ,+solarized-s-base1) - `(transient-inactive-argument :foreground ,+solarized-s-base1) - `(transient-key-exit :foreground ,+solarized-green :bold t) - `(transient-key-stay :foreground ,+solarized-blue :bold t) - ) - #+end_src - -#+RESULTS: overrides-for-solarized-light -| doom--customize-themes-h-91 | doom--customize-themes-h-92 | doom--customize-themes-h-93 | doom--customize-themes-h-94 | doom--customize-themes-h-95 | doom--customize-themes-h-96 | doom--customize-themes-h-97 | doom--customize-themes-h-98 | - -* Keybindings and navigation -Get the hell out of here, snipe! -#+begin_src emacs-lisp -(remove-hook 'doom-first-input-hook #'evil-snipe-mode) -#+end_src - -#+begin_src emacs-lisp -(map! - (:leader - "b" #'consult-buffer - "r" #'consult-recent-file)) -#+end_src - -#+begin_src elisp :tangle yes -(setopt evil-collection-setup-minibuffer t) -#+end_src - -** Flycheck -#+begin_src emacs-lisp -(evil-set-command-property 'flycheck-next-error :repeat nil) -(evil-set-command-property 'flycheck-prev-error :repeat nil) -(evil-set-command-property 'flycheck-previous-error :repeat nil) - -(map! - (:map flycheck-mode-map - :m "]q" #'flycheck-next-error - :m "[q" #'flycheck-previous-error)) -#+end_src - -#+RESULTS: - -** Smerge -#+begin_src emacs-lisp -(evil-set-command-property 'smerge-next :repeat nil) -(evil-set-command-property 'smerge-prev :repeat nil) - -(map! - :n "] n" #'smerge-next - :n "[ n" #'smerge-prev - (:leader - (:desc "smerge" :prefix "g m" - :desc "Keep Current" :n "SPC" #'smerge-keep-current - :desc "Keep All" :n "a" #'smerge-keep-all - :desc "Keep Upper" :n "u" #'smerge-keep-upper - :desc "Keep Lower" :n "l" #'smerge-keep-lower))) -t - #+end_src - -#+RESULTS: -: t - -** Vinegar-style dired -#+begin_src emacs-lisp -(defun dired-mode-p () (eq 'dired-mode major-mode)) - -(defun aspen/dired-minus () - (interactive) - (if (dired-mode-p) - (dired-up-directory) - (when buffer-file-name - (-> (buffer-file-name) - (f-dirname) - (dired))))) - -(map! - :n "-" #'aspen/dired-minus - (:map dired-mode-map - "-" #'aspen/dired-minus)) -#+end_src - -#+RESULTS: - -** Lisp mappings -*** Use paxedit -#+begin_src emacs-lisp -(use-package! paxedit - :hook ((emacs-lisp-mode . paxedit-mode) - (clojure-mode . paxedit-mode) - (common-lisp-mode . paxedit-mode))) -#+end_src - -#+RESULTS: -| paxedit-mode | - -*** Paxedit functions - -#+begin_src emacs-lisp -(define-move-and-insert aspen/insert-at-sexp-end - (when (not (equal (get-char) "(")) - (backward-up-list)) - (forward-sexp) - (backward-char)) - -(define-move-and-insert aspen/insert-at-sexp-start - (backward-up-list) - (forward-char)) - -(define-move-and-insert aspen/insert-at-form-start - (backward-sexp) - (backward-char) - (insert " ")) - -(define-move-and-insert aspen/insert-at-form-end - (forward-sexp) - (insert " ")) - -(defun aspen/paxedit-kill (&optional n) - (interactive "p") - (or (paxedit-comment-kill) - (when (paxedit-symbol-cursor-within?) - (paxedit-symbol-kill)) - (paxedit-implicit-sexp-kill n) - (paxedit-sexp-kill n) - (message paxedit-message-kill))) -#+end_src - -#+RESULTS: -: aspen/paxedit-kill - -*** Paxedit mappings -#+begin_src emacs-lisp -(map! - (:after paxedit - (:map paxedit-mode-map - :i ";" #'paxedit-insert-semicolon - :i "(" #'paxedit-open-round - :i "[" #'paxedit-open-bracket - :i "{" #'paxedit-open-curly - :n [remap evil-yank-line] #'paxedit-copy - :n [remap evil-delete-line] #'aspen/paxedit-kill - :n "g o" #'paxedit-sexp-raise - :n [remap evil-join-whitespace] #'paxedit-compress - :n "g S" #'paxedit-format-1 - :n "g k" #'paxedit-backward-up - :n "g j" #'paxedit-backward-end))) - -(require 'general) -(general-evil-setup t) - -(nmap - ">" (general-key-dispatch 'evil-shift-right - "e" 'paxedit-transpose-forward - ")" 'sp-forward-slurp-sexp - "(" 'sp-backward-barf-sexp - "I" 'aspen/insert-at-sexp-end - ;; "a" 'grfn/insert-at-form-end - )) - -(nmap - "<" (general-key-dispatch 'evil-shift-left - "e" 'paxedit-transpose-backward - ")" 'sp-forward-barf-sexp - "(" 'sp-backward-slurp-sexp - "I" 'aspen/insert-at-sexp-start - ;; "a" 'grfn/insert-at-form-start - )) -#+end_src - -#+RESULTS: - -*** Eval functions -#+begin_src emacs-lisp -(use-package! predd) - -(predd-defmulti eval-sexp (lambda (form) major-mode)) - -(predd-defmethod eval-sexp 'clojure-mode (form) - (cider-interactive-eval form)) - -(predd-defmethod eval-sexp 'emacs-lisp-mode (form) - (pp-eval-expression form)) - -(predd-defmulti eval-sexp-region (lambda (_beg _end) major-mode)) - -(predd-defmethod eval-sexp-region 'clojure-mode (beg end) - (cider-interactive-eval nil nil (list beg end))) - -(predd-defmethod eval-sexp-region 'emacs-lisp-mode (beg end) - (pp-eval-expression (read (buffer-substring beg end)))) - -(predd-defmulti eval-sexp-region-context (lambda (_beg _end _context) major-mode)) - -(predd-defmethod eval-sexp-region-context 'clojure-mode (beg end context) - (cider--eval-in-context (buffer-substring beg end))) - -(defun pp-eval-context-region (beg end context) - (interactive "r\nxContext: ") - (let* ((inner-expr (read (buffer-substring beg end))) - (full-expr (list 'let* context inner-expr))) - (pp-eval-expression full-expr))) - -(predd-defmethod eval-sexp-region-context 'emacs-lisp-mode (beg end context) - (pp-eval-context-region beg end context)) - -(predd-defmulti preceding-sexp (lambda () major-mode)) - -(predd-defmethod preceding-sexp 'clojure-mode () - (cider-last-sexp)) - -(predd-defmethod preceding-sexp 'emacs-lisp-mode () - (elisp--preceding-sexp)) - -(defun eval-sexp-at-point () - (interactive) - (let ((bounds (bounds-of-thing-at-point 'sexp))) - (eval-sexp-region (car bounds) - (cdr bounds)))) - -(defun eval-last-sexp (_) - (interactive) - (eval-sexp (preceding-sexp))) - -;;; - -(defun cider-insert-current-sexp-in-repl (&optional arg) - "Insert the expression at point in the REPL buffer. -If invoked with a prefix ARG eval the expression after inserting it" - (interactive "P") - (cider-insert-in-repl (cider-sexp-at-point) arg)) - -(evil-define-operator fireplace-send (beg end) - (cider-insert-current-sexp-in-repl nil nil (list beg end))) - -(defun +clojure-pprint-expr (form) - (format "(with-out-str (clojure.pprint/pprint %s))" - form)) - -(defun cider-eval-read-and-print-handler (&optional buffer) - "Make a handler for evaluating and reading then printing result in BUFFER." - (nrepl-make-response-handler - (or buffer (current-buffer)) - (lambda (buffer value) - (let ((value* (read value))) - (with-current-buffer buffer - (insert - (if (derived-mode-p 'cider-clojure-interaction-mode) - (format "\n%s\n" value*) - value*))))) - (lambda (_buffer out) (cider-emit-interactive-eval-output out)) - (lambda (_buffer err) (cider-emit-interactive-eval-err-output err)) - '())) - -(defun cider-eval-and-replace (beg end) - "Evaluate the expression in region and replace it with its result" - (interactive "r") - (let ((form (buffer-substring beg end))) - (cider-nrepl-sync-request:eval form) - (kill-region beg end) - (cider-interactive-eval - (+clojure-pprint-expr form) - (cider-eval-read-and-print-handler)))) - -(defun cider-eval-current-sexp-and-replace () - "Evaluate the expression at point and replace it with its result" - (interactive) - (apply #'cider-eval-and-replace (cider-sexp-at-point 'bounds))) - -;;; -#+end_src - -#+RESULTS: -: fireplace-eval-context -*** Eval bindings -fireplace-esque eval binding - -#+begin_src emacs-lisp -(evil-define-operator fireplace-eval (beg end) - (eval-sexp-region beg end)) - -(evil-define-operator fireplace-replace (beg end) - - (cider-eval-and-replace beg end)) - -(evil-define-operator fireplace-eval-context (beg end) - (eval-sexp-region-context beg end)) - -(nmap :keymaps 'cider-mode-map - "c" (general-key-dispatch 'evil-change - "p" (general-key-dispatch 'fireplace-eval - "p" 'cider-eval-sexp-at-point - "c" 'cider-eval-last-sexp - "d" 'cider-eval-defun-at-point - "r" 'cider-test-run-test) - "q" (general-key-dispatch 'fireplace-send - "q" 'cider-insert-current-sexp-in-repl - "c" 'cider-insert-last-sexp-in-repl) - "x" (general-key-dispatch 'fireplace-eval-context - "x" 'cider-eval-sexp-at-point-in-context - "c" 'cider-eval-last-sexp-in-context) - "!" (general-key-dispatch 'fireplace-replace - "!" 'cider-eval-current-sexp-and-replace - "c" 'cider-eval-last-sexp-and-replace) - "y" 'cider-copy-last-result)) - -;;; - -(nmap :keymaps 'emacs-lisp-mode-map - "c" (general-key-dispatch 'evil-change - "p" (general-key-dispatch 'fireplace-eval - "p" 'eval-sexp-at-point - "c" 'eval-last-sexp - "d" 'eval-defun - "r" 'cider-test-run-test) - "x" (general-key-dispatch 'fireplace-eval-context - "x" 'cider-eval-sexp-at-point-in-context - "c" 'cider-eval-last-sexp-in-context) - "!" (general-key-dispatch 'fireplace-replace - "!" 'cider-eval-current-sexp-and-replace - "c" 'cider-eval-last-sexp-and-replace) - "y" 'cider-copy-last-result)) - -(nmap :keymaps 'sly-mode-map - "c" (general-key-dispatch 'evil-change - "p" (general-key-dispatch 'sly-eval - ;; "p" 'eval-sexp-at-point - "c" 'sly-eval-last-expression - "d" 'sly-eval-defun - ;; "r" 'cider-test-run-test - ) - ;; "x" (general-key-dispatch 'fireplace-eval-context - ;; "x" 'cider-eval-sexp-at-point-in-context - ;; "c" 'cider-eval-last-sexp-in-context - ;; ) - ;; "!" (general-key-dispatch 'fireplace-replace - ;; "!" 'cider-eval-current-sexp-and-replace - ;; "c" 'cider-eval-last-sexp-and-replace) - ;; "y" 'cider-copy-last-result - )) - -#+end_src - -#+RESULTS: - -** Coerce - -#+begin_src emacs-lisp -(use-package! string-inflection - :config - (nmap "c" (general-key-dispatch 'evil-change - "r c" (saving-excursion (string-inflection-lower-camelcase)) - "r C" (saving-excursion (string-inflection-camelcase)) - "r m" (saving-excursion (string-inflection-camelcase)) - "r s" (saving-excursion (string-inflection-underscore)) - "r u" (saving-excursion (string-inflection-upcase)) - "r -" (saving-excursion (string-inflection-kebab-case)) - "r k" (saving-excursion (string-inflection-kebab-case)) - ;; "r ." (saving-excursion (string-inflection-dot-case)) - ;; "r ." (saving-excursion (string-inflection-space-case)) - ;; "r ." (saving-excursion (string-inflection-title-case)) - ))) -#+end_src - -#+RESULTS: -: t - -* Mode-specific config -** org-mode -#+begin_src emacs-lisp -(after! org - (load! "org-config") - (load! "org-query")) -#+end_src - -#+RESULTS: -: t -*** Theme overrides - -#+begin_src emacs-lisp -(custom-set-faces! - `(org-drawer :foreground ,+solarized-s-base1 :bold t) - `(org-block :foreground ,+solarized-s-base00) - `(org-meta-line :foreground ,+solarized-s-base1 :italic t) - `(org-document-title :foreground ,+solarized-s-base01 :height 1.3) - `(org-done :foreground ,+solarized-green) - `(org-headline-done :foreground ,+solarized-green) - `(org-special-keyword :foreground ,+solarized-s-base1 :bold t) - `(org-date :foreground ,+solarized-blue :underline t) - `(org-table - :foreground ,+solarized-s-base0 ; used to be green, I think I like this better? - :italic t) - `(org-link :foreground ,+solarized-yellow) - `(org-todo :foreground ,+solarized-cyan) - `(org-code :foreground ,+solarized-s-base1) - `(org-block-begin-line :foreground ,+solarized-s-base1 :italic t) - `(org-block-end-line :foreground ,+solarized-s-base1 :italic t) - `(org-document-info-keyword :foreground ,+solarized-s-base1 :italic t) - - `(org-level-1 :foreground ,+solarized-red) - `(org-level-2 :foreground ,+solarized-green) - `(org-level-3 :foreground ,+solarized-blue) - `(org-level-4 :foreground ,+solarized-yellow) - `(org-level-5 :foreground ,+solarized-cyan) - `(org-level-6 :foreground ,+solarized-violet) - `(org-level-7 :foreground ,+solarized-magenta) - `(org-level-8 :foreground ,+solarized-blue)) -#+end_src - -#+RESULTS: -| doom--customize-themes-h-91 | doom--customize-themes-h-92 | doom--customize-themes-h-93 | doom--customize-themes-h-94 | doom--customize-themes-h-95 | doom--customize-themes-h-96 | doom--customize-themes-h-97 | doom--customize-themes-h-98 | doom--customize-themes-h-99 | - -*** Commands -#+begin_src emacs-lisp -(defun grfn/insert-new-src-block () - (interactive) - (let* ((current-src-block (org-element-at-point)) - (src-block-head (save-excursion - (goto-char (org-element-property - :begin current-src-block)) - (let ((line (thing-at-point 'line t))) - (if (not (s-starts-with? "#+NAME:" (s-trim line))) - line - (forward-line) - (thing-at-point 'line t))))) - (point-to-insert - (if-let (results-loc (org-babel-where-is-src-block-result)) - (save-excursion - (goto-char results-loc) - (org-element-property - :end - (org-element-at-point))) - (org-element-property :end (org-element-at-point))))) - (goto-char point-to-insert) - (insert "\n") - (insert src-block-head) - (let ((contents (point-marker))) - (insert "\n#+END_SRC\n") - (goto-char contents)))) - -(defun grfn/+org-insert-item (orig direction) - (interactive) - (if (and (org-in-src-block-p) - (equal direction 'below)) - (grfn/insert-new-src-block) - (funcall orig direction))) - -(advice-add #'+org--insert-item :around #'grfn/+org-insert-item) -#+end_src -*** Bindings -#+begin_src emacs-lisp -(map! - (:after org - :n "C-c C-x C-o" #'org-clock-out - (:leader - "n k" #'org-archive-subtree-default) - - (:map org-capture-mode-map - :n "g RET" #'org-capture-finalize - :n "g \\" #'org-captue-refile) - - (:map org-mode-map - [tab] #'org-cycle))) -#+end_src - -#+RESULTS: - -*** Babel -#+begin_src emacs-lisp -(use-package! ob-python-extras - :config - ;; (ob-python-extras/map-suggested-keybindings) - ) -#+end_src - -#+RESULTS: - -** eglot -#+begin_src emacs-lisp -(defun disable-eglot-inlay-mode-hints () - (eglot-inlay-hints-mode -1)) -(add-hook 'eglot-managed-mode-hook #'disable-eglot-inlay-mode-hints) -#+end_src - -#+RESULTS: -| disable-eglot-inlay-mode-hints | evil-normalize-keymaps | doom-modeline-override-eglot | doom-modeline-update-eglot | flycheck-eglot-mode | +lsp-optimization-mode | - -** magit -#+begin_src emacs-lisp -(after! magit - (map! :map magit-mode-map - ;; :n "] ]" #'magit-section-forward - ;; :n "[ [" #'magit-section-backward - ) - - (transient-define-suffix magit-commit-wip () - (interactive) - (magit-commit-create '("-m" "wip"))) - - (transient-append-suffix - #'magit-commit - ["c"] - (list "W" "Commit WIP" #'magit-commit-wip)) - - (transient-define-suffix magit-reset-head-back () - (interactive) - (magit-reset-mixed "HEAD~")) - - (transient-define-suffix magit-reset-head-previous () - (interactive) - (magit-reset-mixed "HEAD@{1}")) - - (transient-append-suffix - #'magit-reset - ["f"] - (list "b" "Reset HEAD~" #'magit-reset-head-back)) - (transient-append-suffix - #'magit-reset - ["f"] - (list "o" "Reset HEAD@{1}" #'magit-reset-head-previous))) -#+end_src - -#+RESULTS: - -** elisp -*** Org config mode -The minor-mode for *this file*! - -#+begin_src emacs-lisp -(after! smartparens - (sp-local-pair 'org-config-mode "'" "'" :actions nil) - (sp-local-pair 'org-config-mode "`" "`" :actions nil)) - -(define-minor-mode org-config-mode - "Minor-mode for tangled org .el config" - :group 'org - :lighter "Org-config" - :keymap '() - (sp-update-local-pairs 'org-config-mode)) -#+end_src - -#+RESULTS: -| keymap | - -*** Bindings -#+begin_src emacs-lisp -(map! - (:map emacs-lisp-mode-map - :n "g SPC" #'eval-buffer - :n "g RET" (λ! () (ert t)) )) -#+end_src - -#+RESULTS: - -** tuareg -*** Config - -#+begin_src emacs-lisp -(defun set-ocaml-error-regexp () - (set - 'compilation-error-regexp-alist - (list '("[Ff]ile \\(\"\\(.*?\\)\", line \\(-?[0-9]+\\)\\(, characters \\(-?[0-9]+\\)-\\([0-9]+\\)\\)?\\)\\(:\n\\(\\(Warning .*?\\)\\|\\(Error\\)\\):\\)?" - 2 3 (5 . 6) (9 . 11) 1 (8 compilation-message-face))))) - -(defun aspen/tuareg-setup () - (setq-local sp-max-pair-length (->> '("begin" "sig" "struct") - (--map (length it)) - (-max)) - whitespace-line-column 80)) - -(add-hook 'tuareg-mode-hook #'aspen/tuareg-setup) - -(defun sp-tuareg-post-handler (id action context) - (when (equal action 'insert) - (save-excursion - (insert "x") - (newline) - (indent-according-to-mode)) - (delete-char 1))) - -(after! smartparens-ml - (sp-local-pair 'tuareg-mode "module" "end" :actions nil) - - (dolist (pair-start '("begin" "sig" "struct")) - (sp-local-pair 'tuareg-mode - pair-start "end" - :when '(("SPC" "RET" "")) - :unless '(sp-in-string-p) - :actions '(insert navigate) - :post-handlers '(sp-tuareg-post-handler)))) - -(require 'opam-user-setup "~/.emacs.d/opam-user-setup.el") - -nil - #+end_src - -#+RESULTS: - -#+begin_src emacs-lisp -(after! dune-mode - (add-hook 'dune-mode-hook 'paxedit-mode)) -#+end_src - -#+RESULTS: - -*** Bindings -#+begin_src emacs-lisp -(defun aspen/run-ocaml-test (&optional arg) - (interactive "P") - (pcase (project-name (project-current)) - ("flambda-backend" - (let* ((default-directory (project-root (project-current))) - (filename (buffer-file-name)) - (filename-in-project (s-chop-prefix default-directory filename)) - (test-name (when (s-prefix? "testsuite/tests/" filename-in-project) - (s-chop-prefix "testsuite/tests/" filename-in-project))) - (compile-command (if test-name (format "make -o runtime-stdlib -o boot-compiler promote-one TEST=%s" test-name) "make")) - (compile-command (if arg - (compilation-read-command compile-command) - compile-command))) - (compile compile-command))))) -#+end_src - -#+RESULTS: -: aspen/run-ocaml-test - -#+begin_src emacs-lisp -(map! - (:map tuareg-mode-map - :n "g RET" #'aspen/run-ocaml-test - :n "g SPC" #'dune-promote - :n "g \\" #'utop - :n "g y" #'merlin-locate-type - "C-c C-f" (λ! () (compile "dune fmt")))) -#+end_src - -#+RESULTS: - -*** Theme overrides -#+begin_src emacs-lisp -(custom-set-faces! - `(tuareg-font-lock-governing-face :foreground ,+solarized-s-base01 :bold t) - `(tuareg-font-lock-label-face :foreground ,+solarized-blue) - `(tuareg-font-lock-constructor-face :foreground ,+solarized-yellow) - `(tuareg-font-lock-operator-face :foreground ,+solarized-red) - `(tuareg-font-lock-attribute-face :foreground ,+solarized-red :bold nil) - `(tuareg-font-lock-extension-node-face :background nil :inherit 'font-lock-preprocessor-face) - `(merlin-eldoc-occurrences-face :background ,+solarized-s-base2) - `(merlin-type-face :background ,+solarized-s-base2) - `(utop-prompt :foreground ,+solarized-blue) - `(utop-frozen :foreground ,+solarized-s-base1 :italic t) - `(vertico-group-title :foreground ,+solarized-s-base1) - `(vertico-group-header :foreground ,+solarized-s-base1)) -#+end_src - -#+RESULTS: -| doom--customize-themes-h-30 | doom--customize-themes-h-31 | doom--customize-themes-h-32 | doom--customize-themes-h-33 | doom--customize-themes-h-34 | doom--customize-themes-h-35 | doom--customize-themes-h-52 | -*** ocamldebug - -#+begin_src emacs-lisp -;; directly inspired by the ocamldebug implementation in ocamldebug.el -(require 'ocamldebug) -(defun ocamldebug-ocaml (cmd) - "Runs ocamldebug on the provided command" - (interactive) - (let* ((ocaml-dir (expand-file-name - (locate-dominating-file (buffer-file-name) ".git"))) - (pgm-path (file-name-concat ocaml-dir cmd)) - (comint-name (concat "ocamldebug-" cmd)) - (buffer-name (concat "*" comint-name "*")) - (ocamldebug-command-name - (file-name-concat ocaml-dir "_build/install/main/bin/ocamldebug"))) - (unless (file-exists-p ocamldebug-command-name) - (error "No debugger found; run `make debug` first.")) - (pop-to-buffer buffer-name) - (unless (comint-check-proc buffer-name) - (setq default-directory ocaml-dir) - (setq ocamldebug-debuggee-args - (read-from-minibuffer (format "Args for ocamlc: ") - ocamldebug-debuggee-args)) - ;; In addition to the directories in .ocamldebug, use 'find' to - ;; see also list directories with -I; this finds any new cmo directories - ;; since the last 'make debug' - (let* ((cmo-top-dir (file-name-concat ocaml-dir "_build/main")) - (find-cmo-cmd (concat "find " - cmo-top-dir - " -name '*.cmo' -type f -printf '%h\n' | sort -u")) - (cmo-dirs (shell-command-to-string find-cmo-cmd))) - (setq cmo-dir-list (split-string cmo-dirs "\n" t))) - (let* ((user-args (split-string-shell-command ocamldebug-debuggee-args)) - (includes (mapcan (lambda (dir) (list "-I" dir)) cmo-dir-list)) - (args (append (list - comint-name - ocamldebug-command-name - nil - "-emacs" - "-cd" default-directory) - includes - (list pgm-path) - user-args))) - (apply #'make-comint args) - (set-process-filter (get-buffer-process (current-buffer)) - #'ocamldebug-filter) - (set-process-sentinel (get-buffer-process (current-buffer)) - #'ocamldebug-sentinel) - (ocamldebug-mode))) - (ocamldebug-set-buffer))) -(defun ocamldebug-ocamlc () - "Runs ocamldebug on the ocamlc built from the source file in the active buffer" - (interactive) - (ocamldebug-ocaml "ocamlc")) -(defun ocamldebug-ocamlopt () - "Runs ocamldebug on the ocamlopt built from the source file in the active buffer" - (interactive) - (ocamldebug-ocaml "ocamlopt")) -#+end_src - -#+RESULTS: -: ocamldebug-ocamlopt - -** clojure - -*** Setup - -#+begin_src emacs-lisp -(defun clojure-thing-at-point-setup () - (interactive) - ;; Used by cider-find-dwim to parse the symbol at point - (setq-local - thing-at-point-file-name-chars - (concat thing-at-point-file-name-chars - ">> value - (s-replace "\"" "") - (s-replace "\\n" "\n"))))) - nil nil nil))) - (('clj 'multi) - (funcall-interactively - #'cider-test-run-ns-tests - nil)))) - -(defun cider-copy-last-result () - (interactive) - (cider-interactive-eval - "*1" - (nrepl-make-response-handler - (current-buffer) - (lambda (_ value) - (kill-new value) - (message "Copied last result (%s) to clipboard" - (if (= (length value) 1) "1 char" - (format "%d chars" (length value))))) - nil nil nil))) - -#+end_src - -#+RESULTS: -: cider-copy-last-result - -*** Bindings - - -#+begin_src emacs-lisp -(map! - (:after - clojure-mode - (:map clojure-mode-map - :n "] f" 'forward-sexp - :n "[ f" 'backward-sexp)) - - (:after - cider-mode - (:map cider-mode-map - :n "g SPC" 'cider-eval-buffer - :n "g \\" 'cider-switch-to-repl-buffer - :n "K" 'cider-doc - :n "g K" 'cider-apropos - :n "g d" 'cider-find-dwim - :n "C-w ]" 'cider-find-dwim-other-window - ;; :n "g RET" 'cider-test-run-ns-tests - :n "g RET" 'grfn/run-clj-or-cljs-test - :n "g r" #'cljr-rename-symbol - - "C-c C-r r" 'cljr-add-require-to-ns - "C-c C-r i" 'cljr-add-import-to-ns - - (:localleader - ;; :desc "Inspect last result" :n "i" 'cider-inspect-last-result - ;; :desc "Search for documentation" :n "h s" 'cider-apropos-doc - :desc "Add require to ns" :n "n r" 'cljr-add-require-to-ns - :desc "Add import to ns" :n "n i" 'cljr-add-import-to-ns)) - (:map cider-repl-mode-map - :n "g \\" 'cider-switch-to-last-clojure-buffer))) - #+end_src - - #+RESULTS: - -** rust -#+begin_src emacs-lisp -(defun aspen/rust-setup () - (interactive) - (+evil-embrace-angle-bracket-modes-hook-h) - (setq-local whitespace-line-column 100 - fill-column 100)) - -(add-hook 'rust-mode-hook #'aspen/rust-setup) -#+end_src - -#+RESULTS: -| doom-modeline-env-setup-rust | aspen/rust-setup | - -enable clippy: - -#+begin_src emacs-lisp -(after! eglot - (add-to-list 'eglot-server-programs - '((rust-ts-mode rust-mode rustic-mode) . - ("rust-analyzer" :initializationOptions (:check (:command "clippy")))))) -nil -#+end_src - -#+RESULTS: - -*** Bindings - -#+begin_src emacs-lisp -(map! - (:map rust-mode-map - :n "g RET" #'lsp-rust-analyzer-run - :n "g R" #'xref-find-references - :n "g Y" #'eglot-find-typeDefinition - (:localleader - "m" #'lsp-rust-analyzer-expand-macro))) -#+end_src - -#+RESULTS: - -*** Theme overrides -#+begin_src emacs-lisp -(custom-set-faces! - `(rust-unsafe :foreground ,+solarized-red)) -#+end_src - -#+RESULTS: -| doom--customize-themes-h-30 | doom--customize-themes-h-31 | doom--customize-themes-h-32 | doom--customize-themes-h-33 | doom--customize-themes-h-54 | - -** common-lisp -*** Commands -#+begin_src emacs-lisp -(defun aspen/sly-panettone () - (interactive) - (sly - (concat - (s-trim - (shell-command-to-string - "nix-build -o sbcl -E 'with import ~/code/depot {}; nix.buildLisp.sbclWith [web.panettone]'")) - "/bin/sbcl"))) - -(defun aspen/setup-lisp () - (interactive) - (rainbow-delimiters-mode) - (paxedit-mode 1) - (flycheck-mode -1)) - -(add-hook 'common-lisp-mode-hook #'aspen/setup-lisp) - -(defun sly-run-tests () - (interactive) - ;; TODO: handle other test frameworks - (let ((orig-window (get-buffer-window))) - (sly-eval '(fiveam:run!)) - (funcall-interactively #'sly-mrepl-sync) - (select-window orig-window))) -#+end_src - -#+RESULTS: -: sly-run-tests - -*** Bindings - -#+begin_src emacs-lisp -(map! - (:map sly-mode-map - :n "g \\" #'sly-mrepl-sync - :n "g d" #'sly-edit-definition - :n "K" #'sly-documentation - :n "g SPC" #'sly-compile-and-load-file - :n "g RET" #'sly-run-tests) - - (:map sly-mrepl-mode-map - "C-k" #'sly-mrepl-previous-prompt - "C-r" #'isearch-backward)) -#+end_src - -#+RESULTS: -** prolog -*** Bindings -#+begin_src emacs-lisp -(map! - (:map prolog-mode-map - :n "g SPC" #'prolog-compile-buffer - :n "g \\" #'run-prolog)) -#+end_src - -#+RESULTS: - -* Completion -** Corfu -#+begin_src emacs-lisp -(setopt +corfu-want-ret-to-confirm nil) - -(use-package! corfu - :demand t - :bind (:map corfu-map - ("TAB" . corfu-next) - ([tab] . corfu-next) - ("S-TAB" . corfu-previous) - ([backtab] . corfu-previous)) - :init (setopt corfu-auto t - corfu-auto-delay 0.1 - corfu-preview-current 'insert - corfu-on-exact-match 'insert - corfu-preselect 'prompt - corfu-cycle t - corfu-auto-prefix 2 - completion-cycle-threshold 1 - corfu-quit-no-match t - corfu-quit-at-boundary t) - :config - (map! :map corfu-map - :i "TAB" #'corfu-next - :i [tab] #'corfu-next - :i "S-TAB" #'corfu-previous - :i [backtab] #'corfu-previous)) -#+end_src - -#+RESULTS: -: t - -** Fuzzy search -#+begin_src emacs-lisp -(use-package! hotfuzz - :after (orderless corfu) - :config - (setopt completion-styles '(hotfuzz basic) - completion-ignore-case t)) -#+end_src - -#+RESULTS: -: t - -* Email -#+begin_src emacs-lisp -(after! notmuch - (setq notmuch-saved-searches - '((:name "inbox" :query "tag:inbox tag:important not tag:trash" :key "i") - (:name "flagged" :query "tag:flagged" :key "f") - (:name "sent" :query "tag:sent" :key "s") - (:name "drafts" :query "tag:draft" :key "d") - - ;; (:name "work" :query "tag:inbox and tag:important and path:work/**" - ;; :key "w") - (:name "personal" :query "tag:inbox and tag:important and path:personal/**" - :key "p") - (:name "depot" :query "to:depot@tvl.su or path:tvl/**" :key "v")) - message-send-mail-function 'message-send-mail-with-sendmail - message-sendmail-f-is-evil 't - message-sendmail-envelope-from 'header - message-sendmail-extra-arguments '("--read-envelope-from"))) - -(defun aspen/notmuch-sync () - (interactive) - (let* ((search-buffer (current-buffer)) - (proc (start-process-shell-command - "notmuch-sync" - "*notmuch-sync*" - "cd ~/mail/personal/ && gmi sync")) - (buf (process-buffer proc))) - - (set-process-sentinel - proc - (lambda (proc msg) - (internal-default-process-sentinel proc msg) - (when (and (string= msg "finished\n")) - (kill-buffer buf) - (with-current-buffer search-buffer - (when (eq major-mode 'notmuch-search-mode) - (notmuch-refresh-this-buffer)))))) - - (with-current-buffer buf - (+popup-buffer-mode)) - (display-buffer buf '(display-buffer-at-bottom . ())))) - -(set-popup-rule! - "^\\*notmuch-sync\\*$" - :select nil - :quit 'other) - -(map! :map notmuch-search-mode-map - :n "g SPC" #'aspen/notmuch-sync) -#+end_src - -#+RESULTS: - -** Bindings -#+begin_src emacs-lisp -(map! - (:leader - :desc "Email" :n "o m" #'notmuch-jump-search - :desc "Search email" "s M" #'consult-notmuch)) -#+end_src - -#+RESULTS: -: notmuch-jump-search - - -** Theme - -#+begin_src emacs-lisp -(custom-set-faces! - `(notmuch-message-summary-face - :background ,+solarized-halfway-highlight)) -#+end_src - -#+RESULTS: -| doom--customize-themes-h-91 | doom--customize-themes-h-92 | doom--customize-themes-h-93 | doom--customize-themes-h-94 | doom--customize-themes-h-95 | doom--customize-themes-h-96 | doom--customize-themes-h-97 | doom--customize-themes-h-98 | doom--customize-themes-h-99 | doom--customize-themes-h-100 | - -* Misc -** Matchit -#+begin_src emacs-lisp -(use-package! evil-matchit) -#+end_src - -** Direnv -#+begin_src emacs-lisp -(use-package! direnv - :config (direnv-mode)) -#+end_src -** IRC -*** Connecting to IRC - -#+begin_src emacs-lisp -(defvar irc-servers - '("hackint" - "libera")) - -(defun irc-connect (server) - (interactive - (list (completing-read "Server: " irc-servers))) - (let ((pw (-> (shell-command-to-string - (format "pass irccloud/%s" server)) - (s-trim) - (s-lines) - (-last-item))) - (gnutls-verify-error nil)) - (erc-tls :server "bnc.irccloud.com" - :port 6697 - :nick "aspen" - :password (concat "bnc@" - (s-trim (shell-command-to-string "hostname")) - ":" - pw)))) - -(defun aspen/switch-to-erc-buffer-or-connect () - (interactive) - (if (functionp 'erc-switch-to-buffer) - (call-interactively #'erc-switch-to-buffer) - (call-interactively #'irc-connect))) -#+end_src - -#+RESULTS: -: aspen/switch-to-erc-buffer-or-connect - -#+begin_src emacs-lisp -(map! :leader "o I" #'irc-connect - :leader "o i" #'aspen/switch-to-erc-buffer-or-connect) -#+end_src - -#+RESULTS: -: aspen/switch-to-erc-buffer-or-connect - -*** IRC alerts -#+begin_src emacs-lisp -(use-package! alert) - -(defgroup erc-alert nil - "Alert me using alert.el for important ERC messages" - :group 'erc) - -(defcustom erc-noise-regexp - "\\(Logging in:\\|Signing off\\|You're now away\\|Welcome back\\)" - "This regexp matches unwanted noise." - :type 'regexp - :group 'erc) - -(setq tvl-enabled? t) - -(defun disable-tvl-notifications () - (interactive) - (setq tvl-enabled? nil)) - -(defun enable-tvl-notifications () - (interactive) - (setq tvl-enabled? t)) - -(defun erc-alert-important-p (info) - (let ((message (plist-get info :message)) - (erc-message (-> info (plist-get :data) (plist-get :message))) - (erc-channel (-> info (plist-get :data) (plist-get :channel)))) - (and erc-message - (not (or (string-match "^\\** *Users on #" message) - (string-match erc-noise-regexp - message))) - (or (and tvl-enabled? - (string-equal erc-channel "#tvl")) - (string-match "grfn" message))))) - -(comment - last-info - erc-noise-regexp - (setq tvl-enabled? nil) - ) - -(defun my-erc-hook (&optional match-type nick message) - "Shows a notification, when user's nick was mentioned. -If the buffer is currently not visible, makes it sticky." - (setq last-message message) - (if (or (null match-type) (not (eq match-type 'fool))) - (let (alert-log-messages) - (alert (or message (buffer-string)) - :severity (if (string-match "grfn" (or message "")) - 'high 'low) - :title (or nick (buffer-name)) - :data `(:message ,(or message (buffer-string)) - :channel ,(or nick (buffer-name))))))) - -(add-hook 'erc-text-matched-hook 'my-erc-hook) -(add-hook 'erc-insert-modify-hook 'my-erc-hook) - -(defun my-erc-define-alerts (&rest ignore) - ;; Unless the user has recently typed in the ERC buffer, highlight the fringe - (alert-add-rule - :status '(buried visible idle) - :severity '(moderate high urgent) - :mode 'erc-mode - :predicate - #'(lambda (info) - (and (not (eq (current-buffer) (plist-get info :buffer))) - (string-match "grfn:" (plist-get info :message)))) - :persistent - #'(lambda (info) - ;; If the buffer is buried, or the user has been idle for - ;; `alert-reveal-idle-time' seconds, make this alert - ;; persistent. Normally, alerts become persistent after - ;; `alert-persist-idle-time' seconds. - (memq (plist-get info :status) '(buried idle))) - :style 'message - :continue t) - - (alert-add-rule - :status 'buried - :mode 'erc-mode - :predicate #'erc-alert-important-p - :style 'libnotify - :append t) - - (alert-add-rule - :status 'buried - :mode 'erc-mode - :predicate #'erc-alert-important-p - :style 'message - :append t) - - (alert-add-rule - :mode 'erc-mode - :predicate #'erc-alert-important-p - :style 'log - :append t) - - (alert-add-rule :mode 'erc-mode :style 'ignore :append t)) - -(add-hook 'erc-connect-pre-hook 'my-erc-define-alerts) -#+end_src - -#+RESULTS: -| my-erc-define-alerts | - -*** Don't send ~:q~, etc, to the server -#+begin_src emacs-lisp -(defun fix-irc-message (msg) - (let ((msg (s-trim msg))) - (if (string-equal msg ":q") "" msg))) -(advice-add #'erc-user-input :filter-return #'fix-irc-message) -#+end_src - -#+RESULTS: - -*** Theme overrides -#+begin_src emacs-lisp -(custom-set-faces! - `(erc-button :foreground ,+solarized-blue)) -#+end_src - -#+RESULTS: -| doom--customize-themes-h-30 | doom--customize-themes-h-31 | doom--customize-themes-h-32 | doom--customize-themes-h-43 | doom--customize-themes-h-47 | doom--customize-themes-h-48 | doom--customize-themes-h-49 | doom--customize-themes-h-50 | doom--customize-themes-h-51 | doom--customize-themes-h-52 | doom--customize-themes-h-53 | doom--customize-themes-h-54 | doom--customize-themes-h-56 | doom--customize-themes-h-57 | doom--customize-themes-h-58 | doom--customize-themes-h-59 | doom--customize-themes-h-60 | doom--customize-themes-h-61 | doom--customize-themes-h-62 | doom--customize-themes-h-63 | doom--customize-themes-h-64 | - -*** TODO Nick rainbow colors -Stole this from https://github.com/jtdaugherty/emacs-config/blob/master/common/erc-nick-colors.el. - -IT doesn't work though :( - -#+begin_src emacs-lisp -(setq nick-face-list '()) - -;; Define the list of colors to use when coloring IRC nicks. -(setq-default erc-colors-list (list +solarized-yellow - +solarized-orange - +solarized-red - +solarized-magenta - +solarized-violet - +solarized-blue - +solarized-cyan - +solarized-green)) - -(defun build-nick-face-list () - "build-nick-face-list builds a list of new faces using the -foreground colors specified in erc-colors-list. The nick faces -created here will be used to format IRC nicks." - (let ((i -1)) - (setq nick-face-list - (mapcar - (lambda (COLOR) - (setq i (1+ i)) - (list (custom-declare-face - (make-symbol (format "erc-nick-face-%d" i)) - (list (list t (list :foreground COLOR))) - (format "Nick face %d" i)))) - erc-colors-list)))) - -(defun erc-insert-nick-colors () - "This insert-modify hook looks for nicks in new messages and -computes md5(nick) and uses substring(md5_value, 0, 4) mod (length -nick-face-list) to index the face list and produce the same face for a -given nick each time it is seen. We get a lot of collisions this way, -unfortunately, but it's better than some other methods I tried. -Additionally, if you change the order or size of the erc-colors-list, -you'll change the colors used for nicks." - (if (null nick-face-list) (build-nick-face-list)) - (save-excursion - (goto-char (point-min)) - (if (looking-at "<\\([^>]*\\)>") - (let ((nick (match-string 1))) - (put-text-property (match-beginning 1) (match-end 1) - 'face (nth - (mod (string-to-number - (substring (md5 nick) 0 4) 16) - (length nick-face-list)) - nick-face-list)))))) - -;; This adds the ERC message insert hook. -(add-hook 'erc-insert-modify-hook 'erc-insert-nick-colors) -#+end_src - -#+RESULTS: -| erc-insert-nick-colors | erc-controls-highlight | erc-fill | my-erc-hook | erc-button-add-buttons | erc-match-message | erc-add-timestamp | - -* Hacks -Not having this breaks elisp documentation :( -#+begin_src emacs-lisp -(defvar elisp-demos-user-files nil) -#+end_src - -#+RESULTS: -: elisp-demos-user-files diff --git a/users/aspen/emacs/init.el b/users/aspen/emacs/init.el deleted file mode 100644 index 7674d088b..000000000 --- a/users/aspen/emacs/init.el +++ /dev/null @@ -1,199 +0,0 @@ -;;; init.el -*- lexical-binding: t; -*- - -;; This file controls what Doom modules are enabled and what order they load -;; in. Remember to run 'doom sync' after modifying it! - -;; NOTE Press 'SPC h d h' (or 'C-h d h' for non-vim users) to access Doom's -;; documentation. There you'll find a link to Doom's Module Index where all -;; of our modules are listed, including what flags they support. - -;; NOTE Move your cursor over a module's name (or its flags) and press 'K' (or -;; 'C-c c k' for non-vim users) to view its documentation. This works on -;; flags as well (those symbols that start with a plus). -;; -;; Alternatively, press 'gd' (or 'C-c c d') on a module to browse its -;; directory (for easy access to its source code). - -(doom! :input - ;;bidi ; (tfel ot) thgir etirw uoy gnipleh - ;;chinese - ;;japanese - ;;layout ; auie,ctsrnm is the superior home row - - :completion - ;; company ; the ultimate code completion backend - corfu - ;;helm ; the *other* search engine for love and life - ;;ido ; the other *other* search engine... - ;;ivy ; a search engine for love and life - vertico ; the search engine of the future - - :ui - ;;deft ; notational velocity for Emacs - doom ; what makes DOOM look the way it does - doom-dashboard ; a nifty splash screen for Emacs - ;;doom-quit ; DOOM quit-message prompts when you quit Emacs - (emoji +unicode) ; 🙂 - hl-todo ; highlight TODO/FIXME/NOTE/DEPRECATED/HACK/REVIEW - ;;hydra - ;;indent-guides ; highlighted indent columns - ;;ligatures ; ligatures and symbols to make your code pretty again - ;;minimap ; show a map of the code on the side - modeline ; snazzy, Atom-inspired modeline, plus API - ;;nav-flash ; blink cursor line after big motions - ;;neotree ; a project drawer, like NERDTree for vim - ophints ; highlight the region an operation acts on - (popup +defaults) ; tame sudden yet inevitable temporary windows - ;;tabs ; a tab bar for Emacs - ;;treemacs ; a project drawer, like neotree but cooler - ;;unicode ; extended unicode support for various languages - (vc-gutter +pretty) ; vcs diff in the fringe - vi-tilde-fringe ; fringe tildes to mark beyond EOB - ;;window-select ; visually switch windows - workspaces ; tab emulation, persistence & separate workspaces - ;;zen ; distraction-free coding or writing - - :editor - (evil +everywhere); come to the dark side, we have cookies - file-templates ; auto-snippets for empty files - fold ; (nigh) universal code folding - (format +onsave) ; automated prettiness - ;;god ; run Emacs commands without modifier keys - ;;lispy ; vim for lisp, for people who don't like vim - ;;multiple-cursors ; editing in many places at once - ;;objed ; text object editing for the innocent - ;;parinfer ; turn lisp into python, sort of - ;;rotate-text ; cycle region at point between text candidates - snippets ; my elves. They type so I don't have to - word-wrap ; soft wrapping with language-aware indent - - :emacs - dired ; making dired pretty [functional] - electric ; smarter, keyword-based electric-indent - ;;ibuffer ; interactive buffer management - undo ; persistent, smarter undo for your inevitable mistakes - vc ; version-control and Emacs, sitting in a tree - - :term - ;;eshell ; the elisp shell that works everywhere - ;;shell ; simple shell REPL for Emacs - ;;term ; basic terminal emulator for Emacs - vterm ; the best terminal emulation in Emacs - - :checkers - syntax ; tasing you for every semicolon you forget - (spell +flyspell) ; tasing you for misspelling mispelling - ;;grammar ; tasing grammar mistake every you make - - :tools - ;;ansible - ;;biblio ; Writes a PhD for you (citation needed) - ;;debugger ; FIXME stepping through code, to help you add bugs - direnv - docker - ;;editorconfig ; let someone else argue about tabs vs spaces - ;;ein ; tame Jupyter notebooks with emacs - (eval +overlay) ; run code, run (also, repls) - ;;gist ; interacting with github gists - lookup ; navigate your code and its documentation - lsp ; M-x vscode - magit ; a git porcelain for Emacs - ;;make ; run make tasks from Emacs - pass ; password manager for nerds - ;;pdf ; pdf enhancements - ;;prodigy ; FIXME managing external services & code builders - ;;rgb ; creating color strings - ;;taskrunner ; taskrunner for all your projects - terraform ; infrastructure as code - ;;tmux ; an API for interacting with tmux - ;;tree-sitter ; syntax and parsing, sitting in a tree... - ;;upload ; map local to remote projects via ssh/ftp - - :os - (:if IS-MAC macos) ; improve compatibility with macOS - ;;tty ; improve the terminal Emacs experience - - :lang - agda ; types of types of types of types... - ;;beancount ; mind the GAAP - ;;(cc +lsp) ; C > C++ == 1 - clojure ; java with a lisp - common-lisp ; if you've seen one lisp, you've seen them all - ;;coq ; proofs-as-programs - ;;crystal ; ruby at the speed of c - ;;csharp ; unity, .NET, and mono shenanigans - data ; config/data formats - ;;(dart +flutter) ; paint ui and not much else - ;;dhall - ;;elixir ; erlang done right - ;;elm ; care for a cup of TEA? - emacs-lisp ; drown in parentheses - ;;erlang ; an elegant language for a more civilized age - ;;ess ; emacs speaks statistics - ;;factor - ;;faust ; dsp, but you get to keep your soul - ;;fortran ; in FORTRAN, GOD is REAL (unless declared INTEGER) - ;;fsharp ; ML stands for Microsoft's Language - ;;fstar ; (dependent) types and (monadic) effects and Z3 - ;;gdscript ; the language you waited for - ;;(go +lsp) ; the hipster dialect - ;;(graphql +lsp) ; Give queries a REST - (haskell +lsp) ; a language that's lazier than I am - ;;hy ; readability of scheme w/ speed of python - ;;idris ; a language you can depend on - json ; At least it ain't XML - ;;(java +lsp) ; the poster child for carpal tunnel syndrome - (javascript +lsp) ; all(hope(abandon(ye(who(enter(here)))))) - ;;julia ; a better, faster MATLAB - ;;kotlin ; a better, slicker Java(Script) - ;;latex ; writing papers in Emacs has never been so fun - ;;lean ; for folks with too much to prove - ;;ledger ; be audit you can be - ;;lua ; one-based indices? one-based indices - markdown ; writing docs for people to ignore - ;;nim ; python + lisp at the speed of c - nix ; I hereby declare "nix geht mehr!" - ocaml ; an objective camel - (org ; organize your plain life in plain text - +gnuplot - +present - +pretty - ) - ;;php ; perl's insecure younger brother - ;;plantuml ; diagrams for confusing people more - ;;purescript ; javascript, but functional - python ; beautiful is better than ugly - ;;qt ; the 'cutest' gui framework ever - ;;racket ; a DSL for DSLs - ;;raku ; the artist formerly known as perl6 - ;;rest ; Emacs as a REST client - ;;rst ; ReST in peace - ;;(ruby +rails) ; 1.step {|i| p "Ruby is #{i.even? ? 'love' : 'life'}"} - (rust +lsp) ; Fe2O3.unwrap().unwrap().unwrap().unwrap() - ;;scala ; java, but good - ;;(scheme +guile) ; a fully conniving family of lisps - sh ; she sells {ba,z,fi}sh shells on the C xor - ;;sml - ;;solidity ; do you need a blockchain? No. - ;;swift ; who asked for emoji variables? - ;;terra ; Earth and Moon in alignment for performance. - web ; the tubes - yaml ; JSON, but readable - ;;zig ; C, but simpler - - :email - ;;(mu4e +org +gmail) - notmuch - ;;(wanderlust +gmail) - - :app - ;;calendar - ;;emms - ;;everywhere ; *leave* Emacs!? You must be joking - irc ; how neckbeards socialize - ;;(rss +org) ; emacs as an RSS reader - ;;twitter ; twitter client https://twitter.com/vnought - - :config - literate - (default +bindings +smartparens)) diff --git a/users/aspen/emacs/org-config.el b/users/aspen/emacs/org-config.el deleted file mode 100644 index 89cf7486f..000000000 --- a/users/aspen/emacs/org-config.el +++ /dev/null @@ -1,141 +0,0 @@ -;;; org-config.el -*- lexical-binding: t; -*- - -(defun +aspen/org-setup () - (setq-local truncate-lines -1) - (display-line-numbers-mode -1) - (line-number-mode -1) - (when-let* - ((path (buffer-file-name)) - (fn (file-name-nondirectory path)) - (equal (string-equal fn "config.org"))) - (paxedit-mode 1) - (display-line-numbers-mode 1) - (flyspell-mode -1) - (org-config-mode 1))) - -(add-hook 'org-mode-hook #'+aspen/org-setup 50) - -(defun notes-file (f) - (concat org-directory (if (string-prefix-p "/" f) "" "/") f)) - -(defun aspen/org-project-tag->key (tag) - (s-replace-regexp "^project__" "" tag)) - -(defun aspen/org-project-tag->name (tag) - (s-titleized-words - (s-join " " (s-split "_" (aspen/org-project-tag->key tag))))) - -(defun aspen/org-project-tag->keys (tag) - (s-join "" (cons "p" - (-map (lambda (s) (substring-no-properties s 0 1)) - (s-split "_" (aspen/org-project-tag->key tag)))))) - -(defun aspen/org-projects->agenda-commands (project-tags) - (cl-loop for tag in project-tags - collect `(,(aspen/org-project-tag->keys tag) - ,(aspen/org-project-tag->name tag) - tags-todo - ,tag))) - -(defun aspen/org-projects () - (cl-loop for (tag) in - (org-global-tags-completion-table - (directory-files-recursively "~/notes" "\\.org$")) - when (s-starts-with-p "project__" tag) - collect tag)) - -(comment - (aspen/org-projects->agenda-commands (aspen/org-projects)) - ) - -(setq - org-directory (expand-file-name "~/notes") - +org-dir (expand-file-name "~/notes") - org-default-notes-file (concat org-directory "/inbox.org") - +org-default-todo-file (concat org-directory "/inbox.org") - org-agenda-files (directory-files-recursively - "~/notes" "\\.org$") - org-refile-targets '((org-agenda-files :maxlevel . 3)) - org-outline-path-complete-in-steps nil - org-refile-use-outline-path t - org-file-apps `((auto-mode . emacs) - (,(rx (or (and "." (optional "x") (optional "htm") (optional "l") buffer-end) - (and buffer-start "http" (optional "s") "://"))) - . "firefox %s") - (,(rx ".pdf" buffer-end) . "apvlv %s") - (,(rx "." (or "png" - "jpg" - "jpeg" - "gif" - "tif" - "tiff") - buffer-end) - . "feh %s")) - org-log-done 'time - org-archive-location "~/notes/trash::* From %s" - org-cycle-separator-lines 2 - org-hidden-keywords '(title) - org-tags-column -130 - org-ellipsis "…" - org-imenu-depth 9 - org-capture-templates - `(("t" "Todo" entry - (file +org-default-todo-file) - "* TODO %?\n%i" - :kill-buffer t) - - ("m" "Email" entry - (file +org-default-todo-file) - "* TODO [[%L][%:subject]] :email:\n%i") - - ("n" "Notes" entry - (file +org-default-todo-file) - "* %U %?\n%i" - :prepend t - :kill-buffer t) - - ("c" "Task note" entry - (clock) - "* %U %?\n%i[%l[Context]]\n" - :kill-buffer t - :unnarrowed t) - - ("p" "Projects") - ("px" "Xanthous" entry - (file+headline ,(notes-file "xanthous.org") "Backlog") - "* TODO %?\nContext %a\nIn task: %K") - ("pt" "Tvix" entry - (file+headline ,(notes-file "tvix.org") "Tvix TODO") - "* TODO %?\nContext %a\nIn task: %K") - ("pw" "Windtunnel" entry - (file+headline ,(notes-file "windtunnel.org") "Inbox") - "* TODO %i%?\nContext: %a\nIn task: %K") - ) - - org-capture-templates-contexts - `(("px" ((in-file . "/home/aspen/code/depot/users/aspen/xanthous/.*"))) - ("e" ((in-mode . "notmuch-show-mode")))) - - org-deadline-warning-days 1 - org-agenda-skip-scheduled-if-deadline-is-shown 'todo - org-todo-keywords '((sequence "TODO(t)" "ACTIVE(a)" "|" "DONE(d)" "RUNNING(r)") - (sequence "NEXT(n)" "WAITING(w)" "LATER(l)" "|" "CANCELLED(c)")) - org-agenda-custom-commands - `(("i" "Inbox" tags "inbox") - ("r" "Running jobs" todo "RUNNING") - ("w" "@Work" tags-todo "@work") - ("n" . "Next...") - ("nw" "Next @Work" tags-todo "@work&next") - ("nt" "Next tooling" tags-todo "tooling") - - ;; ("p" . "Project...") - ;; ,@(aspen/org-projects->agenda-commands (aspen/org-projects)) - ) - - org-agenda-dim-blocked-tasks nil - org-enforce-todo-dependencies nil - - org-babel-clojure-backend 'cider) - -(setq whitespace-global-modes '(not org-mode magit-mode vterm-mode)) -(setf (alist-get 'file org-link-frame-setup) 'find-file-other-window) diff --git a/users/aspen/emacs/packages.el b/users/aspen/emacs/packages.el deleted file mode 100644 index 0bcc345d8..000000000 --- a/users/aspen/emacs/packages.el +++ /dev/null @@ -1,14 +0,0 @@ -;; -*- no-byte-compile: t; -*- -;;; $DOOMDIR/packages.el - -(package! dash) -(package! paxedit) -(package! predd - :recipe (:host github :repo "skeeto/predd")) -(package! direnv) -(package! alert) -(package! flycheck-clojure) -(package! evil-matchit) -(package! string-inflection) -(package! protobuf-mode) -(package! hotfuzz) diff --git a/users/aspen/emacs/snippets/haskell-mode/annotation b/users/aspen/emacs/snippets/haskell-mode/annotation deleted file mode 100644 index 8a2854d75..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/annotation +++ /dev/null @@ -1,5 +0,0 @@ -# key: ann -# name: annotation -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# ANN ${1:module} ("${2:HLint: ignore ${3:Reduce duplication}}" :: String) #-} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/benchmark-module b/users/aspen/emacs/snippets/haskell-mode/benchmark-module deleted file mode 100644 index cbb1646e4..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/benchmark-module +++ /dev/null @@ -1,26 +0,0 @@ -# key: bench -# name: benchmark-module -# expand-env: ((yas-indent-line (quote fixed))) -# -- --------------------------------------------------------------------------------- -module ${1:`(if (not buffer-file-name) "Module" - (let ((name (file-name-sans-extension (buffer-file-name))) - (case-fold-search nil)) - (if (cl-search "bench/" name) - (replace-regexp-in-string "/" "." - (replace-regexp-in-string "^\/[^A-Z]*" "" - (car (last (split-string name "src"))))) - (file-name-nondirectory name))))`} ( benchmark, main ) where --------------------------------------------------------------------------------- -import Bench.Prelude --------------------------------------------------------------------------------- -import ${1:$(s-chop-suffix "Bench" yas-text)} --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain [benchmark] - --------------------------------------------------------------------------------- - -benchmark :: Benchmark -benchmark = bgroup "${1:$(->> yas-text (s-chop-suffix "Bench") (s-split ".") -last-item)}" [bench "something dumb" $ nf (1 +) (1 :: Int)] diff --git a/users/aspen/emacs/snippets/haskell-mode/header b/users/aspen/emacs/snippets/haskell-mode/header deleted file mode 100644 index fdd8250d8..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/header +++ /dev/null @@ -1,5 +0,0 @@ -# key: hh -# name: header -# expand-env: ((yas-indent-line 'fixed)) -# -- ---------------------------------------------------------------------------------$2 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/hedgehog-generator b/users/aspen/emacs/snippets/haskell-mode/hedgehog-generator deleted file mode 100644 index 68863f705..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/hedgehog-generator +++ /dev/null @@ -1,8 +0,0 @@ -# key: gen -# name: Hedgehog Generator -# expand-env: ((yas-indent-line (quote fixed))) -# -- -gen${1:Foo} :: Gen $1 -gen$1 = do - $2 - pure $1{..} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/hedgehog-property b/users/aspen/emacs/snippets/haskell-mode/hedgehog-property deleted file mode 100644 index bf39a2a3e..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/hedgehog-property +++ /dev/null @@ -1,9 +0,0 @@ -# -*- mode: snippet -*- -# name: Hedgehog Property -# key: hprop -# expand-env: ((yas-indent-line 'fixed)) -# -- -hprop_${1:somethingIsAlwaysTrue} :: Property -hprop_$1 = property $ do - ${2:x} <- forAll ${3:Gen.int $ Range.linear 1 100} - ${4:x === x} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/hlint b/users/aspen/emacs/snippets/haskell-mode/hlint deleted file mode 100644 index f25a9b8d4..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/hlint +++ /dev/null @@ -1,8 +0,0 @@ -# -*- mode: snippet -*- -# name: hlint -# uuid: hlint -# expand-env: ((yas-indent-line 'fixed)) -# key: hlint -# condition: t -# -- -{-# ANN module ("Hlint: ignore $1" :: String) #- } \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/import-i b/users/aspen/emacs/snippets/haskell-mode/import-i deleted file mode 100644 index 4a7fca2c2..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/import-i +++ /dev/null @@ -1,4 +0,0 @@ -# key: i -# name: import-i -# -- -import ${1:Prelude} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/inl b/users/aspen/emacs/snippets/haskell-mode/inl deleted file mode 100644 index 6e17b83d7..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/inl +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: inl -# key: inl -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# INLINE $1 #-} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/inline b/users/aspen/emacs/snippets/haskell-mode/inline deleted file mode 100644 index 1beafbe50..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/inline +++ /dev/null @@ -1,5 +0,0 @@ -# key: inline -# name: inline -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# INLINE $1 #-} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/language pragma b/users/aspen/emacs/snippets/haskell-mode/language pragma deleted file mode 100644 index 6f84720f4..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/language pragma +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: language pragma -# key: lang -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# LANGUAGE $1 #-} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/lens.field b/users/aspen/emacs/snippets/haskell-mode/lens.field deleted file mode 100644 index b22ea3d2e..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/lens.field +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: lens.field -# key: lens -# expand-env: ((yas-indent-line 'fixed)) -# -- -${1:field} :: Lens' ${2:Source} ${3:Target} -$1 = lens _${4:sourceField} $ \\${2:$(-> yas-text s-word-initials s-downcase)} ${4:$(-> yas-text s-word-initials s-downcase)} -> ${2:$(-> yas-text s-word-initials s-downcase)} { _$4 = ${4:$(-> yas-text s-word-initials s-downcase)} } \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/module b/users/aspen/emacs/snippets/haskell-mode/module deleted file mode 100644 index 4554d33f9..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/module +++ /dev/null @@ -1,32 +0,0 @@ -# -*- mode: snippet -*- -# key: module -# name: module -# condition: (= (length "module") (current-column)) -# expand-env: ((yas-indent-line 'fixed)) -# contributor: Luke Hoersten -# -- --------------------------------------------------------------------------------- --- | --- Module : $1 --- Description : $2 --- Maintainer : Griffin Smith --- Maturity : ${3:Draft, Usable, Maintained, OR MatureAF} --- --- $4 --------------------------------------------------------------------------------- -module ${1:`(if (not buffer-file-name) "Module" - (let ((name (file-name-sans-extension (buffer-file-name))) - (case-fold-search nil)) - (if (or (cl-search "src/" name) - (cl-search "test/" name)) - (replace-regexp-in-string "/" "." - (replace-regexp-in-string "^\/[^A-Z]*" "" - (car (last (split-string name "src"))))) - (file-name-nondirectory name))))`} - ( - ) where --------------------------------------------------------------------------------- -import Prelude --------------------------------------------------------------------------------- - -$0 diff --git a/users/aspen/emacs/snippets/haskell-mode/shut up, hlint b/users/aspen/emacs/snippets/haskell-mode/shut up, hlint deleted file mode 100644 index fccff1d66..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/shut up, hlint +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: shut up, hlint -# key: dupl -# expand-env: ((yas-indent-line 'fixed)) -# -- -{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/test-group b/users/aspen/emacs/snippets/haskell-mode/test-group deleted file mode 100644 index bf6a66f8a..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/test-group +++ /dev/null @@ -1,9 +0,0 @@ -# -*- mode: snippet -*- -# name: test-group -# uuid: test-group -# key: testGroup -# condition: t -# -- -testGroup "${1:name}" -[ $0 -] \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/test-module b/users/aspen/emacs/snippets/haskell-mode/test-module deleted file mode 100644 index 036b0ae99..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/test-module +++ /dev/null @@ -1,27 +0,0 @@ -# -*- mode: snippet -*- -# name: test-module -# key: test -# expand-env: ((yas-indent-line 'fixed)) -# -- --------------------------------------------------------------------------------- -module ${1:`(if (not buffer-file-name) "Module" - (let ((name (file-name-sans-extension (buffer-file-name))) - (case-fold-search nil)) - (if (cl-search "test/" name) - (replace-regexp-in-string "/" "." - (replace-regexp-in-string "^\/[^A-Z]*" "" - (car (last (split-string name "src"))))) - (file-name-nondirectory name))))`} (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import ${1:$(s-chop-suffix "Spec" yas-text)} --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "$1" - [ $0 - ] \ No newline at end of file diff --git a/users/aspen/emacs/snippets/haskell-mode/undefined b/users/aspen/emacs/snippets/haskell-mode/undefined deleted file mode 100644 index 7bcd99b57..000000000 --- a/users/aspen/emacs/snippets/haskell-mode/undefined +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: undefined -# key: u -# expand-env: ((yas-indent-line 'fixed) (yas-wrap-around-region 'nil)) -# -- -undefined$1 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/action-type b/users/aspen/emacs/snippets/js2-mode/action-type deleted file mode 100644 index ef8d1a386..000000000 --- a/users/aspen/emacs/snippets/js2-mode/action-type +++ /dev/null @@ -1,4 +0,0 @@ -# key: at -# name: action-type -# -- -export const ${1:FOO_BAR$(->> yas-text s-upcase (s-replace-all '(("-" . "_") (" " . "_"))))}: '${3:ns}/${1:$(-> yas-text s-dashed-words)}' = '$3/${1:$(-> yas-text s-dashed-words)}'$5 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/before b/users/aspen/emacs/snippets/js2-mode/before deleted file mode 100644 index 4569b6583..000000000 --- a/users/aspen/emacs/snippets/js2-mode/before +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: before -# key: bef -# -- -before(function() { - $1 -}) diff --git a/users/aspen/emacs/snippets/js2-mode/context b/users/aspen/emacs/snippets/js2-mode/context deleted file mode 100644 index d83809f3c..000000000 --- a/users/aspen/emacs/snippets/js2-mode/context +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: context -# key: context -# -- -context('$1', function() { - $2 -}) diff --git a/users/aspen/emacs/snippets/js2-mode/describe b/users/aspen/emacs/snippets/js2-mode/describe deleted file mode 100644 index bd0198181..000000000 --- a/users/aspen/emacs/snippets/js2-mode/describe +++ /dev/null @@ -1,6 +0,0 @@ -# key: desc -# name: describe -# -- -describe('$1', () => { - $2 -}) \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/expect b/users/aspen/emacs/snippets/js2-mode/expect deleted file mode 100644 index eba41ef33..000000000 --- a/users/aspen/emacs/snippets/js2-mode/expect +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: expect -# key: ex -# -- -expect($1).$2 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/function b/users/aspen/emacs/snippets/js2-mode/function deleted file mode 100644 index b423044b4..000000000 --- a/users/aspen/emacs/snippets/js2-mode/function +++ /dev/null @@ -1,6 +0,0 @@ -# key: f -# name: function -# -- -function $1($2) { - $3 -} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/header b/users/aspen/emacs/snippets/js2-mode/header deleted file mode 100644 index 3e303764c..000000000 --- a/users/aspen/emacs/snippets/js2-mode/header +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: header -# key: hh -# expand-env: ((yas-indent-line 'fixed)) -# -- -//////////////////////////////////////////////////////////////////////////////// diff --git a/users/aspen/emacs/snippets/js2-mode/it b/users/aspen/emacs/snippets/js2-mode/it deleted file mode 100644 index a451cfc08..000000000 --- a/users/aspen/emacs/snippets/js2-mode/it +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: it -# key: it -# -- -it('$1', () => { - $2 -}) \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/it-pending b/users/aspen/emacs/snippets/js2-mode/it-pending deleted file mode 100644 index 00da312e1..000000000 --- a/users/aspen/emacs/snippets/js2-mode/it-pending +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: it-pending -# key: xi -# -- -it('$1')$0 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/module b/users/aspen/emacs/snippets/js2-mode/module deleted file mode 100644 index dc79819d8..000000000 --- a/users/aspen/emacs/snippets/js2-mode/module +++ /dev/null @@ -1,12 +0,0 @@ -# key: module -# name: module -# expand-env: ((yas-indent-line (quote fixed))) -# condition: (= (length "module") (current-column)) -# -- -/** - * @fileOverview $1 - * @name ${2:`(file-name-nondirectory (buffer-file-name))`} - * @author Griffin Smith - * @license Proprietary - */ -$3 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/record b/users/aspen/emacs/snippets/js2-mode/record deleted file mode 100644 index 0bb0f0243..000000000 --- a/users/aspen/emacs/snippets/js2-mode/record +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: record -# key: rec -# -- -export default class $1 extends Record({ - $2 -}) {} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/js2-mode/test b/users/aspen/emacs/snippets/js2-mode/test deleted file mode 100644 index 938d490a7..000000000 --- a/users/aspen/emacs/snippets/js2-mode/test +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: test -# key: test -# -- -test('$1', () => { - $2 -}) \ No newline at end of file diff --git a/users/aspen/emacs/snippets/nix-mode/fetchFromGitHub b/users/aspen/emacs/snippets/nix-mode/fetchFromGitHub deleted file mode 100644 index d2447e4b5..000000000 --- a/users/aspen/emacs/snippets/nix-mode/fetchFromGitHub +++ /dev/null @@ -1,12 +0,0 @@ -# -*- mode: snippet -*- -# name: fetchFromGitHub -# uuid: fetchFromGitHub -# key: fetchFromGitHub -# condition: t -# -- -fetchFromGitHub { - owner = "$1"; - repo = "$2"; - rev = "$3"; - sha256 = "0000000000000000000000000000000000000000000000000000"; -} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/nix-mode/pythonPackage b/users/aspen/emacs/snippets/nix-mode/pythonPackage deleted file mode 100644 index 0a74c21e1..000000000 --- a/users/aspen/emacs/snippets/nix-mode/pythonPackage +++ /dev/null @@ -1,16 +0,0 @@ -# key: pypkg -# name: pythonPackage -# condition: t -# -- -${1:pname} = buildPythonPackage rec { - name = "\${pname}-\${version}"; - pname = "$1"; - version = "${2:1.0.0}"; - src = fetchPypi { - inherit pname version; - sha256 = "0000000000000000000000000000000000000000000000000000"; - }; - propagatedBuildInputs = with pythonSelf; [ - $3 - ]; -}; \ No newline at end of file diff --git a/users/aspen/emacs/snippets/nix-mode/sha256 b/users/aspen/emacs/snippets/nix-mode/sha256 deleted file mode 100644 index bc640e5ab..000000000 --- a/users/aspen/emacs/snippets/nix-mode/sha256 +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: sha256 -# uuid: sha256 -# key: sha256 -# condition: t -# -- -sha256 = "0000000000000000000000000000000000000000000000000000"; \ No newline at end of file diff --git a/users/aspen/emacs/snippets/org-mode/SQL source block b/users/aspen/emacs/snippets/org-mode/SQL source block deleted file mode 100644 index b5d43fd6b..000000000 --- a/users/aspen/emacs/snippets/org-mode/SQL source block +++ /dev/null @@ -1,6 +0,0 @@ -# key: sql -# name: SQL source block -# -- -#+BEGIN_SRC sql ${1::async} -$2 -#+END_SRC diff --git a/users/aspen/emacs/snippets/org-mode/combat b/users/aspen/emacs/snippets/org-mode/combat deleted file mode 100644 index b4db0f433..000000000 --- a/users/aspen/emacs/snippets/org-mode/combat +++ /dev/null @@ -1,13 +0,0 @@ -# -*- mode: snippet -*- -# name: combat -# uuid: combat -# key: combat -# condition: t -# -- -| | initiative | max hp | current hp | status | | -|-------------+------------+--------+------------+--------+------| -| Barty Barty | | | | | <--- | -| Hectoroth | | | | | | -| Xanadu | | | | | | -| Aurora | | | | | | -| EFB | | | | | | \ No newline at end of file diff --git a/users/aspen/emacs/snippets/org-mode/date b/users/aspen/emacs/snippets/org-mode/date deleted file mode 100644 index 297529cda..000000000 --- a/users/aspen/emacs/snippets/org-mode/date +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# key: date -# name: date.org -# -- -[`(format-time-string "%Y-%m-%d")`]$0 diff --git a/users/aspen/emacs/snippets/org-mode/date-time b/users/aspen/emacs/snippets/org-mode/date-time deleted file mode 100644 index fde469276..000000000 --- a/users/aspen/emacs/snippets/org-mode/date-time +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: date-time -# key: dt -# -- -[`(format-time-string "%Y-%m-%d %H:%m:%S")`] \ No newline at end of file diff --git a/users/aspen/emacs/snippets/org-mode/description b/users/aspen/emacs/snippets/org-mode/description deleted file mode 100644 index a43bc95cc..000000000 --- a/users/aspen/emacs/snippets/org-mode/description +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: description -# key: desc -# -- -:DESCRIPTION: -$1 -:END: diff --git a/users/aspen/emacs/snippets/org-mode/nologdone b/users/aspen/emacs/snippets/org-mode/nologdone deleted file mode 100644 index e5be85d6b..000000000 --- a/users/aspen/emacs/snippets/org-mode/nologdone +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: nologdone -# key: nologdone -# -- -#+STARTUP: nologdone$0 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/org-mode/python source block b/users/aspen/emacs/snippets/org-mode/python source block deleted file mode 100644 index 247ae51b0..000000000 --- a/users/aspen/emacs/snippets/org-mode/python source block +++ /dev/null @@ -1,6 +0,0 @@ -# key: py -# name: Python source block -# -- -#+BEGIN_SRC python -$0 -#+END_SRC \ No newline at end of file diff --git a/users/aspen/emacs/snippets/org-mode/reveal b/users/aspen/emacs/snippets/org-mode/reveal deleted file mode 100644 index 1bdbdfa5d..000000000 --- a/users/aspen/emacs/snippets/org-mode/reveal +++ /dev/null @@ -1,6 +0,0 @@ -# key: reveal -# name: reveal -# condition: t -# -- -#+ATTR_REVEAL: :frag ${1:roll-in} -$0 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/org-mode/transaction b/users/aspen/emacs/snippets/org-mode/transaction deleted file mode 100644 index 37f2dd31c..000000000 --- a/users/aspen/emacs/snippets/org-mode/transaction +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: transaction -# key: begin -# -- -BEGIN; -$0 -ROLLBACK; \ No newline at end of file diff --git a/users/aspen/emacs/snippets/prolog-mode/tests b/users/aspen/emacs/snippets/prolog-mode/tests deleted file mode 100644 index a9d92a0d5..000000000 --- a/users/aspen/emacs/snippets/prolog-mode/tests +++ /dev/null @@ -1,11 +0,0 @@ -# -*- mode: snippet -*- -# name: tests -# uuid: tests -# key: tests -# condition: t -# -- -:- begin_tests(${1:name}). - -$0 - -:- end_tests($1). \ No newline at end of file diff --git a/users/aspen/emacs/snippets/prolog-mode/use-module b/users/aspen/emacs/snippets/prolog-mode/use-module deleted file mode 100644 index 75fd19b64..000000000 --- a/users/aspen/emacs/snippets/prolog-mode/use-module +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: use-module -# uuid: use-module -# key: use -# condition: t -# -- -:- use_module(${1:library($2)}${3:, [$4]}). \ No newline at end of file diff --git a/users/aspen/emacs/snippets/python-mode/add_column b/users/aspen/emacs/snippets/python-mode/add_column deleted file mode 100644 index 47e83850d..000000000 --- a/users/aspen/emacs/snippets/python-mode/add_column +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: add_column -# key: op.add_column -# -- -op.add_column('${1:table}', sa.Column('${2:name}', sa.${3:String()}))$0 diff --git a/users/aspen/emacs/snippets/python-mode/decorate b/users/aspen/emacs/snippets/python-mode/decorate deleted file mode 100644 index 4f9674857..000000000 --- a/users/aspen/emacs/snippets/python-mode/decorate +++ /dev/null @@ -1,15 +0,0 @@ -# -*- mode: snippet -*- -# name: decorate -# uuid: decorate -# key: decorate -# condition: t -# -- -def wrap(inner): - @wraps(inner) - def wrapped(*args, **kwargs): - ret = inner(*args, **kwargs) - return ret - - return wrapped - -return wrap \ No newline at end of file diff --git a/users/aspen/emacs/snippets/python-mode/dunder b/users/aspen/emacs/snippets/python-mode/dunder deleted file mode 100644 index 71d99dddc..000000000 --- a/users/aspen/emacs/snippets/python-mode/dunder +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: dunder -# uuid: dunder -# key: du -# condition: t -# -- -__$1__$0 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/python-mode/name b/users/aspen/emacs/snippets/python-mode/name deleted file mode 100644 index 1495cc91d..000000000 --- a/users/aspen/emacs/snippets/python-mode/name +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: name -# uuid: name -# key: name -# condition: t -# -- -__name__ \ No newline at end of file diff --git a/users/aspen/emacs/snippets/python-mode/op.get_bind.execute b/users/aspen/emacs/snippets/python-mode/op.get_bind.execute deleted file mode 100644 index aba801c6b..000000000 --- a/users/aspen/emacs/snippets/python-mode/op.get_bind.execute +++ /dev/null @@ -1,7 +0,0 @@ -# key: exec -# name: op.get_bind.execute -# -- -op.get_bind().execute( - """ - `(progn (sqlup-mode) "")`$1 - """) diff --git a/users/aspen/emacs/snippets/python-mode/pdb b/users/aspen/emacs/snippets/python-mode/pdb deleted file mode 100644 index 41c6f87cb..000000000 --- a/users/aspen/emacs/snippets/python-mode/pdb +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: pdb -# uuid: pdb -# key: pdb -# condition: t -# -- -import pdb; pdb.set_trace() \ No newline at end of file diff --git a/users/aspen/emacs/snippets/rust-mode/#[macro_use] b/users/aspen/emacs/snippets/rust-mode/#[macro_use] deleted file mode 100644 index fea942a33..000000000 --- a/users/aspen/emacs/snippets/rust-mode/#[macro_use] +++ /dev/null @@ -1,5 +0,0 @@ -# key: macro_use -# name: #[macro_use] -# -- -#[macro_use] -${1:extern crate} ${2:something};$0 diff --git a/users/aspen/emacs/snippets/rust-mode/async test b/users/aspen/emacs/snippets/rust-mode/async test deleted file mode 100644 index 2352d7b56..000000000 --- a/users/aspen/emacs/snippets/rust-mode/async test +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: snippet -*- -# name: async test -# uuid: atest -# key: atest -# condition: t -# -- -#[tokio::test${1:(flavor = "multi_thread")}] -async fn ${2:test_name}() { - `%`$0 -} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/rust-mode/benchmark b/users/aspen/emacs/snippets/rust-mode/benchmark deleted file mode 100644 index 9ec430753..000000000 --- a/users/aspen/emacs/snippets/rust-mode/benchmark +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: snippet -*- -# name: benchmark -# uuid: benchmark -# key: bench -# condition: t -# -- -#[bench] -fn ${1:benchmark_name}(b: &mut Bencher) { - `%`b.iter(|| $0); -} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/rust-mode/proptest b/users/aspen/emacs/snippets/rust-mode/proptest deleted file mode 100644 index be12af491..000000000 --- a/users/aspen/emacs/snippets/rust-mode/proptest +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: snippet -*- -# name: proptest -# uuid: proptest -# key: proptest -# condition: t -# -- -#[proptest] -fn ${1:test_name}($2) { - `%`$0 -} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/rust-mode/test-module b/users/aspen/emacs/snippets/rust-mode/test-module deleted file mode 100644 index bfa2ca2d1..000000000 --- a/users/aspen/emacs/snippets/rust-mode/test-module +++ /dev/null @@ -1,11 +0,0 @@ -# -*- mode: snippet -*- -# name: test-module -# uuid: test-module -# key: tmod -# condition: t -# -- -mod $1 { - use super::*; - - $0 -} \ No newline at end of file diff --git a/users/aspen/emacs/snippets/rust-mode/tests b/users/aspen/emacs/snippets/rust-mode/tests deleted file mode 100644 index 0a476ab58..000000000 --- a/users/aspen/emacs/snippets/rust-mode/tests +++ /dev/null @@ -1,9 +0,0 @@ -# key: tests -# name: test module -# -- -#[cfg(test)] -mod ${1:tests} { - use super::*; - - $0 -} diff --git a/users/aspen/emacs/snippets/snippet-mode/indent b/users/aspen/emacs/snippets/snippet-mode/indent deleted file mode 100644 index d38ffceaf..000000000 --- a/users/aspen/emacs/snippets/snippet-mode/indent +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: indent -# key: indent -# -- -# expand-env: ((yas-indent-line 'fixed)) \ No newline at end of file diff --git a/users/aspen/emacs/snippets/sql-mode/count(*) group by b/users/aspen/emacs/snippets/sql-mode/count(*) group by deleted file mode 100644 index 6acc46ff3..000000000 --- a/users/aspen/emacs/snippets/sql-mode/count(*) group by +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: count(*) group by -# key: countby -# -- -SELECT count(*), ${1:column} FROM ${2:table} GROUP BY $1; diff --git a/users/aspen/emacs/snippets/terraform-mode/variable b/users/aspen/emacs/snippets/terraform-mode/variable deleted file mode 100644 index 14822f1a0..000000000 --- a/users/aspen/emacs/snippets/terraform-mode/variable +++ /dev/null @@ -1,11 +0,0 @@ -# -*- mode: snippet -*- -# name: variable -# uuid: variable -# key: var -# condition: t -# -- -variable "${1:name}" { - type = ${2:string} - ${3:default = ${4:default}} -} -$0 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/text-mode/date b/users/aspen/emacs/snippets/text-mode/date deleted file mode 100644 index 7b9431147..000000000 --- a/users/aspen/emacs/snippets/text-mode/date +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -# name: date -# key: date -# -- -`(format-time-string "%Y-%m-%d")`$0 \ No newline at end of file diff --git a/users/aspen/emacs/snippets/tuareg-mode/expect-test b/users/aspen/emacs/snippets/tuareg-mode/expect-test deleted file mode 100644 index e0b541fce..000000000 --- a/users/aspen/emacs/snippets/tuareg-mode/expect-test +++ /dev/null @@ -1,9 +0,0 @@ -# -*- mode: snippet -*- -# name: expect-test -# uuid: expect-test -# key: exp -# condition: t -# -- -let%expect_test "${1:name}" = - ${2:}; - [%expect {| $3 |}] \ No newline at end of file diff --git a/users/aspen/emacs/snippets/tuareg-mode/module b/users/aspen/emacs/snippets/tuareg-mode/module deleted file mode 100644 index 9b1701e3a..000000000 --- a/users/aspen/emacs/snippets/tuareg-mode/module +++ /dev/null @@ -1,9 +0,0 @@ -# -*- mode: snippet -*- -# name: module -# uuid: module -# key: mod -# condition: t -# -- -module ${1:Name} = struct - $0 -end \ No newline at end of file diff --git a/users/aspen/emacs/snippets/tuareg-mode/test-module b/users/aspen/emacs/snippets/tuareg-mode/test-module deleted file mode 100644 index b16176e5f..000000000 --- a/users/aspen/emacs/snippets/tuareg-mode/test-module +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: snippet -*- -# name: test-module -# uuid: test-module -# key: tmod -# condition: t -# -- -let%test_module ${1:_} = - (module struct - $0 - end) \ No newline at end of file diff --git a/users/aspen/goodcry-band/astoria.jpg b/users/aspen/goodcry-band/astoria.jpg deleted file mode 100644 index 5e99fb021..000000000 Binary files a/users/aspen/goodcry-band/astoria.jpg and /dev/null differ diff --git a/users/aspen/goodcry-band/bandcamp.svg b/users/aspen/goodcry-band/bandcamp.svg deleted file mode 100644 index 3a2070126..000000000 --- a/users/aspen/goodcry-band/bandcamp.svg +++ /dev/null @@ -1,2 +0,0 @@ - -image/svg+xml \ No newline at end of file diff --git a/users/aspen/goodcry-band/flower-icon.svg b/users/aspen/goodcry-band/flower-icon.svg deleted file mode 100644 index b6be59029..000000000 --- a/users/aspen/goodcry-band/flower-icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/users/aspen/goodcry-band/flower-leaves.svg b/users/aspen/goodcry-band/flower-leaves.svg deleted file mode 100644 index 5a3b6771a..000000000 --- a/users/aspen/goodcry-band/flower-leaves.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/users/aspen/goodcry-band/flower.png b/users/aspen/goodcry-band/flower.png deleted file mode 100644 index b5ad24bac..000000000 Binary files a/users/aspen/goodcry-band/flower.png and /dev/null differ diff --git a/users/aspen/goodcry-band/index.css b/users/aspen/goodcry-band/index.css deleted file mode 100644 index 484fa316e..000000000 --- a/users/aspen/goodcry-band/index.css +++ /dev/null @@ -1,186 +0,0 @@ -@import "./reset.css"; - -:root { - --gray: #b4ada5; - --black: #2f2715; - --background: #fff9f4; - --blue: #195f9a; - --lavender: #5f6eb2; -} - -html { - width: 100%; -} - -body { - background-color: var(--background); - color: var(--black); - display: flex; - flex-direction: column; - align-items: center; - width: 100%; - overflow-x: hidden; - font-family: "Helvetica", sans-serif; -} - -h1, -h2, -subtitle { - font-family: "Playfair Display", serif; -} - -header { - display: flex !important; - flex-direction: column; - align-items: center; - font-size: 30px; - display: inline-block; - text-align: center; - max-width: 100%; - overflow-x: hidden; -} - -@media (min-width: 800px) { - header { - overflow-x: initial; - } -} - -subtitle { - display: block; - padding-top: 0.5rem; - padding-bottom: 2.7rem; -} - -hr { - border-top-style: none; - border-left-style: none; - border-right-style: none; - border-bottom: 1px solid var(--gray); - width: 35%; - margin: 1.4rem 0; -} - -header hr { - margin-top: 0; - margin-bottom: 2.7rem; -} - -.header-image { - width: 75%; - max-width: 75%; - transform: translateX(4%); - margin-top: 1rem; -} - -@media (min-width: 600px) { - .header-image { - max-width: 600px; - margin-bottom: 1.2rem; - } -} - -h2 { - margin-bottom: 1.4rem; - border-bottom: 1px solid var(--gray); - padding-bottom: 0.5rem; -} - -.content { - display: flex; - flex-direction: column; - align-items: center; - margin-bottom: 1.7rem; -} - -.music-embed { - margin-left: -30px; - margin-right: -30px; -} - -.streaming-links { - text-align: center; - color: var(--gray); -} - -.streaming-links a { - color: var(--gray); -} - -a { - color: var(--blue); - text-decoration: none; -} - -p { - text-align: center; - max-width: 400px; - padding: 0 1rem; -} - -a:active { - text-decoration: underline; - color: var(--lavender); -} - -.link-list { - padding: 0 1rem; - list-style: none; - font-size: 1.2em; - text-align: center; -} - -@media (min-width: 800px) { - .link-list { - padding: 0; - } -} - -.link-list li > * { - display: block; - padding: 0.4rem 0; -} - -.social-links { - margin-top: 3rem; - display: flex; - flex-direction: row; - align-items: center; -} - -.social-links > * + * { - margin-left: 0.5rem; -} - -.social-links svg { - fill: var(--gray); -} - -.social-links a { - color: var(--gray); - font-size: 24px; - vertical-align: middle; - cursor: pointer; -} - -.social-links a:hover { - color: var(--blue); -} - -.social-links a:active { - color: var(--lavender); - text-decoration: none; -} - -.social-links a:hover svg { - fill: var(--blue); -} - -.social-links a:active svg { - fill: var(--lavender); -} - -footer img { - width: 80px; - margin: 3rem 0; -} diff --git a/users/aspen/goodcry-band/index.html b/users/aspen/goodcry-band/index.html deleted file mode 100644 index 87826e259..000000000 --- a/users/aspen/goodcry-band/index.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - Good Cry - - - - - - - - -

    - Flower -

    Good Cry

    -
    -
    -

    Music

    -
    - -
    -

    Shows

    -
    -
    -
    -

    - DM us - on Instagram for - booking inquiries -

    -
    - -
    -  Flower -
    - - diff --git a/users/aspen/goodcry-band/reset.css b/users/aspen/goodcry-band/reset.css deleted file mode 100644 index 23dcf53d2..000000000 --- a/users/aspen/goodcry-band/reset.css +++ /dev/null @@ -1,45 +0,0 @@ -*, -*::before, -*::after { - box-sizing: border-box; -} - -* { - margin: 0; -} - -body { - line-height: 1.5; - -webkit-font-smoothing: antialiased; -} - -img, -picture, -video, -canvas, -svg { - display: block; - max-width: 100%; -} - -input, -button, -textarea, -select { - font: inherit; -} - -p, -h1, -h2, -h3, -h4, -h5, -h6 { - overflow-wrap: break-word; -} - -#root, -#__next { - isolation: isolate; -} diff --git a/users/aspen/keyboard/.gitignore b/users/aspen/keyboard/.gitignore deleted file mode 100644 index b2be92b7d..000000000 --- a/users/aspen/keyboard/.gitignore +++ /dev/null @@ -1 +0,0 @@ -result diff --git a/users/aspen/keyboard/README.org b/users/aspen/keyboard/README.org deleted file mode 100644 index b085883a1..000000000 --- a/users/aspen/keyboard/README.org +++ /dev/null @@ -1,10 +0,0 @@ -This repository contains the source of the keyboard layout for my Ergodox EZ, -plus build tooling based on Nix. - -To flash to an Ergodox EZ that's connected to your computer via USB, run: - -#+BEGIN_SRC shell -./flash -#+END_SRC - -then press the reset switch on the keyboard. diff --git a/users/aspen/keyboard/default.nix b/users/aspen/keyboard/default.nix deleted file mode 100644 index 929ec7d62..000000000 --- a/users/aspen/keyboard/default.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ pkgs, ... }: - -with pkgs; - -let avrlibc = pkgsCross.avr.libcCross; in - -rec { - qmkSource = fetchgit { - url = "https://github.com/qmk/qmk_firmware"; - rev = "ab1650606c36f85018257aba65d9c3ff8ec42e71"; - sha256 = "1k59flkvhjzmfl0yz9z37lqhvad7m9r5wy1p1sjk5274rsmylh79"; - fetchSubmodules = true; - }; - - layout = stdenv.mkDerivation rec { - name = "ergodox_ez_grfn.hex"; - - src = qmkSource; - - buildInputs = [ - dfu-programmer - dfu-util - diffutils - git - python3 - pkgsCross.avr.buildPackages.binutils - pkgsCross.avr.buildPackages.gcc - avrlibc - avrdude - ]; - - AVR_CFLAGS = [ - "-isystem ${avrlibc}/avr/include" - "-L${avrlibc}/avr/lib/avr5" - # GCC 12 has improved array-bounds warnings, failing the build of QMK. - # Newer versions of the firmware would work probably, but they heavily - # altered the build system, so it is non-trivial. Backporting the patch - # that fixes it seems difficult – the next change to the offending matrix.c - # after the pinned qmkSource commit is - # https://github.com/qmk/qmk_firmware/commit/11c308d436180974b7719ce78cdffdd83a1302c0 - # which heavily changes the way the code works. - # - # TODO(grfn): address this properly - "-Wno-error=array-bounds" - ]; - - AVR_ASFLAGS = AVR_CFLAGS; - - patches = [ ./increase-tapping-delay.patch ]; - - postPatch = '' - mkdir keyboards/ergodox_ez/keymaps/grfn - cp ${./keymap.c} keyboards/ergodox_ez/keymaps/grfn/keymap.c - ''; - - buildPhase = '' - make ergodox_ez:grfn - ''; - - installPhase = '' - cp ergodox_ez_grfn.hex $out - ''; - }; - - flash = writeShellScript "flash.sh" '' - ${teensy-loader-cli}/bin/teensy-loader-cli \ - -v \ - --mcu=atmega32u4 \ - -w ${layout} - ''; - - meta.ci.targets = [ "layout" ]; -} diff --git a/users/aspen/keyboard/flash b/users/aspen/keyboard/flash deleted file mode 100755 index ab6557a44..000000000 --- a/users/aspen/keyboard/flash +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -exec "$(nix-build --no-out-link ../../.. -A users.aspen.keyboard.flash)" diff --git a/users/aspen/keyboard/increase-tapping-delay.patch b/users/aspen/keyboard/increase-tapping-delay.patch deleted file mode 100644 index 316c435fe..000000000 --- a/users/aspen/keyboard/increase-tapping-delay.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/keyboards/ergodox_ez/config.h b/keyboards/ergodox_ez/config.h -index ae70c4f2e..776110c09 100644 ---- a/keyboards/ergodox_ez/config.h -+++ b/keyboards/ergodox_ez/config.h -@@ -45,7 +45,7 @@ along with this program. If not, see . - /* define if matrix has ghost */ - //#define MATRIX_HAS_GHOST - --#define TAPPING_TERM 200 -+#define TAPPING_TERM 150 - #define IGNORE_MOD_TAP_INTERRUPT // this makes it possible to do rolling combos (zx) with keys that convert to other keys on hold (z becomes ctrl when you hold it, and when this option isn't enabled, z rapidly followed by x actually sends Ctrl-x. That's bad.) - - /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ diff --git a/users/aspen/keyboard/keymap.c b/users/aspen/keyboard/keymap.c deleted file mode 100644 index 741b7b2cf..000000000 --- a/users/aspen/keyboard/keymap.c +++ /dev/null @@ -1,206 +0,0 @@ -#include QMK_KEYBOARD_H -#include "debug.h" -#include "action_layer.h" -#include "version.h" - - -#include "keymap_german.h" - -#include "keymap_nordic.h" - - - -enum custom_keycodes { - PLACEHOLDER = SAFE_RANGE, // can always be here - EPRM, - VRSN, - RGB_SLD, - - EX_PIPE, // |> - THIN_ARROW, // -> - FAT_ARROW, // => -}; - - - -#define LAMBDA UC(0x03BB) - -const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { - - [0] = LAYOUT_ergodox( - KC_EQUAL, KC_1, KC_2, KC_3, KC_4, KC_5, KC_LEFT, - KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_LALT, - KC_ESCAPE, KC_A, KC_S, KC_D, KC_F, KC_G, - KC_LSFT, CTL_T(KC_Z), KC_X, KC_C, KC_V, KC_B, KC_TAB, - LT(1,KC_GRAVE), KC_QUOTE, LALT(KC_LSHIFT),KC_LEFT,KC_RIGHT, - ALT_T(KC_APPLICATION), KC_SPACE, - KC_LBRACKET, - KC_LGUI, LSFT_T(KC_BSPACE), KC_COLN, - - KC_MY_COMPUTER, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINUS, - KC_RALT, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSLASH, - KC_H, KC_J, KC_K, KC_L, LT(2,KC_SCOLON), LT(1,KC_QUOTE), - KC_MINUS, KC_N, KC_M, KC_COMMA, KC_DOT, CTL_T(KC_SLASH), KC_RSFT, - KC_DOWN,KC_UP, KC_LBRACKET,KC_RBRACKET,MO(1), - - KC_PAUSE, TG(3), - KC_RBRACKET, - KC_COLN, RSFT_T(KC_ENTER), KC_SPACE - ), - - [1] = LAYOUT_ergodox( - KC_ESCAPE, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_TRANSPARENT, - KC_TRANSPARENT, KC_EXLM, KC_AT, KC_LCBR, KC_RCBR, KC_PIPE, KC_RABK, - KC_TRANSPARENT, KC_HASH, KC_DLR, KC_LPRN, KC_RPRN, KC_UNDERSCORE, - KC_LABK, KC_PERC, KC_CIRC, KC_LBRACKET, KC_RBRACKET, KC_TILD, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - RGB_MOD, KC_TRANSPARENT, - KC_TRANSPARENT, - RGB_VAD, RGB_VAI, EX_PIPE, - - KC_TRANSPARENT, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, - KC_PGUP, KC_UP, KC_7, KC_8, KC_9, KC_ASTR, KC_F12, - KC_DOWN, KC_4, KC_5, KC_6, KC_PLUS, KC_TRANSPARENT, - KC_PGDOWN, KC_AMPR, KC_1, KC_2, KC_3, KC_BSLASH, KC_TRANSPARENT, - KC_TRANSPARENT, KC_DOT, KC_0, KC_EQUAL, KC_TRANSPARENT, - RGB_TOG, RGB_SLD, - THIN_ARROW, - EX_PIPE, RGB_HUD, RGB_HUI - ), - - [2] = LAYOUT_ergodox( - KC_SCROLLLOCK, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_MS_UP, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_MS_LEFT, KC_MS_DOWN, KC_MS_RIGHT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_MS_BTN1, KC_MS_BTN2, - KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, - KC_MS_BTN1, KC_MS_BTN2, KC_TRANSPARENT, - - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_MS_WH_DOWN, KC_MS_WH_UP, KC_TRANSPARENT, KC_TRANSPARENT, KC_MEDIA_PLAY_PAUSE, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_MEDIA_PREV_TRACK, KC_MEDIA_NEXT_TRACK, KC_TRANSPARENT, KC_TRANSPARENT, - KC_AUDIO_VOL_DOWN, KC_AUDIO_VOL_UP, KC_AUDIO_MUTE, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_WWW_BACK), - - // FPS layout - [3] = LAYOUT_ergodox( - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, - KC_SPACE, KC_TRANSPARENT, KC_TRANSPARENT, - - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT, - KC_TRANSPARENT, TG(3), - KC_TRANSPARENT, - KC_TRANSPARENT, KC_TRANSPARENT, KC_TRANSPARENT), -}; - -const uint16_t PROGMEM fn_actions[] = { - [1] = ACTION_LAYER_TAP_TOGGLE(1) -}; - -// leaving this in place for compatibilty with old keymaps cloned and re-compiled. -const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) -{ - switch(id) { - case 0: - if (record->event.pressed) { - SEND_STRING (QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION); - } - break; - } - return MACRO_NONE; -}; - -bool process_record_user(uint16_t keycode, keyrecord_t *record) { - switch (keycode) { - // dynamically generate these. - case EPRM: - if (record->event.pressed) { - eeconfig_init(); - } - return false; - break; - case VRSN: - if (record->event.pressed) { - SEND_STRING (QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION); - } - return false; - break; - case RGB_SLD: - if (record->event.pressed) { - rgblight_mode(1); - } - return false; - break; - case EX_PIPE: - if (record->event.pressed) { - SEND_STRING ( "|> " ); - } - return false; - break; - case THIN_ARROW: - if (record->event.pressed) { - SEND_STRING ( "-> " ); - } - return false; - break; - - - } - return true; -} - -void matrix_scan_user(void) { - - uint8_t layer = biton32(layer_state); - - ergodox_board_led_off(); - ergodox_right_led_1_off(); - ergodox_right_led_2_off(); - ergodox_right_led_3_off(); - switch (layer) { - case 1: - ergodox_right_led_1_on(); - break; - case 2: - ergodox_right_led_2_on(); - break; - case 3: - ergodox_right_led_3_on(); - break; - case 4: - ergodox_right_led_1_on(); - ergodox_right_led_2_on(); - break; - case 5: - ergodox_right_led_1_on(); - ergodox_right_led_3_on(); - break; - case 6: - ergodox_right_led_2_on(); - ergodox_right_led_3_on(); - break; - case 7: - ergodox_right_led_1_on(); - ergodox_right_led_2_on(); - ergodox_right_led_3_on(); - break; - default: - break; - } - -}; diff --git a/users/aspen/keys.nix b/users/aspen/keys.nix deleted file mode 100644 index 29d5a3fa6..000000000 --- a/users/aspen/keys.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ ... }: -{ - whitby = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDIwl+xQYRCk6Ijz/Ll8eXKZrcTH9/7xwlvIowiuqDSFtGkf+73QJkwVJ0YiKHWAPwIUWMzCEO/Ab2g6j4PcR+XYu8kXbrwT5aW65L/AK1oaav2RfV1bnQEVUP9FRPL52BN42J0ibI2QJZKJVws9JF7vxTWPPG0V0eoxcaRMk1ZEqq+/k3GuN8D69VSV8xo9lB8yZEvTxs0YQRiiF7Q6t/3jhYtz6lCdazQviRcSEOj5AVsDjcf1XIAPOcLK4Q4OEXL49T3UaitSYMyKIO8hzNLiyGAUlSbshAnutPXdyNBypkCs6FrSPSRdBfFjzUVE/a+JWCPmx0q0xAVd497Efxby+Vsa2/TPMp7tSisPaqk3MpPmjBS7eI/y4Pl2GpAB4OVANEBNd1Q6K2/37Pk+PrZtIUBiRG8sM0Od36BjwLCxvG0G5P/UYZ93aC8GzqkRf4evOBMiJCvR2o9CDEDycNyTm1y5dyJzQewOTWX9nsiF1rllc92W0ZALvpO03+W2+k= grfn@chupacabra"; - main = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMcBGBoWd5pPIIQQP52rcFOQN3wAY0J/+K2fuU6SffjA"; - old = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHPiNpPB6Uqs/VSW/C8tR/Z5wCQxKppNL2iETb1ucsYsFf1B2apG5txj06NMT6IWXwWpZXq7ld+/sA+a2I03lO2INP7S1Dto5nAwpNhhKN/UBXk76qYTdY5tEvb9J89S2ZzfQWR30aZ0CEDDrcbc+YktU1eSLdluu6QH+M/uPBweSiVn5wNHkc5sRdbyiVsZSQJ41MO7PQrzGpe7Pxola/ghOHdEFlESJMKA5uoRpCGboxtDE9tMJwG5MxNwHERpfI9FjvvLsJRrp9dRf6A/RQjlV/nb1GmpX0I8pvrXEPxm/l0rOAgE81VSsM+BxJ7ZvCe8u/YqMYJ8xVfskzlVsf griffin@MacBook-Pro"; -} diff --git a/users/aspen/org-clubhouse/.gitignore b/users/aspen/org-clubhouse/.gitignore deleted file mode 100644 index 2a7dd97de..000000000 --- a/users/aspen/org-clubhouse/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Spacemacs -org-clubhouse-autoloads.el -org-clubhouse-pkg.el diff --git a/users/aspen/org-clubhouse/CODE_OF_CONDUCT.org b/users/aspen/org-clubhouse/CODE_OF_CONDUCT.org deleted file mode 100644 index f15e387d5..000000000 --- a/users/aspen/org-clubhouse/CODE_OF_CONDUCT.org +++ /dev/null @@ -1,101 +0,0 @@ -* Contributor Covenant Code of Conduct - :PROPERTIES: - :CUSTOM_ID: contributor-covenant-code-of-conduct - :END: - -** Our Pledge - :PROPERTIES: - :CUSTOM_ID: our-pledge - :END: - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our -project and our community a harassment-free experience for everyone, -regardless of age, body size, disability, ethnicity, sex -characteristics, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, -race, religion, or sexual identity and orientation. - -** Our Standards - :PROPERTIES: - :CUSTOM_ID: our-standards - :END: - -Examples of behavior that contributes to creating a positive environment -include: - -- Using welcoming and inclusive language -- Being respectful of differing viewpoints and experiences -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -- The use of sexualized language or imagery and unwelcome sexual - attention or advances -- Trolling, insulting/derogatory comments, and personal or political - attacks -- Public or private harassment -- Publishing others' private information, such as a physical or - electronic address, without explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -** Our Responsibilities - :PROPERTIES: - :CUSTOM_ID: our-responsibilities - :END: - -Project maintainers are responsible for clarifying the standards of -acceptable behavior and are expected to take appropriate and fair -corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, -or reject comments, commits, code, wiki edits, issues, and other -contributions that are not aligned to this Code of Conduct, or to ban -temporarily or permanently any contributor for other behaviors that they -deem inappropriate, threatening, offensive, or harmful. - -** Scope - :PROPERTIES: - :CUSTOM_ID: scope - :END: - -This Code of Conduct applies within all project spaces, and it also -applies when an individual is representing the project or its community -in public spaces. Examples of representing a project or community -include using an official project e-mail address, posting via an -official social media account, or acting as an appointed representative -at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -** Enforcement - :PROPERTIES: - :CUSTOM_ID: enforcement - :END: - -Instances of abusive, harassing, or otherwise unacceptable behavior may -be reported by contacting the project team at root@gws.fyi. All -complaints will be reviewed and investigated and will result in a -response that is deemed necessary and appropriate to the circumstances. -The project team is obligated to maintain confidentiality with regard to -the reporter of an incident. Further details of specific enforcement -policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in -good faith may face temporary or permanent repercussions as determined -by other members of the project's leadership. - -** Attribution - :PROPERTIES: - :CUSTOM_ID: attribution - :END: - -This Code of Conduct is adapted from the -[[https://www.contributor-covenant.org][Contributor Covenant]], version -1.4, available at -https://www.contributor-covenant.org/version/1/4/code-of-conduct.html - -For answers to common questions about this code of conduct, see -https://www.contributor-covenant.org/faq diff --git a/users/aspen/org-clubhouse/LICENSE b/users/aspen/org-clubhouse/LICENSE deleted file mode 100644 index 1777f0fac..000000000 --- a/users/aspen/org-clubhouse/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (C) 2018 Off Market Data, Inc. DBA Urbint - -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/users/aspen/org-clubhouse/README.org b/users/aspen/org-clubhouse/README.org deleted file mode 100644 index 9cd8fbe89..000000000 --- a/users/aspen/org-clubhouse/README.org +++ /dev/null @@ -1,142 +0,0 @@ -#+TITLE:Org-Clubhouse - -Simple, unopinionated integration between Emacs's [[https://orgmode.org/][org-mode]] and the [[https://clubhouse.io/][Clubhouse]] -issue tracker - -(This used to be at urbint/org-clubhouse, by the way, but moved here as it's -more of a personal project than a company one) - -* Installation - -** [[https://github.com/quelpa/quelpa][Quelpa]] - -#+BEGIN_SRC emacs-lisp -(quelpa '(org-clubhouse - :fetcher github - :repo "glittershark/org-clubhouse")) -#+END_SRC - -** [[https://github.com/hlissner/doom-emacs/][DOOM Emacs]] - -#+BEGIN_SRC emacs-lisp -;; in packages.el -(package! org-clubhouse - :recipe (:fetcher github - :repo "glittershark/org-clubhouse" - :files ("*"))) - -;; in config.el -(def-package! org-clubhouse) -#+END_SRC - -** [[http://spacemacs.org/][Spacemacs]] -#+BEGIN_SRC emacs-lisp -;; in .spacemacs (SPC+fed) - dotspacemacs-additional-packages - '((org-clubhouse :location (recipe :fetcher github :repo "glittershark/org-clubhouse"))) -#+END_SRC - - -* Setup - -Once installed, you'll need to set three global config vars: - -#+BEGIN_SRC emacs-lisp -(setq org-clubhouse-auth-token "" - org-clubhouse-team-name "" - org-clubhouse-username "") -#+END_SRC - -You can generate a new personal API token by going to the "API Tokens" tab on -the "Settings" page in the clubhouse UI. - -Note that ~org-clubhouse-username~ needs to be set to your *mention name*, not -your username, as currently there's no way to get the ID of a user given their -username in the clubhouse API - -* Usage - -** Reading from clubhouse - -- ~org-clubhouse-headlines-from-query~ - Create org-mode headlines from a [[https://help.clubhouse.io/hc/en-us/articles/360000046646-Searching-in-Clubhouse-Story-Search][clubhouse query]] at the cursor's current - position, prompting for the headline indentation level and clubhouse query - text -- ~org-clubhouse-headline-from-story~ - Prompts for headline indentation level and the title of a story (which will - complete using the titles of all stories in your Clubhouse workspace) and - creates an org-mode headline from that story -- ~org-clubhouse-headline-from-story-id~ - Creates an org-mode headline directly from the ID of a clubhouse story - -** Writing to clubhouse - -- ~org-clubhouse-create-story~ - Creates a new Clubhouse story from the current headline, or if a region of - headlines is selected bulk-creates stories with all those headlines -- ~org-clubhouse-create-epic~ - Creates a new Clubhouse epic from the current headline, or if a region of - headlines is selected bulk-creates epics with all those headlines -- ~org-clubhouse-create-story-with-task-list~ - Creates a Clubhouse story from the current headline, making all direct - children of the headline into tasks in the task list of the story -- ~org-clubhouse-push-task-list~ - Writes each child element of the current clubhouse element as a task list - item of the associated clubhouse ID. -- ~org-clubhouse-update-story-title~ - Updates the title of the Clubhouse story linked to the current headline with - the text of the headline -- ~org-clubhouse-update-description~ - Update the status of the Clubhouse story linked to the current element with - the contents of a drawer inside the element called DESCRIPTION, if any exists -- ~org-clubhouse-claim~ - Adds the user configured in ~org-clubhouse-username~ as the owner of the - clubhouse story associated with the headline at point - -*** Automatically updating Clubhouse story statuses - -Org-clubhouse can be configured to update the status of stories as you update -their todo-keyword in org-mode. To opt-into this behavior, set the -~org-clubhouse-mode~ minor-mode: - -#+BEGIN_SRC emacs-lisp -(add-hook 'org-mode-hook #'org-clubhouse-mode nil nil) -#+END_SRC - -The mapping from org-mode todo-keywords is configured via the -~org-clubhouse-state-alist~ variable, which should be an [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Association-Lists.html][alist]] mapping (string) -[[https://orgmode.org/manual/Workflow-states.html][org-mode todo-keywords]] to the (string) names of their corresponding workflow -state. You can have todo-keywords that don't map to a workflow state (I use this -in my workflow extensively) and org-clubhouse will just preserve the previous -state of the story when moving to that state. - -An example config: - -#+BEGIN_SRC emacs-lisp -(setq org-clubhouse-state-alist - '(("TODO" . "To Do") - ("ACTIVE" . "In Progress") - ("DONE" . "Done"))) -#+END_SRC - -* Philosophy - -I use org-mode every single day to manage tasks, notes, literate programming, -etc. Part of what that means for me is that I already have a system for the -structure of my .org files, and I don't want to sacrifice that system for any -external tool. Updating statuses, ~org-clubhouse-create-story~, and -~org-clubhouse-headline-from-story~ are my bread and butter for that reason - -rather than having some sort of bidirectional sync that pulls down full lists of -all the stories in Clubhouse (or whatever issue tracker / project management -tool I'm using at the time). I can be in a mode where I'm taking meeting notes, -think of something that I need to do, make it a TODO headline, and make that -TODO headline a clubhouse story. That's the same reason for the DESCRIPTION -drawers rather than just sending the entire contents of a headline to -Clubhouse - I almost always want to write things like personal notes, literate -code, etc inside of the tasks I'm working on, and don't always want to share -that with Clubhouse. - -* Configuration - -Refer to the beginning of the [[https://github.com/urbint/org-clubhouse/blob/master/org-clubhouse.el][org-clubhouse.el]] file in this repository for -documentation on all supported configuration variables diff --git a/users/aspen/org-clubhouse/org-clubhouse.el b/users/aspen/org-clubhouse/org-clubhouse.el deleted file mode 100644 index e6e29b575..000000000 --- a/users/aspen/org-clubhouse/org-clubhouse.el +++ /dev/null @@ -1,1241 +0,0 @@ -;;; org-clubhouse.el --- Simple, unopinionated integration between org-mode and -;;; Clubhouse - -;;; Copyright (C) 2018 Off Market Data, Inc. DBA Urbint -;;; 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. - -;;; Commentary: -;;; org-clubhouse provides simple, unopinionated integration between Emacs's -;;; org-mode and the Clubhouse issue tracker -;;; -;;; To configure org-clubhouse, create an authorization token in Cluhbouse's -;;; settings, then place the following configuration somewhere private: -;;; -;;; (setq org-clubhouse-auth-token "" -;;; org-clubhouse-team-name "") -;;; - -;;; Code: - -(require 'cl-macs) -(require 'dash) -(require 'dash-functional) -(require 's) -(require 'org) -(require 'org-element) -(require 'subr-x) -(require 'ivy) -(require 'json) - -;;; -;;; Configuration -;;; - -(defvar org-clubhouse-auth-token nil - "Authorization token for the Clubhouse API.") - -(defvar org-clubhouse-username nil - "Username for the current Clubhouse user. - -Unfortunately, the Clubhouse API doesn't seem to provide this via the API given -an API token, so we need to configure this for -`org-clubhouse-claim-story-on-status-updates' to work") - -(defvar org-clubhouse-team-name nil - "Team name to use in links to Clubhouse. -ie https://app.clubhouse.io//stories") - -(defvar org-clubhouse-project-ids nil - "Specific list of project IDs to synchronize with clubhouse. -If unset all projects will be synchronized") - -(defvar org-clubhouse-workflow-name "Default") - -(defvar org-clubhouse-default-story-type nil - "Sets the default story type. If set to 'nil', it will interactively prompt -the user each and every time a new story is created. If set to 'feature', -'bug', or 'chore', that value will be used as the default and the user will -not be prompted") - -(defvar org-clubhouse-state-alist - '(("LATER" . "Unscheduled") - ("[ ]" . "Ready for Development") - ("TODO" . "Ready for Development") - ("OPEN" . "Ready for Development") - ("ACTIVE" . "In Development") - ("PR" . "Review") - ("DONE" . "Merged") - ("[X]" . "Merged") - ("CLOSED" . "Merged")) - "Alist mapping org-mode todo keywords to their corresponding states in - Clubhouse. In `org-clubhouse-mode', moving headlines to these todo keywords - will update to the corresponding status in Clubhouse") - -(defvar org-clubhouse-story-types - '(("feature" . "Feature") - ("bug" . "Bug") - ("chore" . "Chore"))) - -(defvar org-clubhouse-default-story-types - '(("feature" . "Feature") - ("bug" . "Bug") - ("chore" . "Chore") - ("prompt" . "**Prompt each time (do not set a default story type)**"))) - -(defvar org-clubhouse-default-state "Proposed" - "Default state to create all new stories in.") - -(defvar org-clubhouse-claim-story-on-status-update 't - "Controls the assignee behavior of stories on status update. - -If set to 't, will mark the current user as the owner of any clubhouse -stories on any update to the status. - -If set to nil, will never automatically update the assignee of clubhouse -stories. - -If set to a list of todo-state's, will mark the current user as the owner of -clubhouse stories whenever updating the status to one of those todo states.") - -(defvar org-clubhouse-create-stories-with-labels nil - "Controls the way org-clubhouse creates stories with labels based on org tags. - -If set to 't, will create labels for all org tags on headlines when stories are -created. - -If set to 'existing, will set labels on created stories only if the label -already exists in clubhouse - -If set to nil, will never create stories with labels") - -;;; -;;; Utilities -;;; - -(defmacro comment (&rest _) - "Comment out one or more s-expressions." - nil) - -(defun ->list (vec) (append vec nil)) - -(defun reject-archived (item-list) - (-reject (lambda (item) (equal :json-true (alist-get 'archived item))) item-list)) - -(defun alist->plist (key-map alist) - (->> key-map - (-map (lambda (key-pair) - (let ((alist-key (car key-pair)) - (plist-key (cdr key-pair))) - (list plist-key (alist-get alist-key alist))))) - (-flatten-n 1))) - -(defun alist-get-equal (key alist) - "Like `alist-get', but uses `equal' instead of `eq' for comparing keys" - (->> alist - (-find (lambda (pair) (equal key (car pair)))) - (cdr))) - -(defun invert-alist (alist) - "Invert the keys and values of ALIST." - (-map (lambda (cell) (cons (cdr cell) (car cell))) alist)) - -(comment - - (alist->plist - '((foo . :foo) - (bar . :something)) - - '((foo . "foo") (bar . "bar") (ignored . "ignoreme!"))) - ;; => (:foo "foo" :something "bar") - - ) - -(defun find-match-in-alist (target alist) - (->> alist - (-find (lambda (key-value) - (string-equal (cdr key-value) target))) - car)) - -(defun org-clubhouse-collect-headlines (beg end) - "Collects the headline at point or the headlines in a region. Returns a list." - (if (and beg end) - (org-clubhouse-get-headlines-in-region beg end) - (list (org-element-find-headline)))) - - -(defun org-clubhouse-get-headlines-in-region (beg end) - "Collects the headlines from BEG to END" - (save-excursion - ;; This beg/end clean up pulled from `reverse-region`. - ;; it expands the region to include the full lines from the selected region. - - ;; put beg at the start of a line and end and the end of one -- - ;; the largest possible region which fits this criteria - (goto-char beg) - (or (bolp) (forward-line 1)) - (setq beg (point)) - (goto-char end) - ;; the test for bolp is for those times when end is on an empty line; - ;; it is probably not the case that the line should be included in the - ;; reversal; it isn't difficult to add it afterward. - (or (and (eolp) (not (bolp))) (progn (forward-line -1) (end-of-line))) - (setq end (point-marker)) - - ;; move to the beginning - (goto-char beg) - ;; walk by line until past end - (let ((headlines '()) - (before-end 't)) - (while before-end - (add-to-list 'headlines (org-element-find-headline)) - (let ((before (point))) - (org-forward-heading-same-level 1) - (setq before-end (and (not (eq before (point))) (< (point) end))))) - (reverse headlines)))) - -;;; -;;; Org-element interaction -;;; - -;; (defun org-element-find-headline () -;; (let ((current-elt (org-element-at-point))) -;; (if (equal 'headline (car current-elt)) -;; current-elt -;; (let* ((elt-attrs (cadr current-elt)) -;; (parent (plist-get elt-attrs :post-affiliated))) -;; (goto-char parent) -;; (org-element-find-headline))))) - -(defun org-element-find-headline () - (save-mark-and-excursion - (when (not (outline-on-heading-p)) (org-back-to-heading)) - (let ((current-elt (org-element-at-point))) - (when (equal 'headline (car current-elt)) - (cadr current-elt))))) - -(defun org-element-extract-clubhouse-id (elt &optional property) - (when-let* ((clubhouse-id-link (plist-get elt (or property :CLUBHOUSE-ID)))) - (cond - ((string-match - (rx "[[" (one-or-more anything) "]" - "[" (group (one-or-more digit)) "]]") - clubhouse-id-link) - (string-to-number (match-string 1 clubhouse-id-link))) - ((string-match-p - (rx buffer-start - (one-or-more digit) - buffer-end) - clubhouse-id-link) - (string-to-number clubhouse-id-link))))) - -(comment - (let ((strn "[[https://app.clubhouse.io/example/story/2330][2330]]")) - (string-match - (rx "[[" (one-or-more anything) "]" - "[" (group (one-or-more digit)) "]]") - strn) - (string-to-number (match-string 1 strn))) - ) - -(defun org-element-clubhouse-id () - (org-element-extract-clubhouse-id - (org-element-find-headline))) - -(defun org-clubhouse-clocked-in-story-id () - "Return the clubhouse story-id of the currently clocked-in org entry, if any." - (save-mark-and-excursion - (save-current-buffer - (when (org-clocking-p) - (set-buffer (marker-buffer org-clock-marker)) - (save-restriction - (when (or (< org-clock-marker (point-min)) - (> org-clock-marker (point-max))) - (widen)) - (goto-char org-clock-marker) - (org-element-clubhouse-id)))))) - -(comment - (org-clubhouse-clocked-in-story-id) - ) - -(defun org-element-and-children-at-point () - (let* ((elt (org-element-find-headline)) - (contents-begin (or (plist-get elt :contents-begin) - (plist-get elt :begin))) - (end (plist-get elt :end)) - (level (plist-get elt :level)) - (children '())) - (save-excursion - (goto-char (+ contents-begin (length (plist-get elt :title)))) - (while (< (point) end) - (let* ((next-elt (org-element-at-point)) - (elt-type (car next-elt)) - (elt (cadr next-elt))) - (when (and (eql 'headline elt-type) - (eql (+ 1 level) (plist-get elt :level))) - (push elt children)) - (goto-char (plist-get elt :end))))) - (append elt `(:children ,(reverse children))))) - -(defun +org-element-contents (elt) - (if-let ((begin (plist-get (cadr elt) :contents-begin)) - (end (plist-get (cadr elt) :contents-end))) - (buffer-substring-no-properties begin end) - "")) - -(defun org-clubhouse-find-description-drawer () - "Try to find a DESCRIPTION drawer in the current element." - (let ((elt (org-element-at-point))) - (cl-case (car elt) - ('drawer (+org-element-contents elt)) - ('headline - (when-let ((drawer-pos (string-match - ":DESCRIPTION:" - (+org-element-contents elt)))) - (save-excursion - (goto-char (+ (plist-get (cadr elt) :contents-begin) - drawer-pos)) - (org-clubhouse-find-description-drawer))))))) - -(defun org-clubhouse--labels-for-elt (elt) - "Return the Clubhouse labels based on the tags of ELT and the user's config." - (unless (eq nil org-clubhouse-create-stories-with-labels) - (let ((tags (org-get-tags (plist-get elt :contents-begin)))) - (-map (lambda (l) `((name . ,l))) - (cl-case org-clubhouse-create-stories-with-labels - ('t tags) - ('existing (-filter (lambda (tag) (-some (lambda (l) - (string-equal tag (cdr l))) - (org-clubhouse-labels))) - tags))))))) - -;;; -;;; API integration -;;; - -(defvar org-clubhouse-base-url* "https://api.clubhouse.io/api/v3") - -(defun org-clubhouse-auth-url (url &optional params) - (concat url - "?" - (url-build-query-string - (cons `("token" ,org-clubhouse-auth-token) params)))) - -(defun org-clubhouse-baseify-url (url) - (if (s-starts-with? org-clubhouse-base-url* url) url - (concat org-clubhouse-base-url* - (if (s-starts-with? "/" url) url - (concat "/" url))))) - -(cl-defun org-clubhouse-request (method url &key data (params '())) - (message "%s %s %s" method url (prin1-to-string data)) - (let* ((url-request-method method) - (url-request-extra-headers - '(("Content-Type" . "application/json"))) - (url-request-data data) - (buf)) - - (setq url (-> url - org-clubhouse-baseify-url - (org-clubhouse-auth-url params))) - - (setq buf (url-retrieve-synchronously url)) - - (with-current-buffer buf - (goto-char url-http-end-of-headers) - (prog1 (json-read) (kill-buffer))))) - -(cl-defun to-id-name-pairs - (seq &optional (id-attr 'id) (name-attr 'name)) - (->> seq - ->list - (-map (lambda (resource) - (cons (alist-get id-attr resource) - (alist-get name-attr resource)))))) - -(cl-defun org-clubhouse-fetch-as-id-name-pairs - (resource &optional - (id-attr 'id) - (name-attr 'name)) - "Returns the given resource from clubhouse as (id . name) pairs" - (let ((resp-json (org-clubhouse-request "GET" resource))) - (-> resp-json - ->list - reject-archived - (to-id-name-pairs id-attr name-attr)))) - -(defun org-clubhouse-get-story - (clubhouse-id) - (org-clubhouse-request "GET" (format "/stories/%s" clubhouse-id))) - -(defun org-clubhouse-link-to-story (story-id) - (format "https://app.clubhouse.io/%s/story/%d" - org-clubhouse-team-name - story-id)) - -(defun org-clubhouse-link-to-epic (epic-id) - (format "https://app.clubhouse.io/%s/epic/%d" - org-clubhouse-team-name - epic-id)) - -(defun org-clubhouse-link-to-milestone (milestone-id) - (format "https://app.clubhouse.io/%s/milestone/%d" - org-clubhouse-team-name - milestone-id)) - -(defun org-clubhouse-link-to-project (project-id) - (format "https://app.clubhouse.io/%s/project/%d" - org-clubhouse-team-name - project-id)) - -;;; -;;; Caching -;;; - -(comment - (defcache org-clubhouse-projects - (org-sync-clubhouse-fetch-as-id-name-pairs "projectx")) - - (clear-org-clubhouse-projects-cache) - (clear-org-clubhouse-cache) - ) - -(defvar org-clubhouse-cache-clear-functions ()) - -(defmacro defcache (name &optional docstring &rest body) - (let* ((doc (when docstring (list docstring))) - (cache-var-name (intern (concat (symbol-name name) - "-cache"))) - (clear-cache-function-name - (intern (concat "clear-" (symbol-name cache-var-name))))) - `(progn - (defvar ,cache-var-name :no-cache) - (defun ,name () - ,@doc - (when (equal :no-cache ,cache-var-name) - (setq ,cache-var-name (progn ,@body))) - ,cache-var-name) - (defun ,clear-cache-function-name () - (interactive) - (setq ,cache-var-name :no-cache)) - - (push (quote ,clear-cache-function-name) - org-clubhouse-cache-clear-functions)))) - -(defun org-clubhouse-clear-cache () - (interactive) - (-map #'funcall org-clubhouse-cache-clear-functions)) - -;;; -;;; API resource functions -;;; - -(defcache org-clubhouse-projects - "Returns projects as (project-id . name)" - (org-clubhouse-fetch-as-id-name-pairs "projects")) - -(defcache org-clubhouse-epics - "Returns epics as (epic-id . name)" - (org-clubhouse-fetch-as-id-name-pairs "epics")) - -(defcache org-clubhouse-milestones - "Returns milestone-id . name)" - (org-clubhouse-fetch-as-id-name-pairs "milestones")) - -(defcache org-clubhouse-workflow-states - "Returns worflow states as (name . id) pairs" - (let* ((resp-json (org-clubhouse-request "GET" "workflows")) - (workflows (->list resp-json)) - ;; just assume it exists, for now - (workflow (-find (lambda (workflow) - (equal org-clubhouse-workflow-name - (alist-get 'name workflow))) - workflows)) - (states (->list (alist-get 'states workflow)))) - (to-id-name-pairs states - 'name - 'id))) - -(defcache org-clubhouse-labels - "Returns labels as (label-id . name)" - (org-clubhouse-fetch-as-id-name-pairs "labels")) - -(defcache org-clubhouse-whoami - "Returns the ID of the logged in user" - (->> (org-clubhouse-request - "GET" - "/members") - ->list - (find-if (lambda (m) - (->> m - (alist-get 'profile) - (alist-get 'mention_name) - (equal org-clubhouse-username)))) - (alist-get 'id))) - -(defcache org-clubhouse-iterations - "Returns iterations as (iteration-id . name)" - (org-clubhouse-fetch-as-id-name-pairs "iterations")) - -(defun org-clubhouse-stories-in-project (project-id) - "Return the stories in the given PROJECT-ID as org headlines." - (let ((resp-json (org-clubhouse-request "GET" (format "/projects/%d/stories" project-id)))) - (->> resp-json ->list reject-archived - (-reject (lambda (story) (equal :json-true (alist-get 'completed story)))) - (-map (lambda (story) - (cons - (cons 'status - (cond - ((equal :json-true (alist-get 'started story)) - 'started) - ((equal :json-true (alist-get 'completed story)) - 'completed) - ('t - 'open))) - story))) - (-map (-partial #'alist->plist - '((name . :title) - (id . :id) - (status . :status))))))) - -(defun org-clubhouse-workflow-state-id-to-todo-keyword (workflow-state-id) - "Convert the named clubhouse WORKFLOW-STATE-ID to an org todo keyword." - (let* ((state-name (alist-get-equal - workflow-state-id - (invert-alist (org-clubhouse-workflow-states)))) - (inv-state-name-alist - (-map (lambda (cell) (cons (cdr cell) (car cell))) - org-clubhouse-state-alist))) - (or (alist-get-equal state-name inv-state-name-alist) - (if state-name (s-upcase state-name) "UNKNOWN")))) - -;;; -;;; Prompting -;;; - -(defun org-clubhouse-prompt-for-project (cb) - (ivy-read - "Select a project: " - (-map #'cdr (org-clubhouse-projects)) - :require-match t - :history 'org-clubhouse-project-history - :action (lambda (selected) - (let ((project-id - (find-match-in-alist selected (org-clubhouse-projects)))) - (funcall cb project-id))))) - -(defun org-clubhouse-prompt-for-epic (cb) - "Prompt the user for an epic using ivy and call CB with its ID." - (ivy-read - "Select an epic: " - (-map #'cdr (append '((nil . "No Epic")) (org-clubhouse-epics))) - :history 'org-clubhouse-epic-history - :action (lambda (selected) - (let ((epic-id - (find-match-in-alist selected (org-clubhouse-epics)))) - (funcall cb epic-id))))) - -(defun org-clubhouse-prompt-for-milestone (cb) - "Prompt the user for a milestone using ivy and call CB with its ID." - (ivy-read - "Select a milestone: " - (-map #'cdr (append '((nil . "No Milestone")) (org-clubhouse-milestones))) - :require-match t - :history 'org-clubhouse-milestone-history - :action (lambda (selected) - (let ((milestone-id - (find-match-in-alist selected (org-clubhouse-milestones)))) - (funcall cb milestone-id))))) - -(defun org-clubhouse-prompt-for-story-type (cb) - (ivy-read - "Select a story type: " - (-map #'cdr org-clubhouse-story-types) - :history 'org-clubhouse-story-history - :action (lambda (selected) - (let ((story-type - (find-match-in-alist selected org-clubhouse-story-types))) - (funcall cb story-type))))) - -(defun org-clubhouse-prompt-for-default-story-type () - (interactive) - (ivy-read - "Select a default story type: " - (-map #'cdr org-clubhouse-default-story-types) - :history 'org-clubhouse-default-story-history - :action (lambda (selected) - (let ((story-type - (find-match-in-alist selected org-clubhouse-default-story-types))) - (if (string-equal story-type "prompt") - (setq org-clubhouse-default-story-type nil) - (setq org-clubhouse-default-story-type story-type)))))) - -;;; -;;; Epic creation -;;; - -(cl-defun org-clubhouse-create-epic-internal - (title &key milestone-id) - (cl-assert (and (stringp title) - (or (null milestone-id) - (integerp milestone-id)))) - (org-clubhouse-request - "POST" - "epics" - :data - (json-encode - `((name . ,title) - (milestone_id . ,milestone-id))))) - -(defun org-clubhouse-populate-created-epic (elt epic) - (let ((elt-start (plist-get elt :begin)) - (epic-id (alist-get 'id epic)) - (milestone-id (alist-get 'milestone_id epic))) - (save-excursion - (goto-char elt-start) - - (org-set-property "clubhouse-epic-id" - (org-link-make-string - (org-clubhouse-link-to-epic epic-id) - (number-to-string epic-id))) - - (when milestone-id - (org-set-property "clubhouse-milestone" - (org-link-make-string - (org-clubhouse-link-to-milestone milestone-id) - (alist-get milestone-id (org-clubhouse-milestones)))))))) - -(defun org-clubhouse-create-epic (&optional beg end) - "Creates a clubhouse epic using selected headlines. -Will pull the title from the headline at point, or create epics for all the -headlines in the selected region. - -All epics are added to the same milestone, as selected via a prompt. -If the epics already have a CLUBHOUSE-EPIC-ID, they are filtered and ignored." - (interactive - (when (use-region-p) - (list (region-beginning region-end)))) - - (let* ((elts (org-clubhouse-collect-headlines beg end)) - (elts (-remove (lambda (elt) (plist-get elt :CLUBHOUSE-EPIC-ID)) elts))) - (org-clubhouse-prompt-for-milestone - (lambda (milestone-id) - (dolist (elt elts) - (let* ((title (plist-get elt :title)) - (epic (org-clubhouse-create-epic-internal - title - :milestone-id milestone-id))) - (org-clubhouse-populate-created-epic elt epic)) - elts))))) - -;;; -;;; Story creation -;;; - -(defun org-clubhouse-default-state-id () - (alist-get-equal org-clubhouse-default-state (org-clubhouse-workflow-states))) - -(cl-defun org-clubhouse-create-story-internal - (title &key project-id epic-id story-type description labels) - (cl-assert (and (stringp title) - (integerp project-id) - (or (null epic-id) (integerp epic-id)) - (or (null description) (stringp description)))) - (let ((workflow-state-id (org-clubhouse-default-state-id)) - (params `((name . ,title) - (project_id . ,project-id) - (epic_id . ,epic-id) - (story_type . ,story-type) - (description . ,(or description "")) - (labels . ,labels)))) - - (when workflow-state-id - (push `(workflow_state_id . ,workflow-state-id) params)) - - (org-clubhouse-request - "POST" - "stories" - :data - (json-encode params)))) - -(cl-defun org-clubhouse-populate-created-story (elt story &key extra-properties) - (let ((elt-start (plist-get elt :begin)) - (story-id (alist-get 'id story)) - (epic-id (alist-get 'epic_id story)) - (project-id (alist-get 'project_id story)) - (story-type (alist-get 'story_type story))) - - (save-excursion - (goto-char elt-start) - - (org-set-property "clubhouse-id" - (org-link-make-string - (org-clubhouse-link-to-story story-id) - (number-to-string story-id))) - (when epic-id - (org-set-property "clubhouse-epic" - (org-link-make-string - (org-clubhouse-link-to-epic epic-id) - (alist-get epic-id (org-clubhouse-epics))))) - - (org-set-property "clubhouse-project" - (org-link-make-string - (org-clubhouse-link-to-project project-id) - (alist-get project-id (org-clubhouse-projects)))) - - (org-set-property "story-type" - (alist-get-equal story-type org-clubhouse-story-types)) - - (dolist (extra-prop extra-properties) - (org-set-property (car extra-prop) - (alist-get (cdr extra-prop) story))) - - (org-todo "TODO")))) - -(defun org-clubhouse-create-story (&optional beg end &key then) - "Creates a clubhouse story using selected headlines. - -Will pull the title from the headline at point, -or create cards for all the headlines in the selected region. - -All stories are added to the same project and epic, as selected via two prompts. -If the stories already have a CLUBHOUSE-ID, they are filtered and ignored." - (interactive - (when (use-region-p) - (list (region-beginning) (region-end)))) - - (let* ((elts (org-clubhouse-collect-headlines beg end)) - (new-elts (-remove (lambda (elt) (plist-get elt :CLUBHOUSE-ID)) elts))) - (org-clubhouse-prompt-for-project - (lambda (project-id) - (when project-id - (org-clubhouse-prompt-for-epic - (lambda (epic-id) - (let ((create-story - (lambda (story-type) - (-map - (lambda (elt) - (let* ((title (plist-get elt :title)) - (description - (save-mark-and-excursion - (goto-char (plist-get elt :begin)) - (org-clubhouse-find-description-drawer))) - (labels (org-clubhouse--labels-for-elt elt)) - (story (org-clubhouse-create-story-internal - title - :project-id project-id - :epic-id epic-id - :story-type story-type - :description description - :labels labels))) - (org-clubhouse-populate-created-story elt story) - (when (functionp then) - (funcall then story)))) - new-elts)))) - (if org-clubhouse-default-story-type - (funcall create-story org-clubhouse-default-story-type) - (org-clubhouse-prompt-for-story-type create-story)))))))))) - -(defun org-clubhouse-create-story-with-task-list (&optional beg end) - "Creates a clubhouse story using the selected headline, making all direct -children of that headline into tasks in the task list of the story." - (interactive - (when (use-region-p) - (list (region-beginning) (region-end)))) - - (let* ((elt (org-element-and-children-at-point))) - (org-clubhouse-create-story nil nil - :then (lambda (story) - (pp story) - (org-clubhouse-push-task-list - (alist-get 'id story) - (plist-get elt :children)))))) - -;;; -;;; Task creation -;;; - -(cl-defun org-clubhouse-create-task (title &key story-id) - (cl-assert (and (stringp title) - (integerp story-id))) - (org-clubhouse-request - "POST" - (format "/stories/%d/tasks" story-id) - :data (json-encode `((description . ,title))))) - -(defun org-clubhouse-push-task-list (&optional parent-clubhouse-id child-elts) - "Writes each child of the element at point as a task list item. - -When called as (org-clubhouse-push-task-list PARENT-CLUBHOUSE-ID CHILD-ELTS), -allows manually passing a clubhouse ID and list of org-element plists to write" - (interactive) - (let* ((elt (org-element-and-children-at-point)) - (parent-clubhouse-id (or parent-clubhouse-id - (org-element-extract-clubhouse-id elt))) - (child-elts (or child-elts (plist-get elt :children))) - (story (org-clubhouse-get-story parent-clubhouse-id)) - (existing-tasks (alist-get 'tasks story)) - (task-exists - (lambda (task-name) - (cl-some (lambda (task) - (string-equal task-name (alist-get 'description task))) - existing-tasks))) - (elts-with-starts - (-map (lambda (e) (cons (set-marker (make-marker) - (plist-get e :begin)) - e)) - child-elts))) - (dolist (child-elt-and-start elts-with-starts) - (let* ((start (car child-elt-and-start)) - (child-elt (cdr child-elt-and-start)) - (task-name (plist-get child-elt :title))) - (unless (funcall task-exists task-name) - (let ((task (org-clubhouse-create-task - task-name - :story-id parent-clubhouse-id))) - (org-clubhouse-populate-created-task child-elt task start))))))) - -(defun org-clubhouse-populate-created-task (elt task &optional begin) - (let ((elt-start (or begin (plist-get elt :begin))) - (task-id (alist-get 'id task)) - (story-id (alist-get 'story_id task))) - - (save-excursion - (goto-char elt-start) - - (org-set-property "clubhouse-task-id" (format "%d" task-id)) - - (org-set-property "clubhouse-story-id" - (org-link-make-string - (org-clubhouse-link-to-story story-id) - (number-to-string story-id))) - - (org-todo "TODO")))) - -;;; -;;; Task Updates -;;; - -(cl-defun org-clubhouse-update-task-internal - (story-id task-id &rest attrs) - (cl-assert (and (integerp story-id) - (integerp task-id) - (listp attrs))) - (org-clubhouse-request - "PUT" - (format "stories/%d/tasks/%d" story-id task-id) - :data - (json-encode attrs))) - -;;; -;;; Story updates -;;; - -(cl-defun org-clubhouse-update-story-internal - (story-id &rest attrs) - (cl-assert (and (integerp story-id) - (listp attrs))) - (org-clubhouse-request - "PUT" - (format "stories/%d" story-id) - :data - (json-encode attrs))) - -(cl-defun org-clubhouse-update-story-at-point (&rest attrs) - (when-let* ((clubhouse-id (org-element-clubhouse-id))) - (apply - #'org-clubhouse-update-story-internal - (cons clubhouse-id attrs)) - t)) - -(defun org-clubhouse-update-story-title () - "Update the title of the Clubhouse story linked to the current headline. - -Update the title of the story linked to the current headline with the text of -the headline." - (interactive) - - (let* ((elt (org-element-find-headline)) - (title (plist-get elt :title)) - (clubhouse-id (org-element-clubhouse-id))) - (and - (org-clubhouse-update-story-at-point - clubhouse-id - :name title) - (message "Successfully updated story title to \"%s\"" - title)))) - -(defun org-clubhouse-update-status () - "Update the status of the Clubhouse story linked to the current element. - -Update the status of the Clubhouse story linked to the current element with the -entry in `org-clubhouse-state-alist' corresponding to the todo-keyword of the -element." - (interactive) - (let* ((elt (org-element-find-headline)) - (todo-keyword (-> elt - (plist-get :todo-keyword) - (substring-no-properties))) - - (clubhouse-id (org-element-extract-clubhouse-id elt)) - (task-id (plist-get elt :CLUBHOUSE-TASK-ID))) - (cond - (clubhouse-id - (let* ((todo-keyword (-> elt - (plist-get :todo-keyword) - (substring-no-properties)))) - (when-let* ((clubhouse-workflow-state - (alist-get-equal todo-keyword org-clubhouse-state-alist)) - (workflow-state-id - (alist-get-equal clubhouse-workflow-state - (org-clubhouse-workflow-states)))) - (let ((update-assignee? - (if (or (eq 't org-clubhouse-claim-story-on-status-update) - (member todo-keyword - org-clubhouse-claim-story-on-status-update)) - (if org-clubhouse-username - 't - (warn "Not claiming story since `org-clubhouse-username' - is not set") - nil)))) - - (if update-assignee? - (org-clubhouse-update-story-internal - clubhouse-id - :workflow_state_id workflow-state-id - :owner_ids (if update-assignee? - (list (org-clubhouse-whoami)) - (list))) - (org-clubhouse-update-story-internal - clubhouse-id - :workflow_state_id workflow-state-id)) - (message - (if update-assignee? - "Successfully claimed story and updated clubhouse status to \"%s\"" - "Successfully updated clubhouse status to \"%s\"") - clubhouse-workflow-state))))) - - (task-id - (let ((story-id (org-element-extract-clubhouse-id - elt - :CLUBHOUSE-STORY-ID)) - (done? (member todo-keyword org-done-keywords))) - (org-clubhouse-update-task-internal - story-id - (string-to-number task-id) - :complete (if done? 't :json-false)) - (message "Successfully marked clubhouse task status as %s" - (if done? "complete" "incomplete"))))))) - -(defun org-clubhouse-update-description () - "Update the description of the Clubhouse story linked to the current element. - -Update the status of the Clubhouse story linked to the current element with the -contents of a drawer inside the element called DESCRIPTION, if any." - (interactive) - (when-let* ((new-description (org-clubhouse-find-description-drawer))) - (and - (org-clubhouse-update-story-at-point - :description new-description) - (message "Successfully updated story description")))) - -(defun org-clubhouse-update-labels () - "Update the labels of the Clubhouse story linked to the current element. - -Will use the value of `org-clubhouse-create-stories-with-labels' to determine -which labels to set." - (interactive) - (when-let* ((elt (org-element-find-headline)) - (new-labels (org-clubhouse--labels-for-elt elt))) - (and - (org-clubhouse-update-story-at-point - :labels new-labels) - (message "Successfully updated story labels to :%s:" - (->> new-labels - (-map #'cdar) - (s-join ":")))))) - - -;;; -;;; Creating headlines from existing stories -;;; - -(defun org-clubhouse--task-to-headline-text (level task) - (format "%s %s %s -:PROPERTIES: -:clubhouse-task-id: %s -:clubhouse-story-id: %s -:END:" - (make-string level ?*) - (if (equal :json-false (alist-get 'complete task)) - "TODO" "DONE") - (alist-get 'description task) - (alist-get 'id task) - (let ((story-id (alist-get 'story_id task))) - (org-link-make-string - (org-clubhouse-link-to-story story-id) - story-id)))) - -(defun org-clubhouse--story-to-headline-text (level story) - (let ((story-id (alist-get 'id story))) - (format - "%s %s %s %s -:PROPERTIES: -:clubhouse-id: %s -:END: -%s -%s -" - (make-string level ?*) - (org-clubhouse-workflow-state-id-to-todo-keyword - (alist-get 'workflow_state_id story)) - (alist-get 'name story) - (if-let ((labels (->> story - (alist-get 'labels) - ->list - (-map (apply-partially #'alist-get 'name))))) - (format ":%s:" (s-join ":" labels)) - "") - (org-link-make-string - (org-clubhouse-link-to-story story-id) - (number-to-string story-id)) - (let ((desc (alist-get 'description story))) - (if (= 0 (length desc)) "" - (format ":DESCRIPTION:\n%s\n:END:" desc))) - (if-let ((tasks (seq-sort-by - (apply-partially #'alist-get 'position) - #'< - (or (alist-get 'tasks story) - (alist-get 'tasks - (org-clubhouse-get-story story-id)))))) - (mapconcat (apply-partially #'org-clubhouse--task-to-headline-text - (1+ level)) - tasks - "\n") - "")))) - -(defun org-clubhouse-headline-from-my-tasks (level) - "Prompt my active stories and create a single `org-mode' headline at LEVEL." - (interactive "*nLevel: \n") - (if org-clubhouse-username - (let* ((story-list (org-clubhouse--search-stories - (format "owner:%s !is:done !is:archived" - org-clubhouse-username))) - (stories (to-id-name-pairs story-list))) - (org-clubhouse-headline-from-story-id level - (find-match-in-alist - (ivy-read "Select Story: " - (-map #'cdr stories)) - stories))) - (warn "Can't fetch my tasks if `org-clubhouse-username' is unset"))) - -(defun org-clubhouse-headline-from-story-id (level story-id) - "Create a single `org-mode' headline at LEVEL based on the given clubhouse STORY-ID." - (interactive "*nLevel: \nnStory ID: ") - (let* ((story (org-clubhouse-get-story story-id))) - (if (equal '((message . "Resource not found.")) story) - (message "Story ID not found: %d" story-id) - (save-mark-and-excursion - (insert (org-clubhouse--story-to-headline-text level story)) - (org-align-tags))))) - -(defun org-clubhouse--search-stories (query) - (unless (string= "" query) - (-> (org-clubhouse-request "GET" "search/stories" :params `((query ,query))) - cdadr - (append nil) - reject-archived))) - -(defun org-clubhouse-prompt-for-iteration (cb) - "Prompt for iteration and call CB with that iteration" - (ivy-read - "Select an interation: " - (-map #'cdr (org-clubhouse-iterations)) - :require-match t - :history 'org-clubhouse-iteration-history - :action (lambda (selected) - (let ((iteration-id - (find-match-in-alist selected (org-clubhouse-iterations)))) - (funcall cb iteration-id))))) - -(defun org-clubhouse--get-iteration (iteration-id) - (-> (org-clubhouse-request "GET" (format "iterations/%d/stories" iteration-id)) - (append nil))) - -(defun org-clubhouse-headlines-from-iteration (level) - "Create `org-mode' headlines from a clubhouse iteration. - -Create `org-mode' headlines from all the resulting stories at headline level LEVEL." - (interactive "*nLevel: ") - (org-clubhouse-prompt-for-iteration - (lambda (iteration-id) - (let ((story-list (org-clubhouse--get-iteration iteration-id))) - (if (null story-list) - (message "Iteration id returned no stories: %d" iteration-id) - (let ((text (mapconcat (apply-partially - #'org-clubhouse--story-to-headline-text - level) - (reject-archived story-list) "\n"))) - (save-mark-and-excursion - (insert text) - (org-align-all-tags)) - text)))))) - -(defun org-clubhouse-headlines-from-query (level query) - "Create `org-mode' headlines from a clubhouse query. - -Submits QUERY to clubhouse, and creates `org-mode' headlines from all the -resulting stories at headline level LEVEL." - (interactive - "*nLevel: \nMQuery: ") - (let* ((story-list (org-clubhouse--search-stories query))) - (if (null story-list) - (message "Query returned no stories: %s" query) - (let ((text (mapconcat (apply-partially - #'org-clubhouse--story-to-headline-text - level) - (reject-archived story-list) "\n"))) - (if (called-interactively-p) - (save-mark-and-excursion - (insert text) - (org-align-all-tags)) - text))))) - -(defun org-clubhouse-prompt-for-story (cb) - "Prompt the user for a clubhouse story, then call CB with the full story." - (ivy-read "Story title: " - (lambda (search-term) - (let* ((stories (org-clubhouse--search-stories - (if search-term (format "\"%s\"" search-term) - "")))) - (-map (lambda (story) - (propertize (alist-get 'name story) 'story story)) - stories))) - :dynamic-collection t - :history 'org-clubhouse-story-prompt - :action (lambda (s) (funcall cb (get-text-property 0 'story s))) - :require-match t)) - -(defun org-clubhouse-headline-from-story (level) - "Prompt for a story, and create an org headline at LEVEL from that story." - (interactive "*nLevel: ") - (org-clubhouse-prompt-for-story - (lambda (story) - (save-mark-and-excursion - (insert (org-clubhouse--story-to-headline-text level story)) - (org-align-tags))))) - - -(defun org-clubhouse-link () - "Link the current `org-mode' headline with an existing clubhouse story." - (interactive) - (org-clubhouse-prompt-for-story - (lambda (story) - (org-clubhouse-populate-created-story - (org-element-find-headline) - story - :extra-properties '(("clubhouse-story-name" . name))) - (org-todo - (org-clubhouse-workflow-state-id-to-todo-keyword - (alist-get 'workflow_state_id story)))))) - -(defun org-clubhouse-claim () - "Assign the clubhouse story associated with the headline at point to yourself." - (interactive) - (if org-clubhouse-username - (and - (org-clubhouse-update-story-at-point - :owner_ids (list (org-clubhouse-whoami))) - (message "Successfully claimed story")) - (warn "Can't claim story if `org-clubhouse-username' is unset"))) - -(defun org-clubhouse-sync-status (&optional beg end) - "Pull the status(es) for the story(ies) in region and update the todo state. - -Uses `org-clubhouse-state-alist'. Operates over stories from BEG to END" - (interactive - (when (use-region-p) - (list (region-beginning) (region-end)))) - (let ((elts (-filter (lambda (e) (plist-get e :CLUBHOUSE-ID)) - (org-clubhouse-collect-headlines beg end)))) - (save-mark-and-excursion - (dolist (e elts) - (goto-char (plist-get e :begin)) - (let* ((clubhouse-id (org-element-extract-clubhouse-id e)) - (story (org-clubhouse-get-story clubhouse-id)) - (workflow-state-id (alist-get 'workflow_state_id story)) - (todo-keyword (org-clubhouse-workflow-state-id-to-todo-keyword - workflow-state-id))) - (let ((org-after-todo-state-change-hook - (remove 'org-clubhouse-update-status - org-after-todo-state-change-hook))) - (org-todo todo-keyword))))) - (message "Successfully synchronized status of %d stories from Clubhouse" - (length elts)))) - -(cl-defun org-clubhouse-set-epic (&optional story-id epic-id cb &key beg end) - "Set the epic of clubhouse story STORY-ID to EPIC-ID, then call CB. - -When called interactively, prompt for an epic and set the story of the clubhouse -stor{y,ies} at point or region" - (interactive - (when (use-region-p) - (list nil nil nil - :beg (region-beginning) - :end (region-end)))) - (if (and story-id epic-id) - (progn - (org-clubhouse-update-story-internal - story-id :epic-id epic-id) - (when cb (funcall cb))) - (let ((elts (-filter (lambda (elt) (plist-get elt :CLUBHOUSE-ID)) - (org-clubhouse-collect-headlines beg end)))) - (org-clubhouse-prompt-for-epic - (lambda (epic-id) - (-map - (lambda (elt) - (let ((story-id (org-element-extract-clubhouse-id elt))) - (org-clubhouse-set-epic - story-id epic-id - (lambda () - (org-set-property - "clubhouse-epic" - (org-link-make-string - (org-clubhouse-link-to-epic epic-id) - (alist-get epic-id (org-clubhouse-epics)))) - (message "Successfully set the epic on story %d to %d" - story-id epic-id)))))) - elts))))) - -;;; - -(define-minor-mode org-clubhouse-mode - "If enabled, updates to the todo keywords on org headlines will update the -linked ticket in Clubhouse." - :group 'org - :lighter "Org-Clubhouse" - :keymap '() - (add-hook 'org-after-todo-state-change-hook - 'org-clubhouse-update-status - nil - t)) - -(provide 'org-clubhouse) - -;;; org-clubhouse.el ends here diff --git a/users/aspen/pkgs/notmuch-extract-patch.nix b/users/aspen/pkgs/notmuch-extract-patch.nix deleted file mode 100644 index 7f00f925e..000000000 --- a/users/aspen/pkgs/notmuch-extract-patch.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ pkgs, ... }: - -let - inherit (pkgs) lib; - src = pkgs.fetchurl { - url = "https://raw.githubusercontent.com/aaptel/notmuch-extract-patch/f732a53e12a7c91a06755ebfab2007adc9b3063b/notmuch-extract-patch"; - sha256 = "0nawkl04sj7psw6ikzay7kydj3dhd0fkwghcsf5rzaw4bmp4kbax"; - }; - -in -pkgs.runCommand "notmuch-extract-patch" -{ - buildInputs = [ pkgs.python3 ]; -} '' - mkdir -p $out/bin - install -m 755 ${src} $out/bin/notmuch-extract-patch - patchShebangs $out/bin -'' diff --git a/users/aspen/pkgs/py3status.nix b/users/aspen/pkgs/py3status.nix deleted file mode 100644 index 89f52d967..000000000 --- a/users/aspen/pkgs/py3status.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, ... }: - -pkgs.python3Packages.py3status.overridePythonAttrs (old: rec { - name = "${pname}-${old.version}"; - pname = "py3status-glittershark"; - src = pkgs.fetchFromGitHub { - owner = "glittershark"; - repo = "py3status"; - rev = "f243be1458cdabd5a7524adb76b5db99006c810c"; - sha256 = "0ffmv91562yk0wigriw4d5nfg2b32wqx8x78qvdqkawzvgbwrwvl"; - }; -}) diff --git a/users/aspen/resume/chimera.png b/users/aspen/resume/chimera.png deleted file mode 100644 index 6dde989c5..000000000 Binary files a/users/aspen/resume/chimera.png and /dev/null differ diff --git a/users/aspen/resume/collection.sty b/users/aspen/resume/collection.sty deleted file mode 100644 index 4f1540a9d..000000000 --- a/users/aspen/resume/collection.sty +++ /dev/null @@ -1,85 +0,0 @@ -%% start of file `collection.sty'. -%% Copyright 2013-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{collection}[2013/03/28 v1.0.0 collections] - - -%------------------------------------------------------------------------------- -% requirements -%------------------------------------------------------------------------------- - - -\RequirePackage{ifthen} - - -%------------------------------------------------------------------------------- -% code -%------------------------------------------------------------------------------- - -% creates a new collection -% usage: \collectionnew{} -\newcommand*{\collectionnew}[1]{% - \newcounter{collection@#1@count}} - -% adds an item to a collection -% usage: \collectionadd[]{}{} -\newcommand*{\collectionadd}[3][]{% - \expandafter\def\csname collection@#2@item\roman{collection@#2@count}\endcsname{#3}% - \if\relax\noexpand#1\relax% if #1 is empty - \else\expandafter\def\csname collection@#2@key\roman{collection@#2@count}\endcsname{#1}\fi% - \stepcounter{collection@#2@count}} - -% returns the number of items in a collection -% usage: \collectioncount{} -\newcommand*{\collectioncount}[1]{% - \value{collection@#1@count}} - -% gets an item from a collection -% usage: \collectiongetitem{}{} -% where is an integer between 0 and (collectioncount-1) -\newcommand*{\collectiongetitem}[2]{% - \csname collection@#1@item\romannumeral #2\endcsname} - -% gets a key from a collection -% usage: \collectiongetkey{}{} -% where is an integer between 0 and (collectioncount-1) -\newcommand*{\collectiongetkey}[2]{% - \csname collection@#1@key\romannumeral #2\endcsname} - -% loops through a collection and perform the given operation on every element -% usage: \collectionloop{}{} -% where is the code sequence to be evaluated for each collection item, -% code which can refer to \collectionloopid, \collectionloopkey, \collectionloopitem and -% \collectionloopbreak -\newcounter{collection@iterator} -\newcommand*{\collectionloopbreak}{\let\iterate\relax} -\newcommand*{\collectionloop}[2]{% - \setcounter{collection@iterator}{0}% - \loop\ifnum\value{collection@iterator}<\value{collection@#1@count}% - \def\collectionloopid{\arabic{collection@iterator}}% - \def\collectionloopitem{\collectiongetitem{#1}{\collectionloopid}}% - \def\collectionloopkey{\collectiongetkey{#1}{\collectionloopid}}% - #2% - \stepcounter{collection@iterator}% - \repeat} - -% loops through a collection and finds the (first) element matching the given key -% usage: \collectionfindbykey{}{key>} -\newcommand*{\collectionfindbykey}[2]{% - \collectionloop{#1}{% - \ifthenelse{\equal{\collectionloopkey}{#2}}{\collectionloopitem\collectionloopbreak}{}}} - - -\endinput - - -%% end of file `collection.cls'. diff --git a/users/aspen/resume/default.nix b/users/aspen/resume/default.nix deleted file mode 100644 index 4454e74c8..000000000 --- a/users/aspen/resume/default.nix +++ /dev/null @@ -1,40 +0,0 @@ -{ pkgs, ... }: - -with pkgs.lib; - -pkgs.runCommand "resume.pdf" -{ - buildInputs = [ - (pkgs.texlive.combine { - inherit (pkgs.texlive) - capt-of - collection-fontsrecommended - enumitem - etoolbox - fancyvrb - float - fncychap - framed - l3packages - microtype - needspace - parskip - scheme-basic - tabulary - titlesec - ulem - upquote - varwidth - wrapfig - xcolor - ; - }) - ]; -} '' - cp ${builtins.filterSource (path: type: - type == "regular" && - any (ext: hasSuffix ext path) [".sty" ".cls" ".tex" ".png"] - ) ./.}/* . - pdflatex ./resume.tex - cp resume.pdf $out -'' diff --git a/users/aspen/resume/helvetica.sty b/users/aspen/resume/helvetica.sty deleted file mode 100644 index dacc129a1..000000000 --- a/users/aspen/resume/helvetica.sty +++ /dev/null @@ -1,32 +0,0 @@ -%% -%% This is file `helvetica.sty', based on helvet.sty extended to include -%% definitions for rm and tt. This means commands such as \textbf, \textit, -%% etc. will appear in Helvetica. -%% Changes added by Harriet Borton on <1995/12/11> -%% -%% The original source files were: -%% -%% psfonts.dtx (with options: `helvet') -%% -%% Copyright (C) 1994 Sebastian Rahtz -%% All rights reserved. -%% -%% The original file is part of the PSNFSS2e package. -%% ----------------------------------------- -%% -%% This is a generated file. Permission is granted to to customize the -%% declarations in this file to serve the needs of your installation. -%% However, no permission is granted to distribute a modified version of -%% this file under its original name. -\def\fileversion{4.2} -\def\filedate{94/11/11} -\def\docdate {94/11/06} -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{helvetica}[\filedate\space\fileversion\space -Helvetica PSNFSS2e package] -\renewcommand{\sfdefault}{phv} -\renewcommand{\rmdefault}{phv} -\renewcommand{\ttdefault}{pcr} -\endinput -%% -%% End of file `helvetica.sty'. diff --git a/users/aspen/resume/moderncv.cls b/users/aspen/resume/moderncv.cls deleted file mode 100644 index 324890713..000000000 --- a/users/aspen/resume/moderncv.cls +++ /dev/null @@ -1,586 +0,0 @@ -%% start of file `moderncv.cls'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesClass{moderncv}[2013/02/09 v1.3.0 modern curriculum vitae and letter document class] - - -%------------------------------------------------------------------------------- -% class options -% -% (need to be done before the external package loading, for example because -% we need \paperwidth, \paperheight and \@ptsize to be defined before loading -% geometry and fancyhdr) -%------------------------------------------------------------------------------- -% paper size option -\DeclareOption{a4paper}{ - \setlength\paperheight{297mm} - \setlength\paperwidth{210mm}} -\DeclareOption{a5paper}{ - \setlength\paperheight{210mm} - \setlength\paperwidth{148mm}} -\DeclareOption{b5paper}{ - \setlength\paperheight{250mm} - \setlength\paperwidth{176mm}} -\DeclareOption{letterpaper}{ - \setlength\paperheight{11in} - \setlength\paperwidth{8.5in}} -\DeclareOption{legalpaper}{ - \setlength\paperheight{14in} - \setlength\paperwidth{8.5in}} -\DeclareOption{executivepaper}{ - \setlength\paperheight{10.5in} - \setlength\paperwidth{7.25in}} -\DeclareOption{landscape}{ - \setlength\@tempdima{\paperheight} - \setlength\paperheight{\paperwidth} - \setlength\paperwidth{\@tempdima}} - -% font size options -\newcommand\@ptsize{} -\DeclareOption{10pt}{\renewcommand\@ptsize{0}} -\DeclareOption{11pt}{\renewcommand\@ptsize{1}} -\DeclareOption{12pt}{\renewcommand\@ptsize{2}} - -% font type options -\DeclareOption{sans}{\AtBeginDocument{\renewcommand{\familydefault}{\sfdefault}}} -\DeclareOption{roman}{\AtBeginDocument{\renewcommand{\familydefault}{\rmdefault}}} - -% draft/final option -\DeclareOption{draft}{\setlength\overfullrule{5pt}} -\DeclareOption{final}{\setlength\overfullrule{0pt}} - -% execute default options -\ExecuteOptions{a4paper,11pt,final} - -% process given options -\ProcessOptions\relax -\input{size1\@ptsize.clo} - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- -% \AtEndPreamble hook (loading etoolbox instead of defining the macro, as to avoid incompatibilities with etoolbox (and packages relying on it) defining the macro too) -\RequirePackage{etoolbox} -%\let\@endpreamblehook\@empty -%\def\AtEndPreamble{\g@addto@macro\@endpreamblehook} -%\let\document@original\document -%\def\document{\endgroup\@endpreamblehook\begingroup\document@original} - -% if... then... else... constructs -\RequirePackage{ifthen} -% TODO: move to xifthen and \isempty{} instead of \equal{}{} - -% color -\RequirePackage{xcolor} - -% font loading -%\RequirePackage{ifxetex,ifluatex} -%\newif\ifxetexorluatex -%\ifxetex -% \xetexorluatextrue -%\else -% \ifluatex -% \xetexorluatextrue -% \else -% \xetexorluatexfalse -% \fi -%\fi -% automatic loading of latin modern fonts -%\ifxetexorluatex -% \RequirePackage{fontspec} -% \defaultfontfeatures{Ligatures=TeX} -% \RequirePackage{unicode-math} -% \setmainfont{Latin Modern} -% \setsansfont{Latin Modern Sans} -% \setmathfont{Latin Modern Math} -%\else - \RequirePackage[T1]{fontenc} - \IfFileExists{lmodern.sty}% - {\RequirePackage{lmodern}}% - {} -%\fi - -% hyper links (hyperref is loaded at the end of the preamble to pass options required by loaded packages such as CJK) -\newcommand*\pdfpagemode{UseNone}% do not show thumbnails or bookmarks on opening (on supporting browsers); set \pdfpagemode to "UseOutlines" to show bookmarks -\RequirePackage{url} -\urlstyle{tt} -\AtEndPreamble{ - \pagenumbering{arabic}% has to be issued before loading hyperref, as to set \thepage and hence to avoid hyperref issuing a warning and setting pdfpagelabels=false - \RequirePackage[unicode]{hyperref}% unicode is required for unicode pdf metadata - \hypersetup{ - breaklinks, - baseurl = http://, - pdfborder = 0 0 0, - pdfpagemode = \pdfpagemode, - pdfstartpage = 1, - pdfcreator = {\LaTeX{} with 'moderncv' package}, -% pdfproducer = {\LaTeX{}},% will/should be set automatically to the correct TeX engine used - bookmarksopen = true, - bookmarksdepth= 2,% to show sections and subsections - pdfauthor = {\@firstname{}~\@lastname{}}, - pdftitle = {\@firstname{}~\@lastname{} -- \@title{}}, - pdfsubject = {Resum\'{e} of \@firstname{}~\@lastname{}}, - pdfkeywords = {\@firstname{}~\@lastname{}, curriculum vit\ae{}, resum\'{e}}}} - -% graphics -\RequirePackage{graphicx} - -% headers and footers -\RequirePackage{fancyhdr} -\fancypagestyle{plain}{ - \renewcommand{\headrulewidth}{0pt} - \renewcommand{\footrulewidth}{0pt} - \fancyhf{}} -% page numbers in footer if more than 1 page -\newif\if@displaypagenumbers\@displaypagenumberstrue -\newcommand*{\nopagenumbers}{\@displaypagenumbersfalse} -\AtEndPreamble{% - \AtBeginDocument{% - \if@displaypagenumbers% - \@ifundefined{r@lastpage}{}{% - \ifthenelse{\pageref{lastpage}>1}{% - \newlength{\pagenumberwidth}% - \settowidth{\pagenumberwidth}{\color{color2}\addressfont\itshape\strut\thepage/\pageref{lastpage}}% - \fancypagestyle{plain}{% - \fancyfoot[r]{\parbox[b]{\pagenumberwidth}{\color{color2}\pagenumberfont\strut\thepage/\pageref{lastpage}}}}% the parbox is required to ensure alignment with a possible center footer (e.g., as in the casual style) - \pagestyle{plain}}{}}% - \AtEndDocument{\label{lastpage}}\else\fi}} -\pagestyle{plain} - -% reduced list spacing -% package providing hooks into lists -% originally developped by Jakob Schiøtz (see http://dcwww.camd.dtu.dk/~schiotz/comp/LatexTips/tweaklist.sty) -% modified and distributed with moderncv(not available otherwise on ctan) -\RequirePackage{tweaklist} -\renewcommand*{\itemhook}{% - \@minipagetrue% removes spacing before lists as they use \addvspace, which doesn't add vertical space inside minipages - \@noparlisttrue% removes spacing at end of lists, caused by \par - \setlength{\topsep}{0pt}% normally not required thanks to \@minipagetrue - \setlength{\partopsep}{0pt}% normally not required thanks to \@minipagetrue - \setlength{\parsep}{0pt}% not required when \itemsep and \parskip are set to 0pt (?) - \setlength{\parskip}{0pt}% - \setlength{\itemsep}{0pt}} -\renewcommand*{\enumhook}{\itemhook{}} -\renewcommand*{\deschook}{\itemhook{}} - -% lengths calculations -\RequirePackage{calc} - -% advanced command arguments (LaTeX 3) -\RequirePackage{xparse} -% TODO (?): replace all \newcommand by \NewDocumentCommand - -% micro-typography (e.g., character protrusion, font expansion, hyphenatable letterspacing) -\RequirePackage{microtype} - -% compatibility package with older versions of moderncv -\RequirePackageWithOptions{moderncvcompatibility} - - -%------------------------------------------------------------------------------- -% class definition -%------------------------------------------------------------------------------- -% minimal base settings -\setlength\lineskip{1\p@} -\setlength\normallineskip{1\p@} -\renewcommand\baselinestretch{} -\setlength{\parindent}{0\p@} -\setlength{\parskip}{0\p@} -\setlength\columnsep{10\p@} -\setlength\columnseprule{0\p@} -\setlength\fboxsep{3\p@} -\setlength\fboxrule{.4\p@} -\setlength\arrayrulewidth{.4\p@} -\setlength\doublerulesep{2\p@} - -% not set on purpose -%\setlength\arraycolsep{5\p@} -%\setlength\tabcolsep{6\p@} -%\setlength\tabbingsep{\labelsep} - -\raggedbottom -\onecolumn - - -%------------------------------------------------------------------------------- -% overall design commands definitions -%------------------------------------------------------------------------------- -% elements -% defines one's name -% usage: \name{}{} -\newcommand*{\name}[2]{\def\@firstname{#1}\def\@lastname{#2}} -\newcommand*{\pronouns}[1]{\def\@pronouns{#1}} -% defines one's title (optional) -% usage: \title{} -\renewcommand*{\title}[1]{\def\@title{#1}} -% defines one's address (optional) -% usage: \address{<street>}{<city>}{<country>} -% where the <city> and <country> arguments can be omitted or provided empty -\NewDocumentCommand{\address}{mG{}G{}}{\def\@addressstreet{#1}\def\@addresscity{#2}\def\@addresscountry{#3}} -% adds a mobile/fixed/fax number to one's personal information (optional) -% usage: \phone[<optional type>]{<number>} -% where <optional type> should be either "mobile", "fixed" or "fax -\RequirePackage{collection} -\collectionnew{phones} -\newcommand*{\phone}[2][fixed]{\collectionadd[#1]{phones}{#2}} -\newcommand*{\email}[1]{\def\@email{#1}} -% defines one's home page (optional) -% usage: \homepage{<url>} -\newcommand*{\homepage}[1]{\def\@homepage{#1}} -% defines one's github (optional) -% usage: \homepage{<url>} -\newcommand*{\github}[1]{\def\@github{#1}} -% defines additional personal information (optional) -% usage: \extrainfo{<text>} -\newcommand*{\extrainfo}[1]{\def\@extrainfo{#1}} - -% colors -\definecolor{color0}{rgb}{0,0,0}% main default color, normally left to black -\definecolor{color1}{rgb}{0,0,0}% primary theme color -\definecolor{color2}{rgb}{0,0,0}% secondary theme color -\definecolor{color3}{rgb}{0,0,0}% tertiary theme color - -% symbols -% itemize labels (the struts were added to correct inter-item spacing (works for single line items, until a solution is found for multi-line ones...) -\newcommand*{\labelitemi}{\strut\textcolor{color1}{\large\rmfamily\textbullet}}% the \rmfamily is required to force Latin Modern fonts when using sans serif, as OMS/lmss/m/n is not defined and gets substituted by OMS/cmsy/m/n -\newcommand*{\labelitemii}{\strut\textcolor{color1}{\large\bfseries-}} -\newcommand*{\labelitemiii}{\strut\textcolor{color1}{\rmfamily\textperiodcentered}}% alternative: \textasteriskcentered; the \rmfamily is required to force Latin Modern fonts when using sans serif, as OMS/lmss/m/n is not defined and gets substituted by OMS/cmsy/m/n -\newcommand*{\labelitemiv}{\labelitemiii} -% enumerate labels -\renewcommand{\theenumi}{\@arabic\c@enumi} -\renewcommand{\theenumii}{\@alph\c@enumii} -\renewcommand{\theenumiii}{\@roman\c@enumiii} -\renewcommand{\theenumiv}{\@Alph\c@enumiv} -% other symbols -\newcommand*{\listitemsymbol}{\labelitemi~} -\newcommand*{\addresssymbol}{} -\newcommand*{\mobilephonesymbol}{} -\newcommand*{\fixedphonesymbol}{} -\newcommand*{\faxphonesymbol}{} -\newcommand*{\emailsymbol}{} -\newcommand*{\homepagesymbol}{} - -% fonts -\AtBeginDocument{\normalfont\color{color0}} - -% strings for internationalisation -\newcommand*{\refname}{Publications} -\newcommand*{\enclname}{Enclosure} - -% makes the footer (normally used both for the resume and the letter) -% usage: \makefooter -\newcommand*{\makefooter}{}% - -% loads a style variant -% usage: \moderncvstyle{<style variant name>} -\newcommand*{\moderncvstyle}[1]{ - \RequirePackage{moderncvstyle#1}} - -% loads a color scheme -% usage: \moderncvcolor{<color scheme name>} -\newcommand*{\moderncvcolor}[1]{ - \RequirePackage{moderncvcolor#1}} - -% loads an icons set -% usage: \moderncvicons{<icon set name>} -\newcommand*{\moderncvicons}[1]{ - \RequirePackage{moderncvicons#1}} - -% recomputes all automatic lengths -\newcommand*{\recomputelengths}{\recomputecvlengths} -\AtBeginDocument{\recomputelengths{}} - -% creates a length if not yet defined -\newcommand*{\@initializelength}[1]{% - \ifdefined#1\else\newlength{#1}\fi} - - -%------------------------------------------------------------------------------- -% resume design commands definitions -%------------------------------------------------------------------------------- -% elements -% defines one's picture (optional) -% usage: photo[<picture width>][<picture frame thickness>]{<picture filename>} -\NewDocumentCommand{\photo}{O{64pt}O{0.4pt}m}{\def\@photowidth{#1}\def\@photoframewidth{#2}\def\@photo{#3}} -\newcommand*{\quote}[1]{\def\@quote{#1}} - -% fonts -\newcommand*{\namefont}{} -\newcommand*{\titlefont}{} -\newcommand*{\addressfont}{} -\newcommand*{\quotefont}{} -\newcommand*{\sectionfont}{} -\newcommand*{\subsectionfont}{} -\newcommand*{\hintfont}{} -\newcommand*{\pagenumberfont}{\addressfont\itshape} - -% styles -\newcommand*{\namestyle}[1]{{\namefont#1}} -\newcommand*{\titlestyle}[1]{{\titlefont#1}} -\newcommand*{\addressstyle}[1]{{\addressfont#1}} -\newcommand*{\quotestyle}[1]{{\quotefont#1}} -\newcommand*{\sectionstyle}[1]{{\sectionfont#1}} -\newcommand*{\subsectionstyle}[1]{{\subsectionfont#1}} -\newcommand*{\hintstyle}[1]{{\hintfont#1}} -\newcommand*{\pagenumberstyle}[1]{{\pagenumberfont#1}} - -% recompute all resume lengths -\newcommand*{\recomputecvlengths}{} - -% internal maketitle command to issue a new line only when required -\newif\if@firstdetailselement\@firstdetailselementtrue -\newcommand*{\makenewline}{ - \if@firstdetailselement% - \strut% to ensure baseline alignment, e.g. with when put in the margin vs sections that also contains a \strut - \else% - \\\fi% - \@firstdetailselementfalse} - -% makes the resume title -% usage: \makecvtitle -\newcommand*{\makecvtitle}{} - -% makes the resume footer -% usage: \makecvfooter -\newcommand*{\makecvfooter}{\makefooter} - -% makes a resume section -% usage: \section{<title>} -% identical starred and non-starred variants should be defined for compatibility with other packages (e.g. with natbib, that uses \section*{} for the bibliography header) -\NewDocumentCommand{\section}{sm}{} - -% makes a resume subsection -% usage: \subsection{title} -\NewDocumentCommand{\subsection}{sm}{} - -% makes a resume line with a header and a corresponding text -% usage: \cvitem[spacing]{header}{text} -\newcommand*{\cvitem}[3][.25em]{} - -% makes a resume line 2 headers and their corresponding text -% usage: \cvdoubleitem[spacing]{header1}{text1}{header2}{text2} -\newcommand*{\cvdoubleitem}[5][.25em]{} - -% makes a resume line with a list item -% usage: \cvlistitem[label]{item} -\newcommand*{\cvlistitem}[2][\listitemsymbol]{} - -% makes a resume line with 2 list items -% usage: \cvlistdoubleitem[label]{item1}{item2} -\newcommand*{\cvlistdoubleitem}[3][\listitemsymbol]{} - -% makes a typical resume job / education entry -% usage: \cventry[spacing]{years}{degree/job title}{institution/employer}{localization}{optionnal: grade/...}{optional: comment/job description} -\newcommand*{\cventry}[7][.25em]{} - -% makes a resume entry with a proficiency comment -% usage: \cvitemwithcomment[spacing]{header}{text}{comment} -\newcommand*{\cvitemwithcomment}[4][.25em]{} - -% makes a generic hyperlink -% usage: \link[optional text]{link} -\newcommand*{\link}[2][]{% - \ifthenelse{\equal{#1}{}}% - {\href{#2}{#2}}% - {\href{#2}{#1}}} - -% makes a http hyperlink -% usage: \httplink[optional text]{link} -\newcommand*{\httplink}[2][]{% - \ifthenelse{\equal{#1}{}}% - {\href{http://#2}{#2}}% - {\href{http://#2}{#1}}} - -% makes an email hyperlink -% usage: \emaillink[optional text]{link} -\newcommand*{\emaillink}[2][]{% - \ifthenelse{\equal{#1}{}}% - {\href{mailto:#2}{#2}}% - {\href{mailto:#2}{#1}}} - -% cvcolumns environment, where every column is created through \cvcolumn -% usage: \begin{cvcolumns} -% \cvcolumn[width]{head}{content} -% \cvcolumn[width]{head}{content} -% ... -% \end{cvcolumns} -% where "width" is the width as a fraction of the line length (between 0 and 1), "head" is the column header and "content" its content -\newcounter{cvcolumnscounter}% counter for the number of columns -\newcounter{cvcolumnsautowidthcounter}% counter for the number of columns with no column width provided, and which will then be equally distributed -\newcounter{tmpiteratorcounter}% counter for any temporary purpose (e.g., iterating loops) -\newlength{\cvcolumnsdummywidth}\setlength{\cvcolumnsdummywidth}{1000pt}% dummy width for total width, in order to enable arithmetics (TeX has no float variables, only integer counters or lengths) -\newlength{\cvcolumnswidth}% total width available for head / content -\newlength{\cvcolumnsautowidth}% total width of columns with no explicit width provided -\newlength{\cvcolumnautowidth}% width of one of the columns with no explicit width provided (based on equal distribution of remaining space) -\newif\if@cvcolumns@head@empty% whether or not at least one of the columns has a header -\newenvironment*{cvcolumns}% - {% at environment opening: reset counters, lengths and ifs - \setcounter{cvcolumnscounter}{0}% - \setcounter{cvcolumnsautowidthcounter}{0}% - \setlength{\cvcolumnsautowidth}{\cvcolumnsdummywidth}% - \setlength{\cvcolumnautowidth}{0pt}% - \@cvcolumns@head@emptytrue}% - {% at environment closing: typeset environment - % compute the width of each cvcolumn, considering a spacing of \separatorcolumnwidth and the columns with set width - \ifnum\thecvcolumnscounter>0% - \setlength{\cvcolumnswidth}{\maincolumnwidth-\value{cvcolumnscounter}\separatorcolumnwidth+\separatorcolumnwidth}% - \setlength{\cvcolumnautowidth}{\cvcolumnswidth*\ratio{\cvcolumnsautowidth}{\cvcolumnsdummywidth}/\value{cvcolumnsautowidthcounter}}\fi% - % pre-aggregate the tabular definition, heading and content (required before creating the tabular, as the tabular environment doesn't like loops --- probably because "&" generates a \endgroup) - % - the tabular definition is the aggregation of the different "\cvcolumn<i>@def" (by default "p{\cvcolumnautowidth}"), separated by "@{\hspace*{\separatorcolumnwidth}}" - % - the tabular heading is the aggregation of the different "\cvcolumn<i>@head", separated by "&" - % - the tabular content is the aggregation of the different "\cvcolumn<i>@content", separated by "&" - % to aggregate the different elements, \protected@edef or \g@addto@macro is required to avoid that \cvcolumns@def, -@head and -@content get expanded in subsequent redefinitions, which would cause errors due to the expansions of \hspace, of \subsectionstyle and possibly of user content/argument such as font commands - \def\cvcolumns@def{}% - \def\cvcolumns@head{}% - \def\cvcolumns@content{}% - \setcounter{tmpiteratorcounter}{0}% - % loop based on \g@addto@macro - \loop\ifnum\thetmpiteratorcounter<\thecvcolumnscounter% - \ifnum\thetmpiteratorcounter=0\else% - \g@addto@macro\cvcolumns@def{@{\hspace*{\separatorcolumnwidth}}}% - \g@addto@macro\cvcolumns@head{&}% - \g@addto@macro\cvcolumns@content{&}\fi% - \expandafter\g@addto@macro\expandafter\cvcolumns@def\expandafter{\csname cvcolumn\roman{tmpiteratorcounter}@def\endcsname}% - \expandafter\g@addto@macro\expandafter\cvcolumns@head\expandafter{\csname cvcolumn\roman{tmpiteratorcounter}@head\endcsname}% - \expandafter\g@addto@macro\expandafter\cvcolumns@content\expandafter{\csname cvcolumn\roman{tmpiteratorcounter}@content\endcsname}% - \stepcounter{tmpiteratorcounter}% - \repeat% -% % same loop based on \protected@edef -% \loop\ifnum\thetmpiteratorcounter<\thecvcolumnscounter% -% \ifnum\thetmpiteratorcounter=0\else% -% \protected@edef\cvcolumns@def{\cvcolumns@def @{\hspace*{\separatorcolumnwidth}}}% -% \protected@edef\cvcolumns@head{\cvcolumns@head &}% -% \protected@edef\cvcolumns@content{\cvcolumns@content &}\fi% -% \expandafter\protected@edef\expandafter\cvcolumns@def\expandafter{\expandafter\cvcolumns@def\expandafter\protect\csname cvcolumn\roman{tmpiteratorcounter}@def\endcsname}% -% \expandafter\protected@edef\expandafter\cvcolumns@head\expandafter{\expandafter\cvcolumns@head\expandafter\protect\csname cvcolumn\roman{tmpiteratorcounter}@head\endcsname}% -% \expandafter\protected@edef\expandafter\cvcolumns@content\expandafter{\expandafter\cvcolumns@content\expandafter\protect\csname cvcolumn\roman{tmpiteratorcounter}@content\endcsname}% -% \stepcounter{tmpiteratorcounter}% -% \repeat% - % create the tabular - \cvitem{}{% - \begin{tabular}{\cvcolumns@def}% - \if@cvcolumns@head@empty\else% - \cvcolumns@head\\[-.8em]% - {\color{color1}\rule{\maincolumnwidth}{.25pt}}\\\fi% - \cvcolumns@content% - \end{tabular}}} - -% cvcolumn command, to create a column inside a cvcolumns environment -% usage: \cvcolumn[width]{head}{content} -% where "width" is the width as a fraction of the line length (between 0 and 1), "head" is the column header and "content" its content ("head" and "content" can contain "\\", "\newline" or any other paragraph command such as "itemize") -\newcommand*{\cvcolumn}[3][\cvcolumnautowidth]{% -% \def\cvcolumn@width{}% - \ifthenelse{\equal{#1}{\cvcolumnautowidth}}% - {% if no width fraction is provided, count this column as auto-adjusted and set its width to \cvcolumnsautowidth - \stepcounter{cvcolumnsautowidthcounter}% - \expandafter\expandafter\expandafter\def\expandafter\csname cvcolumn\roman{cvcolumnscounter}@def\endcsname{p{\cvcolumnautowidth}}% - \expandafter\expandafter\expandafter\def\expandafter\csname cvcolumn\roman{cvcolumnscounter}@head\endcsname{\protect\parbox[b]{\cvcolumnautowidth}{\protect\subsectionstyle{#2}}}}% - {% if a width is provided, set the width of the column to it and decrease the available space for auto-adjusted columns - \addtolength{\cvcolumnsautowidth}{-#1\cvcolumnsdummywidth}% - \expandafter\expandafter\expandafter\def\expandafter\csname cvcolumn\roman{cvcolumnscounter}@def\endcsname{p{#1\cvcolumnswidth}}% - \expandafter\expandafter\expandafter\def\expandafter\csname cvcolumn\roman{cvcolumnscounter}@head\endcsname{\protect\parbox[b]{#1\cvcolumnswidth}{\protect\subsectionstyle{#2}}}}% - \ifthenelse{\equal{#2}{}}{}{\@cvcolumns@head@emptyfalse}% - \expandafter\expandafter\expandafter\def\expandafter\csname cvcolumn\roman{cvcolumnscounter}@content\endcsname{\protect\cvcolumncell{#3}}% - \stepcounter{cvcolumnscounter}} - -% internal cvcolumncell command, that enables a cvcolumn cell to contain paragraph commands (lists, newlines, etc) -\newcommand*{\cvcolumncell}[1]{{% put cell inside a group, so that command redefinitions are only local - % roughly restore \\ to its regular definition (outside of tabular) - \renewcommand*{\\}{\newline}% - % enclose the contents of the cell inside a vertical box, to allow paragraph commands - \protect\vtop{#1}}} - -% thebibliography environment, for use with BibTeX and possibly multibib -\newlength{\bibindent} -\setlength{\bibindent}{1.5em} -% bibliography item label -\newcommand*{\bibliographyitemlabel}{}% use \@biblabel{\arabic{enumiv}} for BibTeX labels -%\newif\if@multibibfirstbib\@multibibfirstbibfalse -% bibliography head (section, etc}, depending on whether multibib is used -\newcommand*{\bibliographyhead}[1]{\section{#1}} -\AtEndPreamble{\@ifpackageloaded{multibib}{\renewcommand*{\bibliographyhead}[1]{\subsection{#1}}}{}} -% thebibliography environment definition -\newenvironment{thebibliography}[1]{}{} -\newcommand*{\newblock}{\hskip .11em\@plus.33em\@minus.07em} -\let\@openbib@code\@empty - -% itemize, enumerate and description environment -\setlength{\leftmargini} {1em} -\leftmargin\leftmargini -\setlength{\leftmarginii} {\leftmargini} -\setlength{\leftmarginiii} {\leftmargini} -\setlength{\leftmarginiv} {\leftmargini} -\setlength{\leftmarginv} {\leftmargini} -\setlength{\leftmarginvi} {\leftmargini} -\setlength{\labelsep} {.5em}% this is the distance between the label and the body, but it pushes the label to the left rather than pushing the body to the right (to do the latter, modify \leftmargin(i) -\setlength{\labelwidth} {\leftmargini}% unfortunately, \labelwidth is not defined by item level (i.e. no \labeliwidth, \labeliiwidth, etc) -\addtolength{\labelwidth} {-\labelsep} -\@beginparpenalty -\@lowpenalty -\@endparpenalty -\@lowpenalty -\@itempenalty -\@lowpenalty -\newcommand\labelenumi{\theenumi.} -\newcommand\labelenumii{(\theenumii)} -\newcommand\labelenumiii{\theenumiii.} -\newcommand\labelenumiv{\theenumiv.} -\renewcommand\p@enumii{\theenumi} -\renewcommand\p@enumiii{\p@enumii(\theenumii)} -\renewcommand\p@enumiv{\p@enumiii\theenumiii} -% description label -\newcommand*\descriptionlabel[1]{\hspace\labelsep\normalfont\bfseries#1} - -% classical \today definition -\def\today{\ifcase\month\or - January\or February\or March\or April\or May\or June\or - July\or August\or September\or October\or November\or December\fi - \space\number\day, \number\year} - -%\newcommand{\widthofautobox}[1]{% -% \widthof{\begin{tabular}{@{}l@{}}#1\end{tabular}}} - -%\newcommand{\autobox}[2][b]{% -% \parbox[#1]{\widthofautobox{#2}}{#2}} - - -%------------------------------------------------------------------------------- -% letter design commands definitions -%------------------------------------------------------------------------------- -% elements -\newcommand*{\recipient}[2]{\def\@recipientname{#1}\def\@recipientaddress{#2}} -\renewcommand*{\date}[1]{\def\@date{#1}}\date{\today} -\newcommand*{\opening}[1]{\def\@opening{#1}} -\newcommand*{\closing}[1]{\def\@closing{#1}} -\newcommand*{\enclosure}[2][]{% - % if an optional argument is provided, use it to redefine \enclname - \ifthenelse{\equal{#1}{}}{}{\renewcommand*{\enclname}{#1}}% - \def\@enclosure{#2}} - -% recompute all letter lengths -\newcommand*{\recomputeletterlengths}{} - -% makes the letter title -% usage: \makelettertitle -\newcommand*{\makelettertitle}{} - -% makes the letter footer -% usage: \makeletterfooter -\newcommand*{\makeletterfooter}{\makefooter} - -% makes the letter closing -% usage: \makeletterclosing -\newcommand*{\makeletterclosing}{} - - -\endinput - - -%% end of file `moderncv.cls'. diff --git a/users/aspen/resume/moderncvcolorblack.sty b/users/aspen/resume/moderncvcolorblack.sty deleted file mode 100644 index 3a6e1477f..000000000 --- a/users/aspen/resume/moderncvcolorblack.sty +++ /dev/null @@ -1,27 +0,0 @@ -%% start of file `moderncvcolorblack.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvcolorblack}[2013/02/09 v1.3.0 modern curriculum vitae and letter color scheme: black] - - -%------------------------------------------------------------------------------- -% color scheme definition -%------------------------------------------------------------------------------- -\definecolor{color0}{rgb}{0,0,0}% black -\definecolor{color1}{rgb}{0,0,0}% black -\definecolor{color2}{rgb}{0,0,0}% black - - -\endinput - - -%% end of file `moderncvcolorblack.sty'. diff --git a/users/aspen/resume/moderncvcolorblue.sty b/users/aspen/resume/moderncvcolorblue.sty deleted file mode 100644 index 7b949c704..000000000 --- a/users/aspen/resume/moderncvcolorblue.sty +++ /dev/null @@ -1,27 +0,0 @@ -%% start of file `moderncvcolorblue.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvcolorblue}[2013/02/09 v1.3.0 modern curriculum vitae and letter color scheme: blue] - - -%------------------------------------------------------------------------------- -% color scheme definition -%------------------------------------------------------------------------------- -\definecolor{color0}{rgb}{0,0,0}% black -\definecolor{color1}{rgb}{0.22,0.45,0.70}% light blue -\definecolor{color2}{rgb}{0.45,0.45,0.45}% dark grey - - -\endinput - - -%% end of file `moderncvcolorblue.sty'. diff --git a/users/aspen/resume/moderncvcolorgreen.sty b/users/aspen/resume/moderncvcolorgreen.sty deleted file mode 100644 index 4de7f848a..000000000 --- a/users/aspen/resume/moderncvcolorgreen.sty +++ /dev/null @@ -1,27 +0,0 @@ -%% start of file `moderncvcolorgreen.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvcolorgreen}[2013/02/09 v1.3.0 modern curriculum vitae and letter color scheme: green] - - -%------------------------------------------------------------------------------- -% color scheme definition -%------------------------------------------------------------------------------- -\definecolor{color0}{rgb}{0,0,0}% black -\definecolor{color1}{rgb}{0.35,0.70,0.30}% green -\definecolor{color2}{rgb}{0.45,0.45,0.45}% dark grey - - -\endinput - - -%% end of file `moderncvcolorgreen.sty'. diff --git a/users/aspen/resume/moderncvcolorgrey.sty b/users/aspen/resume/moderncvcolorgrey.sty deleted file mode 100644 index 9018726a2..000000000 --- a/users/aspen/resume/moderncvcolorgrey.sty +++ /dev/null @@ -1,27 +0,0 @@ -%% start of file `moderncvcolorgrey.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvcolorgrey}[2013/02/09 v1.3.0 modern curriculum vitae and letter color scheme: grey] - - -%------------------------------------------------------------------------------- -% color scheme definition -%------------------------------------------------------------------------------- -\definecolor{color0}{rgb}{0,0,0}% black -\definecolor{color1}{rgb}{0.55,0.55,0.55}% dark grey -\definecolor{color2}{rgb}{0.55,0.55,0.55}% dark grey - - -\endinput - - -%% end of file `moderncvcolorgrey.sty'. diff --git a/users/aspen/resume/moderncvcolororange.sty b/users/aspen/resume/moderncvcolororange.sty deleted file mode 100644 index 134ae2401..000000000 --- a/users/aspen/resume/moderncvcolororange.sty +++ /dev/null @@ -1,27 +0,0 @@ -%% start of file `moderncvcolororange.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvcolororange}[2013/02/09 v1.3.0 modern curriculum vitae and letter color scheme: orange] - - -%------------------------------------------------------------------------------- -% color scheme definition -%------------------------------------------------------------------------------- -\definecolor{color0}{rgb}{0,0,0}% black -\definecolor{color1}{rgb}{0.95,0.55,0.15}% orange -\definecolor{color2}{rgb}{0.45,0.45,0.45}% dark grey - - -\endinput - - -%% end of file `moderncvcolororange.sty'. diff --git a/users/aspen/resume/moderncvcolorpurple.sty b/users/aspen/resume/moderncvcolorpurple.sty deleted file mode 100644 index d3dc5345b..000000000 --- a/users/aspen/resume/moderncvcolorpurple.sty +++ /dev/null @@ -1,27 +0,0 @@ -%% start of file `moderncvcolorpurple.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvcolorpurple}[2013/02/09 v1.3.0 modern curriculum vitae and letter color scheme: purple] - - -%------------------------------------------------------------------------------- -% color scheme definition -%------------------------------------------------------------------------------- -\definecolor{color0}{rgb}{0,0,0}% black -\definecolor{color1}{rgb}{0.50,0.33,0.80}% purple -\definecolor{color2}{rgb}{0.45,0.45,0.45}% dark grey - - -\endinput - - -%% end of file `moderncvcolorpurple.sty'. diff --git a/users/aspen/resume/moderncvcolorred.sty b/users/aspen/resume/moderncvcolorred.sty deleted file mode 100644 index 681181997..000000000 --- a/users/aspen/resume/moderncvcolorred.sty +++ /dev/null @@ -1,27 +0,0 @@ -%% start of file `moderncvcolorred.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvcolorred}[2013/02/09 v1.3.0 modern curriculum vitae and letter color scheme: red] - - -%------------------------------------------------------------------------------- -% color scheme definition -%------------------------------------------------------------------------------- -\definecolor{color0}{rgb}{0,0,0}% black -\definecolor{color1}{rgb}{0.95,0.20,0.20}% red -\definecolor{color2}{rgb}{0.45,0.45,0.45}% dark grey - - -\endinput - - -%% end of file `moderncvcolorred.sty'. diff --git a/users/aspen/resume/moderncvcompatibility.sty b/users/aspen/resume/moderncvcompatibility.sty deleted file mode 100644 index 1fc53f218..000000000 --- a/users/aspen/resume/moderncvcompatibility.sty +++ /dev/null @@ -1,104 +0,0 @@ -%% start of file `moderncvcompatibility.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvcompatibility}[2013/02/09 v1.3.0 modern curriculum vitae and letter compatibility patches] - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- - - -%------------------------------------------------------------------------------- -% package options -%------------------------------------------------------------------------------- -% old casual option (version 0.1) -%\DeclareOption{casual}{\input{moderncvstylecasual.sty}} - -% old classic option (version 0.1) -%\DeclareOption{classic}{\input{moderncvstyleclassic.sty}} - -\DeclareOption*{} - -% process given options -\ProcessOptions\relax - -%------------------------------------------------------------------------------- -% definitions -%------------------------------------------------------------------------------- -% compatibility with version 0.1 -\newcommand*{\cvresume}[2]{\cvlistdoubleitem{#1}{#2}} - -% compatibility with versions <= 0.2 -% section, cvline, ... with width argument... -%\newcommand*{\section}[2][0.825]{% -% \closesection{}% -% \@sectionopentrue% -% \addcontentsline{toc}{part}{#2} -% \begin{longtable}[t]{@{}r@{\hspace{.025\textwidth}}@{}p{#1\textwidth}@{}}% -%% \colorrule{.15\textwidth}&\mbox{\color{sectiontitlecolor}\sectionfont#2}\\[1ex]}% -% {\color{sectionrectanglecolor}\rule{0.15\textwidth}{1ex}}&\mbox{\color{sectiontitlecolor}\sectionfont#2}\\[1ex]}% -%\newcommand*{\cvline}[3][.825]{% -% \begin{minipage}[t]{\hintscolumnwidth}\raggedleft\small\sffamily#2\end{minipage}&\begin{minipage}[t]{\maincolumnwidth}#3\end{minipage}\\} -%\newcommand*{\cvitem}[3][.825]{% -% \cvline[#1]{#2}{#3\vspace*{.75em}}} % the \vspace*{} inside the cvline environment is a hack... (should conceptually be outside the environment) - -% compatibility with versions <= 0.5 -%\newcommand*{\cvitem}[2]{\cvline{#1}{#2}} -%\newcommand*{\moderncvstyle}[1]{\moderncvtheme{#1}} - -% compatibility with versions <= 0.7 -\newcommand*{\closesection}{} -\newcommand*{\emptysection}{} -\newcommand*{\sethintscolumnlength}[1]{% - \setlength{\hintscolumnwidth}{#1}% - \recomputelengths} -\newcommand*{\sethintscolumntowidth}[1]{% - \settowidth{\hintscolumnwidth}{#1}% - \recomputelengths} - -% compatibility with versions <= 0.15 -\newcommand*{\cvline}[2]{\cvitem{#1}{#2}} -\newcommand*{\cvlanguage}[3]{\cvitemwithcomment{#1}{#2}{#3}} -\newcommand*{\cvcomputer}[4]{\cvdoubleitem{#1}{\small#2}{#3}{\small#4}} -\newcommand*{\moderncvtheme}[2][blue]{% - \moderncvcolor{#1}% - \moderncvstyle{#2}} - -% compatibility with versions <= 0.19 -\newcommand*{\maketitle}{\makecvtitle}% -\title{}% to avoid LaTeX complaining that \maketitle is a called without first a call to \title -\newcommand*{\maketitlenamewidth}{\makecvtitlenamewidth} - -% compatibility with versions <= 1.3.0 -\newcommand*{\firstname}[1]{\def\@firstname{#1}} -\newcommand*{\lastname}[1]{\def\@lastname{#1}} -\newcommand*{\givenname}[1]{\def\@firstname{#1}} -\newcommand*{\familyname}[1]{\def\@lastname{#1}} -\def\@familyname{\@lastname} - -% compatibility with versions <= 1.4.0 -\newcommand*{\mobile}[1]{\collectionadd[mobile]{phones}{#1}} -%\newcommand*{\phone}[1]{\collectionadd[fixed]{phones}{#1}}% implicit, as \phone{...} defaults to \phone[fixed]{...} -\newcommand*{\fax}[1]{\collectionadd[fax]{phones}{#1}} -\newcommand*{\@mobile}{\collectionfindbykey{phones}{mobile}} -\newcommand*{\@phone}{\collectionfindbykey{phones}{fixed}} -\newcommand*{\@fax}{\collectionfindbykey{phones}{fax}} -\newcommand*{\phonesymbol}{\fixedphonesymbol} -\newcommand*{\mobilesymbol}{\mobilephonesymbol} -\newcommand*{\faxsymbol}{\faxphonesymbol} - - -\endinput - - -%% end of file `moderncvcompatibility.sty'. diff --git a/users/aspen/resume/moderncviconsletters.sty b/users/aspen/resume/moderncviconsletters.sty deleted file mode 100644 index 0a4e2864b..000000000 --- a/users/aspen/resume/moderncviconsletters.sty +++ /dev/null @@ -1,50 +0,0 @@ -%% start of file `moderncviconsletters.sty'. -%% Copyright 2013-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncviconsmarvosym}[2013/02/09 v1.3.0 modern curriculum vitae and letter icons: letters] - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- -% MarVoSym font -%\RequirePackage{marvosym} -\newcommand*{\marvosymbol}[1]{} -%\ifxetexorluatex -% \renewcommand*{\marvosymbol}[1]{{\fontspec{MarVoSym}\char#1}} -%\else - \renewcommand*{\marvosymbol}[1]{{\fontfamily{mvs}\fontencoding{U}\fontseries{m}\fontshape{n}\selectfont\char#1}} -%\fi - - -%------------------------------------------------------------------------------- -% symbols definition -%------------------------------------------------------------------------------- -\renewcommand*{\labelitemi}{\strut\textcolor{color1}{\marvosymbol{123}}}% equivalent to \Neutral from marvosym package; alternative: \fontencoding{U}\fontfamily{ding}\selectfont\tiny\symbol{'102} -%\renewcommand*{\labelitemii}{\strut\textcolor{color1}{\large\bfseries-}}% no change from default in moderncv.cls -%\renewcommand*{\labelitemiii}{\strut\textcolor{color1}{\rmfamily\textperiodcentered}}% no change from default in moderncv.cls -%\renewcommand*{\labelitemiv}{\labelitemiii}% no change from default in moderncv.cls - -\renewcommand*{\addresssymbol}{} -\renewcommand*{\mobilephonesymbol}{\textbf{M}~} -\renewcommand*{\fixedphonesymbol}{\textbf{T}~} -\renewcommand*{\faxphonesymbol}{\textbf{F}~} -\renewcommand*{\emailsymbol}{\textbf{E}~} -\renewcommand*{\homepagesymbol}{} - -\renewcommand*{\listitemsymbol}{\labelitemi~} - - -\endinput - - -%% end of file `moderncviconsletters.sty'. diff --git a/users/aspen/resume/moderncviconsmarvosym.sty b/users/aspen/resume/moderncviconsmarvosym.sty deleted file mode 100644 index eb1b1ec72..000000000 --- a/users/aspen/resume/moderncviconsmarvosym.sty +++ /dev/null @@ -1,48 +0,0 @@ -%% start of file `moderncviconsmarvosym.sty'. -%% Copyright 2013-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncviconsmarvosym}[2013/02/09 v1.3.0 modern curriculum vitae and letter icons: marvosym] - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- -% MarVoSym font -%\RequirePackage{marvosym} -\newcommand*{\marvosymbol}[1]{} -%\ifxetexorluatex -% \renewcommand*{\marvosymbol}[1]{{\fontspec{MarVoSym}\char#1}} -%\else - \renewcommand*{\marvosymbol}[1]{{\fontfamily{mvs}\fontencoding{U}\fontseries{m}\fontshape{n}\selectfont\char#1}} -%\fi - - -%------------------------------------------------------------------------------- -% symbols definition -%------------------------------------------------------------------------------- -\renewcommand*{\labelitemi}{\strut\textcolor{color1}{\marvosymbol{123}}}% equivalent to \Neutral from marvosym package; alternative: \fontencoding{U}\fontfamily{ding}\selectfont\tiny\symbol{'102} -%\renewcommand*{\labelitemii}{\strut\textcolor{color1}{\large\bfseries-}}% no change from default in moderncv.cls -%\renewcommand*{\labelitemiii}{\strut\textcolor{color1}{\rmfamily\textperiodcentered}}% no change from default in moderncv.cls -%\renewcommand*{\labelitemiv}{\labelitemiii}% no change from default in moderncv.cls - -\renewcommand*{\addresssymbol}{} -\renewcommand*{\mobilephonesymbol}{\marvosymbol{72}~} -\renewcommand*{\fixedphonesymbol}{\marvosymbol{84}~} -\renewcommand*{\faxphonesymbol}{\marvosymbol{117}~} -\renewcommand*{\emailsymbol}{\marvosymbol{66}~} -\renewcommand*{\homepagesymbol}{{\Large\marvosymbol{205}}~} - - -\endinput - - -%% end of file `moderncviconsmarvosym.sty'. diff --git a/users/aspen/resume/moderncvstylebanking.sty b/users/aspen/resume/moderncvstylebanking.sty deleted file mode 100644 index fb0b70fdc..000000000 --- a/users/aspen/resume/moderncvstylebanking.sty +++ /dev/null @@ -1,287 +0,0 @@ -%% start of file `moderncvstylebanking.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvstylebanking}[2013/02/09 v1.3.0 modern curriculum vitae and letter style scheme: banking] - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- - - -%------------------------------------------------------------------------------- -% overall style definition -%------------------------------------------------------------------------------- -% fonts -%\ifxetexorluatex -% \setmainfont{Tex-Gyre Pagella} -% \setsansfont{Tex-Gyre Pagella} -% \setmathfont{Tex-Gyre Pagella} -% \setmathfont[range=\mathit,\mathsfit]{Tex-Gyre Pagella Italic} -% \setmathfont[range=\mathbfup,\mathbfsfup]{Tex-Gyre Pagella Bold} -% \setmathfont[range=\mathbfit,\mathbfsfit]{Tex-Gyre Pagella Bold Italic} -%\else - \IfFileExists{tgpagella.sty}% - {% - \RequirePackage{tgpagella}% - \renewcommand*{\familydefault}{\rmdefault}}% - {} -%\fi - -% symbols -\moderncvicons{marvosym} - -% commands -\newcommand*{\maketitlesymbol}{% - {~~~{\rmfamily\textbullet}~~~}}% the \rmfamily is required to force Latin Modern fonts when using sans serif, as OMS/lmss/m/n is not defined and gets substituted by OMS/cmsy/m/n -% internal command to add an element to the footer -% it collects the elements in a temporary box, and checks when to flush the box -\newsavebox{\maketitlebox}% -\newsavebox{\maketitletempbox}% -\newlength{\maketitlewidth}% -\newlength{\maketitleboxwidth}% -\newif\if@firstmaketitleelement\@firstmaketitleelementtrue% -% adds an element to the maketitle, separated by maketitlesymbol -% usage: \addtomaketitle[maketitlesymbol]{element} -\newcommand*{\addtomaketitle}[2][\maketitlesymbol]{% - \if@firstmaketitleelement% - \savebox{\maketitletempbox}{\usebox{\maketitlebox}#2}% - \else% - \savebox{\maketitletempbox}{\usebox{\maketitlebox}#1#2}\fi% - \settowidth{\maketitleboxwidth}{\usebox{\maketitletempbox}}% - \ifnum\maketitleboxwidth<\maketitlewidth% - \savebox{\maketitlebox}{\usebox{\maketitletempbox}}% - \@firstmaketitleelementfalse% - \else% - \flushmaketitle{}\\% - \savebox{\maketitlebox}{#2}% - \savebox{\maketitletempbox}{#2}% - \settowidth{\maketitleboxwidth}{\usebox{\maketitlebox}}% - \@firstmaketitleelementfalse\fi} -% internal command to flush the maketitle -\newcommand*{\flushmaketitle}{% - \strut\usebox{\maketitlebox}% - \savebox{\maketitlebox}{}% - \savebox{\maketitletempbox}{}% - \setlength{\maketitleboxwidth}{0pt}} -\renewcommand*{\maketitle}{% - \setlength{\maketitlewidth}{0.8\textwidth}% - \hfil% - \parbox{\maketitlewidth}{% - \centering% - % name and title - \namestyle{\@firstname~\@lastname}% - \ifthenelse{\equal{\@title}{}}{}{\titlestyle{~|~\@title}}\\% \isundefined doesn't work on \@title, as LaTeX itself defines \@title (before it possibly gets redefined by \title) - % detailed information - \addressfont\color{color2}% - \ifthenelse{\isundefined{\@addressstreet}}{}{\addtomaketitle{\addresssymbol\@addressstreet}% - \ifthenelse{\equal{\@addresscity}{}}{}{\addtomaketitle[~--~]{\@addresscity}}% if \addresstreet is defined, \addresscity and \addresscountry will always be defined but could be empty - \ifthenelse{\equal{\@addresscountry}{}}{}{\addtomaketitle[~--~]{\@addresscountry}}% - \flushmaketitle\@firstmaketitleelementtrue\\}% - \collectionloop{phones}{% the key holds the phone type (=symbol command prefix), the item holds the number - \addtomaketitle{\csname\collectionloopkey phonesymbol\endcsname\collectionloopitem}}% - \ifthenelse{\isundefined{\@email}}{}{\addtomaketitle{\emailsymbol\emaillink{\@email}}}% - \ifthenelse{\isundefined{\@homepage}}{}{\addtomaketitle{\homepagesymbol\httplink{\@homepage}}}% - \ifthenelse{\isundefined{\@extrainfo}}{}{\addtomaketitle{\@extrainfo}}% - \flushmaketitle}\\[2.5em]}% need to force a \par after this to avoid weird spacing bug at the first section if no blank line is left after \maketitle - - -%------------------------------------------------------------------------------- -% resume style definition -%------------------------------------------------------------------------------- -% fonts -\renewcommand*{\namefont}{\Huge\bfseries\upshape} -\renewcommand*{\titlefont}{\Huge\mdseries\upshape} -\renewcommand*{\addressfont}{\normalsize\mdseries\upshape} -\renewcommand*{\quotefont}{\large\slshape} -\renewcommand*{\sectionfont}{\Large\bfseries\upshape} -\renewcommand*{\subsectionfont}{\large\upshape\fontseries{sb}\selectfont} -\renewcommand*{\hintfont}{\bfseries} - -% styles -\renewcommand*{\namestyle}[1]{{\namefont\textcolor{color1}{#1}}} -\renewcommand*{\titlestyle}[1]{{\titlefont\textcolor{color2!85}{#1}}} -\renewcommand*{\addressstyle}[1]{{\addressfont\textcolor{color1}{#1}}} -\renewcommand*{\quotestyle}[1]{{\quotefont\textcolor{color1}{#1}}} -\renewcommand*{\sectionstyle}[1]{{\sectionfont\textcolor{color1}{#1}}} -\renewcommand*{\subsectionstyle}[1]{{\subsectionfont\textcolor{color1}{#1}}} -\renewcommand*{\hintstyle}[1]{{\hintfont\textcolor{color0}{#1}}} - -% lengths -\newlength{\quotewidth} -\newlength{\hintscolumnwidth} -\setlength{\hintscolumnwidth}{0.3\textwidth}% -\newlength{\separatorcolumnwidth} -\setlength{\separatorcolumnwidth}{0.025\textwidth}% -\newlength{\maincolumnwidth} -\newlength{\doubleitemcolumnwidth} -\newlength{\listitemsymbolwidth} -\settowidth{\listitemsymbolwidth}{\listitemsymbol} -\newlength{\listitemmaincolumnwidth} -\newlength{\listdoubleitemmaincolumnwidth} - -% commands -\renewcommand*{\recomputecvlengths}{% - \setlength{\quotewidth}{0.65\textwidth}% - % main lenghts - \setlength{\maincolumnwidth}{\textwidth}% - % listitem lengths - \setlength{\listitemmaincolumnwidth}{\maincolumnwidth-\listitemsymbolwidth}% - % doubleitem lengths - \setlength{\doubleitemcolumnwidth}{\maincolumnwidth-\separatorcolumnwidth}% - \setlength{\doubleitemcolumnwidth}{0.5\doubleitemcolumnwidth}% - % listdoubleitem lengths - \setlength{\listdoubleitemmaincolumnwidth}{\maincolumnwidth-\listitemsymbolwidth-\separatorcolumnwidth-\listitemsymbolwidth}% - \setlength{\listdoubleitemmaincolumnwidth}{0.5\listdoubleitemmaincolumnwidth}% - % fancyhdr lengths - \renewcommand{\headwidth}{\textwidth}% - % regular lengths - \setlength{\parskip}{0\p@}} - -\renewcommand*{\makecvtitle}{% - % recompute lengths (in case we are switching from letter to resume, or vice versa) - \recomputecvlengths% - \maketitle% - % optional quote - \ifthenelse{\isundefined{\@quote}}% - {}% - {{\centering\begin{minipage}{\quotewidth}\centering\quotestyle{\@quote}\end{minipage}\\[2.5em]}}% - \par}% to avoid weird spacing bug at the first section if no blank line is left after \maketitle} - -\RenewDocumentCommand{\section}{sm}{% - \par\addvspace{2.5ex}% - \phantomsection{}% reset the anchor for hyperrefs - \addcontentsline{toc}{section}{#2}% - \strut\sectionstyle{#2}% - {\color{color1}\hrule}% - \par\nobreak\addvspace{1ex}\@afterheading} - -\newcommand{\subsectionfill}{\xleaders\hbox to 0.35em{\scriptsize.}\hfill}% different subsectionfills will not be perfectly aligned, but remaining space at the end of the fill will be distributed evenly between leaders, so it will be barely visible -\RenewDocumentCommand{\subsection}{sm}{% - \par\addvspace{1ex}% - \phantomsection{}% - \addcontentsline{toc}{subsection}{#2}% - \strut\subsectionstyle{#2}{\color{color1}{\subsectionfill}}% - \par\nobreak\addvspace{0.5ex}\@afterheading} - -\renewcommand*{\cvitem}[3][.25em]{% - \ifthenelse{\equal{#2}{}}{}{\hintstyle{#2}: }{#3}% - \par\addvspace{#1}} - -\renewcommand*{\cvdoubleitem}[5][.25em]{% - \begin{minipage}[t]{\doubleitemcolumnwidth}\hintstyle{#2}: #3\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \begin{minipage}[t]{\doubleitemcolumnwidth}\ifthenelse{\equal{#4}{}}{}{\hintstyle{#4}: }#5\end{minipage}% - \par\addvspace{#1}} - -\renewcommand*{\cvlistitem}[2][.25em]{% - \listitemsymbol\begin{minipage}[t]{\listitemmaincolumnwidth}#2\end{minipage}% - \par\addvspace{#1}} - -\renewcommand*{\cvlistdoubleitem}[3][.25em]{% - \cvitem[#1]{}{\listitemsymbol\begin{minipage}[t]{\listdoubleitemmaincolumnwidth}#2\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \ifthenelse{\equal{#3}{}}% - {}% - {\listitemsymbol\begin{minipage}[t]{\listdoubleitemmaincolumnwidth}#3\end{minipage}}}} - -\renewcommand*{\cventry}[7][.25em]{ - \begin{tabular*}{\textwidth}{l@{\extracolsep{\fill}}r}% - {\bfseries #4} & {\bfseries #5} \\% - {\itshape #3\ifthenelse{\equal{#6}{}}{}{, #6}} & {\itshape #2}\\% - \end{tabular*}% - \ifx&% - \else{\\\vbox{\small#7}}\fi% - \par\addvspace{#1}} - -\newbox{\cvitemwithcommentmainbox} -\newlength{\cvitemwithcommentmainlength} -\newlength{\cvitemwithcommentcommentlength} -\renewcommand*{\cvitemwithcomment}[4][.25em]{% - \savebox{\cvitemwithcommentmainbox}{\ifthenelse{\equal{#2}{}}{}{\hintstyle{#2}: }#3}% - \setlength{\cvitemwithcommentmainlength}{\widthof{\usebox{\cvitemwithcommentmainbox}}}% - \setlength{\cvitemwithcommentcommentlength}{\maincolumnwidth-\separatorcolumnwidth-\cvitemwithcommentmainlength}% - \begin{minipage}[t]{\cvitemwithcommentmainlength}\ifthenelse{\equal{#2}{}}{}{\hintstyle{#2}: }#3\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \begin{minipage}[t]{\cvitemwithcommentcommentlength}\raggedleft\small\itshape#4\end{minipage}% - \par\addvspace{#1}} - -\renewenvironment{thebibliography}[1]% - {% - \bibliographyhead{\refname}% -% \small% - \begin{list}{\bibliographyitemlabel}% - {% - \setlength{\topsep}{0pt}% - \setlength{\labelwidth}{0pt}% - \setlength{\labelsep}{0pt}% - \leftmargin\labelwidth% - \advance\leftmargin\labelsep% - \@openbib@code% - \usecounter{enumiv}% - \let\p@enumiv\@empty% - \renewcommand\theenumiv{\@arabic\c@enumiv}}% - \sloppy\clubpenalty4000\widowpenalty4000% -% \sfcode`\.\@m% -% \sfcode `\=1000\relax% - }% - {% - \def\@noitemerr{\@latex@warning{Empty `thebibliography' environment}}% - \end{list}% - } - - -%------------------------------------------------------------------------------- -% letter style definition -%------------------------------------------------------------------------------- -% commands -\renewcommand*{\recomputeletterlengths}{ - \recomputecvlengths% - \setlength{\parskip}{6\p@}} - -\renewcommand*{\makelettertitle}{% - % recompute lengths (in case we are switching from letter to resume, or vice versa) - \recomputeletterlengths% - % sender block - \maketitle% - \par% - % recipient block - \begin{minipage}[t]{.5\textwidth} - \raggedright% - \addressfont% - {\bfseries\upshape\@recipientname}\\% - \@recipientaddress% - \end{minipage} - % date - \hfill % US style -% \\[1em] % UK style - \@date\\[2em]% US informal style: "April 6, 2006"; UK formal style: "05/04/2006" - % opening - \raggedright% - \@opening\\[1.5em]% - % ensure no extra spacing after \makelettertitle due to a possible blank line -% \ignorespacesafterend% not working - \hspace{0pt}\par\vspace{-\baselineskip}\vspace{-\parskip}} - -\renewcommand*{\makeletterclosing}{ - \@closing\\[3em]% - {\bfseries \@firstname~\@lastname}% - \ifthenelse{\isundefined{\@enclosure}}{}{% - \\% - \vfill% - {\color{color2}\itshape\enclname: \@enclosure}}} - - -\endinput - - -%% end of file `moderncvstylebanking.sty'. diff --git a/users/aspen/resume/moderncvstylecasual.sty b/users/aspen/resume/moderncvstylecasual.sty deleted file mode 100644 index f8cf856d1..000000000 --- a/users/aspen/resume/moderncvstylecasual.sty +++ /dev/null @@ -1,183 +0,0 @@ -%% start of file `moderncvstylecasual.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvstylecasual}[2013/02/09 v1.3.0 modern curriculum vitae and letter style scheme: casual] - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- -\RequirePackage{moderncvstyleclassic} - - -%------------------------------------------------------------------------------- -% overall style definition -%------------------------------------------------------------------------------- -% commands -% footer symbol used to separate footer elements -\newcommand*{\footersymbol}{% - {~~~{\rmfamily\textbullet}~~~}}% the \rmfamily is required to force Latin Modern fonts when using sans serif, as OMS/lmss/m/n is not defined and gets substituted by OMS/cmsy/m/n -% internal command to add an element to the footer -% it collects the elements in a temporary box, and checks when to flush the box -\newsavebox{\footerbox}% -\newsavebox{\footertempbox}% -\newlength{\footerwidth}% -\newlength{\footerboxwidth}% -\newif\if@firstfooterelement\@firstfooterelementtrue% -% adds an element to the footer, separated by footersymbol -% usage: \addtofooter[footersymbol]{element} -\newcommand*{\addtofooter}[2][\footersymbol]{% - \if@firstfooterelement% - \savebox{\footertempbox}{\usebox{\footerbox}#2}% - \else% - \savebox{\footertempbox}{\usebox{\footerbox}#1#2}\fi% - \settowidth{\footerboxwidth}{\usebox{\footertempbox}}% - \ifnum\footerboxwidth<\footerwidth% - \savebox{\footerbox}{\usebox{\footertempbox}}% - \@firstfooterelementfalse% - \else% - \flushfooter\\% - \savebox{\footerbox}{#2}% - \savebox{\footertempbox}{#2}% - \settowidth{\footerboxwidth}{\usebox{\footerbox}}% - \@firstfooterelementfalse\fi} -% internal command to flush the footer -\newcommand*{\flushfooter}{% - \strut\usebox{\footerbox}% - \savebox{\footerbox}{}% - \savebox{\footertempbox}{}% - \setlength{\footerboxwidth}{0pt}} - - -%------------------------------------------------------------------------------- -% resume style definition -%------------------------------------------------------------------------------- -% fonts -\renewcommand*{\namefont}{\fontsize{38}{40}\mdseries\upshape} -\renewcommand*{\addressfont}{\normalsize\mdseries\slshape} -\newcommand*{\pronounsfont}{\fontsize{18}{40}\mdseries\upshape} - -% commands -\renewcommand*{\makecvtitle}{% - % recompute lengths (in case we are switching from letter to resume, or vice versa) - \recomputecvlengths% - % ensure footer with personal information - \makecvfooter% - % optional picture - \newbox{\makecvtitlepicturebox}% - \savebox{\makecvtitlepicturebox}{% - \ifthenelse{\isundefined{\@photo}}% - {}% - {% - \setlength\fboxrule{\@photoframewidth}% - \ifdim\@photoframewidth=0pt% - \setlength{\fboxsep}{0pt}\fi% - {\color{color1}\framebox{\includegraphics[width=\@photowidth]{\@photo}}}}}% - \usebox{\makecvtitlepicturebox}% - % name - \@initializelength{\makecvtitlepicturewidth}% - \settowidth{\makecvtitlepicturewidth}{\usebox{\makecvtitlepicturebox}}% - \parbox[b]{\textwidth-\makecvtitlepicturewidth}{% - \raggedleft\namefont{\color{color2!50}\@firstname} {\color{color2}\@lastname} {\color{color2!50}\pronounsfont{\@pronouns}}}\\[-.35em]% alternate design: \MakeLowercase and no space - {\color{color2!50}\rule{\textwidth}{.25ex}}% - % optional title - \ifthenelse{\equal{\@title}{}}{}{\\[1.25em]\null\hfill\titlestyle{\@title}}\\[2.5em]% \null is required as there is no box on the line after \\, so glue (and leaders) disappears; this is in contrast to after \par, where the next line starts with an indent box (even after \noindent). - % optional quote - \ifthenelse{\isundefined{\@quote}}% - {}% - {{\null\hfill\begin{minipage}{\quotewidth}\centering\quotestyle{\@quote}\end{minipage}\hfill\null\\[2.5em]}}% - \par}% to avoid weird spacing bug at the first section if no blank line is left after \maketitle - -\renewcommand*{\makecvfooter}{% - \setlength{\footerwidth}{0.8\textwidth}% - \fancypagestyle{plain}{% - \fancyfoot[c]{% - \parbox[b]{\footerwidth}{% - \centering% - \color{color2}\addressfont% - \ifthenelse{\isundefined{\@addressstreet}}{}{\addtofooter[]{\addresssymbol\@addressstreet}% - \ifthenelse{\equal{\@addresscity}{}}{}{\addtofooter[~--~]{\@addresscity}}% if \addresstreet is defined, \addresscity and \addresscountry will always be defined but could be empty - \ifthenelse{\equal{\@addresscountry}{}}{}{\addtofooter[~--~]{\@addresscountry}}% - \flushfooter\@firstfooterelementtrue\\}% - \collectionloop{phones}{% the key holds the phone type (=symbol command prefix), the item holds the number - \addtofooter{\csname\collectionloopkey phonesymbol\endcsname\collectionloopitem}}% - \ifthenelse{\isundefined{\@email}}{}{\addtofooter{\emailsymbol\emaillink{\@email}}}% - \ifthenelse{\isundefined{\@homepage}}{}{\addtofooter{\homepagesymbol\httplink{\@homepage}}}% - \ifthenelse{\isundefined{\@github}}{}{\addtofooter{\httplink{http://github.com/\@github}}}% - \ifthenelse{\isundefined{\@extrainfo}}{}{\addtofooter{\@extrainfo}}% - \ifthenelse{\lengthtest{\footerboxwidth=0pt}}{}{\flushfooter}% the lengthtest is required to avoid flushing an empty footer, which could cause a blank line due to the \\ after the address, if no other personal info is used - }}}% - \pagestyle{plain}} - - -%------------------------------------------------------------------------------- -% letter style definition -%------------------------------------------------------------------------------- -\renewcommand*{\makelettertitle}{% - % recompute lengths (in case we are switching from letter to resume, or vice versa) - \recomputeletterlengths% - % ensure footer with personal information - \makeletterfooter% - % recipient block - \begin{minipage}[t]{.5\textwidth} - \raggedright% - \addressfont% - {\bfseries\upshape\@recipientname}\\% - \@recipientaddress% - \end{minipage} - % date - \hfill% US style -% \\[1em]% UK style - \@date\\[2em]% US informal style: "April 6, 2006"; UK formal style: "05/04/2006" - % opening - \raggedright% - \@opening\\[1.5em]% - % ensure no extra spacing after \makelettertitle due to a possible blank line -% \ignorespacesafterend% not working - \hspace{0pt}\par\vspace{-\baselineskip}\vspace{-\parskip}} - -\renewcommand*{\makeletterfooter}{% - \setlength{\footerwidth}{0.8\textwidth}% - \fancypagestyle{plain}{% - \fancyfoot[c]{% - \parbox[b]{\footerwidth}{% - \centering% - \addressfont\color{color2}% - \vspace{-\baselineskip}% to cancel out the extra vertical space taken by the name (below) and ensure perfect alignment of letter and cv footers - \strut{\bfseries\upshape\@firstname~\@lastname}\\% the \strut is required to ensure the line is exactly \baselineskip tall - \ifthenelse{\isundefined{\@addressstreet}}{}{\addtofooter[]{\addresssymbol\@addressstreet}% - \ifthenelse{\equal{\@addresscity}{}}{}{\addtofooter[~--~]{\@addresscity}}% if \addresstreet is defined, \addresscity and addresscountry will always be defined but could be empty - \ifthenelse{\equal{\@addresscountry}{}}{}{\addtofooter[~--~]{\@addresscountry}}% - \flushfooter\@firstfooterelementtrue\\}% - \collectionloop{phones}{% the key holds the phone type (=symbol command prefix), the item holds the number - \addtofooter{\csname\collectionloopkey phonesymbol\endcsname\collectionloopitem}}% - \ifthenelse{\isundefined{\@email}}{}{\addtofooter{\emailsymbol\emaillink{\@email}}}% - \ifthenelse{\isundefined{\@homepage}}{}{\addtofooter{\homepagesymbol\httplink{\@homepage}}}% - \ifthenelse{\isundefined{\@extrainfo}}{}{\addtofooter{\@extrainfo}}% - \ifthenelse{\lengthtest{\footerboxwidth=0pt}}{}{\flushfooter}% the lengthtest is required to avoid flushing an empty footer, which could cause a blank line due to the \\ after the address, if no other personal info is used - }}}% - \pagestyle{plain}} - -\renewcommand*{\makeletterclosing}{ - \@closing\\[3em]% - {\bfseries\@firstname~\@lastname}% - \ifthenelse{\isundefined{\@enclosure}}{}{% - \\% - \vfil% - {\color{color2}\itshape\enclname: \@enclosure}}% - \vfil} - - -\endinput - - -%% end of file `moderncvstylecasual.sty'. diff --git a/users/aspen/resume/moderncvstyleclassic.sty b/users/aspen/resume/moderncvstyleclassic.sty deleted file mode 100644 index 63cf97aa3..000000000 --- a/users/aspen/resume/moderncvstyleclassic.sty +++ /dev/null @@ -1,294 +0,0 @@ -%% start of file `moderncvstyleclassic.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvstyleclassic}[2013/02/09 v1.3.0 modern curriculum vitae and letter style scheme: classic] - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- -% Latin Modern fonts -%\ifxetexorluatex -% \setmainfont{Latin Modern Roman} -% \setsansfont{Latin Modern Sans} -% \setmathfont{Latin Modern Math} -%\else - \IfFileExists{lmodern.sty}% - {\RequirePackage{lmodern}}% - {} -%\fi - - -%------------------------------------------------------------------------------- -% overall style definition -%------------------------------------------------------------------------------- -% symbols -\moderncvicons{marvosym} - - -%------------------------------------------------------------------------------- -% resume style definition -%------------------------------------------------------------------------------- -% fonts -\renewcommand*{\namefont}{\fontsize{34}{36}\mdseries\upshape} -\renewcommand*{\titlefont}{\LARGE\mdseries\slshape} -\renewcommand*{\addressfont}{\small\mdseries\slshape} -\renewcommand*{\quotefont}{\large\slshape} -\renewcommand*{\sectionfont}{\Large\mdseries\upshape} -\renewcommand*{\subsectionfont}{\large\mdseries\upshape} -\renewcommand*{\hintfont}{} - -% styles -\renewcommand*{\namestyle}[1]{{\namefont\textcolor{color0}{#1}}} -\renewcommand*{\titlestyle}[1]{{\titlefont\textcolor{color2}{#1}}} -\renewcommand*{\addressstyle}[1]{{\addressfont\textcolor{color1}{#1}}} -\renewcommand*{\quotestyle}[1]{{\quotefont\textcolor{color1}{#1}}} -\renewcommand*{\sectionstyle}[1]{{\sectionfont\textcolor{color1}{#1}}} -\renewcommand*{\subsectionstyle}[1]{{\subsectionfont\textcolor{color1}{#1}}} -\renewcommand*{\hintstyle}[1]{{\hintfont\textcolor{color0}{#1}}} - -% lengths -\newlength{\quotewidth} -\newlength{\hintscolumnwidth} -\setlength{\hintscolumnwidth}{0.175\textwidth} -\newlength{\separatorcolumnwidth} -\setlength{\separatorcolumnwidth}{0.025\textwidth} -\newlength{\maincolumnwidth} -\newlength{\doubleitemmaincolumnwidth} -\newlength{\listitemsymbolwidth} -\settowidth{\listitemsymbolwidth}{\listitemsymbol} -\newlength{\listitemmaincolumnwidth} -\newlength{\listdoubleitemmaincolumnwidth} - -% commands -\renewcommand*{\recomputecvlengths}{% - \setlength{\quotewidth}{0.65\textwidth}% - % main lenghts - \setlength{\maincolumnwidth}{\textwidth-\separatorcolumnwidth-\hintscolumnwidth}% - % listitem lengths - \setlength{\listitemmaincolumnwidth}{\maincolumnwidth-\listitemsymbolwidth}% - % doubleitem lengths - \setlength{\doubleitemmaincolumnwidth}{\maincolumnwidth-\hintscolumnwidth-\separatorcolumnwidth-\separatorcolumnwidth}% - \setlength{\doubleitemmaincolumnwidth}{0.5\doubleitemmaincolumnwidth}% - % listdoubleitem lengths - \setlength{\listdoubleitemmaincolumnwidth}{\maincolumnwidth-\listitemsymbolwidth-\separatorcolumnwidth-\listitemsymbolwidth}% - \setlength{\listdoubleitemmaincolumnwidth}{0.5\listdoubleitemmaincolumnwidth}% - % fancyhdr lengths - \renewcommand{\headwidth}{\textwidth}% - % regular lengths - \setlength{\parskip}{0\p@}} - -% optional maketitle width to force a certain width (if set to 0pt, the width is calculated automatically) -\newlength{\makecvtitlenamewidth} -\setlength{\makecvtitlenamewidth}{0pt}% dummy value -\renewcommand*{\makecvtitle}{% - % recompute lengths (in case we are switching from letter to resume, or vice versa) - \recomputecvlengths% - % optional detailed information (pre-rendering) - \def\phonesdetails{}% - \collectionloop{phones}{% the key holds the phone type (=symbol command prefix), the item holds the number - \protected@edef\phonesdetails{\phonesdetails\protect\makenewline\csname\collectionloopkey phonesymbol\endcsname\collectionloopitem}}% - \newbox{\makecvtitledetailsbox}% - \savebox{\makecvtitledetailsbox}{% - \addressfont\color{color2}% - \begin{tabular}[b]{@{}r@{}}% - \ifthenelse{\isundefined{\@addressstreet}}{}{\makenewline\addresssymbol\@addressstreet% - \ifthenelse{\equal{\@addresscity}{}}{}{\makenewline\@addresscity}% if \addresstreet is defined, \addresscity and addresscountry will always be defined but could be empty - \ifthenelse{\equal{\@addresscountry}{}}{}{\makenewline\@addresscountry}}% - \phonesdetails% needed to be pre-rendered as loops and tabulars seem to conflict - \ifthenelse{\isundefined{\@email}}{}{\makenewline\emailsymbol\emaillink{\@email}}% - \ifthenelse{\isundefined{\@homepage}}{}{\makenewline\homepagesymbol\httplink{\@homepage}}% - \ifthenelse{\isundefined{\@extrainfo}}{}{\makenewline\@extrainfo}% - \end{tabular} - }% - % optional photo (pre-rendering) - \newbox{\makecvtitlepicturebox}% - \savebox{\makecvtitlepicturebox}{% - \ifthenelse{\isundefined{\@photo}}% - {}% - {% - \hspace*{\separatorcolumnwidth}% - \color{color1}% - \setlength{\fboxrule}{\@photoframewidth}% - \ifdim\@photoframewidth=0pt% - \setlength{\fboxsep}{0pt}\fi% - \framebox{\includegraphics[width=\@photowidth]{\@photo}}}}% - % name and title - \newlength{\makecvtitledetailswidth}\settowidth{\makecvtitledetailswidth}{\usebox{\makecvtitledetailsbox}}% - \newlength{\makecvtitlepicturewidth}\settowidth{\makecvtitlepicturewidth}{\usebox{\makecvtitlepicturebox}}% - \ifthenelse{\lengthtest{\makecvtitlenamewidth=0pt}}% check for dummy value (equivalent to \ifdim\makecvtitlenamewidth=0pt) - {\setlength{\makecvtitlenamewidth}{\textwidth-\makecvtitledetailswidth-\makecvtitlepicturewidth}}% - {}% - \begin{minipage}[b]{\makecvtitlenamewidth}% - \namestyle{\@firstname\ \@lastname}% - \ifthenelse{\equal{\@title}{}}{}{\\[1.25em]\titlestyle{\@title}}% - \end{minipage}% - \hfill% - % optional detailed information (rendering) - \llap{\usebox{\makecvtitledetailsbox}}% \llap is used to suppress the width of the box, allowing overlap if the value of makecvtitlenamewidth is forced - % optional photo (rendering) - \usebox{\makecvtitlepicturebox}\\[2.5em]% - % optional quote - \ifthenelse{\isundefined{\@quote}}% - {}% - {{\centering\begin{minipage}{\quotewidth}\centering\quotestyle{\@quote}\end{minipage}\\[2.5em]}}% - \par}% to avoid weird spacing bug at the first section if no blank line is left after \makecvtitle - -\newlength{\baseletterheight} -\settoheight{\baseletterheight}{\sectionstyle{o}} -\setlength{\baseletterheight}{\baseletterheight-0.95ex} -\RenewDocumentCommand{\section}{sm}{% - \par\addvspace{2.5ex}% - \phantomsection{}% reset the anchor for hyperrefs - \addcontentsline{toc}{section}{#2}% - \parbox[t]{\hintscolumnwidth}{\strut\raggedleft\raisebox{\baseletterheight}{\color{color1}\rule{\hintscolumnwidth}{0.95ex}}}% - \hspace{\separatorcolumnwidth}% - \parbox[t]{\maincolumnwidth}{\strut\sectionstyle{#2}}% - \par\nobreak\addvspace{1ex}\@afterheading}% to avoid a pagebreak after the heading - -\RenewDocumentCommand{\subsection}{sm}{% - \par\addvspace{1ex}% - \phantomsection{}% reset the anchor for hyperrefs - \addcontentsline{toc}{subsection}{#2}% - \begin{tabular}{@{}p{\hintscolumnwidth}@{\hspace{\separatorcolumnwidth}}p{\maincolumnwidth}@{}}% - \raggedleft\hintstyle{} &{\strut\subsectionstyle{#2}}% - \end{tabular}% - \par\nobreak\addvspace{0.5ex}\@afterheading}% to avoid a pagebreak after the heading - -\renewcommand*{\cvitem}[3][.25em]{% - \begin{tabular}{@{}p{\hintscolumnwidth}@{\hspace{\separatorcolumnwidth}}p{\maincolumnwidth}@{}}% - \raggedleft\hintstyle{#2} &{#3}% - \end{tabular}% - \par\addvspace{#1}} - -\renewcommand*{\cvdoubleitem}[5][.25em]{% - \cvitem[#1]{#2}{% - \begin{minipage}[t]{\doubleitemmaincolumnwidth}#3\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \begin{minipage}[t]{\hintscolumnwidth}\raggedleft\hintstyle{#4}\end{minipage}% - \hspace*{\separatorcolumnwidth}% - \begin{minipage}[t]{\doubleitemmaincolumnwidth}#5\end{minipage}}} - -\renewcommand*{\cvlistitem}[2][.25em]{% - \cvitem[#1]{}{\listitemsymbol\begin{minipage}[t]{\listitemmaincolumnwidth}#2\end{minipage}}} - -\renewcommand*{\cvlistdoubleitem}[3][.25em]{% - \cvitem[#1]{}{\listitemsymbol\begin{minipage}[t]{\listdoubleitemmaincolumnwidth}#2\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \ifthenelse{\equal{#3}{}}% - {}% - {\listitemsymbol\begin{minipage}[t]{\listdoubleitemmaincolumnwidth}#3\end{minipage}}}} - -\renewcommand*{\cventry}[7][.25em]{% - \cvitem[#1]{#2}{% - {\bfseries#3}% - \ifthenelse{\equal{#4}{}}{}{, {\slshape#4}}% - \ifthenelse{\equal{#5}{}}{}{, #5}% - \ifthenelse{\equal{#6}{}}{}{, #6}% - .\strut% - \ifx&% - \else{\newline{}\begin{minipage}[t]{\linewidth}\small#7\end{minipage}}\fi}} - -\newbox{\cvitemwithcommentmainbox} -\newlength{\cvitemwithcommentmainlength} -\newlength{\cvitemwithcommentcommentlength} -\renewcommand*{\cvitemwithcomment}[4][.25em]{% - \savebox{\cvitemwithcommentmainbox}{{\bfseries#3}}% - \setlength{\cvitemwithcommentmainlength}{\widthof{\usebox{\cvitemwithcommentmainbox}}}% - \setlength{\cvitemwithcommentcommentlength}{\maincolumnwidth-\separatorcolumnwidth-\cvitemwithcommentmainlength}% - \cvitem[#1]{#2}{% - \begin{minipage}[t]{\cvitemwithcommentmainlength}\bfseries#3\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \begin{minipage}[t]{\cvitemwithcommentcommentlength}\raggedleft\small\itshape#4\end{minipage}}} - -\renewenvironment{thebibliography}[1]% - {% - \bibliographyhead{\refname}% -% \small% - \begin{list}{\bibliographyitemlabel}% - {% - \setlength{\topsep}{0pt}% - \setlength{\labelwidth}{\hintscolumnwidth}% - \setlength{\labelsep}{\separatorcolumnwidth}% - \leftmargin\labelwidth% - \advance\leftmargin\labelsep% - \@openbib@code% - \usecounter{enumiv}% - \let\p@enumiv\@empty% - \renewcommand\theenumiv{\@arabic\c@enumiv}}% - \sloppy\clubpenalty4000\widowpenalty4000% -% \sfcode`\.\@m% -% \sfcode `\=1000\relax% - }% - {% - \def\@noitemerr{\@latex@warning{Empty `thebibliography' environment}}% - \end{list}% - } - - -%------------------------------------------------------------------------------- -% letter style definition -%------------------------------------------------------------------------------- -% commands -\renewcommand*{\recomputeletterlengths}{% - \recomputecvlengths% - \setlength{\parskip}{6\p@}} - -\renewcommand*{\makelettertitle}{% - % recompute lengths (in case we are switching from letter to resume, or vice versa) - \recomputeletterlengths% - % sender contact info - \hfill% - \begin{minipage}{.5\textwidth}% - \raggedleft% - \addressfont\textcolor{color2}{% - {\bfseries\upshape\@firstname~\@lastname}\@firstdetailselementfalse% - \ifthenelse{\isundefined{\@addressstreet}}{}{\makenewline\addresssymbol\@addressstreet% - \ifthenelse{\equal{\@addresscity}{}}{}{\makenewline\@addresscity}% if \addresstreet is defined, \addresscity and addresscountry will always be defined but could be empty - \ifthenelse{\equal{\@addresscountry}{}}{}{\makenewline\@addresscountry}}% - \collectionloop{phones}{% the key holds the phone type (=symbol command prefix), the item holds the number - \makenewline\csname\collectionloopkey phonesymbol\endcsname\collectionloopitem}% - \ifthenelse{\isundefined{\@email}}{}{\makenewline\emailsymbol\emaillink{\@email}}% - \ifthenelse{\isundefined{\@homepage}}{}{\makenewline\homepagesymbol\httplink{\@homepage}}% - \ifthenelse{\isundefined{\@extrainfo}}{}{\makenewline\@extrainfo}}% - \end{minipage}\\[1em] - % recipient block - \begin{minipage}[t]{.5\textwidth} - \raggedright% - \addressfont% - {\bfseries\upshape\@recipientname}\\% - \@recipientaddress% - \end{minipage} - % date - \hfill% US style -% \\[1em]% UK style - \@date\\[2em]% US informal style: "January 1, 1900"; UK formal style: "01/01/1900" - % opening - \raggedright% - \@opening\\[1.5em]% - % ensure no extra spacing after \makelettertitle due to a possible blank line -% \ignorespacesafterend% not working - \hspace{0pt}\par\vspace{-\baselineskip}\vspace{-\parskip}} - -\renewcommand*{\makeletterclosing}{ - \@closing\\[3em]% - {\bfseries \@firstname~\@lastname}% - \ifthenelse{\isundefined{\@enclosure}}{}{% - \\% - \vfill% - {\color{color2}\itshape\enclname: \@enclosure}}} - - -\endinput - - -%% end of file `moderncvstyleclassic.sty'. diff --git a/users/aspen/resume/moderncvstyleempty.sty b/users/aspen/resume/moderncvstyleempty.sty deleted file mode 100644 index 85932464d..000000000 --- a/users/aspen/resume/moderncvstyleempty.sty +++ /dev/null @@ -1,34 +0,0 @@ -%% start of file `moderncvstyleempty.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvstyleempty}[2013/02/09 v1.3.0 modern curriculum vitae scheme: empty] - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- - - -%------------------------------------------------------------------------------- -% package options -%------------------------------------------------------------------------------- - - -%------------------------------------------------------------------------------- -% style definition -%------------------------------------------------------------------------------- -% see moderncv.cls for command declarations that needs to be implemented, e.g. \maketitle, \section, \subsections, \cvline, etc - -\endinput - - -%% end of file `moderncvstyleempty.sty'. diff --git a/users/aspen/resume/moderncvstyleoldstyle.sty b/users/aspen/resume/moderncvstyleoldstyle.sty deleted file mode 100644 index ff732f4e2..000000000 --- a/users/aspen/resume/moderncvstyleoldstyle.sty +++ /dev/null @@ -1,306 +0,0 @@ -%% start of file `moderncvstyleoldstyle.sty'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -%------------------------------------------------------------------------------- -% identification -%------------------------------------------------------------------------------- -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{moderncvstyleoldstyle}[2013/02/09 v1.3.0 modern curriculum vitae and letter style scheme: oldstyle] - - -%------------------------------------------------------------------------------- -% required packages -%------------------------------------------------------------------------------- -% change the layout of the page on the fly, for resume or letter layout -\RequirePackage{changepage} - - -%------------------------------------------------------------------------------- -% overall style definition -%------------------------------------------------------------------------------- -% fonts -%\ifxetexorluatex -% \setmainfont[Numbers={OldStyle,Proportional}, BoldFont={Kurier Bold}, ItalicFont={Kurier Light Italic}, BoldItalicFont={Kurier Bold Italic}]{Kurier Light} -% \setsansfont[Numbers={OldStyle,Proportional}, BoldFont={Kurier Bold}, ItalicFont={Kurier Light Italic}, BoldItalicFont={Kurier Bold Italic}]{Kurier Light} -% \setmathfont{Kurier Light} -% \setmathfont[range=\mathit,\mathsfit]{Kurier Light Italic} -% \setmathfont[range=\mathbfup,\mathbfsfup]{Kurier Bold} -% \setmathfont[range=\mathbfit,\mathbfsfit]{Kurier Bold Italic} -%\else - \IfFileExists{kurier.sty}% - {\RequirePackage[light,math]{kurier}}% - {} -%\fi - -% symbols -\moderncvicons{letters} - - -%------------------------------------------------------------------------------- -% resume style definition -%------------------------------------------------------------------------------- -% fonts -\renewcommand*{\namefont}{\fontsize{34}{36}\mdseries\upshape} -\renewcommand*{\titlefont}{\LARGE\mdseries\slshape} -\renewcommand*{\addressfont}{\small\mdseries} -\renewcommand*{\quotefont}{\large\itshape} -\renewcommand*{\sectionfont}{\Large\bfseries\upshape} -\renewcommand*{\subsectionfont}{\large\bfseries\itshape} -\renewcommand*{\hintfont}{\bfseries} - -% styles -\renewcommand*{\namestyle}[1]{{\namefont\textcolor{color0}{#1}}} -\renewcommand*{\titlestyle}[1]{{\titlefont\textcolor{color2}{#1}}} -\renewcommand*{\addressstyle}[1]{{\addressfont\textcolor{color2}{#1}}} -\renewcommand*{\quotestyle}[1]{{\quotefont\textcolor{color1}{#1}}} -\renewcommand*{\sectionstyle}[1]{{\sectionfont\textcolor{color1}{#1}}} -\renewcommand*{\subsectionstyle}[1]{{\subsectionfont\textcolor{color1}{#1}}} -\renewcommand*{\hintstyle}[1]{{\hintfont\textcolor{color0}{#1}}} - -% lengths -\newlength{\quotewidth} -\newlength{\hintscolumnwidth} -\setlength{\hintscolumnwidth}{0.3\textwidth}% -\newlength{\separatorcolumnwidth} -\setlength{\separatorcolumnwidth}{0.025\textwidth}% -\newlength{\maincolumnwidth} -\newlength{\doubleitemcolumnwidth} -\newlength{\listitemsymbolwidth} -\settowidth{\listitemsymbolwidth}{\listitemsymbol} -\newlength{\listitemmaincolumnwidth} -\newlength{\listdoubleitemmaincolumnwidth} - -% commands -\setlength{\marginparwidth}{0\p@}% -\setlength{\marginparsep}{0\p@} -\renewcommand*{\recomputecvlengths}{% - % regular lengths - \changepage{}{+\marginparwidth+\marginparsep}{}{}{}{}{}{}{}% if a letter was typeset before the resume, \marginparwidth and \marginparsep will be non-zero; otherwise, this has no effect - \setlength{\marginparwidth}{0\p@}% - \setlength{\marginparsep}{0\p@} - \setlength{\parskip}{0\p@}% - % maketitle lengths - \setlength{\quotewidth}{0.65\textwidth}% - % main lenghts - \setlength{\maincolumnwidth}{\textwidth-\hintscolumnwidth-\separatorcolumnwidth}% - % listitem lengths - \setlength{\listitemmaincolumnwidth}{\maincolumnwidth-\listitemsymbolwidth}% - % doubleitem lengths - \setlength{\doubleitemcolumnwidth}{\maincolumnwidth-\separatorcolumnwidth}% - \setlength{\doubleitemcolumnwidth}{0.5\doubleitemcolumnwidth}% - % listdoubleitem lengths - \setlength{\listdoubleitemmaincolumnwidth}{\maincolumnwidth-\listitemsymbolwidth-\separatorcolumnwidth-\listitemsymbolwidth}% - \setlength{\listdoubleitemmaincolumnwidth}{0.5\listdoubleitemmaincolumnwidth}% - % fancyhdr lengths - \renewcommand{\headwidth}{\textwidth}} - -\newcommand{\makecvinfo}[1]{% - \newbox{\makecvinfobox}% - \savebox{\makecvinfobox}{\parbox[t]{\hintscolumnwidth}{#1}}% - \newlength{\makecvinfoheight}% - \setlength{\makecvinfoheight}{\totalheightof{\usebox{\makecvinfobox}}}% the total height of the parbox is the sum of its height (\the\ht\makeinfobox) and its depth (\the\dp\makeinfobox); the \totalheightof command is provided by the "calc" package - \usebox{\makecvinfobox}\vspace{-\makecvinfoheight}% - \newlength{\leftcolumnwidth}% - \setlength{\leftcolumnwidth}{\hintscolumnwidth+\separatorcolumnwidth}% - \par\vspace{-\baselineskip}\vspace{-\parskip}\leftskip=\leftcolumnwidth} - -\renewcommand*{\makecvtitle}{ - % recompute lengths (in case we are switching from letter to resume, or vice versa) - \recomputecvlengths% - % optional picture box - \newbox{\makecvtitlepicturebox}% - \savebox{\makecvtitlepicturebox}{% - \ifthenelse{\isundefined{\@photo}}% - {}% - {% - \color{color1}% - \setlength\fboxrule{\@photoframewidth}% - \ifdim\@photoframewidth=0pt% - \setlength{\fboxsep}{0pt}\fi% - \framebox{\includegraphics[width=\@photowidth]{\@photo}}}}% - % name and title - \newlength{\makecvtitlepicturewidth}\settowidth{\makecvtitlepicturewidth}{\usebox{\makecvtitlepicturebox}}% - \newlength{\makecvtitlenamewidth}\setlength{\makecvtitlenamewidth}{\textwidth-\makecvtitlepicturewidth}% - \begin{minipage}[b]{\makecvtitlenamewidth}% - \namestyle{\@firstname\ \@lastname}% - \ifthenelse{\equal{\@title}{}}{}{\\[1.25em]\titlestyle{\@title}}% - \end{minipage}% - % optional photo - \usebox{\makecvtitlepicturebox}\\[2.5em]% - % optional quote - \ifthenelse{\isundefined{\@quote}}% - {}% - {{\centering\begin{minipage}{\quotewidth}\centering\quotestyle{\@quote}\end{minipage}\\[2.5em]}}% - % optional details - \makecvinfo{% - \addressfont\color{color2}% - \ifthenelse{\isundefined{\@addressstreet}}{}{\makenewline\addresssymbol\@addressstreet% - \ifthenelse{\equal{\@addresscity}{}}{}{\makenewline\@addresscity}% if \addresstreet is defined, \addresscity and \addresscountry will always be defined but could be empty - \ifthenelse{\equal{\@addresscountry}{}}{}{\makenewline\@addresscountry}}% - \collectionloop{phones}{% the key holds the phone type (=symbol command prefix), the item holds the number - \makenewline\csname\collectionloopkey phonesymbol\endcsname\collectionloopitem}% - \ifthenelse{\isundefined{\@email}}{}{\makenewline\emailsymbol\emaillink{\@email}}% - \ifthenelse{\isundefined{\@homepage}}{}{\makenewline\homepagesymbol\httplink{\@homepage}}% - \ifthenelse{\isundefined{\@extrainfo}}{}{\makenewline\@extrainfo}}} - -\RenewDocumentCommand{\section}{sm}{% - \par\addvspace{2.5ex}% - \phantomsection{}% reset the anchor for hyperrefs - \addcontentsline{toc}{section}{#2}% - \strut\sectionstyle{#2}% - \par\nobreak\addvspace{1ex}\@afterheading}% to avoid a pagebreak after the heading - -\RenewDocumentCommand{\subsection}{sm}{% - \par\addvspace{1ex}% - \phantomsection{}% reset the anchor for hyperrefs - \addcontentsline{toc}{subsection}{#2}% - \strut\subsectionstyle{#2}% - \par\nobreak\addvspace{0.5ex}\@afterheading}% to avoid a pagebreak after the heading - -\renewcommand*{\cvitem}[3][.25em]{% - \ifthenelse{\equal{#2}{}}{}{\hintstyle{#2}: }{#3}% - \par\addvspace{#1}} - -\renewcommand*{\cvdoubleitem}[5][.25em]{% - \begin{minipage}[t]{\doubleitemcolumnwidth}\hintstyle{#2}: #3\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \begin{minipage}[t]{\doubleitemcolumnwidth}\ifthenelse{\equal{#4}{}}{}{\hintstyle{#4}: }#5\end{minipage}% - \par\addvspace{#1}} - -\renewcommand*{\cvlistitem}[2][.25em]{% - \cvitem[#1]{}{\listitemsymbol\begin{minipage}[t]{\listitemmaincolumnwidth}#2\end{minipage}}} - -\renewcommand*{\cvlistdoubleitem}[3][.25em]{% - \cvitem[#1]{}{\listitemsymbol\begin{minipage}[t]{\listdoubleitemmaincolumnwidth}#2\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \ifthenelse{\equal{#3}{}}% - {}% - {\listitemsymbol\begin{minipage}[t]{\listdoubleitemmaincolumnwidth}#3\end{minipage}}}} - -\newbox{\cventryyearbox} -\newlength{\cventrytitleboxwidth} -\renewcommand*{\cventry}[7][.25em]{% - \savebox{\cventryyearbox}{% - \hspace*{2\separatorcolumnwidth}% - \hintstyle{#2}}% - \setlength{\cventrytitleboxwidth}{\widthof{\usebox{\cventryyearbox}}}% - \setlength{\cventrytitleboxwidth}{\maincolumnwidth-\cventrytitleboxwidth}% - \begin{minipage}{\maincolumnwidth}% - \parbox[t]{\cventrytitleboxwidth}{% - \strut% - {\bfseries#3}% - \ifthenelse{\equal{#4}{}}{}{, {\slshape#4}}% - \ifthenelse{\equal{#5}{}}{}{, #5}% - \ifthenelse{\equal{#6}{}}{}{, #6}% - .\strut}% - \usebox{\cventryyearbox}% - \end{minipage}% - \ifx&% - \else{% - \newline{}% - \begin{minipage}[t]{\maincolumnwidth}% - \small% - #7% - \end{minipage}}\fi% - \par\addvspace{#1}} - -\newbox{\cvitemwithcommentmainbox} -\newlength{\cvitemwithcommentmainlength} -\newlength{\cvitemwithcommentcommentlength} -\renewcommand*{\cvitemwithcomment}[4][.25em]{% - \savebox{\cvitemwithcommentmainbox}{\ifthenelse{\equal{#2}{}}{}{\hintstyle{#2}: }#3}% - \setlength{\cvitemwithcommentmainlength}{\widthof{\usebox{\cvitemwithcommentmainbox}}}% - \setlength{\cvitemwithcommentcommentlength}{\maincolumnwidth-\separatorcolumnwidth-\cvitemwithcommentmainlength}% - \begin{minipage}[t]{\cvitemwithcommentmainlength}\ifthenelse{\equal{#2}{}}{}{\hintstyle{#2}: }#3\end{minipage}% - \hfill% fill of \separatorcolumnwidth - \begin{minipage}[t]{\cvitemwithcommentcommentlength}\raggedleft\small\itshape#4\end{minipage}% - \par\addvspace{#1}} - -\renewenvironment{thebibliography}[1]% - {% - \bibliographyhead{\refname}% -% \small% - \begin{list}{\bibliographyitemlabel}% - {% - \setlength{\topsep}{0pt}% - \setlength{\labelwidth}{\hintscolumnwidth}% - \setlength{\labelsep}{\separatorcolumnwidth}% - \leftmargin\labelwidth% - \advance\leftmargin\labelsep% - \@openbib@code% - \usecounter{enumiv}% - \let\p@enumiv\@empty% - \renewcommand\theenumiv{\@arabic\c@enumiv}}% - \sloppy\clubpenalty4000\widowpenalty4000% -% \sfcode`\.\@m% -% \sfcode `\=1000\relax% - }% - {% - \def\@noitemerr{\@latex@warning{Empty `thebibliography' environment}}% - \end{list}% - } - - -%------------------------------------------------------------------------------- -% letter style definition -%------------------------------------------------------------------------------- -% commands -%\newlength{\textwidthdelta}% -\renewcommand*{\recomputeletterlengths}{% - \recomputecvlengths% - \setlength{\parskip}{6\p@}% - \leftskip=0pt% -% \setlength{\textwidthdelta}{+\marginparwidth+\marginparsep}% - \setlength{\marginparwidth}{\hintscolumnwidth}% - \setlength{\marginparsep}{2\separatorcolumnwidth}% -% \addtolength{\textwidthdelta}{-\marginparwidth-\marginparsep}% -% \changepage{}{\textwidthdelta}{-\textwidthdelta}{}{}{}{}{}{}%\changepage{<textheight>}{<textwidth>}{<evensidemargin>}{<oddsidemargin>}{<columnsep>}{<topmargin>}{<headheight>}{<headsep>}{<footskip>} - \changepage{}{-\marginparwidth-\marginparsep}{}{}{}{}{}{}{}%\changepage{<textheight>}{<textwidth>}{<evensidemargin>}{<oddsidemargin>}{<columnsep>}{<topmargin>}{<headheight>}{<headsep>}{<footskip>} - } - -\renewcommand*{\makelettertitle}{% - % recompute lengths (in case we are switching from letter to resume, or vice versa) - \recomputeletterlengths% - % recipient block - {\addressfont% - {\bfseries\upshape\@recipientname}\\% - \@recipientaddress}\\[1em]% - % date - \@date\\[2em]% - % opening - \@opening\\[1.5em]% - % sender contact info - \hspace{0pt}% - \marginpar{% - \addressfont\textcolor{color2}{% - {\bfseries\@firstname~\@lastname}\@firstdetailselementfalse% - \ifthenelse{\isundefined{\@addressstreet}}{}{\makenewline\addresssymbol\@addressstreet% - \ifthenelse{\equal{\@addresscity}{}}{}{\makenewline\@addresscity}% if \addresstreet is defined, \addresscity and \addresscountry will always be defined but could be empty - \ifthenelse{\equal{\@addresscountry}{}}{}{\makenewline\@addresscountry}}% - \collectionloop{phones}{% the key holds the phone type (=symbol command prefix), the item holds the number - \makenewline\csname\collectionloopkey phonesymbol\endcsname\collectionloopitem}% - \ifthenelse{\isundefined{\@email}}{}{\makenewline\emailsymbol\emaillink{\@email}}% - \ifthenelse{\isundefined{\@homepage}}{}{\makenewline\homepagesymbol\httplink{\@homepage}}% - \ifthenelse{\isundefined{\@extrainfo}}{}{\makenewline\@extrainfo}}}% - % ensure no extra spacing after \makelettertitle due to a possible blank line -% \ignorespacesafterend% not working - \par\vspace{-\baselineskip}\vspace{-\parskip}} - -\renewcommand*{\makeletterclosing}{ - \@closing\\[3em]% - {\bfseries\@firstname~\@lastname}% - \ifthenelse{\isundefined{\@enclosure}}{}{% - \\% - \vfill% - {\color{color2}\itshape\enclname: \@enclosure}}} - - -\endinput - - -%% end of file `moderncvstyleoldstyle.sty'. diff --git a/users/aspen/resume/picture.png b/users/aspen/resume/picture.png deleted file mode 100644 index 63b21b532..000000000 Binary files a/users/aspen/resume/picture.png and /dev/null differ diff --git a/users/aspen/resume/resume.tex b/users/aspen/resume/resume.tex deleted file mode 100644 index 11febeb01..000000000 --- a/users/aspen/resume/resume.tex +++ /dev/null @@ -1,252 +0,0 @@ -%% start of file `template.tex'. -%% Copyright 2006-2013 Xavier Danaux (xdanaux@gmail.com). -%% Copyright 2014-2023 Griffin Smith (root@gws.fyi). -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -\documentclass[10pt,a4paper,sans]{moderncv} % possible options include font size ('10pt', '11pt' and '12pt'), paper size ('a4paper', 'letterpaper', 'a5paper', 'legalpaper', 'executivepaper' and 'landscape') and font family ('sans' and 'roman') - -\usepackage[inline]{enumitem} - - -% moderncv themes -% style options are 'casual' (default), 'classic', 'oldstyle' and 'banking' -\moderncvstyle{casual} -% color options 'blue' (default), 'orange', 'green', 'red', 'purple', 'grey' and 'black' -\moderncvcolor{black} -% to set the default font; use '\sfdefault' for the default sans serif font, -% '\rmdefault' for the default roman one, or any tex font name -%\renewcommand{\familydefault}{\sfdefault} -\nopagenumbers{} - -\usepackage[utf8]{inputenc} - -\usepackage[scale=0.8, margin=0.65in]{geometry} -\setlength{\hintscolumnwidth}{2.6cm} - -\name{Aspen}{Smith} -\pronouns{she/her} -\title{Software Engineer} -\phone[mobile]{(720) 206-7218} -\email{aspen@gws.fyi} -\homepage{gws.fyi} -\extrainfo{she/her} - - -\begin{document} -\makecvtitle{} -\section{Skills} -\cvitem{Rust}{Expertise in high-performance, low latency, low-level systems -development with Rust, including everything from fundamental data structure -implementation to asynchronous distributed systems development} -\cvitem{Clojure}{Extensive experience architecting, deploying, and building -complex web applications in Clojure and Clojurescript, with a focus on -Re-Frame and Reagent. Experience testing distributed systems in Clojure using -Jepsen.} -\cvitem{Haskell}{Passionate love for pure functional programming as a hobbyist -pursuit, but also practical experience building production systems in Haskell at -scale, and using Haskell's advanced type system extensions where appropriate to -deliver increased ergonomics and safety.} -\cvitem{Nix}{Experience with adopting and teaching nix at scale in a production -stack both for local development dependencies and for configuring and building -production software. Core contributer to a fork of the nix implementation itself -(tvix) aimed at providing increased safety, performance, and flexibility.} -\cvitem{Unix/Linux}{Experience with administrating highly available distributed -systems. Passion for the Unix philosophy of discrete, composable units of -functionality.} -\cvitem{Ruby}{Experience building both full-stack applications with Ruby on -Rails in addition to smaller microservices and custom frameworks. Deep -understanding of the internals of the Ruby interpreter and object system.} -\cvitem{Javascript}{Experience developing real-time responsive single-page web -applications using React, in addition to significant contributions to the React -open-source community.} -\cvitem{SQL}{Deep understanding of relational databases as an -implementer, in the context of an innovative new database implementing a query -planner and incremental materialization for the PostgreSQL and MySQL dialects of -SQL from the ground up -- and of course also a user} - -\subsection{Additional Tools} -\cvitem{}{\footnotesize - \begin{itemize*} - \item Vim - \item Emacs (yes, also) - \item Kubernetes - \item Git - \item Terraform - \item AWS - \item GCP - \item Datomic - \item Elasticsearch - \item Redis - \item Docker - \item Java - \item Scala - \item QuickCheck (and similar tools) - \item Jepsen - \item Python - \item Elixir - \end{itemize*} - \newline - \textbf{Novice Level:} - \begin{itemize*} - \item C++ - \item Erlang - \item Prolog - \item Idris - \item Agda - \item Tensorflow - \end{itemize*}} - -\section{Experience} -\cventry{2020--2023}{Staff Software Engineer}{ReadySet}{Remote}{} -{Founding engineer at a startup bringing a high performance - partially-stateful, incrementally-maintained SQL database based on the Noria - thesis to market - \begin{itemize} - \item Served as the main technical leadership for the project throughout its - maturation from a research codebase to a production-grade system - \item Extended the Noria PhD thesis by implementing methods from multiple - research papers, masters theses, and other papers from database - research, in addition to original database research and development. - \item Invented or helped develop multiple novel database techniques in - partially materialized dataflow, including index planning and - selection, pagination, post-lookup aggregate processing, partial - ``straddled'' joins, weak indexes for correct execution of partial - joins, and more. - \item Invented novel ways to test SQL databases, including a new deterministic - generator for SQL queries. - \item Developed the clustered high availability distributed runtime mode from - a buggy research feature into a production ready distributed system - that passed a suite of Jepsen tests. - \item Implemented a significant fraction of the SQL query planner, which - required both implementing algorithms specified in database research - papers and inventing new techniques to work around the limitations of - partially materialized dataflow - \item Optimized critical components of the code base, including algorithmic - optimizations, CPU cache analysis, low-level data structures, and - broad system runtime analysis - \item Implemented a type inference engine and expression evaluator that - supported multiple dialects of SQL configured at compile-time, with - maximum code reuse while preserving maintainability - \item Mentored multiple junior and senior engineers - \item Open-Source contributions visible at - \url{https://github.com/readysettech/readyset/commits?author=glittershark} - \end{itemize}} -\cventry{2019--2020}{Engineering Manager}{Urbint}{New York, NY}{} -{\begin{itemize} - \item Lead of the platform team with two direct reports - a senior SRE and - a senior software engineer. - \item Performed user research on developers, project managers, product - managers, and other internal stakeholders to build the roadmap for the - platform team. - \item Built and maintained a system to deploy one-off full stack - application instances from pull requests to enable easier testing. - \item Led a large, multi-project migration between CI systems that resulted - in a decrease of average build times from 2 hours to less than 10 minutes. - \item Maintained and extended Nix-based build and development - infrastructure for both software engineers and machine learning engineers. - \end{itemize}} -\cventry{2018--2019}{Senior Software Engineer}{Urbint}{New York, NY}{} -{\begin{itemize} - \item Built, trained, and maintained a large, deep-learning-based - image-detection model for semi-automated (human-in-the-loop) video - classification. - \item Designed, built, and maintained a novel in-house tool for collection of - training data. - \item Maintained and guaranteed reliability of a large data pipeline for - video processing and classification. - \end{itemize}} -\cventry{2017--2018}{Senior Software Engineer}{Urbint}{New York, NY}{} -{\begin{itemize} - \item Integral in the architecture of a novel, serializable ACID - transactional graph database built on RocksDB, first in Elixir then in - Haskell. - \item Helped ship customer deliverables involving multi-day data - processing jobs for disparate data sources. - \item Instructed other developers in the use of and theory behind Haskell - \item Brought computational graph theory to bear on the problem of unifying - disparate, highly heterogeneous data sources across the world of open data. - \end{itemize}} -\cventry{2016--2017}{Senior Software Engineer}{SecurityScorecard, Inc.}{New York, NY}{} -{Lead frontend developer for a rapidly-moving and growing security software startup. - \begin{itemize} - \item Took part in collaborative product design meetings to make UX - tradeoffs with product designers and managers. - \item Drove application architecture for a large, complex, data-driven frontend - application. - \item Championed increased use of production monitoring and alerting. - \item Worked with business stakeholders to set long- and short-term priorities for - application development. - \item Mentored junior team members. - \end{itemize}} -\cventry{2015--2016}{Lead Developer}{Nomi, Inc.}{New York, NY}{} -{Lead web services developer transitioning to a full-stack role implementing - shared software components and architecting a large, complex microservices - application ingesting hundreds of gigabytes of IoT data per week. - \begin{itemize} - \item Lead application architecture of the majority of the backend services to - encourage consistent REST API design and code sharing. - \item Championed the use of Haskell for rapid, safe development of the API Gateway - service. - \item Took ownership of operations and server maintenance of a >100-instance AWS - account using Puppet. - \end{itemize}} -\cventry{2014--2015}{Lead Developer}{LandlordsNY, LLC}{New York, NY}{} -{Sole engineer for a small startup connecting landlords and property managers and - facilitating the online sharing of information in a historically technology-averse - industry. - \begin{itemize} - \item Drove product design, visual design, and UX architecture for a major revamping - of the core product. - \item Interfaced with customers to set priorities for new feature development. - \item Conducted hiring and recruiting to build out an engineering team. - \end{itemize}} -\cventry{2012--2014}{Associate Developer}{Visionlink Inc.}{Boulder, CO}{} -{Integral member of an agile development team building the nation's most-used Information - and Referral platform for organizations such as United Way Worldwide and the American Red - Cross. - \begin{itemize} - \item Refactored and revamped legacy code to increase performance and long-term - maintainablity. - \item Worked on several triage-teams to rapidly fix production bugs with strict deadlines. - \item Built a complex, yet highly-performant tool for searching human services by category. - \item Acted as a core designer and developer of a major product revamp. - \begin{itemize} - \item Drove a complete rethinking of the data model in the product, leading to greater - unification, simplicity, and consistency; - \item Championed the adoption of a test-driven-development model; - \item Drove product documentation and code standardization. - \end{itemize} - \end{itemize}} - -\section{Project Highlights} -\newcommand{\project}[3]{\item \textbf{#1} -- \textit{#2}\newline{}#3} -\cvitem{}{ - \begin{itemize} - \project{How much does Rust's bounds checking actually cost?} - {\url{https://blog.readyset.io/bounds-checks/}}{Blog post providing a deep - evaluation of the runtime cost of bounds checking in safe languages like Rust. - Front page of Hacker News, doubled month-over-month ReadySet waitlist signups} - \project{Tvix}{\url{https://tvix.dev}}{ - % TODO(aspen): and now in your own words :) - Modular Reimplementation of the Nix build tool in Rust} - \project{Panettone}{\url{https://code.tvl.fyi/tree/web/panettone}}{ - Aggressively simple bug-tracker developed in Common Lisp for the community - involved in the development of Tvix. Hosted at https://b.tvl.fyi} - \project{Org-Clubhouse}{\url{https://github.com/glittershark/org-clubhouse}}{ - Emacs library for integration between org-mode and the Clubhouse issue - tracker} - \project{Github Bug Bounty}{\url{https://bounty.github.com/researchers/glittershark.html}}{ - Discovered and responsibly disclosed a persistent XSS on Github's main - website} - \project{core-async-storage}{\url{https://github.com/glittershark/core-async-storage}}{ - Simple Clojurescript wrapper around React Native's AsyncStorage using - core.async} - \end{itemize} -} - -\end{document} -% vim: set tw=95 colorcolumn=-1: diff --git a/users/aspen/resume/tweaklist.sty b/users/aspen/resume/tweaklist.sty deleted file mode 100644 index adc939893..000000000 --- a/users/aspen/resume/tweaklist.sty +++ /dev/null @@ -1,56 +0,0 @@ -%% start of file `tweaklist.sty'. -%% Original by Jakob Schiøtz, downloaded from http://dcwww.camd.dtu.dk/~schiotz/comp/LatexTips/tweaklist.sty; not found on ctan. -%% Modified by Xavier Danaux (xdanaux@gmail.com). -% -% The tweaklist.sty package redefines the itemize, enumerate and description packages, so that all parameters can be adjusted. -% This was done by copying the original definitions, and adding "hook commands" that are executed when entering the environment. -% The hook commands are initially empty, but can be redefined with \renewcommand. -% -% This work may be distributed and/or modified under the -% conditions of the LaTeX Project Public License version 1.3c, -% available at http://www.latex-project.org/lppl/. - - -% hooks for the itemize environment -\def\itemhook{} -\def\itemhooki{} -\def\itemhookii{} -\def\itemhookiii{} -\def\itemhookiv{} -% hooks for the enumerate environment -\def\enumhook{} -\def\enumhooki{} -\def\enumhookii{} -\def\enumhookiii{} -\def\enumhookiv{} -% hook for the description environment -\def\deschook{} -% original environment definitions, with hooks added -\def\enumerate{% - \ifnum \@enumdepth >\thr@@\@toodeep\else - \advance\@enumdepth\@ne - \edef\@enumctr{enum\romannumeral\the\@enumdepth}% - \expandafter - \list - \csname label\@enumctr\endcsname - {% - \enumhook \csname enumhook\romannumeral\the\@enumdepth\endcsname% - \usecounter\@enumctr\def\makelabel##1{\hss\llap{##1}}% - }% - \fi} -\def\itemize{% - \ifnum \@itemdepth >\thr@@\@toodeep\else - \advance\@itemdepth\@ne - \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% - \expandafter - \list - \csname\@itemitem\endcsname - {% - \itemhook \csname itemhook\romannumeral\the\@itemdepth\endcsname% - \def\makelabel##1{\hss\llap{##1}}% - }% - \fi} -\newenvironment{description} - {\list{}{\deschook\labelwidth\z@ \itemindent-\leftmargin - \let\makelabel\descriptionlabel}} - {\endlist} diff --git a/users/aspen/secrets/.envrc b/users/aspen/secrets/.envrc deleted file mode 100644 index 051d09d29..000000000 --- a/users/aspen/secrets/.envrc +++ /dev/null @@ -1 +0,0 @@ -eval "$(lorri direnv)" diff --git a/users/aspen/secrets/bbbg.age b/users/aspen/secrets/bbbg.age deleted file mode 100644 index 379441b74..000000000 --- a/users/aspen/secrets/bbbg.age +++ /dev/null @@ -1,10 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 CpJBgQ m4qtDYzsJSeA/ERvTW2OUyz2vdoRtRe9BjsjVH7Fu3g -qqDn0+6EdgNKUxVMVl5kqgO4Tzv4ZiFOV78zG0Qsn1E --> ssh-ed25519 LfBFbQ ELj73TcIkW2zFNRBzNNCQ9l91LIEZLig4tEQ8A+M1y4 -feux6mZi9xogEgTYJKcEqplHfUYHjWuANWMNJU/S1hE --> ssh-ed25519 lZtaEQ Hr05IXb2k0fqgFj+nn2WZpHmD9zBp1vLkYRuDl1VQE4 -FJjagi1owB6qiCV5tKsrSSF3htJVN2IMDWI2XLRBbeI ---- BZ3SftG5yiToa9VUNpxDGUzehiGjYGBZAVo9gwdtFIM -{zO]@YR3ܙDy7 -8,25{H`YQh) 1r[ #ћ@N`3I|*~!# H<Rz|G+Y^XU'kg}WpadbZ"w.ܧg<1OT5Z&ult;%/k0de \ No newline at end of file diff --git a/users/aspen/secrets/buildkite-ssh-key.age b/users/aspen/secrets/buildkite-ssh-key.age deleted file mode 100644 index 61ad41638..000000000 Binary files a/users/aspen/secrets/buildkite-ssh-key.age and /dev/null differ diff --git a/users/aspen/secrets/buildkite-token.age b/users/aspen/secrets/buildkite-token.age deleted file mode 100644 index 5bd4923de..000000000 Binary files a/users/aspen/secrets/buildkite-token.age and /dev/null differ diff --git a/users/aspen/secrets/cloudflare.age b/users/aspen/secrets/cloudflare.age deleted file mode 100644 index c94fef706..000000000 --- a/users/aspen/secrets/cloudflare.age +++ /dev/null @@ -1,9 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 CpJBgQ 5lJGEVwg5v6612p4iOoO+ShR5kLiQAG/7m2f6R6KLRc -CvFJQChj9IssFIIvVCh6/qRPfdvLx72rf3aXBD4EAEo --> ssh-ed25519 LfBFbQ uqcGghDi2DOAJPD/7udNpdyU4NccMJSdh8mdhzEKNyU -zT+oVqOOUvTGU8fl0X/kARGESerZfUEjW3F1g6ASlxk --> ssh-ed25519 GeE7sQ Ehb6kwx8irEbfeFy4gzK/oWmIZRdt/MEbPysJHVRsBA -grBUiZAB9Iu37LEhNU8VBvf3jMjiO+QJfJn9dnZ3DI8 ---- Zb/3hWF4WXpQlGJ+0eB4P9ZI6uCdUv5s5n7BnEaKfZM -1^9]ጶte)Gr6.\#& H&xhM{Di^^-k5ѽh*jn)VޚG{g zeYIh]G \ No newline at end of file diff --git a/users/aspen/secrets/ddclient-password.age b/users/aspen/secrets/ddclient-password.age deleted file mode 100644 index 3bbc2e51f..000000000 --- a/users/aspen/secrets/ddclient-password.age +++ /dev/null @@ -1,7 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 CpJBgQ 0dDM/za4zwsdUAP76WW0Hkn8izwx+EALTdTjchNza2E -mvCGCUDSiBWG3dtyKeQRgFFbbnyj+Y4LqYAF5swHp8E --> ssh-ed25519 GeE7sQ dlSYhoyTL13/INfpzu6/GKfTe1Et7f1uoAuDqHSR+zI -i08xx3W71DysQwEtrpsduMGu3pIapof0RmdE/MChXTQ ---- a95MBBmtIydoVL5P4+WedeTWHAg+wa8TEnowZf3k18Q -kxϤɷ25s֫E94p><Mr.Lxp \ No newline at end of file diff --git a/users/aspen/secrets/default.nix b/users/aspen/secrets/default.nix deleted file mode 100644 index 26b1998f5..000000000 --- a/users/aspen/secrets/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -{ depot, ... }: -depot.ops.secrets.mkSecrets ./. (import ./secrets.nix) diff --git a/users/aspen/secrets/secrets.nix b/users/aspen/secrets/secrets.nix deleted file mode 100644 index 76126f811..000000000 --- a/users/aspen/secrets/secrets.nix +++ /dev/null @@ -1,15 +0,0 @@ -let - grfn = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMcBGBoWd5pPIIQQP52rcFOQN3wAY0J/+K2fuU6SffjA"; - mugwump = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFE2fxPgWO+zeQoLBTgsgxP7Vg7QNHlrQ+Rb3fHFTomB"; - ogopogo = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINoS7PqM8d7xc8nn0yfiPGfRaH8U/nq2Jm27nRO3L5P0"; - bbbg = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/VzrNEY47KPTce3dgfORkAbweWkr4BI8j54BAIs7bG"; -in - -{ - "bbbg.age".publicKeys = [ grfn mugwump bbbg ]; - "cloudflare.age".publicKeys = [ grfn mugwump ogopogo ]; - "ddclient-password.age".publicKeys = [ grfn ogopogo ]; - "buildkite-ssh-key.age".publicKeys = [ grfn mugwump ogopogo ]; - "buildkite-token.age".publicKeys = [ grfn mugwump ogopogo ]; - "windtunnel-bot-github-token.age".publicKeys = [ grfn mugwump ogopogo ]; -} diff --git a/users/aspen/secrets/shell.nix b/users/aspen/secrets/shell.nix deleted file mode 100644 index 6e70458d1..000000000 --- a/users/aspen/secrets/shell.nix +++ /dev/null @@ -1,8 +0,0 @@ -let - depot = import ../../.. { }; -in -depot.third_party.nixpkgs.mkShell { - buildInputs = [ - depot.third_party.agenix.cli - ]; -} diff --git a/users/aspen/secrets/windtunnel-bot-github-token.age b/users/aspen/secrets/windtunnel-bot-github-token.age deleted file mode 100644 index 39fd7cb3a..000000000 --- a/users/aspen/secrets/windtunnel-bot-github-token.age +++ /dev/null @@ -1,9 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 CpJBgQ PiY6IidA+GRbpjL91BVe9UdejWvi02SRcijiMOjXcm4 -XegOhgjdEdzXtz31PsGVyOZ10gH6P82Q1/txZcSxjIY --> ssh-ed25519 LfBFbQ uqRF0nKMk1GrK+6pEBdmyHKu2ewDFlWwlKC+myey4gc -dgnX4eprSolXxCDNoVmGzGK9xLEmtmeg/cJihD4/8sU --> ssh-ed25519 GeE7sQ ikAIyFR/qH1a+aa5mumiiDwa5o5aLsQeJKwQwMzgs1M -8htzhM5t2VnjRBrC+VrL23f9chlQjVGzjxMaFB7Arrs ---- Qm16HTo5wGUBKS0ly3OZDWp2etLyDS/zlxOHxPjS8PI -7NY6k|p2'&=mq`5T N9N)RVU-•) M(%p \ No newline at end of file diff --git a/users/aspen/system/.gitignore b/users/aspen/system/.gitignore deleted file mode 100644 index 41fbeb02c..000000000 --- a/users/aspen/system/.gitignore +++ /dev/null @@ -1 +0,0 @@ -**/result diff --git a/users/aspen/system/home/.skip-subtree b/users/aspen/system/home/.skip-subtree deleted file mode 100644 index e69de29bb..000000000 diff --git a/users/aspen/system/home/common/solarized.nix b/users/aspen/system/home/common/solarized.nix deleted file mode 100644 index 554ee0523..000000000 --- a/users/aspen/system/home/common/solarized.nix +++ /dev/null @@ -1,18 +0,0 @@ -rec { - base03 = "#002B36"; - base02 = "#073642"; - base01 = "#586e75"; - base00 = "#657b83"; - base0 = "#839496"; - base1 = "#93a1a1"; - base2 = "#eee8d5"; - base3 = "#fdf6e3"; - yellow = "#b58900"; - orange = "#cb4b16"; - red = "#dc322f"; - magenta = "#d33682"; - violet = "#6c71c4"; - blue = "#268bd2"; - cyan = "#2aa198"; - green = "#859900"; -} diff --git a/users/aspen/system/home/default.nix b/users/aspen/system/home/default.nix deleted file mode 100644 index 90df02b37..000000000 --- a/users/aspen/system/home/default.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ pkgs, depot, lib, ... }: - -with lib; - -rec { - home = confPath: (import (pkgs.home-manager.src + "/modules") { - inherit pkgs; - - configuration = { config, lib, ... }: { - imports = [ confPath ]; - lib.depot = depot; - - # home-manager exposes no API to override the package set that - # is used, unless called from the NixOS module. - # - # To get around it, the module argument is overridden here. - _module.args.pkgs = mkForce pkgs; - }; - }); - - dobharchu = home ./machines/dobharchu.nix; - - dobharchuHome = dobharchu.activation-script; - - ogopogo = home ./machines/ogopogo.nix; - - ogopogoHome = ogopogo.activation-script; - - yeren = home ./machines/yeren.nix; - - yerenHome = yeren.activation-script; - - lusca = home ./machines/lusca.nix; - - luscaHome = lusca.activation-script; - - meta.ci.targets = [ - "ogopogoHome" - "luscaHome" - "yerenHome" - ]; -} diff --git a/users/aspen/system/home/home.nix b/users/aspen/system/home/home.nix deleted file mode 100644 index 39045c147..000000000 --- a/users/aspen/system/home/home.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ config, pkgs, ... }: - -{ - imports = [ - (throw "Pick a machine from ./machines") - ]; - - # Let Home Manager install and manage itself. - programs.home-manager.enable = true; - - # This value determines the Home Manager release that your - # configuration is compatible with. This helps avoid breakage - # when a new Home Manager release introduces backwards - # incompatible changes. - # - # You can update Home Manager without changing this value. See - # the Home Manager release notes for a list of state version - # changes in each release. - home.stateVersion = "19.09"; -} diff --git a/users/aspen/system/home/machines/dobharchu.nix b/users/aspen/system/home/machines/dobharchu.nix deleted file mode 100644 index c26f3baef..000000000 --- a/users/aspen/system/home/machines/dobharchu.nix +++ /dev/null @@ -1,20 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - imports = [ - ../platforms/darwin.nix - ../modules/common.nix - # ../modules/games.nix - ]; - - home.packages = with pkgs; [ - coreutils - gnupg - nix-prefetch-github - pass - pinentry_mac - ]; - - programs.home-manager.enable = true; - home.stateVersion = "21.11"; -} diff --git a/users/aspen/system/home/machines/lusca.nix b/users/aspen/system/home/machines/lusca.nix deleted file mode 100644 index 2e2604e70..000000000 --- a/users/aspen/system/home/machines/lusca.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ pkgs, lib, config, ... }: - -let inherit (builtins) pathExists; -in { - imports = [ - ../platforms/linux.nix - ../modules/common.nix - - ../modules/email.nix - ../modules/depot-inbox.nix - ../modules/desktop.nix - ] ++ (lib.optional (pathExists ../modules/private.nix) - ../modules/private.nix); - - home.username = lib.mkForce "aspen"; - home.homeDirectory = lib.mkForce "/home/aspen"; - - # for when hacking - programs.home-manager.enable = true; - home.stateVersion = "20.03"; - - system.machine = { - wirelessInterface = "wlp1s0"; - i3FontSize = 9; - battery = 1; - }; - - programs.alacritty.settings.font.size = lib.mkForce 5.5; - - home.packages = with pkgs; [ - discord - steam - tdesktop - slack - (makeDesktopItem { - name = "Ogopogo Emacs"; - desktopName = "Ogopogo Emacs"; - icon = "emacs"; - exec = "ssh -Y ogopogo emacs"; - }) - ]; - - xsession.windowManager.i3.config.keybindings.XF86AudioMedia = "exec lock"; -} diff --git a/users/aspen/system/home/machines/ogopogo.nix b/users/aspen/system/home/machines/ogopogo.nix deleted file mode 100644 index 38dace208..000000000 --- a/users/aspen/system/home/machines/ogopogo.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ pkgs, lib, config, ... }: - -let - inherit (builtins) pathExists; - laptopKeyboardId = "5"; -in - -{ - imports = [ - ../platforms/linux.nix - ../modules/common.nix - ../modules/desktop.nix - ../modules/games.nix - ../modules/obs.nix - ../modules/development/agda.nix - # ../modules/development/readyset.nix - ../modules/development/ocaml.nix - ] ++ (lib.optional (pathExists ../modules/private.nix) ../modules/private.nix); - - programs.home-manager.enable = true; - home.stateVersion = "21.11"; - - system.machine = { - wirelessInterface = "wlp4s0"; - i3FontSize = 9; - battery = null; - }; - - home.packages = with pkgs; [ - zoom-us - slack - mariadb - graphviz - gnuplot - mypaint - xdot - tdesktop - subsurface - (discord.override rec { - version = "0.0.22"; - src = fetchurl { - url = "https://dl.discordapp.net/apps/linux/${version}/discord-${version}.tar.gz"; - sha256 = "19xbmrd782m4lp2l0ww5v3ip227g0z8pplxigxga96q43rvp6p0p"; - }; - }) - steam - ]; - - systemd.user.services.laptop-keyboard = { - Unit = { - Description = "Swap caps+escape and alt+super, but only on the built-in laptop keyboard"; - After = [ "graphical-session-pre.target" ]; - PartOf = [ "graphical-session.target" ]; - }; - - Install = { WantedBy = [ "graphical-session.target" ]; }; - - Service = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = ( - "${pkgs.xorg.setxkbmap}/bin/setxkbmap " - + "-device ${laptopKeyboardId} " - + "-option caps:swapescape " - + "-option compose:ralt " - + "-option altwin:swap_alt_win" - ); - }; - }; - - xsession.windowManager.i3.config.keybindings.F9 = "exec lock"; - - # Telegram adds this to ~/.config/mimeapps.list if it isn't already there, - # preventing home manager from installing (since it doesn't want to overwrite - # the file) - xdg.mimeApps.defaultApplications."x-scheme-handler/tg" = - "userapp-Telegram Desktop-K290F1.desktop"; -} diff --git a/users/aspen/system/home/machines/roswell.nix b/users/aspen/system/home/machines/roswell.nix deleted file mode 100644 index 514f19caf..000000000 --- a/users/aspen/system/home/machines/roswell.nix +++ /dev/null @@ -1,63 +0,0 @@ -{ pkgs, lib, config, ... }: - -let - inherit (builtins) pathExists; -in - -{ - imports = [ - ../platforms/linux.nix - ../modules/shell.nix - ../modules/development.nix - ../modules/emacs.nix - ../modules/vim.nix - # ../modules/development/readyset.nix - ../modules/tmux.nix - ] ++ (lib.optional (pathExists ../modules/private.nix) ../modules/private.nix); - - home.packages = with pkgs; [ - # System utilities - bat - htop - killall - bind - zip - unzip - tree - nmap - bc - pv - - # Security - gnupg - keybase - openssl - - # Nix things - nixfmt-classic - nix-prefetch-github - nixpkgs-review - cachix - - # ReadySet stuff - nodejs - mysql80 - - (writeShellScriptBin "xdg-open" "echo xdg-open: \"$@\"") - ]; - - programs.password-store.enable = true; - - programs.home-manager.enable = true; - home.stateVersion = "20.03"; - - xsession.enable = lib.mkForce false; - - services.lorri.enable = true; - - programs.direnv = { - enable = true; - enableBashIntegration = true; - enableZshIntegration = true; - }; -} diff --git a/users/aspen/system/home/machines/yeren.nix b/users/aspen/system/home/machines/yeren.nix deleted file mode 100644 index 54e79f950..000000000 --- a/users/aspen/system/home/machines/yeren.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ pkgs, lib, config, ... }: - -let - inherit (builtins) pathExists; - laptopKeyboardId = "5"; -in - -{ - imports = [ - ../platforms/linux.nix - ../modules/common.nix - ../modules/desktop.nix - ../modules/development/agda.nix - # ../modules/development/readyset.nix - ../modules/development/ocaml.nix - ] ++ (lib.optional (pathExists ../modules/private.nix) ../modules/private.nix); - - # for when hacking - programs.home-manager.enable = true; - home.stateVersion = "20.03"; - - system.machine = { - wirelessInterface = "wlp0s20f3"; - i3FontSize = 9; - }; - - home.packages = with pkgs; [ - zoom-us - slack - mariadb - graphviz - gnuplot - mypaint - xdot - tdesktop - subsurface - discord - steam - ]; - - systemd.user.services.laptop-keyboard = { - Unit = { - Description = "Swap caps+escape and alt+super, but only on the built-in laptop keyboard"; - After = [ "graphical-session-pre.target" ]; - PartOf = [ "graphical-session.target" ]; - }; - - Install = { WantedBy = [ "graphical-session.target" ]; }; - - Service = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = ( - "${pkgs.xorg.setxkbmap}/bin/setxkbmap " - + "-device ${laptopKeyboardId} " - + "-option caps:swapescape " - + "-option compose:ralt " - + "-option altwin:swap_alt_win" - ); - }; - }; - - xsession.windowManager.i3.config.keybindings.F9 = "exec lock"; - - xdg.mimeApps.defaultApplications."x-scheme-handler/tg" = - "telegramdesktop.desktop"; - - programs.zsh.shellAliases = { - "graph" = "curl -s localhost:6033/graph | dot -Tpng | feh -"; - }; - - programs.ssh.matchBlocks."grfn-dev" = { - host = "grfn-dev"; - forwardAgent = true; - user = "ubuntu"; - }; -} diff --git a/users/aspen/system/home/modules/.gitignore b/users/aspen/system/home/modules/.gitignore deleted file mode 100644 index a211cae6c..000000000 --- a/users/aspen/system/home/modules/.gitignore +++ /dev/null @@ -1 +0,0 @@ -private.nix diff --git a/users/aspen/system/home/modules/alacritty.nix b/users/aspen/system/home/modules/alacritty.nix deleted file mode 100644 index 561cab4d7..000000000 --- a/users/aspen/system/home/modules/alacritty.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - programs.alacritty = { - enable = true; - settings = { - font.size = 6; - font.normal.family = "Meslo LGSDZ Nerd Font"; - - keyboard.bindings = [ - { - key = "Escape"; - mods = "Control"; - action = "ToggleViMode"; - } - ]; - - colors = with import ../common/solarized.nix; rec { - draw_bold_text_with_bright_colors = false; - - # Default colors - primary = { - background = base3; - foreground = base00; - }; - - cursor = { - text = base3; - cursor = base00; - }; - - # Normal colors - normal = { - inherit red green yellow blue magenta cyan; - black = base02; - white = base2; - }; - - # Bright colors - # bright = normal; - bright = { - black = base03; - red = orange; - green = base01; - yellow = base00; - blue = base0; - magenta = violet; - cyan = base1; - white = base3; - }; - - vi_mode_cursor.cursor = red; - }; - }; - }; -} diff --git a/users/aspen/system/home/modules/common.nix b/users/aspen/system/home/modules/common.nix deleted file mode 100644 index 5117187d6..000000000 --- a/users/aspen/system/home/modules/common.nix +++ /dev/null @@ -1,88 +0,0 @@ -{ config, lib, pkgs, ... }: - -# Everything in here needs to work on linux or darwin, with or without a desktop -# environment - -{ - imports = [ - ../modules/shell.nix - # ../modules/development.nix - ../modules/emacs.nix - ../modules/vim.nix - ../modules/tarsnap.nix - ../modules/twitter.nix - ../modules/lib/cloneRepo.nix - ]; - - home.username = "aspen"; - home.homeDirectory = "/home/aspen"; - - programs.password-store.enable = true; - - aspen.impure.clonedRepos.passwordStore = { - github = "glittershark/pass"; - path = ".local/share/password-store"; - }; - - home.packages = with pkgs; [ - # System utilities - bat - htop - killall - bind - zip - unzip - tree - nmap - bc - pv - - # Security - gnupg - keybase - openssl - - # Nix things - nixfmt-classic - nix-prefetch-github - nixpkgs-review - cachix - (writeShellScriptBin "rebuild-mugwump" '' - set -eo pipefail - cd ~/code/depot - nix build -f . users.aspen.system.system.mugwumpSystem -o /tmp/mugwump - nix copy -f . users.aspen.system.system.mugwumpSystem \ - --to ssh://mugwump - system=$(readlink -ef /tmp/mugwump) - ssh mugwump sudo nix-env -p /nix/var/nix/profiles/system --set $system - ssh mugwump sudo $system/bin/switch-to-configuration switch - rm /tmp/mugwump - '') - (writeShellScriptBin "rebuild-roswell" '' - set -eo pipefail - cd ~/code/depot - nix build -f . users.aspen.system.system.roswellSystem -o /tmp/roswell - nix copy -f . users.aspen.system.system.roswellSystem \ - --to ssh://roswell - system=$(readlink -ef /tmp/roswell) - ssh roswell sudo nix-env -p /nix/var/nix/profiles/system --set $system - ssh roswell sudo $system/bin/switch-to-configuration switch - rm /tmp/roswell - '') - (writeShellScriptBin "rebuild-home" '' - set -eo pipefail - cd ~/code/depot - home=$(nix-build -A users.aspen.system.home.$(hostname)Home -o /tmp/home) - nix-env -p /nix/var/nix/per-user/aspen/home --set $home - $home/activate - '') - ]; - - programs.ssh = { enable = true; }; - - programs.direnv = { - enable = true; - enableBashIntegration = true; - enableZshIntegration = true; - }; -} diff --git a/users/aspen/system/home/modules/depot-inbox.nix b/users/aspen/system/home/modules/depot-inbox.nix deleted file mode 100644 index 0694e6db2..000000000 --- a/users/aspen/system/home/modules/depot-inbox.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - depot = config.lib.depot; -in - -{ - systemd.user = { - services.sync-depot-public-inbox = { - Service.ExecStart = pkgs.writeShellScript "sync-depot-public-inbox" '' - ${depot.tools.fetch-depot-inbox}/bin/fetch-depot-inbox \ - /home/aspen/mail/tvl/ - ${pkgs.notmuch}/bin/notmuch new - ''; - }; - - timers.sync-depot-public-inbox = { - Unit.Description = "Sync the depot public inbox"; - Timer = { - OnCalendar = "*:*"; - Unit = "sync-depot-public-inbox.service"; - }; - Install.WantedBy = [ "timers.target" ]; - }; - }; -} diff --git a/users/aspen/system/home/modules/desktop.nix b/users/aspen/system/home/modules/desktop.nix deleted file mode 100644 index e1841cd3c..000000000 --- a/users/aspen/system/home/modules/desktop.nix +++ /dev/null @@ -1,40 +0,0 @@ -{ config, lib, pkgs, ... }: - -# Things that only work in the presence of a linux desktop environment - -{ - imports = [ - ./i3.nix - ./alacritty.nix - ]; - - home.packages = with pkgs; [ - (writeShellApplication { - name = "edit-input"; - - runtimeInputs = [ xdotool xclip ]; - text = '' - set -euo pipefail - - sleep 0.2 - xdotool key ctrl+a ctrl+c - xclip -out -selection clipboard > /tmp/EDIT - emacsclient -c /tmp/EDIT - xclip -in -selection clipboard < /tmp/EDIT - sleep 0.2 - xdotool key ctrl+v - rm /tmp/EDIT - ''; - }) - ]; - - services.syncthing.tray.enable = true; - - gtk = { - enable = true; - gtk3.bookmarks = [ - "file:///home/aspen/code" - "file:///home/aspen/notes" - ]; - }; -} diff --git a/users/aspen/system/home/modules/development.nix b/users/aspen/system/home/modules/development.nix deleted file mode 100644 index 0da6d9cba..000000000 --- a/users/aspen/system/home/modules/development.nix +++ /dev/null @@ -1,215 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - - clj2nix = pkgs.callPackage - (pkgs.fetchFromGitHub { - owner = "hlolli"; - repo = "clj2nix"; - rev = "3ab3480a25e850b35d1f532a5e4e7b3202232383"; - sha256 = "1lry026mlpxp1j563qs13nhxf37i2zpl7lh0lgfdwc44afybqka6"; - }) - { }; - - pg-dump-upsert = pkgs.buildGoModule rec { - pname = "pg-dump-upsert"; - version = "165258deaebded5e9b88f7a0acf3a4b7350e7bf4"; - - src = pkgs.fetchFromGitHub { - owner = "tomyl"; - repo = "pg-dump-upsert"; - rev = version; - sha256 = "1an4h8jjbj3r618ykjwk9brii4h9cxjqy47c4c8rivnvhimgf4wm"; - }; - - vendorHash = "sha256:1a5fx6mrv30cl46kswicd8lf5i5shn1fykchvbnbhdpgxhbz6qi4"; - }; - -in - -with lib; - -{ - imports = [ - ./lib/zshFunctions.nix - # TODO(aspen): agda build is broken in the nixpkgs checkout - # ./development/agda.nix - ./development/rust.nix - ]; - - home.packages = with pkgs; [ - jq - yq - gron - gitAndTools.tig - gitAndTools.gh - shellcheck - httpie - entr - gnumake - inetutils - tokei - jsonnet - ngrok - amber - ocamlPackages.patdiff - - gdb - lldb - hyperfine - clang-tools - - clj2nix - clojure - leiningen - clj-kondo - - pg-dump-upsert - - nodePackages.prettier - ] ++ optionals (stdenv.isLinux) [ - julia-stable-bin - valgrind - - linuxPackages.perf - rr - ]; - - programs.git = { - enable = true; - package = pkgs.gitFull; - userEmail = "root@gws.fyi"; - userName = "Aspen Smith"; - ignores = [ - "*.sw*" - ".classpath" - ".project" - ".settings/" - ".dir-locals.el" - ".stack-work-profiling" - ".projectile" - ]; - extraConfig = { - github.user = "glittershark"; - merge.conflictstyle = "diff3"; - rerere.enabled = "true"; - advice.skippedCherryPicks = "false"; - }; - - delta = { - enable = true; - options = { - syntax-theme = "Solarized (light)"; - hunk-style = "plain"; - commit-style = "box"; - }; - }; - }; - - home.file.".gdbinit".text = '' - set history filename ~/.gdb_history - set history save on - set history size unlimited - set history remove-duplicates unlimited - set history expansion on - ''; - - home.file.".psqlrc".text = '' - \set QUIET 1 - - \timing - \set ON_ERROR_ROLLBACK interactive - \set VERBOSITY verbose - \x auto - \set PROMPT1 '%[%033[1m%]%M/%/%R%[%033[0m%]%# ' - \set PROMPT2 '...%# ' - \set HISTFILE ~/.psql_history- :DBNAME - \set HISTCONTROL ignoredups - \pset null [null] - - \pset linestyle 'unicode' - \pset unicode_border_linestyle single - \pset unicode_column_linestyle single - \pset unicode_header_linestyle double - - \unset QUIET - ''; - - programs.readline = { - enable = true; - extraConfig = '' - set editing-mode vi - ''; - }; - - programs.zsh = { - shellAliases = { - # Git - "gwip" = "git add . && git commit -am wip"; - "gpr" = "g pull-request"; - "gcl" = "git clone"; - "grs" = "gr --soft"; - "grhh" = "grh HEAD"; - "grh" = "gr --hard"; - "gr" = "git reset"; - "gcb" = "gc -b"; - "gco" = "gc"; - "gcd" = "gc development"; - "gcm" = "gc master"; - "gcc" = "gc canon"; - "gc" = "git checkout"; - "gbg" = "git branch | grep"; - "gba" = "git branch -a"; - "gb" = "git branch"; - "gcv" = "git commit --verbose"; - "gci" = "git commit"; - "gm" = "git merge"; - "gdc" = "gd --cached"; - "gd" = "git diff"; - "gsl" = "git stash list"; - "gss" = "git show stash"; - "gsad" = "git stash drop"; - "gsa" = "git stash"; - "gst" = "gs"; - "gs" = "git status"; - "gg" = "gl --decorate --oneline --graph --date-order --all"; - "gl" = "git log"; - "gf" = "git fetch"; - "gur" = "gu --rebase"; - "gu" = "git pull"; - "gpf" = "gp -f"; - "gpa" = "gp --all"; - "gpu" = "git push -u origin \"$(git symbolic-ref --short HEAD)\""; - "gp" = "git push"; - "ganw" = "git diff -w --no-color | git apply --cached --ignore-whitespace"; - "ga" = "git add"; - "gnp" = "git --no-pager"; - "g" = "git"; - "grim" = "git fetch && git rebase -i --autostash origin/master"; - "grom" = "git fetch && git rebase --autostash origin/master"; - "groc" = "git fetch && git rebase --autostash origin/canon"; - "grc" = "git rebase --continue"; - "gcan" = "git commit --amend --no-edit"; - "grl" = "git reflog"; - - # Haskell - "crl" = "cabal repl"; - "cr" = "cabal run"; - "cnb" = "cabal new-build"; - "cob" = "cabal old-build"; - "cnr" = "cabal new-run"; - "cor" = "cabal old-run"; - "ho" = "hoogle"; - }; - - functions = { - gdelmerged = '' - git branch --merged | egrep -v 'master' | tr -d '+ ' | xargs git branch -d - ''; - - gref = '' - git show -s --pretty=reference "$1" | xclip -selection clipboard - ''; - }; - }; -} diff --git a/users/aspen/system/home/modules/development/agda.nix b/users/aspen/system/home/modules/development/agda.nix deleted file mode 100644 index 55381994c..000000000 --- a/users/aspen/system/home/modules/development/agda.nix +++ /dev/null @@ -1,58 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - agda-categories = with pkgs.agdaPackages; mkDerivation rec { - pname = "agda-categories"; - version = "2128fab"; - src = pkgs.fetchFromGitHub { - owner = "agda"; - repo = "agda-categories"; - rev = version; - sha256 = "08mc20qaz9vp5rhi60rh8wvjkg5aby3bgwwdhfnxha1663qf1q24"; - }; - - buildInputs = [ standard-library ]; - }; - -in - -{ - imports = [ - ../lib/cloneRepo.nix - ]; - - home.packages = with pkgs; [ - (pkgs.agda.withPackages - (p: with p; [ - p.standard-library - - ])) - ]; - - aspen.impure.clonedRepos = { - agda-stdlib = { - github = "agda/agda-stdlib"; - path = "code/agda-stdlib"; - }; - - agda-categories = { - github = "agda/agda-categories"; - path = "code/agda-categories"; - }; - - categories-examples = { - github = "agda/categories-examples"; - path = "code/categories-examples"; - }; - }; - - home.file.".agda/defaults".text = '' - standard-library - ''; - - home.file.".agda/libraries".text = '' - /home/aspen/code/agda-stdlib/standard-library.agda-lib - /home/aspen/code/agda-categories/agda-categories.agda-lib - ''; - -} diff --git a/users/aspen/system/home/modules/development/kube.nix b/users/aspen/system/home/modules/development/kube.nix deleted file mode 100644 index 876b0c08d..000000000 --- a/users/aspen/system/home/modules/development/kube.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ config, lib, pkgs, ... }: -{ - home.packages = with pkgs; [ - kubectl - kubetail - sops - kubie - # pkgs-unstable.argocd # provided by urbos - ]; - - programs.zsh.shellAliases = { - "kc" = "kubectl"; - "kg" = "kc get"; - "kga" = "kc get --all-namespaces"; - "kpd" = "kubectl get pods"; - "kpa" = "kubectl get pods --all-namespaces"; - "klf" = "kubectl logs -f"; - "kdep" = "kubectl get deployments"; - "ked" = "kubectl edit deployment"; - "kpw" = "kubectl get pods -w"; - "kew" = "kubectl get events -w"; - "kdel" = "kubectl delete"; - "knw" = "kubectl get nodes -w"; - "kev" = "kubectl get events --sort-by='.metadata.creationTimestamp'"; - - "arsy" = "argocd app sync --prune"; - }; - - home.file.".kube/kubie.yaml".text = '' - shell: zsh - prompt: - zsh_use_rps1: true - ''; -} diff --git a/users/aspen/system/home/modules/development/ocaml.nix b/users/aspen/system/home/modules/development/ocaml.nix deleted file mode 100644 index 5dcdd8980..000000000 --- a/users/aspen/system/home/modules/development/ocaml.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - home.packages = with pkgs; [ - ocaml - - # ocamlPackages.merlin - # ocamlPackages.utop - # ocamlPackages.ocp-indent - # ocamlPackages.ocamlformat - ]; - - programs.opam = { - enable = true; - enableZshIntegration = true; - }; -} diff --git a/users/aspen/system/home/modules/development/readyset.nix b/users/aspen/system/home/modules/development/readyset.nix deleted file mode 100644 index afe762468..000000000 --- a/users/aspen/system/home/modules/development/readyset.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - imports = [ - ./rust.nix - ]; - - home.packages = with pkgs; [ - # These go in $PATH so I can run it from rofi and parent to my WM - (writeShellScriptBin "dotclip" "xclip -out -selection clipboard | dot -Tpng | feh -") - (writeShellScriptBin "dotcontroller" "curl -s localhost:6033/graph | dot -Tpng | feh -") - - rain - awscli2 - ssm-session-manager-plugin - amazon-ecr-credential-helper - postgresql_15 - - # TODO remove override when https://github.com/NixOS/nixpkgs/pull/233826 is merged - (sysbench.overrideDerivation (oldAttrs: { - configureFlags = oldAttrs.configureFlags ++ [ "--with-pgsql" ]; - buildInputs = oldAttrs.buildInputs ++ [ postgresql ]; - })) - ]; - - programs.zsh.shellAliases = { - "tf" = "terraform"; - }; - - home.file.".docker/config.json".text = builtins.toJSON { - credHelpers = { - "305232526136.dkr.ecr.us-east-2.amazonaws.com" = "ecr-login"; - }; - }; - - programs.zsh.functions."purge_deployment" = '' - for key in $(http :8500/v1/kv/$1 keys==true | jq -r .'[]'); do http DELETE ":8500/v1/kv/$key"; done - ''; -} diff --git a/users/aspen/system/home/modules/development/rust.nix b/users/aspen/system/home/modules/development/rust.nix deleted file mode 100644 index 80c1bb573..000000000 --- a/users/aspen/system/home/modules/development/rust.nix +++ /dev/null @@ -1,48 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - inherit (config.lib) depot; -in - -with lib; - -{ - - home.packages = with pkgs; [ - rustup - - cargo-bloat - cargo-edit - cargo-expand - cargo-hakari - cargo-nextest - cargo-udeps - sccache - evcxr - - # benchmarking+profiling - cargo-criterion - cargo-flamegraph - inferno - hotspot - ] ++ optionals (stdenv.isLinux) [ - cargo-rr - ]; - - programs.zsh.shellAliases = { - "cg" = "cargo"; - "cb" = "cargo build"; - "ct" = "cargo test"; - "ctw" = "fd -e rs | entr cargo test"; - "cch" = "cargo check"; - }; - - home.file.".cargo/config".text = '' - [build] - rustc-wrapper = "${pkgs.sccache}/bin/sccache" - - [target.x86_64-unknown-linux-gnu] - linker = "clang" - rustflags = ["-C", "link-arg=-fuse-ld=${pkgs.mold}/bin/mold"] - ''; -} diff --git a/users/aspen/system/home/modules/emacs.nix b/users/aspen/system/home/modules/emacs.nix deleted file mode 100644 index 6936da4b9..000000000 --- a/users/aspen/system/home/modules/emacs.nix +++ /dev/null @@ -1,108 +0,0 @@ -{ pkgs, lib, config, ... }: - -with lib; - -let - # doom-emacs = pkgs.callPackage (builtins.fetchTarball { - # url = https://github.com/vlaci/nix-doom-emacs/archive/master.tar.gz; - # }) { - # doomPrivateDir = ./doom.d; # Directory containing your config.el init.el - # # and packages.el files - # }; - - depot = config.lib.depot; - -in -{ - imports = [ - ./lib/cloneRepo.nix - ]; - - # home.packages = [ doom-emacs ]; - # home.file.".emacs.d/init.el".text = '' - # (load "default.el") - # ''; - # - - config = mkMerge [ - { - home.packages = with pkgs; [ - # LaTeX (for org export) - (pkgs.texlive.combine { - inherit (pkgs.texlive) - capt-of - collection-fontsrecommended - dvipng - fancyvrb - float - fncychap - framed - mathpartir - needspace - parskip - scheme-basic - semantic - tabulary - titlesec - ulem - upquote - varwidth - wrapfig - bussproofs - bussproofs-extra - ; - }) - - ispell - - ripgrep - coreutils - fd - clang - gnutls - emacsPackages.telega - ]; - - programs.emacs = { - enable = true; - package = pkgs.emacs; - extraPackages = (epkgs: - (with epkgs; [ - tvlPackages.dottime - tvlPackages.tvl - vterm - telega - ]) - ); - }; - - aspen.impure.clonedRepos = { - orgClubhouse = { - github = "glittershark/org-clubhouse"; - path = "code/org-clubhouse"; - }; - - doomEmacs = { - github = "hlissner/doom-emacs"; - path = ".emacs.d"; - after = [ "emacs.d" ]; - onClone = "bin/doom install"; - }; - - "emacs.d" = { - github = "glittershark/emacs.d"; - path = ".doom.d"; - after = [ "orgClubhouse" ]; - }; - }; - - programs.zsh.shellAliases = { - "ec" = "emacsclient"; - }; - } - (mkIf pkgs.stdenv.isLinux { - # Notes - services.syncthing.enable = true; - }) - ]; -} diff --git a/users/aspen/system/home/modules/email.nix b/users/aspen/system/home/modules/email.nix deleted file mode 100644 index a43e3ab5a..000000000 --- a/users/aspen/system/home/modules/email.nix +++ /dev/null @@ -1,86 +0,0 @@ -{ lib, pkgs, config, ... }: - -with lib; - -let - - # from home-manager/modules/services/lieer.nix - escapeUnitName = name: - let - good = upperChars ++ lowerChars ++ stringToCharacters "0123456789-_"; - subst = c: if any (x: x == c) good then c else "-"; - in - stringAsChars subst name; - - accounts = { - personal = { - primary = true; - address = "root@gws.fyi"; - aliases = [ "aspen@gws.fyi" ]; - passEntry = "root-gws-msmtp"; - }; - }; - -in -{ - # 2022-09-26: workaround for home-manager defaulting to removed pkgs.gmailieer - # attribute, can likely be removed soon - programs.lieer.package = pkgs.lieer; - - programs.lieer.enable = true; - programs.notmuch.enable = true; - services.lieer.enable = true; - programs.msmtp.enable = true; - - home.packages = with pkgs; [ - mu - msmtp - config.lib.depot.users.aspen.pkgs.notmuch-extract-patch - ]; - - systemd.user.services = mapAttrs' - (name: account: { - name = escapeUnitName "lieer-${name}"; - value.Service = { - ExecStart = mkForce "${pkgs.writeShellScript "sync-${name}" '' - ${pkgs.lieer}/bin/gmi sync --path ~/mail/${name} - ''}"; - Environment = - "NOTMUCH_CONFIG=${config.home.sessionVariables.NOTMUCH_CONFIG}"; - }; - - }) - accounts; - - accounts.email.maildirBasePath = "mail"; - accounts.email.accounts = mapAttrs - (_: - params@{ passEntry, ... }: - { - realName = "Aspen Smith"; - passwordCommand = "pass ${passEntry}"; - - flavor = "gmail.com"; - - imapnotify = { - enable = true; - boxes = [ "Inbox" ]; - }; - - gpg = { - key = "0F11A989879E8BBBFDC1E23644EF5B5E861C09A7"; - signByDefault = true; - }; - - notmuch.enable = true; - lieer = { - enable = true; - sync = { - enable = true; - frequency = "*:*"; - }; - }; - msmtp.enable = true; - } // builtins.removeAttrs params [ "passEntry" ]) - accounts; -} diff --git a/users/aspen/system/home/modules/firefox.nix b/users/aspen/system/home/modules/firefox.nix deleted file mode 100644 index c7e78685a..000000000 --- a/users/aspen/system/home/modules/firefox.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - - xdg.mimeApps = rec { - enable = true; - defaultApplications = { - "text/html" = [ "firefox.desktop" ]; - "x-scheme-handler/http" = [ "firefox.desktop" ]; - "x-scheme-handler/https" = [ "firefox.desktop" ]; - "x-scheme-handler/ftp" = [ "firefox.desktop" ]; - "x-scheme-handler/chrome" = [ "firefox.desktop" ]; - "application/x-extension-htm" = [ "firefox.desktop" ]; - "application/x-extension-html" = [ "firefox.desktop" ]; - "application/x-extension-shtml" = [ "firefox.desktop" ]; - "application/xhtml+xml" = [ "firefox.desktop" ]; - "application/x-extension-xhtml" = [ "firefox.desktop" ]; - "application/x-extension-xht" = [ "firefox.desktop" ]; - }; - associations.added = defaultApplications; - }; -} diff --git a/users/aspen/system/home/modules/games.nix b/users/aspen/system/home/modules/games.nix deleted file mode 100644 index dc6331d64..000000000 --- a/users/aspen/system/home/modules/games.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ config, lib, pkgs, ... }: - -with pkgs; -with lib; - -let - - df-orig = dwarf-fortress-packages.dwarf-fortress-original; - - df-full = (dwarf-fortress-packages.dwarf-fortress-full.override { - theme = null; - enableIntro = false; - enableFPS = true; - enableDFHack = true; - }); - - init = runCommand "init.txt" { } '' - substitute "${df-orig}/data/init/init_default.txt" $out \ - --replace "[INTRO:YES]" "[INTRO:NO]" \ - --replace "[VOLUME:255]" "[VOLUME:0]" \ - --replace "[FPS:NO]" "[FPS:YES]" - ''; - - d_init = runCommand "d_init.txt" { } '' - substitute "${df-orig}/data/init/d_init_default.txt" $out \ - --replace "[AUTOSAVE:NONE]" "[AUTOSAVE:SEASONAL]" \ - --replace "[AUTOSAVE_PAUSE:NO]" "[AUTOSAVE_PAUSE:YES]" \ - --replace "[INITIAL_SAVE:NO]" "[INITIAL_SAVE:YES]" \ - --replace "[EMBARK_WARNING_ALWAYS:NO]" "[EMBARK_WARNING_ALWAYS:YES]" \ - --replace "[VARIED_GROUND_TILES:YES]" "[VARIED_GROUND_TILES:NO]" \ - --replace "[SHOW_FLOW_AMOUNTS:NO]" "[SHOW_FLOW_AMOUNTS:YES]" - ''; - - df = runCommand "dwarf-fortress" { } '' - mkdir -p $out/bin - sed \ - -e '4icp -f ${init} "$DF_DIR/data/init/init.txt"' \ - -e '4icp -f ${d_init} "$DF_DIR/data/init/d_init.txt"' \ - < "${df-full}/bin/dwarf-fortress" >"$out/bin/dwarf-fortress" - - shopt -s extglob - ln -s ${df-full}/bin/!(dwarf-fortress) $out/bin - - chmod +x $out/bin/dwarf-fortress - ''; - -in -mkMerge [ - { home.packages = [ crawl ]; } - (mkIf stdenv.isLinux { home.packages = [ df prismlauncher ]; }) -] diff --git a/users/aspen/system/home/modules/i3.nix b/users/aspen/system/home/modules/i3.nix deleted file mode 100644 index f91527da4..000000000 --- a/users/aspen/system/home/modules/i3.nix +++ /dev/null @@ -1,397 +0,0 @@ -{ config, lib, pkgs, ... }: -let - inherit (config.lib) depot; - - mod = "Mod4"; - solarized = import ../common/solarized.nix; - # TODO pull this out into lib - emacsclient = eval: pkgs.writeShellScript "emacsclient-eval" '' - msg=$(emacsclient --eval '${eval}' 2>&1) - echo "''${msg:1:-1}" - ''; - - i3status-conf = pkgs.writeText "i3status.conf" '' - general { - output_format = i3bar - colors = true - color_good = "#859900" - - interval = 1 - } - - order += "external_script current_task" - order += "external_script inbox" - order += "spotify" - order += "weather_owm" - order += "volume_status" - order += "wireless ${config.system.machine.wirelessInterface}" - # order += "ethernet enp3s0f0" - order += "cpu_usage" - ${lib.optionalString (!isNull config.system.machine.battery) '' - order += "battery ${toString config.system.machine.battery}" - ''} - # order += "volume master" - order += "time" - order += "tztime utc" - - mpd { - format = "%artist - %album - %title" - } - - wireless ${config.system.machine.wirelessInterface} { - format_up = "W: (%quality - %essid - %bitrate) %ip" - format_down = "W: -" - } - - ethernet enp3s0f0 { - format_up = "E: %ip" - format_down = "E: -" - } - - battery ${toString config.system.machine.battery} { - format = "%status %percentage (%remaining)" - path = "/sys/class/power_supply/BAT%d/uevent" - low_threshold = 10 - } - - cpu_usage { - format = "CPU: %usage" - } - - load { - format = "%5min" - } - - time { - format = " %a %h %d ⌚ %I:%M " - } - - spotify { - color_playing = "#fdf6e3" - color_paused = "#93a1a1" - format_stopped = "" - format_down = "" - format = "{title} - {artist} ({album})" - } - - external_script inbox { - script_path = '${emacsclient "(aspen/num-inbox-items-message)"}' - format = 'Inbox: {output}' - cache_timeout = 120 - color = "#93a1a1" - } - - external_script current_task { - script_path = '${ - emacsclient "(aspen/org-current-clocked-in-task-message)" - }' - # format = '{output}' - cache_timeout = 60 - color = "#93a1a1" - } - - tztime utc { - timezone = "UTC" - format = " %H·%M " - } - - volume_status { - format = "☊ {percentage}" - format_muted = "☊ X" - # device = "default" - # mixer_idx = 0 - } - - weather_owm { - api_key = '@owmApiKey@' - unit_temperature = 'c' - format = '{icon} {temperature}[ {rain}]' - } - ''; - - i3status-command = pkgs.writeShellScript "i3status.sh" '' - sed -s "s/@owmApiKey@/$(pass owm-api-key)/" \ - < ${i3status-conf} \ - > /tmp/i3status.conf - py3status -c /tmp/i3status.conf - ''; - - inherit (builtins) map; - inherit (lib) mkMerge range; -in -{ - options = with lib; { - system.machine = { - wirelessInterface = mkOption { - description = '' - Name of the primary wireless interface. Used by i3status, etc. - ''; - default = "wlp3s0"; - type = types.str; - }; - - i3FontSize = mkOption { - description = "Font size to use in i3 window decorations etc."; - default = 6; - type = types.int; - }; - - battery = mkOption { - description = "Battery index for this system's battery"; - default = 0; - type = types.nullOr types.int; - }; - }; - }; - - config = - let - fontName = "MesloLGSDZ"; - fontSize = config.system.machine.i3FontSize; - fonts = { - names = [ fontName ]; - size = fontSize * 1.0; - }; - decorationFont = "${fontName} ${toString fontSize}"; - in - { - home.packages = with pkgs; [ - rofi - rofi-pass - depot.users.aspen.pkgs.py3status - i3lock - i3status - dconf # for gtk - - # Screenshots - maim - - # GIFs - picom - peek - - (pkgs.writeShellScriptBin "lock" '' - playerctl pause - ${pkgs.i3lock}/bin/i3lock -c 222222 - '') - ]; - - xsession.scriptPath = ".xsession"; - - xsession.windowManager.i3 = { - enable = true; - config = { - modifier = mod; - keybindings = - mkMerge ( - (map - (n: { - "${mod}+${toString n}" = - "workspace ${toString n}"; - "${mod}+Shift+${toString n}" = - "move container to workspace ${toString n}"; - }) - (range 0 9)) - ++ [ - (rec { - "${mod}+h" = "focus left"; - "${mod}+j" = "focus down"; - "${mod}+k" = "focus up"; - "${mod}+l" = "focus right"; - "${mod}+semicolon" = "focus parent"; - - "${mod}+Shift+h" = "move left"; - "${mod}+Shift+j" = "move down"; - "${mod}+Shift+k" = "move up"; - "${mod}+Shift+l" = "move right"; - - "${mod}+Shift+x" = "kill"; - - "${mod}+Return" = "exec alacritty"; - - "${mod}+Shift+s" = "split h"; - "${mod}+Shift+v" = "split v"; - "${mod}+e" = "layout toggle split"; - "${mod}+w" = "layout tabbed"; - "${mod}+s" = "layout stacking"; - - "${mod}+f" = "fullscreen"; - - "${mod}+Shift+r" = "restart"; - - "${mod}+r" = "mode resize"; - - # Marks - "${mod}+Shift+m" = ''exec i3-input -F "mark %s" -l 1 -P 'Mark: ' ''; - "${mod}+m" = ''exec i3-input -F '[con_mark="%s"] focus' -l 1 -P 'Go to: ' ''; - - # Screenshots - "${mod}+q" = "exec \"maim | xclip -selection clipboard -t image/png\""; - "${mod}+Shift+q" = "exec \"maim -s | xclip -selection clipboard -t image/png\""; - "${mod}+Ctrl+q" = "exec ${pkgs.writeShellScript "peek.sh" '' - ${pkgs.picom}/bin/picom & - picom_pid=$! - ${pkgs.peek}/bin/peek || true - kill -SIGINT $picom_pid - ''}"; - - # Launching applications - "${mod}+u" = "exec ${pkgs.writeShellScript "rofi" '' - rofi \ - -modi 'combi' \ - -combi-modi "window,drun,ssh,run" \ - -font '${decorationFont}' \ - -show combi - ''}"; - - # Passwords - "${mod}+p" = "exec rofi-pass -font '${decorationFont}'"; - - # Edit current buffer - "${mod}+v" = "exec edit-input"; - - # Media - "XF86AudioPlay" = "exec playerctl -p spotify play-pause"; - "XF86AudioNext" = "exec playerctl -p spotify next"; - "XF86AudioPrev" = "exec playerctl -p spotify previous"; - "XF86AudioRaiseVolume" = "exec pulseaudio-ctl up"; - "XF86AudioLowerVolume" = "exec pulseaudio-ctl down"; - "XF86AudioMute" = "exec pulseaudio-ctl mute"; - - # Lock - Pause = "exec lock"; - - # Brightness - "XF86MonBrightnessDown" = "exec ${pkgs.brightnessctl}/bin/brightnessctl -q s 5%-"; - "XF86MonBrightnessUp" = "exec ${pkgs.brightnessctl}/bin/brightnessctl -q s 5%+"; - - # Sleep/hibernate - # "${mod}+Escape" = "exec systemctl suspend"; - # "${mod}+Shift+Escape" = "exec systemctl hibernate"; - - # Scratch buffer - "${mod}+minus" = "scratchpad show"; - "${mod}+Shift+minus" = "move scratchpad"; - "${mod}+space" = "focus mode_toggle"; - "${mod}+Shift+space" = "floating toggle"; - - # Screen Layout - "${mod}+Shift+t" = "exec xrandr --auto"; - - # Notifications - "${mod}+Shift+n" = "exec killall -SIGUSR1 .dunst-wrapped"; - "${mod}+n" = "exec killall -SIGUSR2 .dunst-wrapped"; - "Control+space" = "exec ${pkgs.dunst}/bin/dunstctl close"; - "Control+Shift+space" = "exec ${pkgs.dunst}/bin/dunstctl close-all"; - "Control+grave" = "exec ${pkgs.dunst}/bin/dunstctl history-pop"; - "Control+Shift+period" = "exec ${pkgs.dunst}/bin/dunstctl action"; - }) - ] - ); - - inherit fonts; - - colors = with solarized; rec { - focused = { - border = base01; - background = base01; - text = base3; - indicator = red; - childBorder = base02; - }; - focusedInactive = focused // { - border = base03; - background = base03; - # text = base1; - }; - unfocused = focusedInactive; - background = base03; - }; - - modes.resize = { - l = "resize shrink width 5 px or 5 ppt"; - k = "resize grow height 5 px or 5 ppt"; - j = "resize shrink height 5 px or 5 ppt"; - h = "resize grow width 5 px or 5 ppt"; - - Return = "mode \"default\""; - }; - - bars = [{ - statusCommand = "${i3status-command}"; - inherit fonts; - position = "top"; - colors = with solarized; rec { - background = base03; - statusline = base3; - separator = base1; - activeWorkspace = { - border = base03; - background = base1; - text = base3; - }; - focusedWorkspace = activeWorkspace; - inactiveWorkspace = activeWorkspace // { - background = base01; - }; - urgentWorkspace = activeWorkspace // { - background = red; - }; - }; - }]; - - window.titlebar = true; - }; - }; - - services.dunst = { - enable = true; - settings = with solarized; { - global = { - font = "MesloLGSDZ ${toString (config.system.machine.i3FontSize * 1.5)}"; - allow_markup = true; - format = "<b>%s</b>\n%b"; - sort = true; - alignment = "left"; - geometry = "600x15-40+40"; - idle_threshold = 120; - separator_color = "frame"; - separator_height = 1; - word_wrap = true; - padding = 8; - horizontal_padding = 8; - max_icon_size = 45; - }; - - frame = { - width = 0; - color = "#aaaaaa"; - }; - - urgency_low = { - background = base03; - foreground = base3; - timeout = 5; - }; - - urgency_normal = { - background = base02; - foreground = base3; - timeout = 7; - }; - - urgency_critical = { - background = red; - foreground = base3; - timeout = 0; - }; - }; - }; - - gtk = { - enable = true; - iconTheme.name = "Adwaita"; - theme.name = "Adwaita"; - }; - }; -} diff --git a/users/aspen/system/home/modules/lib/cloneRepo.nix b/users/aspen/system/home/modules/lib/cloneRepo.nix deleted file mode 100644 index f3cf59d24..000000000 --- a/users/aspen/system/home/modules/lib/cloneRepo.nix +++ /dev/null @@ -1,76 +0,0 @@ -{ lib, config, ... }: -with lib; -{ - options = { - aspen.impure.clonedRepos = mkOption { - description = "Repositories to clone"; - default = { }; - type = with types; attrsOf ( - let - sm = submodule { - options = { - url = mkOption { - type = nullOr str; - description = "URL of repository to clone"; - default = null; - }; - - github = mkOption { - type = nullOr str; - description = "Github owner/repo of repository to clone"; - default = null; - }; - - path = mkOption { - type = str; - description = "Path to clone to"; - }; - - onClone = mkOption { - type = str; - description = '' - Shell command to run after cloning the repo for the first time. - Runs inside the repo itself. - ''; - default = ""; - }; - - after = mkOption { - type = listOf str; - description = "Activation hooks that this repository must be cloned after"; - default = [ ]; - }; - }; - }; - in - addCheck sm (cr: (! isNull cr.url || ! isNull cr.github)) - ); - }; - }; - - config = { - home.activation = - mapAttrs - (_: { url - , path - , github - , onClone - , after - , ... - }: - let repoURL = if isNull url then "git@github.com:${github}" else url; - in hm.dag.entryAfter ([ "writeBoundary" ] ++ after) '' - $DRY_RUN_CMD mkdir -p $(dirname "${path}") - if [[ ! -d ${path} ]]; then - if $DRY_RUN_CMD git clone "${repoURL}" "${path}"; then - pushd ${path} - $DRY_RUN_CMD ${onClone} - popd - else - echo "Git repository ${path} failed to clone" - fi - fi - '') - config.aspen.impure.clonedRepos; - }; -} diff --git a/users/aspen/system/home/modules/lib/zshFunctions.nix b/users/aspen/system/home/modules/lib/zshFunctions.nix deleted file mode 100644 index 228dc6379..000000000 --- a/users/aspen/system/home/modules/lib/zshFunctions.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ - options = { - programs.zsh.functions = mkOption { - description = "An attribute set that maps function names to their source"; - default = { }; - type = with types; attrsOf (either str path); - }; - }; - - config.programs.zsh.initExtra = concatStringsSep "\n" ( - mapAttrsToList - (name: funSrc: '' - function ${name}() { - ${funSrc} - } - '') - config.programs.zsh.functions - ); -} diff --git a/users/aspen/system/home/modules/obs.nix b/users/aspen/system/home/modules/obs.nix deleted file mode 100644 index 7962320f8..000000000 --- a/users/aspen/system/home/modules/obs.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - inherit (pkgs) obs-studio; - obs-input-overlay = pkgs.obs-studio-plugins.input-overlay; -in - -{ - home.packages = [ - obs-studio - obs-input-overlay - ]; - - xdg.configFile."obs-studio/plugins/input-overlay/bin/64bit/input-overlay.so".source = - "${obs-input-overlay}/lib/obs-plugins/input-overlay.so"; - xdg.configFile."obs-studio/plugins/input-overlay/data".source = - "${obs-input-overlay}/share/obs/obs-plugins/input-overlay"; -} diff --git a/users/aspen/system/home/modules/ptt.nix b/users/aspen/system/home/modules/ptt.nix deleted file mode 100644 index 436c8f261..000000000 --- a/users/aspen/system/home/modules/ptt.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - - pttKeycode = "152"; - sourceID = "3"; - - mute = pkgs.writeShellScript "mute-mic" '' - xset -r ${pttKeycode} - ${pkgs.pulseaudio}/bin/pactl set-source-mute ${sourceID} 1 - ''; - - unmute = pkgs.writeShellScript "unmute-mic" '' - xset -r ${pttKeycode} - ${pkgs.pulseaudio}/bin/pactl set-source-mute ${sourceID} 0 - ''; - -in - -{ - home.packages = with pkgs; [ - xbindkeys - ]; - - - home.file.".xbindkeysrc.scm".text = '' - (xbindkey '("c:${pttKeycode}") "${unmute}") - (xbindkey '(release "c:${pttKeycode}") "${mute}") - ''; - - systemd.user.services."xbindkeys" = { - Unit = { - Description = "Keybind daemon for push-to-talk"; - After = [ "graphical-session-pre.target" ]; - PartOf = [ "graphical-session.target" ]; - }; - - Install = { WantedBy = [ "graphical-session.target" ]; }; - - Service = { - ExecStart = "${pkgs.xbindkeys}/bin/xbindkeys -n -v"; - }; - }; -} diff --git a/users/aspen/system/home/modules/pure.zsh-theme b/users/aspen/system/home/modules/pure.zsh-theme deleted file mode 100755 index 666e28259..000000000 --- a/users/aspen/system/home/modules/pure.zsh-theme +++ /dev/null @@ -1,155 +0,0 @@ -#!/bin/zsh -f -# vim: ft=zsh: -# MIT License -# For my own and others sanity -# git: -# %b => current branch -# %a => current action (rebase/merge) -# prompt: -# %F => color dict -# %f => reset color -# %~ => current path -# %* => time -# %n => username -# %m => shortname host -# %(?..) => prompt conditional - %(condition.true.false) - -# turns seconds into human readable time -# 165392 => 1d 21h 56m 32s -prompt_pure_human_time() { - local tmp=$1 - local days=$(( tmp / 60 / 60 / 24 )) - local hours=$(( tmp / 60 / 60 % 24 )) - local minutes=$(( tmp / 60 % 60 )) - local seconds=$(( tmp % 60 )) - (( $days > 0 )) && echo -n "${days}d " - (( $hours > 0 )) && echo -n "${hours}h " - (( $minutes > 0 )) && echo -n "${minutes}m " - echo "${seconds}s" -} - -is_git_repo() { - command git rev-parse --is-inside-work-tree &>/dev/null - return $? -} - -# fastest possible way to check if repo is dirty -prompt_pure_git_dirty() { - # check if we're in a git repo - is_git_repo || return - # check if it's dirty - [[ "$PURE_GIT_UNTRACKED_DIRTY" == 0 ]] && local umode="-uno" || local umode="-unormal" - command test -n "$(git status --porcelain --ignore-submodules ${umode})" - - (($? == 0)) && echo '*' -} - -prompt_pure_git_wip() { - is_git_repo || return - local subject="$(command git show --pretty=%s --quiet HEAD 2>/dev/null)" - [ "$subject" == 'wip' ] && echo '[WIP]' -} - -# displays the exec time of the last command if set threshold was exceeded -prompt_pure_cmd_exec_time() { - local stop=$EPOCHSECONDS - local start=${cmd_timestamp:-$stop} - integer elapsed=$stop-$start - (($elapsed > ${PURE_CMD_MAX_EXEC_TIME:=5})) && prompt_pure_human_time $elapsed -} - -prompt_pure_preexec() { - cmd_timestamp=$EPOCHSECONDS - - # shows the current dir and executed command in the title when a process is active - print -Pn "\e]0;" - echo -nE "$PWD:t: $2" - print -Pn "\a" -} - -# string length ignoring ansi escapes -prompt_pure_string_length() { - echo ${#${(S%%)1//(\%([KF1]|)\{*\}|\%[Bbkf])}} -} - -prompt_pure_nix_info() { - local packages_info='' - if [[ -z $NIX_SHELL_PACKAGES ]]; then - packages_info='[nix-shell]' - else - packages_info="{ $NIX_SHELL_PACKAGES }" - fi - - case $IN_NIX_SHELL in - 'pure') - echo "$fg_bold[green][nix-shell] " - ;; - 'impure') - echo "$fg_bold[magenta][nix-shell] " - ;; - *) ;; - esac -} - -prompt_pure_precmd() { - if [[ "$TERM" == "dumb" ]]; then - return - fi - - # shows the full path in the title - print -Pn '\e]0;%~\a' - - # git info - vcs_info - - local prompt_pure_preprompt="\n$(prompt_pure_nix_info)$fg_bold[green]$prompt_pure_username%F{blue}%~%F{yellow}$vcs_info_msg_0_`prompt_pure_git_dirty` $fg_no_bold[red]`prompt_pure_git_wip`%f %F{yellow}`prompt_pure_cmd_exec_time`%f " - print -P $prompt_pure_preprompt - - # check async if there is anything to pull - # (( ${PURE_GIT_PULL:-1} )) && { - # # check if we're in a git repo - # command git rev-parse --is-inside-work-tree &>/dev/null && - # # make sure working tree is not $HOME - # [[ "$(command git rev-parse --show-toplevel)" != "$HOME" ]] && - # # check check if there is anything to pull - # command git fetch &>/dev/null && - # # check if there is an upstream configured for this branch - # command git rev-parse --abbrev-ref @'{u}' &>/dev/null && { - # local arrows='' - # (( $(command git rev-list --right-only --count HEAD...@'{u}' 2>/dev/null) > 0 )) && arrows='⇣' - # (( $(command git rev-list --left-only --count HEAD...@'{u}' 2>/dev/null) > 0 )) && arrows+='⇡' - # print -Pn "\e7\e[A\e[1G\e[`prompt_pure_string_length $prompt_pure_preprompt`C%F{cyan}${arrows}%f\e8" - # } - # } &! - - # reset value since `preexec` isn't always triggered - unset cmd_timestamp -} - - -prompt_pure_setup() { - # prevent percentage showing up - # if output doesn't end with a newline - export PROMPT_EOL_MARK='' - - prompt_opts=(cr subst percent) - - zmodload zsh/datetime - autoload -Uz add-zsh-hook - autoload -Uz vcs_info - - add-zsh-hook precmd prompt_pure_precmd - add-zsh-hook preexec prompt_pure_preexec - - zstyle ':vcs_info:*' enable git - zstyle ':vcs_info:git*' formats ' %b' - zstyle ':vcs_info:git*' actionformats ' %b|%a' - - # show username@host if logged in through SSH - [[ "$SSH_CONNECTION" != '' ]] && prompt_pure_username='%n@%m ' - - # prompt turns red if the previous command didn't exit with 0 - PROMPT='%(?.%F{green}.%F{red})❯%f ' -} - -prompt_pure_setup "$@" diff --git a/users/aspen/system/home/modules/rtlsdr.nix b/users/aspen/system/home/modules/rtlsdr.nix deleted file mode 100644 index c8a404a1f..000000000 --- a/users/aspen/system/home/modules/rtlsdr.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - - nixpkgs-gnuradio = import - (pkgs.fetchFromGitHub { - owner = "doronbehar"; - repo = "nixpkgs"; - rev = "712561aa5f10bfe6112a1726a912585612a70d1f"; - sha256 = "04yqflbwjcfl9vlplphpj82csqqz9k6m3nj1ybhwgmsc4by7vivl"; - }) - { }; - -in - -{ - home.packages = with pkgs; [ - rtl-sdr - nixpkgs-gnuradio.gnuradio - nixpkgs-gnuradio.gnuradio.plugins.osmosdr - nixpkgs-gnuradio.gqrx - ]; -} diff --git a/users/aspen/system/home/modules/shell.nix b/users/aspen/system/home/modules/shell.nix deleted file mode 100644 index 844f76c28..000000000 --- a/users/aspen/system/home/modules/shell.nix +++ /dev/null @@ -1,166 +0,0 @@ -{ config, lib, pkgs, ... }: -let - shellAliases = rec { - # NixOS stuff - ncg = "nix-collect-garbage"; - - # Nix - ns = "nix-shell"; - nb = "nix build -f ."; - nbl = "nix build -f . --builders ''"; # nix build local - lwo = "lorri watch --once"; - - # Docker and friends - "dcu" = "docker-compose up"; - "dcud" = "docker-compose up -d"; - "dc" = "docker-compose"; - "dcr" = "docker-compose restart"; - "dclf" = "docker-compose logs -f"; - "dck" = "docker"; - "dockerclean" = "dockercleancontainers && dockercleanimages"; - "dockercleanimages" = - "docker images -a --no-trunc | grep none | awk '{print $$3}' | xargs -L 1 -r docker rmi"; - "dockercleancontainers" = - "docker ps -a --no-trunc| grep 'Exit' | awk '{print $$1}' | xargs -L 1 -r docker rm"; - - # Directories - stck = "dirs -v"; - b = "cd ~1"; - ".." = "cd .."; - "..." = "cd ../.."; - "...." = "cd ../../.."; - "....." = "cd ../../../.."; - - # Aliases from old config - "http" = "http --style solarized"; - "grep" = "grep $GREP_OPTIONS"; - "df" = "df -h"; - "ll" = "ls -al"; - "la" = "ls -a"; - }; -in -{ - home.packages = with pkgs; [ zsh autojump ]; - - home.sessionVariables = { - EDITOR = "vim"; - LS_COLORS = - "no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.avi=01;35:*.fli=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.ogg=01;35:*.mp3=01;35:*.wav=01;35:"; - BROWSER = "firefox"; - BAT_THEME = "ansi-light"; - }; - - programs.bash = { - enable = true; - inherit shellAliases; - }; - - programs.zsh = { - enable = true; - autosuggestion.enable = true; - autocd = true; - - inherit shellAliases; - - history = rec { - save = 100000; - size = save; - }; - - oh-my-zsh = { - enable = true; - - plugins = [ - "battery" - "colorize" - "command-not-found" - "github" - "gitignore" - "postgres" - "systemd" - "themes" - "vi-mode" - ]; - - custom = "${pkgs.stdenv.mkDerivation { - name = "oh-my-zsh-custom"; - unpackPhase = ":"; - installPhase = '' - mkdir -p $out/themes - mkdir -p $out/custom/plugins - ln -s ${./pure.zsh-theme} $out/themes/pure.zsh-theme - ''; - }}"; - - theme = "pure"; - }; - - plugins = [{ - name = "pure-theme"; - src = pkgs.fetchFromGitHub { - owner = "sindresorhus"; - repo = "pure"; - rev = "0a92b02dd4172f6c64fdc9b81fe6cd4bddb0a23b"; - sha256 = "0l8jqhmmjn7p32hdjnv121xsjnqd2c0plhzgydv2yzrmqgyvx7cc"; - }; - }]; - - initExtraFirst = '' - if [[ "$TERM" = "dumb" ]]; then - return - fi - ''; - - initExtraBeforeCompInit = '' - zstyle ':completion:*' completer _complete _ignored _correct _approximate - zstyle ':completion:*' matcher-list \'\' 'm:{[:lower:]}={[:upper:]} m:{[:lower:][:upper:]}={[:upper:][:lower:]} r:|[._- :]=** r:|=**' 'l:|=* r:|=*' - zstyle ':completion:*' max-errors 5 - zstyle ':completion:*' use-cache yes - zstyle ':completion::complete:grunt::options:' expire 1 - zstyle ':completion:*' prompt '%e errors' - # zstyle :compinstall filename '~/.zshrc' - autoload -Uz compinit - ''; - - initExtra = '' - if [[ "$TERM" != "dumb" ]]; then - source ${./zshrc} - source ${ - pkgs.fetchFromGitHub { - owner = "zsh-users"; - repo = "zsh-syntax-highlighting"; - rev = "7678a8a22780141617f809002eeccf054bf8f448"; - sha256 = "0xh4fbd54kvwwpqvabk8lpw7m80phxdzrd75q3y874jw0xx1a9q6"; - } - }/zsh-syntax-highlighting.zsh - source ${pkgs.autojump}/share/autojump/autojump.zsh - source ${ - pkgs.fetchFromGitHub { - owner = "chisui"; - repo = "zsh-nix-shell"; - rev = "a65382a353eaee5a98f068c330947c032a1263bb"; - sha256 = "0l41ac5b7p8yyjvpfp438kw7zl9dblrpd7icjg1v3ig3xy87zv0n"; - } - }/nix-shell.plugin.zsh - - export RPS1="" - autoload -U promptinit; promptinit - prompt pure - fi - - if [[ "$TERM" == "dumb" ]]; then - unsetopt zle - unsetopt prompt_cr - unsetopt prompt_subst - unset zle_bracketed_paste - export PS1='$ ' - fi - ''; - }; - - programs.fzf = { - enable = true; - enableBashIntegration = true; - enableZshIntegration = true; - }; -} diff --git a/users/aspen/system/home/modules/tarsnap.nix b/users/aspen/system/home/modules/tarsnap.nix deleted file mode 100644 index fb2a05085..000000000 --- a/users/aspen/system/home/modules/tarsnap.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - home.packages = with pkgs; [ - tarsnap - ]; - - home.file.".tarsnaprc".text = '' - ### Recommended options - - # Tarsnap cache directory - cachedir /home/aspen/.cache/tarsnap - - # Tarsnap key file - keyfile /home/aspen/.private/tarsnap.key - - # Don't archive files which have the nodump flag set. - nodump - - # Print statistics when creating or deleting archives. - print-stats - - # Create a checkpoint once per GB of uploaded data. - checkpoint-bytes 1G - - ### Commonly useful options - - # Use SI prefixes to make numbers printed by --print-stats more readable. - humanize-numbers - - ### Other options, not applicable to most systems - - # Aggressive network behaviour: Use multiple TCP connections when - # writing archives. Use of this option is recommended only in - # cases where TCP congestion control is known to be the limiting - # factor in upload performance. - #aggressive-networking - - # Exclude files and directories matching specified patterns. - # Only one file or directory per command; multiple "exclude" - # commands may be given. - #exclude - - # Include only files and directories matching specified patterns. - # Only one file or directory per command; multiple "include" - # commands may be given. - #include - - # Attempt to reduce tarsnap memory consumption. This option - # will slow down the process of creating archives, but may help - # on systems where the average size of files being backed up is - # less than 1 MB. - #lowmem - - # Try even harder to reduce tarsnap memory consumption. This can - # significantly slow down tarsnap, but reduces its memory usage - # by an additional factor of 2 beyond what the lowmem option does. - #verylowmem - - # Snapshot time. Use this option if you are backing up files - # from a filesystem snapshot rather than from a "live" filesystem. - #snaptime <file> - ''; -} diff --git a/users/aspen/system/home/modules/tmux.nix b/users/aspen/system/home/modules/tmux.nix deleted file mode 100644 index adbaa02f3..000000000 --- a/users/aspen/system/home/modules/tmux.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - programs.tmux = { - enable = true; - customPaneNavigationAndResize = true; - keyMode = "vi"; - newSession = true; - prefix = "C-a"; - shell = "${pkgs.zsh}/bin/zsh"; - shortcut = "a"; - - extraConfig = '' - set -g status-bg "colour0" - set -g message-command-fg "colour7" - set -g status-justify "centre" - set -g status-left-length "100" - set -g status "on" - set -g pane-active-border-fg "colour14" - set -g message-bg "colour11" - set -g status-right-length "100" - set -g status-right-attr "none" - set -g message-fg "colour7" - set -g message-command-bg "colour11" - set -g status-attr "none" - # set -g status-utf8 "on" - set -g pane-border-fg "colour11" - set -g status-left-attr "none" - setw -g window-status-fg "colour10" - setw -g window-status-attr "none" - setw -g window-status-activity-bg "colour0" - setw -g window-status-activity-attr "none" - setw -g window-status-activity-fg "colour14" - setw -g window-status-separator "" - setw -g window-status-bg "colour0" - set -g status-left "#[fg=colour15,bg=colour14,bold] #S #[fg=colour14,bg=colour11,nobold,nounderscore,noitalics]#[fg=colour7,bg=colour11] #F #[fg=colour11,bg=colour0,nobold,nounderscore,noitalics]#[fg=colour10,bg=colour0] #W #[fg=colour0,bg=colour0,nobold,nounderscore,noitalics]" - set -g status-right "#{battery_status_bg} Batt: #{battery_percentage} #{battery_remain} | #[fg=colour0,bg=colour0,nobold,nounderscore,noitalics]#[fg=colour10,bg=colour0] %a #[fg=colour11,bg=colour0,nobold,nounderscore,noitalics]#[fg=colour7,bg=colour11] %b %d  %R #[fg=colour14,bg=colour11,nobold,nounderscore,noitalics]#[fg=colour15,bg=colour14] #H " - setw -g window-status-format "#[fg=colour0,bg=colour0,nobold,nounderscore,noitalics]#[default] #I  #W #[fg=colour0,bg=colour0,nobold,nounderscore,noitalics]" - setw -g window-status-current-format "#[fg=colour0,bg=colour11,nobold,nounderscore,noitalics]#[fg=colour7,bg=colour11] #I  #W #[fg=colour11,bg=colour0,nobold,nounderscore,noitalics]" - ''; - }; -} diff --git a/users/aspen/system/home/modules/twitter.nix b/users/aspen/system/home/modules/twitter.nix deleted file mode 100644 index ab5647e41..000000000 --- a/users/aspen/system/home/modules/twitter.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ pkgs, lib, ... }: - -{ - imports = [ - ./lib/zshFunctions.nix - ]; - - home.packages = with pkgs; [ - t - ]; - - home.sessionVariables = { - TWITTER_WHOAMI = "glittershark1"; - }; - - programs.zsh = { - shellAliases = { - "mytl" = "t tl $TWITTER_WHOAMI"; - }; - - functions = { - favelast = "t fave $(t tl -l $1 | head -n1 | cut -d' ' -f1)"; - rtlast = "t rt $(t tl -l $1 | head -n1 | cut -d' ' -f1)"; - tthread = "t reply $(t tl -l $TWITTER_WHOAMI | head -n1 | cut -d' ' -f1) $@"; - }; - }; -} diff --git a/users/aspen/system/home/modules/vim.nix b/users/aspen/system/home/modules/vim.nix deleted file mode 100644 index b87cb09ad..000000000 --- a/users/aspen/system/home/modules/vim.nix +++ /dev/null @@ -1,48 +0,0 @@ -{ config, pkgs, ... }: -{ - programs.neovim = { - enable = true; - viAlias = true; - vimAlias = true; - plugins = with pkgs.vimPlugins; [ - ctrlp - deoplete-nvim - syntastic - vim-abolish - vim-airline - vim-airline-themes - vim-bufferline - vim-closetag - # vim-colors-solarized - # solarized - (pkgs.vimUtils.buildVimPlugin { - pname = "vim-colors-solarized"; - version = "git"; - src = pkgs.fetchFromGitHub { - owner = "glittershark"; - repo = "vim-colors-solarized"; - rev = "4857c3221ec3f2693a45855154cb61a2cefb514d"; - sha256 = "0kqp5w14g7adaiinmixm7z3x4w74lv1lcgbqjbirx760f0wivf9y"; - }; - }) - vim-commentary - vim-dispatch - vim-endwise - vim-repeat - vim-fugitive - vim-markdown - vim-nix - vim-rhubarb - vim-sexp - vim-sexp-mappings-for-regular-people - vim-sleuth - vim-startify - vim-surround - vim-unimpaired - vinegar - ]; - extraConfig = '' - source ${./vimrc} - ''; - }; -} diff --git a/users/aspen/system/home/modules/vimrc b/users/aspen/system/home/modules/vimrc deleted file mode 100644 index 01572f394..000000000 --- a/users/aspen/system/home/modules/vimrc +++ /dev/null @@ -1,1121 +0,0 @@ -" vim:set fdm=marker fmr={{{,}}} ts=2 sts=2 sw=2 expandtab: - - -" Basic Options {{{ -set nocompatible -set modeline -set modelines=10 -syntax enable -filetype plugin indent on -set ruler -set showcmd -set number -set incsearch -set smartcase -set ignorecase -set scrolloff=10 -set tabstop=4 -set shiftwidth=4 -set softtabstop=4 -set nosmartindent -set expandtab -set noerrorbells visualbell t_vb= -set laststatus=2 -set hidden -let mapleader = ' ' -let maplocalleader = '\' -set undofile -" set undodir=~/.vim/undo -set wildignore=*.pyc,*.o,.git -set clipboard=unnamedplus -" set backupdir=$HOME/.vim/backup -" set directory=$HOME/.vim/tmp -set foldmarker={{{,}}} -set colorcolumn=+1 -set concealcursor= -set formatoptions+=j -set wildmenu -set wildmode=longest,list:full -set noincsearch -" }}} - -" GUI options {{{ -set go-=m -set go-=T -set go-=r -set go-=L -set go-=e -set guifont=Meslo\ LG\ S\ DZ\ 9 -" }}} - -" Colors {{{ -" set t_Co=256 - -fu! ReverseBackground() - if &bg=="light" - se bg=dark - else - se bg=light - endif -endf -com! BgToggle call ReverseBackground() -nm <F12> :BgToggle<CR> - -set background=light -colorscheme solarized -" }}} - -" --------------------------------------------------------------------------- - -" CtrlP {{{ -let g:ctrlp_custom_ignore = { - \ 'dir': '(node_modules|target)' - \ } -let g:ctrlp_max_files = 0 -let g:ctrlp_max_depth = 100 -" }}} - -" YouCompleteMe {{{ -let g:ycm_semantic_triggers = { - \ 'c' : ['->', '.'], - \ 'objc' : ['->', '.'], - \ 'ocaml' : ['.', '#'], - \ 'cpp,objcpp' : ['->', '.', '::'], - \ 'perl' : ['->'], - \ 'php' : ['->', '::'], - \ 'cs,java,javascript,d,python,perl6,scala,vb,elixir,go' : ['.'], - \ 'vim' : ['re![_a-zA-Z]+[_\w]*\.'], - \ 'lua' : ['.', ':'], - \ 'erlang' : [':'], - \ 'clojure' : [], - \ 'haskell' : ['re!.*', '.', ' ', '('] - \ } - " \ 'haskell' : ['.', '(', ' '] - " \ 'ruby' : ['.', '::'], - " \ 'clojure' : ['(', '.', '/', '['] -" }}} - -" Neocomplete {{{ -if !has('nvim') - " Use neocomplete. - let g:neocomplete#enable_at_startup = 1 - " Use smartcase. - let g:neocomplete#enable_smart_case = 1 - " Set minimum syntax keyword length. - let g:neocomplete#sources#syntax#min_keyword_length = 3 - let g:neocomplete#lock_buffer_name_pattern = '\*ku\*' - - " Define dictionary. - " let g:neocomplete#sources#dictionary#dictionaries = { - " \ 'default' : '', - " \ 'vimshell' : $HOME.'/.vimshell_hist', - " \ 'scheme' : $HOME.'/.gosh_completions' - " \ } - - " Define keyword. - if !exists('g:neocomplete#keyword_patterns') - let g:neocomplete#keyword_patterns = {} - endif - let g:neocomplete#keyword_patterns['default'] = '\h\w*' - - " Plugin key-mappings. - inoremap <expr><C-g> neocomplete#undo_completion() - inoremap <expr><C-l> neocomplete#complete_common_string() - - " Recommended key-mappings. - " <CR>: close popup and save indent. - inoremap <silent> <CR> <C-r>=<SID>my_cr_function()<CR> - function! s:my_cr_function() - return (pumvisible() ? "\<C-y>" : "" ) . "\<CR>" - " For no inserting <CR> key. - "return pumvisible() ? "\<C-y>" : "\<CR>" - endfunction - " <TAB>: completion. - inoremap <expr><TAB> pumvisible() ? "\<C-n>" : "\<TAB>" - " <C-h>, <BS>: close popup and delete backword char. - inoremap <expr><C-h> neocomplete#smart_close_popup()."\<C-h>" - inoremap <expr><BS> neocomplete#smart_close_popup()."\<C-h>" - " Close popup by <Space>. - "inoremap <expr><Space> pumvisible() ? "\<C-y>" : "\<Space>" - - " AutoComplPop like behavior. - "let g:neocomplete#enable_auto_select = 1 - - " Shell like behavior(not recommended). - "set completeopt+=longest - "let g:neocomplete#enable_auto_select = 1 - "let g:neocomplete#disable_auto_complete = 1 - "inoremap <expr><TAB> pumvisible() ? "\<Down>" : "\<C-x>\<C-u>" - - " Enable omni completion. - " autocmd FileType css setlocal omnifunc=csscomplete#CompleteCSS - " autocmd FileType html,markdown setlocal omnifunc=htmlcomplete#CompleteTags - " autocmd FileType javascript setlocal omnifunc=javascriptcomplete#CompleteJS - " autocmd FileType python setlocal omnifunc=pythoncomplete#Complete - " autocmd FileType xml setlocal omnifunc=xmlcomplete#CompleteTags - - " Enable heavy omni completion. - if !exists('g:neocomplete#sources#omni#input_patterns') - let g:neocomplete#sources#omni#input_patterns = {} - endif -endif -" }}} - -" Deoplete {{{ -if has('nvim') - let g:deoplete#enable_at_startup = 1 - - inoremap <silent> <CR> <C-r>=<SID>my_cr_function()<CR> - function! s:my_cr_function() - return (pumvisible() ? "\<C-y>" : "" ) . "\<CR>" - " For no inserting <CR> key. - "return pumvisible() ? "\<C-y>" : "\<CR>" - endfunction - " <TAB>: completion. - inoremap <expr><TAB> pumvisible() ? "\<C-n>" : "\<TAB>" - inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<TAB>" -endif -" }}} - -" Neovim Terminal mode {{{ -if has('nvim') - tnoremap <Esc> <C-\><C-n> - nnoremap \\ :tabedit term://zsh<CR> - nnoremap q\ :call <SID>OpenRepl()<CR> - - if !exists('g:repl_size') - let g:repl_size=9 - endif - - function! s:OpenRepl() " {{{ - " Check if buffer exists and is open - if exists('s:repl_bufname') && bufexists(s:repl_bufname) && bufwinnr(s:repl_bufname) >=? 0 - " If so, just switch to it - execute bufwinnr(s:repl_bufname) . 'wincmd' 'w' - norm i - return - endif - - if !exists('b:console') - let b:console=$SHELL - endif - - let l:console_cmd = b:console - - execute 'bot' g:repl_size . 'new' - set winfixheight nobuflisted - call termopen(l:console_cmd) - let s:repl_bufname = bufname('%') - norm i - endfunction " }}} -endif -" }}} - -" Tagbar options {{{ -let g:tagbar_autoclose = 1 -let g:tagbar_autofocus = 1 -let g:tagbar_compact = 1 -" }}} - -" delimitMate options {{{ -let g:delimitMate_expand_cr = 1 -" }}} - -" UltiSnips options {{{ -let g:UltiSnipsExpandTrigger = '<c-j>' - "g:UltiSnipsJumpForwardTrigger <c-j> - "g:UltiSnipsJumpBackwardTrigger <c-k> -" }}} - -" VDebug Options {{{ -let g:vdebug_options = {'server': '192.168.56.1'} -" }}} - -" Statusline {{{ -let g:airline_powerline_fonts=1 - -if !exists('g:airline_symbols') - let g:airline_symbols = {} -endif -let g:airline_symbols.space = "\ua0" - -let g:airline#extensions#tagbar#flags = 'f' -let g:airline#extensions#tabline#enabled = 1 -let g:airline#extensions#tabline#show_buffers = 0 -let g:airline#extensions#tabline#show_tabs = 1 -let g:airline#extensions#tabline#tab_min_count = 2 -let g:airline#extensions#tmuxline#enabled = 0 - -let g:tmuxline_theme = 'airline' -let g:tmuxline_preset = 'full' - -"set statusline= -"set statusline+=%2*[%n%H%M%R%W]%*\ " flags and buf no -"set statusline+=%-40f%<\ " path -"set statusline+=%=%40{fugitive#statusline()}\ " Vim status -"set statusline+=%1*%y%*%*\ " file type -"set statusline+=%10((%l,%c)%)\ " line and column -"set statusline+=%P " percentage of file -" }}} - -" Code review mode {{{ -fun! GetFontName() - return substitute(&guifont, '^\(.\{-}\)[0-9]*$', '\1', '') -endfun - -fun! <SID>CodeReviewMode() - let &guifont = GetFontName() . ' 15' -endfun -com! CodeReviewMode call <SID>CodeReviewMode() -" }}} - -" Syntastic {{{ -let g:syntastic_enable_signs = 0 - -" Python {{{ -let g:syntastic_python_checkers = ['flake8'] -let g:syntastic_python_flake8_post_args = "--ignore=E101,E223,E224,E301,E302,E303,E501,E701,W,F401,E111,E261" - -" }}} -" Javascript {{{ -let g:syntastic_javascript_checkers = ['eslint'] -let g:flow#autoclose = 1 -let g:flow#enable = 1 - -" augroup syntastic_javascript_jsx -" autocmd! -" autocmd BufReadPre,BufNewFile *.js -" autocmd BufReadPre,BufNewFile *.jsx -" \ let g:syntastic_javascript_checkers = ['jsxhint'] -" augroup END - -" }}} -" Haml {{{ -let g:syntastic_haml_checkers = ['haml_lint'] - -" }}} -" Html {{{ -let g:syntastic_html_checkers = [] - -" }}} -" Ruby {{{ -let g:syntastic_ruby_checkers = ['rubocop'] -" }}} -" SASS/SCSS {{{ -let g:syntastic_scss_checkers = ['scss_lint'] -" }}} -" Haskell {{{ -" let g:syntastic_haskell_checkers = ['ghc-mod'] -" }}} -" Elixir {{{ -let g:syntastic_elixir_checkers = ['elixir'] -let g:syntastic_enable_elixir_checker = 1 -" }}} -" }}} - -" Bufferline {{{ -let g:bufferline_echo=0 -" }}} - -" Eclim {{{ -let g:EclimCompletionMethod = 'omnifunc' -augroup eclim - au! - au FileType java call <SID>JavaSetup() - au FileType java set textwidth=120 -augroup END - -function! s:JavaSetup() abort - noremap <C-I> :JavaImport<CR> - nnoremap K :JavaDocPreview<CR> - nnoremap ]d :JavaSearchContext<CR> - nnoremap [d :JavaSearchContext<CR> - nnoremap g<CR> :JUnit<CR> - nnoremap g\ :Mvn test<CR> -endfunction -" }}} - -" Signify options {{{ -let g:signify_mapping_next_hunk = ']h' -let g:signify_mapping_prev_hunk = '[h' -let g:signify_vcs_list = ['git'] -let g:signify_sign_change = '~' -let g:signify_sign_delete = '-' -" }}} - -" Simplenote {{{ -let g:SimplenoteFiletype = 'markdown' -let g:SimplenoteSortOrder = 'pinned,modifydate,tagged,createdate' -let g:SimplenoteVertical = 1 - -nnoremap <Leader>nn :Simplenote -n<CR> -nnoremap <Leader>nl :Simplenote -l<CR> -nnoremap <Leader>nw :Simplenote -l work<CR> -nnoremap <Leader>nt :Simplenote -t<CR> -" }}} - -" Emmet {{{ -" Expand abbreviation -let g:user_emmet_leader_key = '<C-y>' -" }}} - -" Startify {{{ -let g:startify_bookmarks=[ '~/.vimrc', '~/.zshrc' ] -" }}} - -" Abolish {{{ -let g:abolish_save_file = expand('~/.vim/after/plugin/abolish.vim') -" }}} - -" Rails projections {{{ - -if !exists('g:rails_projections') - let g:rails_projections = {} -endif - -call extend(g:rails_projections, { - \ "config/routes.rb": { "command": "routes" }, - \ "config/structure.sql": { "command": "structure" } - \ }, 'keep') - -if !exists('g:rails_gem_projections') - let g:rails_gem_projections = {} -endif - -call extend(g:rails_gem_projections, { - \ "active_model_serializers": { - \ "app/serializers/*_serializer.rb": { - \ "command": "serializer", - \ "template": "class %SSerializer < ActiveModel::Serializer\nend", - \ "affinity": "model"}}, - \ "react-rails": { - \ "app/assets/javascripts/components/*.jsx": { - \ "command": "component", - \ "template": "var %S = window.%S = React.createClass({\n render: function() {\n }\n});", - \ "alternate": "spec/javascripts/components/%s_spec.jsx" }, - \ "spec/javascripts/components/*_spec.jsx": { - \ "alternate": "app/assets/javascripts/components/{}.jsx" }}, - \ "rspec": { - \ "spec/**/support/*.rb": { - \ "command": "support"}}, - \ "cucumber": { - \ "features/*.feature": { - \ "command": "feature", - \ "template": "Feature: %h"}, - \ "features/support/*.rb": { - \ "command": "support"}, - \ "features/support/env.rb": { - \ "command": "support"}, - \ "features/step_definitions/*_steps.rb": { - \ "command": "steps"}}, - \ "carrierwave": { - \ "app/uploaders/*_uploader.rb": { - \ "command": "uploader", - \ "template": "class %SUploader < CarrierWave::Uploader::Base\nend"}}, - \ "draper": { - \ "app/decorators/*_decorator.rb": { - \ "command": "decorator", - \ "affinity": "model", - \ "template": "class %SDecorator < Draper::Decorator\nend"}}, - \ "fabrication": { - \ "spec/fabricators/*_fabricator.rb": { - \ "command": ["fabricator", "factory"], - \ "alternate": "app/models/%s.rb", - \ "related": "db/schema.rb#%p", - \ "test": "spec/models/%s_spec.rb", - \ "template": "Fabricator :%s do\nend", - \ "affinity": "model"}}, - \ "factory_girl": { - \ "spec/factories/*.rb": { - \ "command": "factory", - \ "alternate": "app/models/%i.rb", - \ "related": "db/structure.sql#%s", - \ "test": "spec/models/%s_spec.rb", - \ "template": "FactoryGirl.define do\n factory :%i do\n end\nend", - \ "affinity": "model"}, - \ "spec/factories.rb": { - \ "command": "factory"}, - \ "test/factories.rb": { - \ "command": "factory"}} - \ }, 'keep') -" }}} - -" Other projections {{{ -let g:projectionist_heuristics = { - \ "config.ru&docker-compose.yml&app/&config/&OWNERS": { - \ "app/jobs/*.rb": { - \ "type": "job", - \ "alternate": "spec/jobs/{}_spec.rb" - \ }, - \ "app/models/*.rb": { - \ "type": "model", - \ "alternate": "spec/models/{}_spec.rb" - \ }, - \ "app/resources/*_resource.rb": { - \ "type": "resource", - \ "alternate": "spec/resources/{}_resource_spec.rb" - \ }, - \ "config/*.yml": { - \ "type": "config" - \ }, - \ "spec/*_spec.rb": { - \ "type": "spec", - \ "alternate": "app/{}.rb" - \ }, - \ "spec/factories/*.rb": { - \ "type": "factory", - \ } - \ }, - \ "svc-gateway.cabal": { - \ "src/*.hs": { - \ "type": "src", - \ "alternate": "test/{}Spec.hs" - \ }, - \ "test/*Spec.hs": { - \ "type": "spec", - \ "alternate": "src/{}.hs", - \ "template": [ - \ "module Gateway.Resource.HierarchySpec (main, spec) where", - \ "", - \ "import Prelude", - \ "import Test.Hspec", - \ "import Data.Aeson", - \ "", - \ "import Gateway.Resource.Hierarchy", - \ "", - \ "main :: IO ()", - \ "main = hspec spec", - \ "", - \ "spec :: Spec", - \ "spec = do", - \ " describe \"something\" $ undefined" - \ ] - \ }, - \ "svc-gateway.cabal": { - \ "type": "cabal" - \ } - \ }, - \ "package.json&.flowconfig": { - \ "src/*.*": { - \ "type": "src", - \ "alternate": "test/{}_spec.js" - \ } - \ }, - \ "pom.xml&src/main/clj/|src/main/cljs": { - \ "*": { - \ "start": "USE_NREPL=1 bin/run -m elephant.dev-system" , - \ "connect": "nrepl://localhost:5554", - \ "piggieback": "(figwheel-sidecar.repl-api/repl-env)" - \ }, - \ "pom.xml": { "type": "pom" }, - \ "src/main/clj/*.clj": { - \ "alternate": "src/test/clj/{}_test.clj", - \ "template": ["(ns {dot|hyphenate})"] - \ }, - \ "src/test/clj/*_test.clj": { - \ "alternate": "src/main/clj/{}.clj", - \ "dispatch": ":RunTests {dot|hyphenate}-test", - \ "template": ["(ns {dot|hyphenate}-test", - \ " (:require [clojure.test :refer :all]))"] - \ }, - \ "src/main/cljs/*.cljs": { - \ "alternate": "src/test/cljs/{}_test.cljs" - \ }, - \ "src/main/cljs/*_test.cljs": { - \ "alternate": "src/main/cljs/{}.cljs", - \ "dispatch": ":RunTests {dot|hyphenate}-test" - \ }, - \ "src/main/clj/*.cljc": { - \ "alternate": "src/test/clj/{}_test.cljc" - \ }, - \ "src/main/clj/*_test.cljc": { - \ "alternate": "src/test/clj/{}.cljc", - \ "dispatch": ":RunTests {dot|hyphenate}-test" - \ } - \ }} -" }}} - -" AutoPairs {{{ -let g:AutoPairsCenterLine = 0 -" }}} - -" Filetypes {{{ - -" Python {{{ -aug Python - au! - au FileType python set tabstop=4 shiftwidth=4 softtabstop=4 expandtab -aug END -let g:python_highlight_all=1 -" }}} - -" PHP {{{ -aug PHP - au! - "au FileType php setlocal fdm=marker fmr={{{,}}} -aug END " }}} - -" Mail {{{ -aug Mail - au FileType mail setlocal spell -aug END " }}} - -" Haskell {{{ -let g:haskell_conceal_wide = 1 -let g:haskellmode_completion_ghc = 0 -let g:necoghc_enable_detailed_browse = 1 - -augroup Haskell - autocmd! - autocmd FileType haskell setlocal textwidth=110 shiftwidth=2 - autocmd FileType haskell setlocal omnifunc=necoghc#omnifunc - autocmd FileType haskell call <SID>HaskellSetup() - autocmd FileType haskell setlocal keywordprg=hoogle\ -cie -augroup END - -function! s:HaskellSetup() - set sw=4 - " compiler cabal - " let b:start='cabal run' - " let b:console='cabal repl' - " let b:dispatch='cabal test' - compiler stack - let b:start='stack run' - let b:console='stack ghci' - let b:dispatch='stack test' - nnoremap <buffer> gy :HdevtoolsType<CR> - nnoremap <buffer> yu :HdevtoolsClear<CR> -endfunction -" }}} - -" Ruby {{{ - -function! s:RSpecSyntax() - syn keyword rspecMethod describe context it its specify shared_context - \ shared_examples shared_examples_for shared_context include_examples - \ include_context it_should_behave_like it_behaves_like before after - \ around fixtures controller_name helper_name scenario feature - \ background given described_class - syn match rspecMethod '\<let\>!\=' - syn match rspecMethod '\<subject\>!\=' - syn keyword rspecMethod violated pending expect expect_any_instance_of allow - \ allow_any_instance_of double instance_double mock mock_model - \ stub_model xit - syn match rspecMethod '\.\@<!\<stub\>!\@!' - - call s:RSpecHiDefaults() -endfunction - -function! s:RSpecHiDefaults() - hi def link rspecMethod rubyFunction -endfunction - -augroup Ruby - au! - " au FileType ruby let b:surround_114 = "\\(module|class,def,if,unless,case,while,until,begin,do) \r end" - " au FileType ruby set fdm=syntax - au FileType ruby set tw=110 - au FileType ruby set omnifunc= - au FileType ruby nnoremap <buffer> gy orequire 'pry'; binding.pry<ESC>^ - au FileType ruby nnoremap <buffer> gY Orequire 'pry'; binding.pry<ESC>^ - au FileType ruby nnoremap <buffer> yu :g/require 'pry'; binding.pry/d<CR> - au BufNewFile,BufRead *_spec.rb call <SID>RSpecSyntax() -augroup END - -let ruby_operators = 1 -let ruby_space_errors = 1 - -let g:rubycomplete_rails = 1 -command! -range ConvertHashSyntax <line1>,<line2>s/:(\S{-})(\s{-})=> /\1:\2/ -" }}} - -" Clojure {{{ - -aug Clojure - au! - autocmd FileType clojure nnoremap <C-S> :Slamhound<CR> - autocmd FileType clojure nnoremap <silent> gr :w <bar> Require <bar> e<CR> - let g:clojure_align_multiline_strings = 1 - let g:clojure_fuzzy_indent_patterns = - \ ['^with', '^def', '^let', '^fact'] - let g:clojure_special_indent_words = - \ 'deftype,defrecord,reify,proxy,extend-type,extend-protocol,letfn,html' - - autocmd FileType clojure setlocal textwidth=80 - autocmd FileType clojure setlocal lispwords+=GET,POST,PATCH,PUT,DELETE | - \ setlocal lispwords+=context,select - autocmd BufNewFile,BufReadPost *.cljx setfiletype clojure - autocmd BufNewFile,BufReadPost *.cljx setlocal omnifunc= - autocmd BufNewFile,BufReadPost *.cljs setlocal omnifunc= - autocmd FileType clojure call <SID>TangentInit() - autocmd FileType clojure call <SID>sexp_mappings() - autocmd BufRead *.cljc ClojureHighlightReferences - autocmd FileType clojure let b:AutoPairs = { - \ '"': '"', - \ '{': '}', - \ '(': ')', - \ '[': ']'} - " Don't auto-pair quote reader macros - " \'`': '`', - " \ '''': '''', - - autocmd User ProjectionistActivate call s:projectionist_connect() - - function! s:projectionist_connect() abort - let connected = !empty(fireplace#path()) - if !connected - for [root, value] in projectionist#query('connect') - try - silent execute "FireplaceConnect" value root - let connected = 1 - break - catch /.*Connection refused.*/ - endtry - endfor - endif - - " if connected && exists(':Piggieback') - " for [root, value] in projectionist#query('piggieback') - " silent execute "Piggieback" value - " break - " endfor - " endif - endfunction - - " autocmd BufNewFile,BufReadPost *.cljx setlocal omnifunc= - " autocmd BufNewFile,BufReadPost *.cljs setlocal omnifunc= - - autocmd FileType clojure let b:console='lein repl' - autocmd FileType clojure call <SID>ClojureMaps() - - function! s:ClojureMaps() abort - nnoremap <silent> <buffer> [m :call search('^(def', 'Wzb')<CR> - nnoremap <silent> <buffer> ]m :call search('^(def', 'Wz')<CR> - endfunction - - command! Scratch call <SID>OpenScratch() - autocmd FileType clojure nnoremap <buffer> \s :Scratch<CR> - - let g:scratch_buffer_name = 'SCRATCH' - - function! s:OpenScratch() - if bufwinnr(g:scratch_buffer_name) > 0 - execute bufwinnr(g:scratch_buffer_name) . 'wincmd' 'w' - return - endif - - vsplit SCRATCH - set buftype=nofile - set filetype=clojure - let b:scratch = 1 - endfunction -aug END - -function! s:sexp_mappings() abort - if !exists('g:sexp_loaded') - return - endif - - nmap <buffer> cfo <Plug>(sexp_raise_list) - nmap <buffer> cfO <Plug>(sexp_raise_element) - nmap <buffer> cfe <Plug>(sexp_raise_element) -endfunction - -function! s:TangentInit() abort - set textwidth=80 - command! TReset call fireplace#session_eval('(user/reset)') - command! TGo call fireplace#session_eval('(user/go)') - command! TMigrate call fireplace#session_eval('(user/migrate)') - command! TRollback call fireplace#session_eval('(user/rollback)') - nnoremap g\ :TReset<CR> -endfunction - -" }}} - -" Go {{{ - -let g:go_highlight_functions = 1 -let g:go_highlight_methods = 1 -let g:go_highlight_structs = 1 -let g:go_highlight_operators = 1 -let g:go_highlight_build_constraints = 1 - -augroup Go - autocmd! - autocmd FileType go setlocal omnifunc=go#complete#Complete - autocmd FileType go setlocal foldmethod=syntax - autocmd FileType go setlocal foldlevel=100 - autocmd FileType go nnoremap <buffer> <F9> :GoTest<CR> - autocmd FileType go inoremap <buffer> <F9> <ESC>:GoTest<CR>i -augroup END - -" }}} - -" RAML {{{ - -function! s:buffer_syntax() " {{{ - syn keyword ramlRAML RAML contained - syn match ramlVersionString '^#%RAML \d\.\d' contains=ramlRAML -endfunction " }}} - -augroup RAML - autocmd! - autocmd BufRead,BufNewFile *.raml set filetype=yaml - autocmd BufRead,BufNewFile *.raml call s:buffer_syntax() -augroup END - -hi def link ramlVersionString Special -hi def link ramlRAML Error -" }}} - -" Mustache/Handlebars {{{ -let g:mustache_abbreviations = 1 -" }}} - -" Netrw {{{ -augroup netrw - autocmd! - autocmd FileType netrw nnoremap <buffer> Q :Rexplore<CR> - - " Hee hee, oil and vinegar - function! s:setup_oil() abort - nnoremap <buffer> q <C-6> - xnoremap <buffer> q <C-6> - endfunction -augroup END -" }}} -" }}} - -" Remove trailing whitespace {{{ -fun! <SID>StripTrailingWhitespaces() - let l = line(".") - let c = col(".") - %s/\s\+$//e - call cursor(l, c) -endfun - -augroup striptrailingwhitespaces " {{{ -autocmd FileType c,cpp,java,php,ruby,python,sql,javascript,sh,jst,less,haskell,haml,coffee,scss,clojure,objc,elixir,yaml,json,eruby - \ autocmd BufWritePre <buffer> :call <SID>StripTrailingWhitespaces() -augroup END " }}} - -" }}} - -" Goyo {{{ -let g:limelight_conceal_ctermfg = "10" -let g:limelight_conceal_guifg = "#586e75" -autocmd! User GoyoEnter Limelight -autocmd! User GoyoLeave Limelight! -" }}} - -"----------------------------------------------------------------------------- - -" Commands {{{ - -" Edit temporary SQL files {{{ -let s:curr_sql = 0 -fun! <SID>EditSqlTempFile() - let l:fname = '/tmp/q' . s:curr_sql . '.sql' - execute 'edit' l:fname - let s:curr_sql = s:curr_sql + 1 -endfun -com! EditSqlTempFile call <SID>EditSqlTempFile() -" }}} - -" Double Indentation -command! -range DoubleIndentation <line1>,<line2>s/^\(\s.\{-}\)\(\S\)/\1\1\2/ - -" Quick-and-dirty fix capitalization of sql files -command! -range FixSqlCapitalization <line1>,<line2>v/\v(^\s*--.*$)|(TG_)/norm guu - -" VimPipe Commands {{{ -" let g:sql_type_default = 'pgsql' -command! SqlLive let b:vimpipe_command="vagrant ssh -c '~/mysql'" -command! SqlRails let b:vimpipe_command="bin/rails dbconsole" -command! SqlHeroku let b:vimpipe_command="heroku pg:psql" -command! SqlEntities let b:vimpipe_command="psql -h 127.1 entities nomi" -command! SqlUsers let b:vimpipe_command="psql -h 127.1 users nomi" -command! SqlTangent let b:vimpipe_command="psql -h local.docker tangent super" -" }}} - -" Git commands {{{ -command! -nargs=* Gpf Gpush -f <args> -command! -nargs=* Gcv Gcommit --verbose <args> -" }}} - -" Focus dispatch to only the last failures -command! -nargs=* FocusFailures FocusDispatch rspec --only-failures <args> - -" }}} - -" Autocommands {{{ - -augroup fugitive " {{{ - au! - autocmd BufNewFile,BufRead fugitive://* set bufhidden=delete -augroup END " }}} - -augroup omni " {{{ - au! - " autocmd FileType javascript setlocal omnifunc=tern#Complete - "autocmd FileType python setlocal omnifunc=pythoncomplete#Complete - autocmd FileType php setlocal omnifunc= -augroup END " }}} - -augroup sql " {{{ - au! - autocmd FileType sql let b:vimpipe_command="psql -h 127.0.0.1 landlordsny_development landlordsny" - autocmd FileType sql let b:vimpipe_filetype="postgresql" - autocmd FileType sql set syntax=postgresql - autocmd FileType postgresql set nowrap - autocmd BufNewFile,BufReadPost *.sql set syntax=pgsql -augroup END " }}} - -augroup markdown " {{{ - au! - autocmd FileType markdown let b:vimpipe_command='markdown' - autocmd FileType markdown let b:vimpipe_filetype='html' - autocmd FileType markdown set tw=80 -augroup END " }}} - -augroup typescript " {{{ - au! - autocmd FileType typescript let b:vimpipe_command='tsc' - autocmd FileType typescript let b:vimpipe_filetype='javascript' - autocmd FileType typescript TSSstarthere - autocmd FileType typescript nnoremap <buffer> gd :TSSdef<CR> -augroup END " }}} - -augroup jsx " {{{ - au! - " autocmd FileType jsx set syntax=javascript - autocmd FileType javascript set filetype=javascript.jsx -augroup END " }}} - -augroup nicefoldmethod " {{{ - au! - " Don't screw up folds when inserting text that might affect them, until - " leaving insert mode. Foldmethod is local to the window. Protect against - " screwing up folding when switching between windows. - autocmd InsertEnter * - \ if !exists('w:last_fdm') | - \ let w:last_fdm=&foldmethod | - \ setlocal foldmethod=manual | - \ endif - autocmd InsertLeave,WinLeave * - \ if exists('w:last_fdm') | - \ let &l:foldmethod=w:last_fdm | - \ unlet w:last_fdm | - \ endif -augroup END " }}} - -augroup visualbell " {{{ - au! - autocmd GUIEnter * set visualbell t_vb= -augroup END -" }}} - -augroup quickfix " {{{ - au! - autocmd QuickFixCmdPost grep cwindow -augroup END " }}} - -augroup php " {{{ - au! -augroup END "}}} - -augroup rubylang " {{{ - au! - autocmd FileType ruby compiler rake -augroup END " }}} - -augroup javascript "{{{ - au! - autocmd FileType javascript let &errorformat = - \ '%E%.%#%n) %s:,' . - \ '%C%.%#Error: %m,' . - \ '%C%.%#at %s (%f:%l:%c),' . - \ '%Z%.%#at %s (%f:%l:%c),' . - \ '%-G%.%#,' -augroup END " }}} - -augroup git " {{{ - autocmd! - autocmd FileType gitcommit set textwidth=72 -augroup END -" }}} -" }}} - -" Leader commands {{{ - -" Edit specific files {{{ -nnoremap <silent> <leader>ev :split $MYVIMRC<CR> -nnoremap <silent> <leader>eb :split ~/.vim_bundles<CR> -nnoremap <silent> <leader>es :UltiSnipsEdit<CR> -nnoremap <silent> <leader>ea :split ~/.vim/after/plugin/abolish.vim<CR> - -nnoremap <silent> <leader>sv :so $MYVIMRC<CR> -nnoremap <silent> <leader>sb :so ~/.vim_bundles<CR> -nnoremap <silent> <leader>sa :so ~/.vim/after/plugin/abolish.vim<CR> - -nnoremap <Leader>el :EditSqlTempFile<CR> -" }}} - -" Toggle navigation panels {{{ -nnoremap <Leader>l :TagbarToggle<CR> -nnoremap <Leader>mb :MBEToggle<CR> -nnoremap <Leader>u :GundoToggle<CR> - -nnoremap <Leader>t :CtrlP<CR> -nnoremap <Leader>z :FZF<CR> -nnoremap <Leader>b :CtrlPBuffer<CR> -nnoremap <Leader>a :CtrlPTag<CR> -nnoremap <Leader>r :CtrlPGitBranch<CR> -" }}} - -" CtrlP {{{ -let g:ctrlp_custom_ignore = { - \ 'dir': 'node_modules', - \ } -" }}} - -" Git leader commands {{{ -noremap <Leader>g :Git<SPACE> -noremap <Leader>gu :Gpull<CR> -noremap <Leader>gp :Gpush<CR> -noremap <Leader>s :Gstatus<CR> -noremap <Leader>cv :Gcommit --verbose<CR> -noremap <Leader>ca :Gcommit --verbose --amend<CR> - -nnoremap <Leader>dl :diffg LOCAL<CR> -nnoremap <Leader>dr :diffg REMOTE<CR> -nnoremap <Leader>db :diffg BASE<CR> -nnoremap <Leader>du :diffu<CR> -nnoremap <Leader>dg :diffg<CR> - -nnoremap <Leader>d2 :diffg //2<CR>:diffu<CR> -nnoremap <Leader>d3 :diffg //3<CR>:diffu<CR> - -nnoremap <Leader>yt :SignifyToggle<CR> -" }}} - -" Breakpoint Leader Commands {{{ -nnoremap <Leader>x :Breakpoint<CR> -nnoremap <Leader>dx :BreakpointRemove *<CR> -" }}} - -" Tabularize {{{ - " Leader Commands {{{ - nnoremap <localleader>t= :Tabularize /=<CR> - vmap <localleader>t= :Tabularize /=<CR> - - nnoremap <localleader>t> :Tabularize /=><CR> - vmap <localleader>t> :Tabularize /=><CR> - " }}} - - " => Aligning {{{ - function! s:rocketalign() - let l:p = '^.*=>\s.*$' - echo l:p - if exists(':Tabularize') && getline('.') =~# '^.*=' && - \ (getline(line('.')-1) =~# l:p || getline(line('.')+1) =~# l:p) - let column = strlen(substitute(getline('.')[0:col('.')],'[^=>]','','g')) - let position = strlen(matchstr(getline('.')[0:col('.')],'.*=>\s*\zs.*')) - Tabularize/=>/l1 - normal! $ - call search(repeat('[^=>]*=>',column).'\s\{-\}'.repeat('.',position),'ce',line('.')) - endif - endfunction - "inoremap <buffer> <space>=><space> =><Esc>:call <SID>rocketalign()<CR>a - " }}} - - " = Aligning {{{ - function! s:eqalign() - let l:p = '^.*=\s.*$' - if exists(':Tabularize') && getline('.') =~# '^.*=' && - \ (getline(line('.')-1) =~# l:p || getline(line('.')+1) =~# l:p) - let column = strlen(substitute(getline('.')[0:col('.')],'[^=]','','g')) - let position = strlen(matchstr(getline('.')[0:col('.')],'.*=\s*\zs.*')) - Tabularize/=/l1 - normal! $ - call search(repeat('[^=]*=',column).'\s\{-\}'.repeat('.',position),'ce',line('.')) - endif - endfunction - "inoremap <buffer><silent> <space>=<space> =<Esc>:call <SID>eqalign()<CR>a - " }}} - - " : Aligning {{{ - function! s:colonalign() - let l:p : '^.*:\s.*$' - if exists(':Tabularize') && getline('.') :~# '^.*:' && - \ (getline(line('.')-1) :~# l:p || getline(line('.')+1) :~# l:p) - let column : strlen(substitute(getline('.')[0:col('.')],'[^:]','','g')) - let position : strlen(matchstr(getline('.')[0:col('.')],'.*:\s*\zs.*')) - Tabularize/:/l1 - normal! $ - call search(repeat('[^:]*:',column).'\s\{-\}'.repeat('.',position),'ce',line('.')) - endif - endfunction - "inoremap <buffer><silent> <space>:<space> :<Esc>:call <SID>colonalign()<CR>a - " }}} -" }}} - -" }}} - -" Mappings {{{ -" 'delete current' -nnoremap dc 0d$ -nnoremap com :silent !tmux set status<CR> -nnoremap <F9> :Make<CR> -nnoremap g<CR> :Dispatch<CR> -nnoremap g\ :Start<CR> -inoremap <F9> <ESC>:Make<CR>i - -" Navigate buffers {{{ -nnoremap gb :bn<CR> -nnoremap gB :bp<CR> -" }}} - -" Window Navigation {{{ -nnoremap <space>w <C-w> -nnoremap <space>h <C-w>h -nnoremap <space>j <C-w>j -nnoremap <space>k <C-w>k -nnoremap <space>l <C-w>l -nnoremap <space>z <C-w>z -" }}} - - -" Sort with motion {{{ -if !exists("g:sort_motion_flags") - let g:sort_motion_flags = "" -endif -function! s:sort_motion(mode) abort - if a:mode == 'line' - execute "'[,']sort " . g:sort_motion_flags - elseif a:mode == 'char' - execute "normal! `[v`]y" - let sorted = join(sort(split(@@, ', ')), ', ') - execute "normal! v`]c" . sorted - elseif a:mode == 'V' || a:mode == '' - execute "'<,'>sort " . g:sort_motion_flags - endif -endfunction - -function! s:sort_lines() - let beginning = line('.') - let end = v:count + beginning - 1 - execute beginning . ',' . end . 'sort' -endfunction - -xnoremap <silent> <Plug>SortMotionVisual :<C-U>call <SID>sort_motion(visualmode())<CR> -nnoremap <silent> <Plug>SortMotion :<C-U>set opfunc=<SID>sort_motion<CR>g@ -nnoremap <silent> <Plug>SortLines :<C-U>call <SID>sort_lines()<CR> - -map go <Plug>SortMotion -vmap go <Plug>SortMotionVisual -map goo <Plug>SortLines -" }}} -" }}} - -let g:hare_executable = 'cabal exec -- ghc-hare' diff --git a/users/aspen/system/home/modules/zshrc b/users/aspen/system/home/modules/zshrc deleted file mode 100644 index a12173d68..000000000 --- a/users/aspen/system/home/modules/zshrc +++ /dev/null @@ -1,327 +0,0 @@ -#!/usr/bin/zsh -# vim: set fdm=marker fmr={{{,}}}: - -stty -ixon - -# Compinstall {{{ -zstyle ':completion:*' completer _complete _ignored _correct _approximate -zstyle ':completion:*' matcher-list '' 'm:{[:lower:]}={[:upper:]} m:{[:lower:][:upper:]}={[:upper:][:lower:]} r:|[._- :]=** r:|=**' 'l:|=* r:|=*' -zstyle ':completion:*' max-errors 5 -zstyle ':completion:*' use-cache yes -zstyle ':completion::complete:grunt::options:' expire 1 -zstyle ':completion:*' prompt '%e errors' -zstyle :compinstall filename '~/.zshrc' -autoload -Uz compinit -compinit -# }}} - -# Zsh-newuser-install {{{ -HISTFILE=~/.histfile -HISTSIZE=1000 -SAVEHIST=1000 -setopt appendhistory autocd extendedglob notify autopushd -unsetopt beep nomatch -bindkey -v -# }}} - -# Basic options {{{ -set -o vi -umask 022 -export VIRTUAL_ENV_DISABLE_PROMPT=1 -# export PATH=~/.local/bin:~/.cabal/bin:$PATH:~/code/go/bin:~/bin:~/npm/bin:~/.gem/ruby/2.1.0/bin:~/.gem/ruby/2.0.0/bin:/home/smith/bin -# }}} - -# Zsh highlight highlighters {{{ -ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern root) -# }}} - -# More basic options {{{ -setopt no_hist_verify -setopt histignorespace -# }}} - -# Utility Functions {{{ - -# Set the terminal's title bar. -function titlebar() { -echo -ne "\033]0;$*\007" -} - -function quiet() { -"$@" >/dev/null -} - -function quieter() { -"$@" >/dev/null 2>&1 -} - -# From http://stackoverflow.com/questions/370047/#370255 -function path_remove() { -IFS=: -# convert it to an array -t=($PATH) -unset IFS -# perform any array operations to remove elements from the array -t=(${t[@]%%$1}) -IFS=: -# output the new array -echo "${t[*]}" -} - -# }}} - -# Force screen to use zsh {{{ -# }}} - -# Environment {{{ -# }}} - -# Directory Stuff {{{ - -# Always use color output for `ls` - -# Directory listing - -# Easier navigation: .., ..., - - -# File size - -# Recursively delete `.DS_Store` files - -# Create a new directory and enter it -function md() { - mkdir -p "$@" && cd "$@" -} - -# }}} - -# MPD/MPC stuff {{{ -function mp() { -# Test if drive is already mounted -if ! lsblk | grep /media/external >/dev/null; then - if ! sudo mount /media/external; then - echo "External drive not plugged in, or could not mount" - return 1 - fi -fi -if (mpc >/dev/null 2>&1); then - ncmpcpp -else - mpd && - (pgrep mpdscribble || mpdscribble) && - ncmpcpp -fi -} - -# kill mp -function kmp() { -killall ncmpcpp -mpd --kill - -local files - -if (files=$(lsof 2>&1 | grep -v docker | grep external)); then - echo - echo "==> Still processes using external drive:" - echo - echo $files -else - sudo umount /media/external -fi -} - - -function mppal() { -mpc search album "$1" | mpc add && - mpc play; -} -# }}} - -# Git stuff {{{ -# function ga() { git add "${@:-.}"; } # Add all files by default -# Add non-whitespace changes -# function gc() { git checkout "${@:-master}"; } # Checkout master by default - -# open all changed files (that still actually exist) in the editor -function ged() { -local files=() -for f in $(git diff --name-only "$@"); do - [[ -e "$f" ]] && files=("${files[@]}" "$f") -done -local n=${#files[@]} -echo "Opening $n $([[ "$@" ]] || echo "modified ")file$([[ $n != 1 ]] && \ - echo s)${@:+ modified in }$@" -q "${files[@]}" -} - -# git find-replace -function gfr() { -if [[ "$#" == "0" ]]; then - echo 'Usage:' - echo ' gg_replace term replacement file_mask' - echo - echo 'Example:' - echo ' gg_replace cappuchino cappuccino *.html' - echo -else - find=$1; shift - replace=$1; shift - - ORIG_GLOBIGNORE=$GLOBIGNORE - GLOBIGNORE=*.* - if [[ "$#" = "0" ]]; then - set -- ' ' $@ - fi - - while [[ "$#" -gt "0" ]]; do - for file in `git grep -l $find -- $1`; do - sed -e "s/$find/$replace/g" -i'' $file - done - shift - done - - GLOBIGNORE=$ORIG_GLOBIGNORE -fi -} - -function vconflicts() { -$EDITOR $(git status --porcelain | awk '/^UU/ { print $2 }') -} -# }}} - -# fzf {{{ -v() { - local file - file=$(fzf-tmux --query="$1" --select-1 --exit-0) - [ -n "$file" ] && ${EDITOR:-vim} "$file" -} - -c() { - local dir - dir=$(find ${1:-*} -path '*/\.*' -prune -o -type d -print 2> /dev/null | fzf +m) && cd "$dir" -} - -co() { - local branch - branch=$(git branch -a | sed -s "s/\s*\**//g" | fzf --query="$1" --select-1 --exit-0) && git checkout "$branch" -} - - -# fh - repeat history -# h() { -# eval $(([ -n "$ZSH_NAME" ] && fc -l 1 || history) | fzf +s | sed 's/ *[0-9]* *//') -# } - -# fkill - kill process -fkill() { - ps -ef | sed 1d | fzf-tmux -m | awk '{print $2}' | xargs kill -${1:-9} -} -# }}} - -# Tmux utils {{{ -kill_detached() { - for sess in $(tmux ls | grep -v attached | sed -s "s/:.*$//"); do - tmux kill-session -t $sess; - done -} -# }}} - -# Docker {{{ - - -# dbp foo/bar . -function dbp () { - docker build -t $1 ${@:2} && docker push $1 -} - -# }}} - -# Twitter! {{{ - - -# favelast <username> -function favelast() { - t fave $(t tl -l $1 | head -n1 | first) -} - -function rtlast() { - t rt $(t tl -l $1 | head -n1 | first) -} - -function tthread() { - t reply $(t tl -l $TWITTER_WHOAMI | head -n1 | first) $@ -} -# }}} - -# Geeknote {{{ -gnc() { - gn create --title $1 --content '' && - gn find --count=1 "$1" - gn edit 1 -} -# }}} - -# Misc aliases {{{ - -function fw() { # fix white - local substitution - local substitution='s/\x1b\[90m/\x1b[92m/g' - $@ > >(perl -pe "$substitution") 2> >(perl -pe "$substitution" 1>&2) -} -# }}} - -# Grep options {{{ -unset GREP_OPTIONS -export GREP_OPTIONS= -# }}} - - -# Run docker containers {{{ - # -d \ - # -v $HOME/.pentadactyl:/home/firefox/.pentadactyl:rw \ - # -v $HOME/.pentadactylrc:/home/firefox/.pentadactylrc:rw \ - # -v $HOME/.mozilla:/home/firefox/.mozilla:rw \ - # -v $HOME/.config:/home/firefox/.config \ - # -v $HOME/Downloads:/home/firefox/Downloads:rw \ - # -v /etc/fonts:/etc/fonts \ - # -v /tmp/.X11-unix:/tmp/.X11-unix \ - # -v /dev/snd:/dev/snd \ - # --net=host \ - # -v $XDG_RUNTIME_DIR:$XDG_RUNTIME_DIR \ - # -e uid=$(id -u) \ - # -e gid=$(id -g) \ - # -e DISPLAY=$DISPLAY \ - # -e XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR \ - # --name firefox \ - # --rm -it \ - # glittershark/firefox -# }}} - -# Change cursor shape on insert/normal mode {{{ -# (https://unix.stackexchange.com/q/433273/64261) - -KEYTIMEOUT=5 - -_fix_cursor() { - echo -ne '\e[5 q' -} - -precmd_functions+=(_fix_cursor) - -function zle-keymap-select { - if [[ ${KEYMAP} == vicmd ]] || - [[ $1 = 'block' ]]; then - echo -ne '\e[1 q' - - elif [[ ${KEYMAP} == main ]] || - [[ ${KEYMAP} == viins ]] || - [[ ${KEYMAP} = '' ]] || - [[ $1 = 'beam' ]]; then - echo -ne '\e[5 q' - fi -} -zle -N zle-keymap-select - -# }}} - -[ -f ./.localrc ] && source ./.localrc diff --git a/users/aspen/system/home/platforms/darwin.nix b/users/aspen/system/home/platforms/darwin.nix deleted file mode 100644 index f98b80f26..000000000 --- a/users/aspen/system/home/platforms/darwin.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ - config = { - home.packages = with pkgs; [ - coreutils - gnupg - pinentry_mac - ]; - - home.activation.linkApplications = lib.hm.dag.entryAfter [ "writeBoundary" ] '' - $DRY_RUN_CMD ln -sf $VERBOSE_ARG \ - ~/.nix-profile/Applications/* ~/Applications/ - ''; - - programs.zsh.initExtra = '' - export NIX_PATH=$HOME/.nix-defexpr/channels:$NIX_PATH - - if [[ "$TERM" == "alacritty" ]]; then - export TERM="xterm-256color" - fi - ''; - }; -} diff --git a/users/aspen/system/home/platforms/linux.nix b/users/aspen/system/home/platforms/linux.nix deleted file mode 100644 index d7a04e872..000000000 --- a/users/aspen/system/home/platforms/linux.nix +++ /dev/null @@ -1,78 +0,0 @@ -{ config, pkgs, ... }: - -let - - depot = config.lib.depot; - -in -{ - imports = [ - ../modules/alacritty.nix - ../modules/development.nix - ../modules/emacs.nix - ../modules/email.nix - ../modules/firefox.nix - ../modules/shell.nix - ../modules/vim.nix - ]; - - xsession.enable = true; - - home.packages = with pkgs; [ - # Desktop stuff - arandr - firefox - feh - chromium - xclip - xorg.xev - picom - peek - signal-desktop - apvlv # pdf viewer - vlc - irssi - gnutls - pandoc - barrier - gimp # TODO(aspen): use glimpse once it build again - - # System utilities - powertop - usbutils - pciutils - gdmap - lsof - tree - nmap - iftop - - # Security - gnupg - keybase - openssl - yubikey-manager - # TODO(aspen): lagging behind yubikey-manager and doesn't support cryptography >= 39 - # yubikey-manager-qt - - # Spotify...etc - spotify - playerctl - ]; - - services.redshift = { - enable = true; - provider = "geoclue2"; - }; - - services.pasystray.enable = true; - - services.gpg-agent = { - enable = true; - pinentryPackage = pkgs.pinentry-qt; - }; - - services.lorri.enable = true; - - services.dropbox = { enable = true; }; -} diff --git a/users/aspen/system/install b/users/aspen/system/install deleted file mode 100755 index a9a45953d..000000000 --- a/users/aspen/system/install +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash - -set -eo pipefail - -if [[ -f /etc/nixos/.system-installed ]]; then - echo "=== System config already installed, skipping" -else - echo "==> Installing system config" - - [[ -d /etc/nixos ]] && sudo mv /etc/nixos{,.bak} - sudo mkdir -p /etc/nixos - sudo cp /etc/nixos.bak/hardware-configuration.nix /etc/nixos - - sudo cp ./system/configuration.nix /etc/nixos/ - sudo ln -s $(pwd)/system/{machines,modules,pkgs} /etc/nixos - sudo touch /etc/nixos/.system-installed - - echo "==> System config installed, your old configuration is at /etc/nixos.bak" -fi -echo - -if [[ -f ~/.config/nixpkgs/system-installed ]]; then - echo "=== home-manager config already installed, skipping" -else - echo "==> Installing home-manager config" - nix-channel --add https://github.com/rycee/home-manager/archive/master.tar.gz home-manager - nix-channel --update - # nix-shell '<home-manager>' -A install - - [[ -d ~/.config/nixpkgs ]] && mv ~/.config/{nixpkgs,nixpkgs.bak} - mkdir -p ~/.config/nixpkgs - ln -s $(pwd)/home/* ~/.config/nixpkgs - - echo "==> home-manager config installed" -fi diff --git a/users/aspen/system/system/.skip-subtree b/users/aspen/system/system/.skip-subtree deleted file mode 100644 index e69de29bb..000000000 diff --git a/users/aspen/system/system/configuration.nix b/users/aspen/system/system/configuration.nix deleted file mode 100644 index eae567015..000000000 --- a/users/aspen/system/system/configuration.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ config, pkgs, ... }: - -let machine = throw "Pick a machine from ./machines"; in -{ - imports = - [ - /etc/nixos/hardware-configuration.nix - ./modules/common.nix - machine - ]; -} diff --git a/users/aspen/system/system/default.nix b/users/aspen/system/system/default.nix deleted file mode 100644 index 07bc886c6..000000000 --- a/users/aspen/system/system/default.nix +++ /dev/null @@ -1,48 +0,0 @@ -args @ { depot, pkgs, ... }: - -rec { - mugwump = import ./machines/mugwump.nix; - - mugwumpSystem = (depot.ops.nixos.nixosFor mugwump).system; - - roswell = import ./machines/roswell.nix; - - roswellSystem = (depot.ops.nixos.nixosFor ({ ... }: { - imports = [ - ./machines/roswell.nix - "${pkgs.home-manager.src}/nixos" - ]; - - # Use the same nixpkgs as everything else - home-manager.useGlobalPkgs = true; - - home-manager.users.aspen = { config, lib, ... }: { - imports = [ ../home/machines/roswell.nix ]; - lib.depot = depot; - }; - })).system; - - ogopogo = import ./machines/ogopogo.nix; - - ogopogoSystem = (depot.ops.nixos.nixosFor ogopogo).system; - - yeren = import ./machines/yeren.nix; - - yerenSystem = (depot.ops.nixos.nixosFor yeren).system; - - lusca = import ./machines/lusca.nix; - - luscaSystem = (depot.ops.nixos.nixosFor lusca).system; - - iso = import ./iso.nix args; - - meta.ci.targets = [ - "mugwumpSystem" - "roswellSystem" - "luscaSystem" - "ogopogoSystem" - "yerenSystem" - - "iso" - ]; -} diff --git a/users/aspen/system/system/iso.nix b/users/aspen/system/system/iso.nix deleted file mode 100644 index 9fa8e7ec7..000000000 --- a/users/aspen/system/system/iso.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - configuration = { ... }: { - imports = [ - (pkgs.path + "/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix") - (pkgs.path + "/nixos/modules/installer/cd-dvd/channel.nix") - ]; - - networking.networkmanager.enable = true; - networking.useDHCP = false; - networking.firewall.enable = false; - networking.wireless.enable = lib.mkForce false; - }; -in -(depot.third_party.nixos { - inherit configuration; -}).config.system.build.isoImage diff --git a/users/aspen/system/system/machines/bumblebee.nix b/users/aspen/system/system/machines/bumblebee.nix deleted file mode 100644 index 8bb52f75f..000000000 --- a/users/aspen/system/system/machines/bumblebee.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, lib, pkgs, ... }: -{ - imports = [ - ../modules/reusable/battery.nix - ]; - - networking.hostName = "bumblebee"; - - powerManagement = { - enable = true; - cpuFreqGovernor = "powersave"; - powertop.enable = true; - }; - - # Hibernate on low battery - laptop.onLowBattery = { - enable = true; - action = "hibernate"; - thresholdPercentage = 5; - }; - - services.xserver.xkb.options = "caps:swapescape"; -} diff --git a/users/aspen/system/system/machines/lusca.nix b/users/aspen/system/system/machines/lusca.nix deleted file mode 100644 index 4a9202187..000000000 --- a/users/aspen/system/system/machines/lusca.nix +++ /dev/null @@ -1,143 +0,0 @@ -{ depot, modulesPath, config, lib, pkgs, ... }: - -{ - imports = [ - (modulesPath + "/installer/scan/not-detected.nix") - ../modules/common.nix - ../modules/laptop.nix - ../modules/xserver.nix - ../modules/fonts.nix - ../modules/sound.nix - ../modules/tvl.nix - ../modules/development.nix - ../modules/prometheus-exporter.nix - ]; - - networking.hostName = "lusca"; - - system.stateVersion = "24.05"; - - time.timeZone = "America/New_York"; - - services.avahi = { - enable = true; - nssmdns4 = true; - }; - - boot = { - initrd = { - availableKernelModules = - [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "sd_mod" ]; - kernelModules = [ ]; - - luks.devices."cryptroot".device = - "/dev/disk/by-uuid/9e525746-5bca-4451-8710-a6f0e09b751c"; - }; - - kernelModules = [ "kvm-amd" ]; - - kernelParams = [ - "resume=LABEL=SWAP" - "resume_offset=795904" # sudo btrfs inspect-internal map-swapfile -r /swap/swapfile - ]; - - resumeDevice = "/dev/disk/by-uuid/4c099cee-8d42-49c1-916c-62a0b5effbd2"; - - kernel.sysctl = { "kernel.perf_event_paranoid" = -1; }; - }; - - hardware.cpu.amd.updateMicrocode = - lib.mkDefault config.hardware.enableRedistributableFirmware; - - fileSystems = { - "/" = { - device = "/dev/disk/by-uuid/4c099cee-8d42-49c1-916c-62a0b5effbd2"; - fsType = "btrfs"; - options = [ "subvol=root" ]; - }; - - "/home" = { - device = "/dev/disk/by-uuid/4c099cee-8d42-49c1-916c-62a0b5effbd2"; - fsType = "btrfs"; - options = [ "subvol=home" ]; - }; - - "/nix" = { - device = "/dev/disk/by-uuid/4c099cee-8d42-49c1-916c-62a0b5effbd2"; - fsType = "btrfs"; - options = [ "subvol=nix" ]; - }; - - "/swap" = { - device = "/dev/disk/by-uuid/4c099cee-8d42-49c1-916c-62a0b5effbd2"; - fsType = "btrfs"; - options = [ "subvol=swap" ]; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/0E7D-3C3F"; - fsType = "vfat"; - }; - }; - - swapDevices = [{ device = "/swap/swapfile"; }]; - - systemd.sleep.extraConfig = '' - HibernateDelaySec=30m - SuspendState=mem - ''; - - services.earlyoom = { - enable = true; - freeMemThreshold = 5; - }; - - services.tailscale.enable = true; - - services.fwupd = { - enable = true; - extraRemotes = [ "lvfs-testing" ]; - }; - - services.tlp.enable = lib.mkForce false; - services.power-profiles-daemon.enable = true; - - services.thermald.enable = true; - - services.fprintd.enable = true; - security.pam.services = { - login.fprintAuth = true; - sudo.fprintAuth = true; - i3lock.fprintAuth = true; - i3lock-color.fprintAuth = true; - lightdm.fprintAuth = true; - lightdm-greeter.fprintAuth = true; - }; - - security.polkit.extraConfig = '' - polkit.addRule(function(action, subject) { - if (action.id.indexOf("net.reactivated.fprint.") == 0 || action.id.indexOf("net.reactivated.Fprint.") == 0) { - polkit.log("action=" + action); - polkit.log("subject=" + subject); - return polkit.Result.YES; - } - }); - ''; - - services.udev.extraRules = '' - # Ethernet expansion card support - ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="0bda", ATTR{idProduct}=="8156", ATTR{power/autosuspend}="20" - ''; - - hardware.sensor.iio.enable = true; - - hardware.graphics.enable32Bit = true; - - # TPM - security.tpm2 = { - enable = true; - pkcs11.enable = true; - tctiEnvironment.enable = true; - }; - users.users.aspen.extraGroups = [ "tss" ]; -} diff --git a/users/aspen/system/system/machines/mugwump.nix b/users/aspen/system/system/machines/mugwump.nix deleted file mode 100644 index 4b72a2476..000000000 --- a/users/aspen/system/system/machines/mugwump.nix +++ /dev/null @@ -1,152 +0,0 @@ -{ config, lib, pkgs, modulesPath, depot, ... }: - -with lib; - -{ - imports = [ - ../modules/common.nix - (modulesPath + "/installer/scan/not-detected.nix") - (depot.path.origSrc + "/ops/modules/prometheus-fail2ban-exporter.nix") - (depot.path.origSrc + "/users/aspen/xanthous/server/module.nix") - (depot.third_party.agenix.src + "/modules/age.nix") - ]; - - networking.hostName = "mugwump"; - - system.stateVersion = "22.05"; - - boot = { - loader.systemd-boot.enable = true; - - kernelModules = [ "kvm-intel" ]; - extraModulePackages = [ ]; - - initrd = { - availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ]; - kernelModules = [ - "uas" - "usbcore" - "usb_storage" - "vfat" - "nls_cp437" - "nls_iso8859_1" - ]; - - postDeviceCommands = pkgs.lib.mkBefore '' - mkdir -m 0755 -p /key - sleep 2 - mount -n -t vfat -o ro `findfs UUID=9048-A9D5` /key - ''; - - luks.devices."cryptroot" = { - device = "/dev/disk/by-uuid/803a9028-339c-4617-a213-4fe138161f6d"; - keyFile = "/key/keyfile"; - preLVM = false; - }; - }; - }; - - fileSystems = { - "/" = { - device = "/dev/mapper/cryptroot"; - fsType = "btrfs"; - }; - "/boot" = { - device = "/dev/disk/by-uuid/7D74-0E4B"; - fsType = "vfat"; - }; - }; - - networking.interfaces = { - enp0s25.useDHCP = false; - wlp2s0.useDHCP = false; - }; - - networking.firewall.enable = true; - networking.firewall.allowedTCPPorts = [ 22 80 443 ]; - - security.sudo.extraRules = [{ - groups = [ "wheel" ]; - commands = [{ command = "ALL"; options = [ "NOPASSWD" ]; }]; - }]; - - nix.gc.dates = "monthly"; - - users.users.aspen.openssh.authorizedKeys.keys = [ - depot.users.aspen.keys.whitby - ]; - - age.secrets = - let - secret = name: depot.users.aspen.secrets."${name}.age"; - in - { - cloudflare.file = secret "cloudflare"; - - buildkite-ssh-key = { - file = secret "buildkite-ssh-key"; - group = "keys"; - mode = "0440"; - }; - - buildkite-token = { - file = secret "buildkite-token"; - group = "keys"; - mode = "0440"; - }; - - windtunnel-bot-github-token = { - file = secret "windtunnel-bot-github-token"; - group = "keys"; - mode = "0440"; - }; - }; - - services.fail2ban = { - enable = true; - ignoreIP = [ - "172.16.0.0/16" - ]; - }; - - services.openssh = { - allowSFTP = false; - settings = { - PasswordAuthentication = false; - PermitRootLogin = "no"; - }; - }; - - security.acme.defaults.email = "root@gws.fyi"; - security.acme.acceptTerms = true; - - services.xanthous-server.enable = true; - - virtualisation.docker = { - enable = true; - storageDriver = "btrfs"; - }; - - services.buildkite-agents = listToAttrs (map - (n: rec { - name = "mugwump-${toString n}"; - value = { - inherit name; - enable = true; - tokenPath = config.age.secretsDir + "/buildkite-token"; - privateSshKeyPath = config.age.secretsDir + "/buildkite-ssh-key"; - runtimePackages = with pkgs; [ - docker - nix - gnutar - gzip - ]; - }; - }) - (range 1 1)); - - users.users."buildkite-agent-mugwump-1" = { - isSystemUser = true; - extraGroups = [ "docker" "keys" ]; - }; -} diff --git a/users/aspen/system/system/machines/ogopogo.nix b/users/aspen/system/system/machines/ogopogo.nix deleted file mode 100644 index 2891d91a9..000000000 --- a/users/aspen/system/system/machines/ogopogo.nix +++ /dev/null @@ -1,124 +0,0 @@ -{ depot, modulesPath, config, lib, pkgs, ... }: - -{ - imports = [ - (modulesPath + "/installer/scan/not-detected.nix") - (depot.third_party.agenix.src + "/modules/age.nix") - ../modules/common.nix - ../modules/xserver.nix - ../modules/fonts.nix - ../modules/sound.nix - ../modules/tvl.nix - ../modules/development.nix - ../modules/wireshark.nix - ../modules/metrics.nix - ../modules/prometheus-exporter.nix - ]; - - networking.hostName = "ogopogo"; - - system.stateVersion = "22.11"; - - boot = { - initrd = { - availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; - kernelModules = [ ]; - }; - - kernelModules = [ "kvm-amd" ]; - blacklistedKernelModules = [ ]; - extraModulePackages = [ ]; - - kernel.sysctl = { - "kernel.perf_event_paranoid" = -1; - }; - }; - - fileSystems = { - "/" = { - device = "/dev/disk/by-uuid/d67506cf-7039-484d-97c0-00321a7858dc"; - fsType = "ext4"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/AE73-03A3"; - fsType = "vfat"; - }; - - "/data" = { - device = "/dev/disk/by-uuid/03e0f4dc-9778-42e2-a59e-45522610e509"; - fsType = "ext4"; - }; - }; - - swapDevices = [{ - device = "/dev/disk/by-uuid/8bdae7c8-5160-491f-8cd0-4f0a79acadf9"; - }]; - - services.earlyoom = { - enable = true; - freeMemThreshold = 5; - }; - - hardware.enableAllFirmware = true; - - services.pulseaudio.extraConfig = '' - load-module module-remap-source source_name=KompleteAudio6_1 source_properties=device.description=KompleteAudio6Input1 master=alsa_input.usb-Native_Instruments_Komplete_Audio_6_458E0FFD-00.multichannel-input remix=no channels=1 master_channel_map=front-left channel_map=mono - load-module module-remap-source source_name=KompleteAudio6_2 source_properties=device.description=KompleteAudio6Input2 master=alsa_input.usb-Native_Instruments_Komplete_Audio_6_458E0FFD-00.multichannel-input remix=no channels=1 master_channel_map=front-right channel_map=mono - load-module module-remap-sink sink_name=KompleteAudio6_12 sink_properties=device.description=KompleteAudio6_12 remix=no master=alsa_output.usb-Native_Instruments_Komplete_Audio_6_458E0FFD-00.analog-surround-21 channels=2 master_channel_map=front-left,front-right channel_map=front-left,front-right - ''; - - services.fwupd.enable = true; - - services.tailscale.enable = true; - - hardware.keyboard.zsa.enable = true; - - # Nvidia - services.xserver = { - videoDrivers = [ "nvidia" ]; - dpi = 100; - }; - hardware.graphics.enable = true; - services.picom = { - enable = true; - vSync = true; - }; - hardware.graphics.enable32Bit = true; - hardware.nvidia.open = true; - - services.postgresql = { - enable = true; - enableTCPIP = true; - authentication = "host all all 0.0.0.0/0 md5"; - dataDir = "/data/postgresql"; - package = pkgs.postgresql_15; - settings = { - wal_level = "logical"; - }; - }; - - # ddclient - age.secrets = - let - secret = name: depot.users.aspen.secrets."${name}.age"; - in - { - ddclient-password.file = secret "ddclient-password"; - }; - - services.ddclient = { - enable = true; - domains = [ "home.gws.fyi" ]; - interval = "1d"; - zone = "gws.fyi"; - protocol = "cloudflare"; - username = "root@gws.fyi"; - passwordFile = config.age.secretsDir + "/ddclient-password"; - quiet = true; - } - # TODO(aspen): Remove when upgrading past 4.0.0 - // lib.optionalAttrs (lib.versionOlder pkgs.ddclient.version "4.0.0") { - ssl = false; - }; -} diff --git a/users/aspen/system/system/machines/roswell.nix b/users/aspen/system/system/machines/roswell.nix deleted file mode 100644 index da62eec93..000000000 --- a/users/aspen/system/system/machines/roswell.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ depot, config, lib, pkgs, modulesPath, ... }: - -{ - imports = [ - ../modules/common.nix - ../modules/development.nix - "${modulesPath}/installer/scan/not-detected.nix" - "${modulesPath}/virtualisation/amazon-image.nix" - ]; - - system.stateVersion = "22.05"; - - networking.hostName = "roswell"; - - boot.loader.systemd-boot.enable = lib.mkForce false; - boot.loader.efi.canTouchEfiVariables = lib.mkForce false; - - services.openssh.settings.PasswordAuthentication = false; - - services.tailscale.enable = true; - - security.sudo.wheelNeedsPassword = false; - - environment.systemPackages = with pkgs; [ - cloud-utils - ]; -} diff --git a/users/aspen/system/system/machines/yeren.nix b/users/aspen/system/system/machines/yeren.nix deleted file mode 100644 index bb3f48127..000000000 --- a/users/aspen/system/system/machines/yeren.nix +++ /dev/null @@ -1,135 +0,0 @@ -{ depot, modulesPath, config, lib, pkgs, ... }: - -{ - imports = [ - (modulesPath + "/installer/scan/not-detected.nix") - ../modules/common.nix - ../modules/laptop.nix - ../modules/xserver.nix - ../modules/fonts.nix - ../modules/sound.nix - ../modules/tvl.nix - ../modules/development.nix - ]; - - networking.hostName = "yeren"; - - system.stateVersion = "21.03"; - - time.timeZone = "America/New_York"; - - services.avahi = { - enable = true; - nssmdns4 = true; - }; - - boot = { - initrd = { - availableKernelModules = [ "xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ]; - kernelModules = [ ]; - - luks.devices = { - "cryptroot".device = "/dev/disk/by-uuid/dcfbc22d-e0d2-411b-8dd3-96704d3aae2e"; - }; - }; - - # TODO(aspen): remove after https://github.com/NixOS/nixpkgs/pull/378830/ - kernelPackages = pkgs.linuxKernel.packages.linux_6_11; - - kernelModules = [ "kvm-intel" ]; - blacklistedKernelModules = [ "psmouse" ]; - extraModulePackages = [ - config.boot.kernelPackages.digimend - ]; - kernelParams = [ - "i915.preliminary_hw_support=1" - "pcie_aspm=force" - ]; - - # https://bbs.archlinux.org/viewtopic.php?pid=1933643#p1933643 - extraModprobeConfig = '' - options snd-intel-dspcfg dsp_driver=1 - ''; - - kernel.sysctl = { - "kernel.perf_event_paranoid" = -1; - }; - }; - - fileSystems = { - "/" = { - device = "/dev/mapper/cryptroot"; - fsType = "btrfs"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/53A9-248B"; - fsType = "vfat"; - }; - }; - - swapDevices = [{ - device = "/dev/disk/by-uuid/b627cb0e-0451-4f25-94d0-6497e01f0da4"; - }]; - - services.earlyoom = { - enable = true; - freeMemThreshold = 5; - }; - - services.xserver = { - exportConfiguration = true; - extraConfig = '' - Section "Device" - Identifier "Intel Graphics" - Driver "intel" - Option "TripleBuffer" "true" - Option "TearFree" "true" - Option "DRI" "true" - Option "AccelMethod" "sna" - EndSection - ''; - }; - - hardware.firmware = with pkgs; [ - alsa-firmware - sof-firmware - ]; - - hardware.graphics.extraPackages = with pkgs; [ - vaapiIntel - vaapiVdpau - libvdpau-va-gl - intel-media-driver - ]; - - # Disabled for now until libfprint-tod can get a version bump - # services.fprintd = { - # enable = true; - # package = pkgs.fprintd-tod; - # }; - - systemd.services.fprintd.environment.FP_TOD_DRIVERS_DIR = - "${pkgs.libfprint-2-tod1-goodix}/usr/lib/libfprint-2/tod-1"; - - security.pam.services = { - login.fprintAuth = true; - sudo.fprintAuth = true; - i3lock.fprintAuth = false; - i3lock-color.fprintAuth = false; - lightdm.fprintAuth = true; - lightdm-greeter.fprintAuth = true; - }; - - hardware.graphics.enable32Bit = true; - - services.pulseaudio.extraConfig = '' - load-module module-remap-source source_name=KompleteAudio6_1 source_properties=device.description=KompleteAudio6Input1 master=alsa_input.usb-Native_Instruments_Komplete_Audio_6_458E0FFD-00.multichannel-input remix=no channels=1 master_channel_map=front-left channel_map=mono - load-module module-remap-source source_name=KompleteAudio6_2 source_properties=device.description=KompleteAudio6Input2 master=alsa_input.usb-Native_Instruments_Komplete_Audio_6_458E0FFD-00.multichannel-input remix=no channels=1 master_channel_map=front-right channel_map=mono - load-module module-remap-sink sink_name=KompleteAudio6_12 sink_properties=device.description=KompleteAudio6_12 remix=no master=alsa_output.usb-Native_Instruments_Komplete_Audio_6_458E0FFD-00.analog-surround-21 channels=2 master_channel_map=front-left,front-right channel_map=front-left,front-right - ''; - - services.fwupd.enable = true; - - services.tailscale.enable = true; -} diff --git a/users/aspen/system/system/modules/common.nix b/users/aspen/system/system/modules/common.nix deleted file mode 100644 index 3eaeb2efc..000000000 --- a/users/aspen/system/system/modules/common.nix +++ /dev/null @@ -1,97 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - - depot = import ../../../../.. { }; - -in - -with lib; - -{ - boot = { - loader.systemd-boot.enable = true; - loader.efi.canTouchEfiVariables = true; - tmp.cleanOnBoot = true; - }; - - networking.useDHCP = false; - networking.networkmanager.enable = true; - systemd.services.NetworkManager-wait-online.enable = lib.mkForce false; - systemd.services.systemd-networkd-wait-online.enable = lib.mkForce false; - - i18n = { - defaultLocale = "en_US.UTF-8"; - }; - - time.timeZone = lib.mkDefault "America/New_York"; - - environment.systemPackages = with pkgs; [ - wget - vim - zsh - git - w3m - libnotify - file - lm_sensors - dnsutils - htop - man-pages - man-pages-posix - ]; - - documentation.dev.enable = true; - documentation.man.generateCaches = true; - - services.openssh = { - enable = true; - settings = { X11Forwarding = true; }; - }; - - users.users.aspen.openssh.authorizedKeys.keys = - [ depot.users.aspen.keys.main ]; - - programs.ssh.startAgent = true; - - networking.firewall.enable = mkDefault false; - - users.mutableUsers = true; - programs.zsh.enable = true; - environment.pathsToLink = [ "/share/zsh" ]; - users.users.aspen = { - isNormalUser = true; - initialPassword = "password"; - extraGroups = [ - "wheel" - "networkmanager" - "audio" - ]; - shell = pkgs.zsh; - }; - - nix = { - settings.trusted-users = [ "aspen" ]; - distributedBuilds = true; - - gc = { - automatic = true; - dates = mkDefault "weekly"; - options = "--delete-older-than 30d"; - }; - }; - - services.udev.packages = with pkgs; [ - yubikey-personalization - ]; - - services.pcscd.enable = true; - - services.udev.extraRules = '' - # UDEV rules for Teensy USB devices - ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", ENV{ID_MM_DEVICE_IGNORE}="1" - ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789A]?", ENV{MTP_NO_PROBE}="1" - SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789ABCD]?", MODE:="0666" - KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", MODE:="0666" - ''; -} diff --git a/users/aspen/system/system/modules/containers.nix b/users/aspen/system/system/modules/containers.nix deleted file mode 100644 index 587e7426b..000000000 --- a/users/aspen/system/system/modules/containers.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - virtualisation.podman = { - enable = true; - defaultNetwork.settings = { dns_enabled = true; }; - dockerCompat = true; - dockerSocket.enable = true; - }; - - users.users.aspen.extraGroups = [ "docker" ]; -} diff --git a/users/aspen/system/system/modules/desktop.nix b/users/aspen/system/system/modules/desktop.nix deleted file mode 100644 index 9a5fc825e..000000000 --- a/users/aspen/system/system/modules/desktop.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - imports = [ - ./xserver.nix - ./fonts.nix - ./sound.nix - ./kernel.nix - ]; - - programs.nm-applet.enable = true; - - users.users.aspen.extraGroups = [ - "audio" - "video" - ]; - - services.geoclue2.enable = true; -} diff --git a/users/aspen/system/system/modules/development.nix b/users/aspen/system/system/modules/development.nix deleted file mode 100644 index 6e96ae3c8..000000000 --- a/users/aspen/system/system/modules/development.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - imports = [ - ./containers.nix - ]; - - security.pam.loginLimits = [ - { - domain = "aspen"; - type = "soft"; - item = "nofile"; - value = "65535"; - } - ]; -} diff --git a/users/aspen/system/system/modules/fcitx.nix b/users/aspen/system/system/modules/fcitx.nix deleted file mode 100644 index 812f598f9..000000000 --- a/users/aspen/system/system/modules/fcitx.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - i18n.inputMethod = { - enabled = "fcitx"; - fcitx.engines = with pkgs.fcitx-engines; [ - cloudpinyin - ]; - }; -} diff --git a/users/aspen/system/system/modules/fonts.nix b/users/aspen/system/system/modules/fonts.nix deleted file mode 100644 index 85de89914..000000000 --- a/users/aspen/system/system/modules/fonts.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ config, lib, pkgs, ... }: -{ - fonts = { - packages = with pkgs; [ - noto-fonts-emoji - twitter-color-emoji - weather-icons - ] ++ builtins.filter lib.isDerivation (builtins.attrValues pkgs.nerd-fonts); - - fontconfig.defaultFonts.emoji = [ "Twitter Color Emoji" ]; - }; -} diff --git a/users/aspen/system/system/modules/laptop.nix b/users/aspen/system/system/modules/laptop.nix deleted file mode 100644 index 57b2bc5a4..000000000 --- a/users/aspen/system/system/modules/laptop.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - services.logind = { - powerKey = "hibernate"; - powerKeyLongPress = "poweroff"; - lidSwitch = "suspend-then-hibernate"; - lidSwitchExternalPower = "ignore"; - }; - - systemd.sleep.extraConfig = '' - HibernateDelaySec=30m - SuspendState=mem - ''; - - services.tlp.enable = true; - - services.upower = { - enable = true; - criticalPowerAction = "Hibernate"; - percentageAction = 3; - }; - - services.libinput.touchpad.naturalScrolling = true; -} diff --git a/users/aspen/system/system/modules/metrics.nix b/users/aspen/system/system/modules/metrics.nix deleted file mode 100644 index 0abfb27ee..000000000 --- a/users/aspen/system/system/modules/metrics.nix +++ /dev/null @@ -1,197 +0,0 @@ -{ depot, config, lib, pkgs, ... }: - -with lib; - -let - nodesToScrape = [ - "ogopogo" - # "dobharchu" - "mugwump" - # "yeren" - "lusca" - ]; - - nodesRunningNginx = [ - "ogopogo" - "mugwump" - ]; - - nodesRunningPostgres = [ - "ogopogo" - ]; - - blackboxTargets = [ - "https://gws.fyi" - "https://windtunnel.ci" - "https://app.windtunnel.ci" - "https://metrics.gws.fyi" - ]; -in -{ - imports = [ - (depot.third_party.agenix.src + "/modules/age.nix") - ]; - - config = { - services.postgresql = { - ensureUsers = [{ - name = config.services.grafana.settings.database.user; - ensureDBOwnership = true; - }]; - - ensureDatabases = [ - config.services.grafana.settings.database.name - ]; - }; - - services.grafana = { - enable = true; - dataDir = "/var/lib/grafana"; - - settings = { - server = { - http_port = 3000; - root_url = "https://metrics.gws.fyi"; - domain = "metrics.gws.fyi"; - }; - analytics.reporting_enabled = false; - - database = { - type = "postgres"; - user = "grafana"; - name = "grafana"; - host = "/run/postgresql"; - }; - }; - - provision = { - enable = true; - datasources.settings.datasources = [{ - name = "Prometheus"; - type = "prometheus"; - url = "http://localhost:9090"; - }]; - }; - }; - - security.acme.defaults.email = "root@gws.fyi"; - security.acme.acceptTerms = true; - - services.nginx = { - enable = true; - statusPage = true; - recommendedGzipSettings = true; - recommendedOptimisation = true; - recommendedTlsSettings = true; - recommendedProxySettings = true; - - virtualHosts = { - "metrics.gws.fyi" = { - enableACME = true; - forceSSL = true; - locations."/" = { - proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}"; - }; - }; - }; - }; - - age.secrets = { - cloudflare.file = depot.users.aspen.secrets."cloudflare.age"; - }; - - security.acme.certs."metrics.gws.fyi" = { - dnsProvider = "cloudflare"; - credentialsFile = config.age.secretsDir + "/cloudflare"; - webroot = mkForce null; - }; - - services.prometheus = { - enable = true; - retentionTime = "30d"; - exporters = { - blackbox = { - enable = true; - openFirewall = true; - configFile = pkgs.writeText "blackbox-exporter.yaml" (builtins.toJSON { - modules = { - https_2xx = { - prober = "http"; - http = { - method = "GET"; - fail_if_ssl = false; - fail_if_not_ssl = true; - preferred_ip_protocol = "ip4"; - }; - }; - }; - }); - }; - }; - - scrapeConfigs = [ - { - job_name = "node"; - scrape_interval = "5s"; - static_configs = - map - (node: { - targets = [ "${node}:${toString config.services.prometheus.exporters.node.port}" ]; - labels.node = node; - }) - nodesToScrape; - } - { - job_name = "nginx"; - scrape_interval = "5s"; - static_configs = - map - (node: { - targets = [ "${node}:${toString config.services.prometheus.exporters.nginx.port}" ]; - labels.node = node; - }) - nodesRunningNginx; - } - { - job_name = "postgres"; - scrape_interval = "5s"; - static_configs = - map - (node: { - targets = [ "${node}:${toString config.services.prometheus.exporters.postgres.port}" ]; - labels.node = node; - }) - nodesRunningPostgres; - } - { - job_name = "blackbox"; - metrics_path = "/probe"; - params.module = [ "https_2xx" ]; - scrape_interval = "5s"; - static_configs = [{ - targets = [ - "https://gws.fyi" - "https://windtunnel.ci" - "https://app.windtunnel.ci" - "https://metrics.gws.fyi" - ]; - }]; - relabel_configs = [ - { - source_labels = [ "__address__" ]; - target_label = "__param_target"; - } - { - source_labels = [ "__param_target" ]; - target_label = "instance"; - } - { - target_label = "__address__"; - replacement = "localhost:${toString config.services.prometheus.exporters.blackbox.port}"; - } - ]; - } - ]; - }; - }; -} diff --git a/users/aspen/system/system/modules/prometheus-exporter.nix b/users/aspen/system/system/modules/prometheus-exporter.nix deleted file mode 100644 index 2916fc70e..000000000 --- a/users/aspen/system/system/modules/prometheus-exporter.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -{ - services.prometheus.exporters = { - node = { - enable = true; - openFirewall = false; - - enabledCollectors = [ - "processes" - "systemd" - "tcpstat" - "wifi" - ]; - }; - - nginx = mkIf config.services.nginx.enable { - enable = true; - openFirewall = true; - sslVerify = false; - constLabels = [ "host=${config.networking.hostName}" ]; - }; - - postgres = mkIf config.services.postgresql.enable { - enable = true; - runAsLocalSuperUser = true; - }; - }; -} diff --git a/users/aspen/system/system/modules/reusable/README.org b/users/aspen/system/system/modules/reusable/README.org deleted file mode 100644 index 34d9bfdcb..000000000 --- a/users/aspen/system/system/modules/reusable/README.org +++ /dev/null @@ -1,2 +0,0 @@ -This directory contains things I'm eventually planning on contributing upstream -to nixpkgs diff --git a/users/aspen/system/system/modules/rtlsdr.nix b/users/aspen/system/system/modules/rtlsdr.nix deleted file mode 100644 index ce58ebb0d..000000000 --- a/users/aspen/system/system/modules/rtlsdr.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - - environment.systemPackages = with pkgs; [ - rtl-sdr - ]; - - services.udev.packages = with pkgs; [ - rtl-sdr - ]; - - # blacklist for rtl-sdr - boot.blacklistedKernelModules = [ - "dvb_usb_rtl28xxu" - ]; -} diff --git a/users/aspen/system/system/modules/sound.nix b/users/aspen/system/system/modules/sound.nix deleted file mode 100644 index bf669d584..000000000 --- a/users/aspen/system/system/modules/sound.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - # Enable sound. - services.pulseaudio.enable = true; - services.pipewire.enable = false; - - environment.systemPackages = with pkgs; [ - pulseaudio-ctl - paprefs - pasystray - pavucontrol - ]; - - services.pulseaudio.package = pkgs.pulseaudioFull; -} diff --git a/users/aspen/system/system/modules/tvl.nix b/users/aspen/system/system/modules/tvl.nix deleted file mode 100644 index f91315fc7..000000000 --- a/users/aspen/system/system/modules/tvl.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - nix = { - buildMachines = [{ - hostName = "whitby.tvl.fyi"; - sshUser = "aspen"; - sshKey = "/root/.ssh/id_rsa"; - system = "x86_64-linux"; - maxJobs = 64; - supportedFeatures = [ "big-parallel" "kvm" "nixos-test" "benchmark" ]; - }]; - - extraOptions = '' - builders-use-substitutes = true - ''; - - settings = { - substituters = [ - "https://cache.nixos.org" - ]; - trusted-substituters = [ - "https://cache.nixos.org" - "ssh://nix-ssh@whitby.tvl.fyi" - ]; - }; - }; - - programs.ssh.knownHosts.whitby = { - extraHostNames = [ "whitby" "whitby.tvl.fyi" "49.12.129.211" ]; - publicKeyFile = pkgs.writeText "whitby.pub" '' - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILNh/w4BSKov0jdz3gKBc98tpoLta5bb87fQXWBhAl2I - ''; - }; -} diff --git a/users/aspen/system/system/modules/wireshark.nix b/users/aspen/system/system/modules/wireshark.nix deleted file mode 100644 index b233d4004..000000000 --- a/users/aspen/system/system/modules/wireshark.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - programs.wireshark = { - enable = true; - package = pkgs.wireshark; - }; - users.users.aspen.extraGroups = [ "wireshark" ]; -} diff --git a/users/aspen/system/system/modules/xserver.nix b/users/aspen/system/system/modules/xserver.nix deleted file mode 100644 index fca49ab9c..000000000 --- a/users/aspen/system/system/modules/xserver.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ config, pkgs, ... }: -{ - # Enable the X11 windowing system. - services.xserver = { - enable = true; - xkb.layout = "us"; - - - windowManager.i3.enable = true; - }; - - services.displayManager.defaultSession = "none+i3"; - - services.libinput.enable = true; -} diff --git a/users/aspen/terraform/globals.nix b/users/aspen/terraform/globals.nix deleted file mode 100644 index c6bc24c22..000000000 --- a/users/aspen/terraform/globals.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ pkgs, ... }: - -{ - provider.aws = map - (region: { - inherit region; - alias = region; - profile = "personal"; - }) [ - "us-east-1" - "us-east-2" - "us-west-2" - ]; - - data.external.cloudflare_api_key = { - program = [ - (pkgs.writeShellScript "cloudflare_api_key" '' - jq -n --arg api_key "$(pass cloudflare-api-key)" '{"api_key":$api_key}' - '') - ]; - }; - - provider.cloudflare = { - email = "root@gws.fyi"; - api_key = "\${data.external.cloudflare_api_key.result.api_key}"; - }; -} diff --git a/users/aspen/terraform/nixosMachine.nix b/users/aspen/terraform/nixosMachine.nix deleted file mode 100644 index 23cd83880..000000000 --- a/users/aspen/terraform/nixosMachine.nix +++ /dev/null @@ -1,208 +0,0 @@ -{ depot, pkgs, lib, ... }: - -# mostly stolen from espes - -{ name -, instanceType -, configuration -, prefix ? "${name}_" -, region ? "us-east-2" -, rootVolumeSizeGb ? 50 -, securityGroupId ? null -, extraIngressPorts ? [ ] -}: - -let - os = depot.ops.nixos.nixosFor ({ modulesPath, ... }: { - imports = [ - (pkgs.path + "/nixos/modules/virtualisation/amazon-image.nix") - configuration - ]; - - ec2.hvm = true; - networking.hostName = name; - # TODO: remove this once the terraform tls provider supports ed25519 keys - # https://github.com/hashicorp/terraform-provider-tls/issues/26 - services.openssh.extraConfig = '' - PubkeyAcceptedKeyTypes=+ssh-rsa - PubkeyAcceptedAlgorithms=+ssh-rsa - ''; - }); - - targetUser = "root"; - - ec2Amis = import "${pkgs.path}/nixos/modules/virtualisation/ec2-amis.nix"; - - osRoot = os.config.system.build.toplevel; - - osRootPath = builtins.unsafeDiscardStringContext (toString osRoot.outPath); - drvPath = builtins.unsafeDiscardStringContext (toString osRoot.drvPath); - - machineResource = "aws_instance.${prefix}machine"; - - recursiveMerge = builtins.foldl' lib.recursiveUpdate { }; - - securityGroupId' = - if isNull securityGroupId - then "\${aws_security_group.${prefix}group.id}" - else securityGroupId; -in -recursiveMerge [ - (lib.optionalAttrs (isNull securityGroupId) { - resource.aws_security_group."${prefix}group" = { - provider = "aws.${region}"; - vpc_id = null; - - # terraform isn't good about knowing what other resources depend on - # security groups - lifecycle.create_before_destroy = true; - }; - - resource.aws_security_group_rule.all_egress = { - provider = "aws.${region}"; - security_group_id = securityGroupId'; - type = "egress"; - protocol = "-1"; - from_port = 0; - to_port = 0; - cidr_blocks = [ "0.0.0.0/0" ]; - ipv6_cidr_blocks = [ "::/0" ]; - - description = null; - prefix_list_ids = null; - self = null; - }; - }) - rec { - data.external.my_ip = { - program = [ - (pkgs.writeShellScript "my_ip" '' - ${pkgs.jq}/bin/jq \ - -n \ - --arg ip "$(curl ifconfig.me)" \ - '{"ip":$ip}' - '') - ]; - }; - - resource.aws_security_group_rule.provision_ssh_access = { - provider = "aws.${region}"; - security_group_id = securityGroupId'; - type = "ingress"; - protocol = "TCP"; - from_port = 22; - to_port = 22; - cidr_blocks = [ "\${data.external.my_ip.result.ip}/32" ]; - ipv6_cidr_blocks = [ ]; - description = null; - prefix_list_ids = null; - self = null; - }; - - resource.tls_private_key."${prefix}key" = { - algorithm = "RSA"; - }; - - resource.aws_key_pair."${prefix}generated_key" = { - provider = "aws.${region}"; - key_name = "generated-key-\${sha256(tls_private_key.${prefix}key.public_key_openssh)}"; - public_key = "\${tls_private_key.${prefix}key.public_key_openssh}"; - }; - - resource.aws_instance."${prefix}machine" = { - provider = "aws.${region}"; - ami = ec2Amis."21.05"."${region}".hvm-ebs; - instance_type = instanceType; - vpc_security_group_ids = [ securityGroupId' ]; - key_name = "\${aws_key_pair.${prefix}generated_key.key_name}"; - root_block_device = { - volume_size = rootVolumeSizeGb; - tags.Name = name; - }; - tags.Name = name; - }; - - resource.null_resource."${prefix}deploy_nixos" = { - triggers = { - # deploy if the machine is recreated - machine_id = "\${${machineResource}.id}"; - - # deploy on os changes - os_drv = drvPath; - }; - - connection = { - type = "ssh"; - host = "\${${machineResource}.public_ip}"; - user = targetUser; - private_key = "\${tls_private_key.${prefix}key.private_key_pem}"; - }; - - # do the actual deployment - provisioner = [ - # wait till ssh is up - { remote-exec.inline = [ "true" ]; } - - # copy the nixos closure - { - local-exec.command = '' - export PATH="${pkgs.openssh}/bin:$PATH" - - scratch="$(mktemp -d)" - trap 'rm -rf -- "$scratch"' EXIT - - # write out ssh key - echo -n "''${tls_private_key.${prefix}key.private_key_pem}" > $scratch/id_rsa.pem - chmod 0600 $scratch/id_rsa.pem - - export NIX_SSHOPTS="\ - -o StrictHostKeyChecking=no\ - -o UserKnownHostsFile=/dev/null\ - -o GlobalKnownHostsFile=/dev/null\ - -o IdentityFile=$scratch/id_rsa.pem" - - nix-build ${drvPath} - nix-copy-closure \ - --to ${targetUser}@''${${machineResource}.public_ip} \ - ${osRootPath} \ - --gzip \ - --use-substitutes - ''; - } - - # activate it - { - remote-exec.inline = [ - # semicolons mandatory - '' - set -e; - nix-env --profile /nix/var/nix/profiles/system --set ${osRootPath}; - ${osRootPath}/bin/switch-to-configuration switch; - '' - ]; - } - ]; - }; - } - - { - resource.aws_security_group_rule = builtins.listToAttrs (map - (port: { - name = "ingress_${toString port}"; - value = { - provider = "aws.${region}"; - security_group_id = securityGroupId'; - type = "ingress"; - protocol = "TCP"; - from_port = port; - to_port = port; - cidr_blocks = [ "0.0.0.0/0" ]; - ipv6_cidr_blocks = [ ]; - description = null; - prefix_list_ids = null; - self = null; - }; - }) - extraIngressPorts); - } -] diff --git a/users/aspen/terraform/workspace.nix b/users/aspen/terraform/workspace.nix deleted file mode 100644 index f1563d2a8..000000000 --- a/users/aspen/terraform/workspace.nix +++ /dev/null @@ -1,107 +0,0 @@ -{ pkgs, depot, ... }: -name: { plugins }: module_tf: - -let - - inherit (pkgs) lib runCommand writeText writeScript; - inherit (lib) filterAttrsRecursive; - - allPlugins = (p: plugins p ++ (with p; [ - external - local - tls - p.null - ])); - - tf = pkgs.terraform.withPlugins allPlugins; - - cleanTerraform = filterAttrsRecursive (k: _: ! (builtins.elem k [ - "__readTree" - "__readTreeChildren" - ])); - - plugins_tf = { - terraform.required_providers = (builtins.listToAttrs (map - (p: { - name = lib.last (lib.splitString "/" p.provider-source-address); - value = { - source = p.provider-source-address; - version = p.version; - }; - }) - (allPlugins pkgs.terraform.plugins))); - }; - - - module_tf' = module_tf // { - inherit (depot.users.aspen.terraform) globals; - plugins = plugins_tf; - }; - - module = runCommand "module" { } '' - mkdir $out - ${lib.concatStrings (lib.mapAttrsToList (k: config_tf: - (let - # TODO: filterAttrsRecursive? - configJson = writeText "${k}.tf.json" - (builtins.toJSON (cleanTerraform config_tf)); - in '' - ${pkgs.jq}/bin/jq . ${configJson} > $out/${lib.escapeShellArg k}.tf.json - '')) - (cleanTerraform module_tf'))} - ''; - - - tfcmd = writeScript "${name}-tfcmd" '' - set -e - dir="''${TF_STATE_ROOT:-$HOME/tfstate}/${name}" - cd "$dir" - rm -f *.json - cp ${module}/*.json . - exec ${tf}/bin/terraform "$(basename "$0")" - ''; - - init = writeScript "${name}-init" '' - set -e - dir="''${TF_STATE_ROOT:-$HOME/tfstate}/${name}" - [ -d "$dir" ] || mkdir -p "$dir" - cd "$dir" - rm -f *.json - cp ${module}/*.json . - exec ${tf}/bin/terraform init - ''; - - # TODO: import (-config) - tfcmds = runCommand "${name}-tfcmds" { } '' - mkdir -p $out/bin - ln -s ${init} $out/bin/init - ln -s ${tfcmd} $out/bin/validate - ln -s ${tfcmd} $out/bin/plan - ln -s ${tfcmd} $out/bin/apply - ln -s ${tfcmd} $out/bin/destroy - ''; - -in -{ - inherit name module; - terraform = tf; - cmds = tfcmds; - - # run = { - # init = depot.nix.nixRunWrapper "init" tfcmds; - # validate = depot.nix.nixRunWrapper "validate" tfcmds; - # plan = depot.nix.nixRunWrapper "plan" tfcmds; - # apply = depot.nix.nixRunWrapper "apply" tfcmds; - # destroy = depot.nix.nixRunWrapper "destroy" tfcmds; - # }; - - test = runCommand "${name}-test" { } '' - set -e - export TF_STATE_ROOT=$(pwd) - ${tfcmds}/bin/init - ${tfcmds}/bin/validate - touch $out - ''; - - meta.targets = [ "module" "test" ]; -} diff --git a/users/aspen/web/.envrc b/users/aspen/web/.envrc deleted file mode 100644 index b80e28b4b..000000000 --- a/users/aspen/web/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -eval "$(lorri direnv)" diff --git a/users/aspen/web/.gitignore b/users/aspen/web/.gitignore deleted file mode 100644 index 2b72eaed2..000000000 --- a/users/aspen/web/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -result -letsencrypt -index.html diff --git a/users/aspen/web/Makefile b/users/aspen/web/Makefile deleted file mode 100644 index ee6ed2fd8..000000000 --- a/users/aspen/web/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -.PHONY: deploy purge_cf do_deploy renew backup open - -deploy: do_deploy purge_cf - -purge_cf: - @$(shell nix-build `git rev-parse --show-toplevel` -A 'users.aspen.web.purge-cf')/bin/purge-cf.sh - -do_deploy: - @$(shell nix-build `git rev-parse --show-toplevel` -A 'users.aspen.web')/bin/deploy.sh - - -renew: - @echo Renewing... - @certbot certonly \ - --manual \ - --domain www.gws.fyi \ - --preferred-challenges dns \ - --server https://acme-v02.api.letsencrypt.org/directory \ - --agree-tos \ - --work-dir $(shell pwd)/letsencrypt/work \ - --logs-dir $(shell pwd)/letsencrypt/logs \ - --config-dir $(shell pwd)/letsencrypt/config - @echo "Reimporting certificate" - @aws acm import-certificate \ - --profile personal \ - --certificate file://letsencrypt/config/live/www.gws.fyi/cert.pem \ - --certificate-chain file://letsencrypt/config/live/www.gws.fyi/fullchain.pem \ - --private-key file://letsencrypt/config/live/www.gws.fyi/privkey.pem \ - --certificate-arn arn:aws:acm:us-east-1:797089351721:certificate/628e54f3-55f9-49c0-811a-eba516b68e30 \ - --region us-east-1 - -backup: - @tarsnap -cf $(shell uname -n)-letsencrypt-$(shell date +%Y-%m-%d_%H-%M-%S) \ - letsencrypt/ - -open: - $$BROWSER "https://www.gws.fyi" - -preview: - $$BROWSER "$(shell mg build website)/index.html" diff --git a/users/aspen/web/config.el b/users/aspen/web/config.el deleted file mode 100644 index b05d897d3..000000000 --- a/users/aspen/web/config.el +++ /dev/null @@ -1,6 +0,0 @@ -(require 'org) - -(setq org-html-postamble nil) - -(defadvice org-export-grab-title-from-buffer - (around org-export-grab-title-from-buffer-disable activate)) diff --git a/users/aspen/web/default.nix b/users/aspen/web/default.nix deleted file mode 100644 index a16cd16c0..000000000 --- a/users/aspen/web/default.nix +++ /dev/null @@ -1,62 +0,0 @@ -args@{ pkgs, depot, ... }: -with pkgs; -let - site = import ./site.nix args; - resume = import ../resume args; - bucket = "s3://gws.fyi"; - distributionID = "E2ST43JNBH8C64"; - - css = runCommand "main.css" - { - buildInputs = [ pkgs.minify ]; - } '' - minify --type css < ${./main.css} > $out - ''; - - keys = runCommand "ssh-keys" { } '' - touch $out - echo "${depot.users.aspen.keys.main}" >> $out - ''; - - website = - runCommand "gws.fyi" { } '' - mkdir -p $out - cp ${css} $out/main.css - cp ${site.index} $out/index.html - cp -r ${site.recipes} $out/recipes - cp ${resume} $out/resume.pdf - cp ${keys} $out/keys - cp ${./pubkey.gpg} $out/pubkey.gpg - ''; - - purge-cf = writeShellApplication { - name = "purge-cf.sh"; - runtimeInputs = [ httpie jq pass ]; - text = '' - cfapi() { - http \ - "https://api.cloudflare.com/client/v4/$1" \ - X-Auth-Email:root@gws.fyi \ - "X-Auth-Key: $(pass cloudflare-api-key)" \ - "''${@:2}" - } - - zone_id=$( - cfapi zones \ - | jq -r '.result[] | select(.name == "gws.fyi") | .id' - ) - - cfapi "zones/$zone_id/purge_cache" purge_everything:=true - ''; - }; -in -(writeShellApplication { - name = "deploy.sh"; - runtimeInputs = [ awscli2 ]; - text = '' - aws --profile personal s3 sync ${website}/ ${bucket} - echo "Deployed to http://gws.fyi" - ''; -}).overrideAttrs { - passthru = { inherit website site purge-cf; }; -} diff --git a/users/aspen/web/index.org b/users/aspen/web/index.org deleted file mode 100644 index 128398414..000000000 --- a/users/aspen/web/index.org +++ /dev/null @@ -1,56 +0,0 @@ -#+OPTIONS: title:nil toc:nil num:nil -#+HTML_HEAD: <title>aspen smith -#+HTML_HEAD: - -my name is aspen smith and i'm a software engineer and musician. - -* code - -- [[https://github.com/glittershark/][github]] -- [[https://code.tvl.fyi/tree/users/aspen][my directory in the tvl monorepo]] - -* work - -i'm currently a software engineer at jane street, working on the ocaml compiler -frontend and foundations for data-race free parallel programming - -previously, i worked on database internals at [[https://readyset.io/][readyset]], an incrementally -maintained, partially stateful materialized view maintenance system for sql -that's wire-compatible with postgresql and mysql, based on [[https://github.com/mit-pdos/noria][noria]]. - -# * projects - -# # - [[https://windtunnel.ci/][windtunnel]], a continuous benchmarking software-as-a-service currently -# # accepting early alpha users (send me an email if you want to try it out!) -# - [[https://tvix.dev/][tvix]], a project to reimplement nix in rust with a focus on better performance, -# maintainability, and extensibility. i'm a committer to the project, and mostly -# focus on the implementation of the language evaluator. -# # - [[https://code.tvl.fyi/tree/users/aspen/achilles][achilles]], a compiler for (what I plan to become) a dependently typed, -# # low-level functional programming language targeting LLVM -# - [[https://code.tvl.fyi/tree/users/aspen/xanthous][xanthous]], a terminal roguelike in haskell that I work on intermittently and -# exclusively for fun - -* music - -- i play bass in [[https://goodcry.band][good cry]], a rock band based in brooklyn -- my friend [[https://tasshin.com/][tasshin]] and i wrote, recorded and made music videos for 6 songs - together: - - [[https://www.youtube.com/watch?v=uX11-ClOf5k&list=PLXcbtcE8U1zcQsIWV7uzz-fUm2o9ggSbW&index=5][u're welcome bro]] - - [[https://www.youtube.com/watch?v=i1ZNdzkkJe4&list=PLXcbtcE8U1zcQsIWV7uzz-fUm2o9ggSbW&index=4]["cool"]] - - [[https://www.youtube.com/watch?v=5GOciie5Pjk&list=PLXcbtcE8U1zcQsIWV7uzz-fUm2o9ggSbW&index=3][being love]] - - [[https://www.youtube.com/watch?v=ew-rhBQmGpY&list=PLXcbtcE8U1zcQsIWV7uzz-fUm2o9ggSbW&index=2][gonna]] - - [[https://www.youtube.com/watch?v=GJBTaH2EozQ&list=PLXcbtcE8U1zcQsIWV7uzz-fUm2o9ggSbW&index=1][love like there's no tomorrow]] - - [[https://www.youtube.com/watch?v=K7UElh21py4][holy]] -- https://sacrosanct.bandcamp.com/, a post-rock project with a [[https://bandcamp.com/h34rken][friend of mine]] -- [[https://soundcloud.com/missingggg][my current soundcloud]], releasing instrumental music under the name *missing* -- you can also find a log of all the music I listen to [[https://www.last.fm/user/wildgriffin45][on last.fm]] - -* contact - -- [[mailto:web@gws.fyi][web@gws.fyi]] -- [[https://twitter.com/glittershark1][twitter]] -- [[https://bsky.app/profile/gws.fyi][bluesky]] -- https://keybase.io/glittershark -- aspen on IRC (hackint or libera.chat) -- [[https://gws.fyi/pubkey.gpg][gpg key: 0F11A989879E8BBBFDC1E23644EF5B5E861C09A7]] -- signal / telegram / discord available upon request diff --git a/users/aspen/web/main.css b/users/aspen/web/main.css deleted file mode 100644 index cdcd44076..000000000 --- a/users/aspen/web/main.css +++ /dev/null @@ -1,139 +0,0 @@ -@import url(https://fonts.googleapis.com/css?family=Inconsolata|Inter&display=swap); - -body { - margin-top: 40px; - max-width: 900px; - line-height: 1.6; - font-size: 16px; - background: #f8f3ff; - color: #3a1616; - padding: 0 10px; - font-family: Inter, sans-serif; -} - -@media (min-width: 1050px) { - body { - margin-left: 150px; - } -} - -@media (min-width: 2000px) { - body { - margin-left: 300px; - } -} - -input { - padding: 10px 16px; - margin: 2px 0; - box-sizing: border-box; - border: 2px solid #dabebe; - border-radius: 6px; - background: #f8f3ff; - color: #3a1616; - font-size: 16px; - -webkit-transition: 0.5s; - transition: 0.5s; - outline: 0; -} - -input:focus { - border: 2px solid #3a1616; -} - -.button { - background-color: #f8f3ff; - border: none; - color: #000; - padding: 6px 14px; - text-align: center; - text-decoration: none; - display: inline-block; - font-size: 16px; - margin: 4px 2px; - transition-duration: 0.4s; - cursor: pointer; - border: 2px solid #3a1616; - border-radius: 6px; -} - -.button:hover { - background-color: #3a1616; - color: #fff; -} - -.isa_error, -.isa_info, -.isa_success, -.isa_warning { - width: 90%; - margin: 10px 0; - padding: 12px; -} - -.isa_info { - color: #00529b; - background-color: #bde5f8; -} - -.isa_success { - color: #4f8a10; - background-color: #dff2bf; -} - -.isa_warning { - color: #9f6000; - background-color: #feefb3; -} - -.isa_error { - color: #d8000c; - background-color: #ffd2d2; -} - -h1, -h2, -h3 { - line-height: 1.2; - font-family: Inter, sans-serif; -} - -h1.title, -h2.title, -h3.title { - text-align: left; - margin-bottom: 1.5em; -} - -h2 { - font-size: 18px; -} - -img { - max-width: 750px; - border-radius: 10px; -} - -a { - cursor: pointer; - color: #217ab7; - line-height: inherit; -} - -a:hover { - background-color: #e3d6ff; -} - -a:visited { - color: #43458b; - border-color: #43458b; -} - -pre { - font-family: Inconsolata, monospace; -} - -::selection { - color: #fff; - background: #ff4081; -} diff --git a/users/aspen/web/orgExportHTML.nix b/users/aspen/web/orgExportHTML.nix deleted file mode 100644 index c0c94a764..000000000 --- a/users/aspen/web/orgExportHTML.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ pkgs, depot, ... }: - -with pkgs; -with lib; - -opts: - -let - src = if isAttrs opts then opts.src else opts; - headline = if isAttrs opts then opts.headline else null; - configFile = opts.configFile or ./config.el; - - bn = builtins.baseNameOf src; - filename = elemAt (splitString "." bn) 0; - - outName = - if isNull headline - then - let - bn = builtins.baseNameOf src; - filename = elemAt (splitString "." bn) 0; - in - if depot.nix.utils.isDirectory src - then filename - else filename + ".html" - else "${filename}-${replaceStrings [" "] ["-"] filename}.html"; - - escapeDoubleQuotes = replaceStrings [ "\"" ] [ "\\\"" ]; - - navToHeadline = optionalString (! isNull headline) '' - (search-forward "${escapeDoubleQuotes headline}") - (org-narrow-to-subtree) - ''; - -in - -runCommand outName { inherit src; } '' - buildFile() { - cp "$1" file.org - ${pkgs.emacs}/bin/emacs --batch \ - --load ${configFile} \ - --visit file.org \ - --eval "(progn - ${escapeDoubleQuotes navToHeadline} - (org-html-export-to-html))" \ - --kill - rm file.org - substitute file.html "$2" \ - --replace-quiet '' "" - rm file.html - } - - if [ -d $src ]; then - for file in $src/*; do - result=''${file/$src/$out} - mkdir -p $(dirname $result) - buildFile $file ''${result/.org/.html} - done - else - buildFile $src $out - fi -'' diff --git a/users/aspen/web/pubkey.gpg b/users/aspen/web/pubkey.gpg deleted file mode 100644 index 2a7e744cc..000000000 --- a/users/aspen/web/pubkey.gpg +++ /dev/null @@ -1,206 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQENBFSsgHkBCAC8hkveavGgqfK4zN+ZKWmzToa/YQHHatA68cIzlmXebuevV9bE -vNVYz6qI9Y6QPvxoIXlnmKzcZkWzE9X3bXdtlucojXeUzVxfkTIWWL50+DMZtzTY -IGaK4h7J6xuF27S2WZjE18Bf+mvwrGgl2B6eCd2L2Jw3PwdH7LI9+zl0B9Eo6QUJ -1O1NZu5ry135uzIfs4u1U0s+OVnBcq+y4NR0Tejsw7WwY5/JLlljM2CJYPhFGT7h -yx6ApI4TeoOwDOXg4UKl78znMpUiJP0yD8u5/BHiq64H4oxkDiRenOneZ9B6vupX -o0+ri94h1Dirb/D2Bq/LxdNWqLz/xDlU5GEBABEBAAG0HEdyaWZmaW4gU21pdGgg -PHJvb3RAZ3dzLmZ5aT6JATwEEwEIACYCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIe -AQIXgAUCWVumdgIZAQAKCRBE71tehhwJp2dZB/9QimuyGMtXB3ElfdRLlQ3dT4uT -KMW38VBMyEXOlMF1VhRolRWp4CTsEUYSJhhNg/b/NW7KgXBaX3ZJEAZqwyttxx0r -1v9Rysb9yrxkKAsnyNs774sMaEj+Zj+gtik4jxT8EZ3hV3ohCUrEKiImPKkPTeFl -xYk9QjXZPE4CAMBfmybawIk7cMHp0XzJppia9XAwA7zDXQnoc/rL8feVxXUbcPb1 -RjAtGI/Pg4vhZKCJ4urvtkSvcKXkiqq3taGjIUV1cvTjwTs1ceL32J0oghR6zbIt -OLj9AfqlLjBY+9Mdyeo+Jd1FGBu8i+C13sv+yLFZHEopi5hnHXgsEvIZwcSviQE5 -BBMBCAAjBQJZW6VqAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQRO9b -XoYcCafMiwgAggljWWQuVBf/vTK6Yg7VgOo7XEPShzu7mNt1fucCdiAk01NvZV3/ -EnkpuWJHyQ8hPU+xOHxCz22Mhv4IpIhmCSXQiOhGrQ+byPRMXEeyse1Pn7YVW9jx -7rk5Lh95YYqBy4LLACi8Cvo8OfbwtIPO5G/JKD3rGFHWcANya3ZdNlLr8RlJQa1/ -W7nZ/i+TnfGC7AvaR/5JfwBAxA5YMI4hK+RHiRWGuIPTwYrel2bKToRboXL76fRI -9pI8SKzuRr7dSX/pCWFLPQRdlwlF3n5iiADo73XyXcOUP2g6oadNzvsqctq6kGML -KEHAoqhsAUMs+J8sSPcyfhJOIQPQRYExFokCMwQQAQgAHRYhBBP5Ly1Y78tmaShO -tNywW0z4mvxmBQJZvsjBAAoJENywW0z4mvxm76sP/3DZ3i0f7B7zRCkzzbyYrTU6 -kbZK8FzvGhNenU8JNQ5370lxiebVp7gwUsYORmgcA7mkenqVjSjYNK+/hTNcaiIU -KVn/TxrrTWtCNE3d5fNHRdR9Ac9FOw7CHJGac3/UOsxE++cpW2+7S0SH59usl+17 -tLbO9YzsTncvsWR8maGnjaTV0Jz+Ccd1GkBHv0Edpmzki+oseqI8YlRK5uNmhuMB -G06k51hgvjwYpF6fUwRauv77XnI71fRa4m8AX+LGt/NMz9GmFfhDTlC+YnsiVbk8 -bkAAR4axCfKvbUQm5GRs/iKLFBlpwC1/FsjTdgWOWhpF1J/jhiIFZsG4DyqnkJLb -W7WI6QJPeB05i6EjI+ub/2SGJXVlPIRH9S5DCX8k0QNk2kANplaLoE6+xkki09TE -4PTEK9c63Hi6X39Z/pgw25/mgArp3VVTSrK1ZIiiL+o9bvTowtc3uHHtG1fV8RMK -DOfWhI00TqpTend8DsgfpYR4vfLasmDBkXI9GmeIzX4XABVMtb5IS3ZDUNMEgPuk -kMwrASg8ln8UqZpRMtXPg9l3INiIoXoDfLHjyS4FXBqSLIi778uuNZvYXyJNKYlz -aYfma4I9m6bpkS9U4gFYnkuX3rAL8RiyKru5EGlE8+GL6PxnRuChj1g0mgazSNBA -79Af1iA6JpwnUsQxXxkWiQIcBBABCAAGBQJZwDbFAAoJEMelPMWNOx+MLYoP/3CT -16deQZCNjfVmBKWzvwEEOTQVoRs1xEl63lKtXOrWtStZPPnnIXqfXKi22p/owykB -WGdE84RgRAGBJYPriHjbxx/BK6eaUkmyekaa0tFadDOpctK/YmTZkp3l/FOCezGl -QK0je2koxBei63qL+tfFIP4MNTuIwxezrSwCXaXRlsblIvLNBSK8cBHz1WjZG4Ch -bV4RxoW75teHqtbsLId97WRXojErjIpA6ypqmUEyG9YrOdOFd1QA9QXWm5RO8xhw -8JTnUDeyrL00H+2zEnxz02vDT5qJyXLBF5FrHgQvvdq9ZJo85/LZH6EZZt8D4N+l -sWij2wTQZ+GrzhXgOWyWeVWsYiWRegrCVc1HDJnT3c4ALjHDdHQvZjYG1alPT06h -J+MEdGvPWRcGEuM4m4MP6p/PYq7xqmf4Kxw2JWd1e3gVffRTC04dXcxmMzVHG+vo -mtdPjquPzawd7rMKqvECbzwBIHSVLAqDvcian+U83fv0NK1vP5wSQFK3531/1xwp -UVx2jJHpuVw6goW8vm5RMHP3fgaDjBU9E9l7K7UszYr6zUxOGNJ6S1IPkBcz5K4e -ncrqhG5Tr0mFP+iV6V+bQ5hfBhXIYhVBqieumGD/ZU8QUjyxj/myb4lPoIBsBxxi -FWwHRTKn8qQFZvJY7xXrX0BsLGAgTxKupEADLR/0tCdHcmlmZmluIFNtaXRoIDx3 -aWxkZ3JpZmZpbjQ1QGdtYWlsLmNvbT6JATcEEwEIACEFAlSsgHkCGwMFCwkIBwIG -FQgJCgsCBBYCAwECHgECF4AACgkQRO9bXoYcCaed+Qf+JSDZ3odMwlnrbb2kwsld -uAt9VhRm+dfdIm25nAgxJUxIju8uIgE9v+8dRdGFwrV8pKBYYOCMi8MFNYuu9zS6 -6wXS4opd/DeYDj2yaN0wBYEfeXMCwVLVDHU7AHrsxQWRSxbcUOi2Mm2sig70ZSq2 -iNicX2f6eUSr/4CjocTP6jOqcHd6Di4odEy/hK6ukCCW8ia1Uujh7JYCU7quHnuE -1N184W2Jf6hUieFC2kE+Nmhix0LsYYe6c1InembHRZ85BpOsWWuE9cS6IuVO/jbN -ZcgS7NkuCHkG7CubPnSZX/EDwmyr9Pd57tr9BANuDNvTGgcbaXhJj5nlIx/usDsr -RIkBOgQTAQgAJAIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAUCWCyKLgIZAQAK -CRBE71tehhwJp/Q/B/9I+URRL9FuzA3bnljchtDVUtPVWfKzPUzKTJkUGnrmO3J6 -YM97JUoU9YZUP0JGvBuTzM4FVqNG7aEdyQBiHa4b7rBzVIUD+hMYlvowJTVKsG3j -f+TcX4Ms9wTpDRd9+kjZPTONZom5C+a5yTqipKK78CubCQJESQktYJoMr3P3FOG/ -nTi9NCeVEah2ud2fsrfOvqTqpcL02O/jTqA4jDDznw2TmeQ/NMc+Dz5hIIHod8D5 -QXoNPvMPFcCGe3oSPzQ5RlKpF1MvzSb35c9TY5BbOVRZPSUR5elkAE1yrXPpwkNo -bQl9/2eCxhcOcT9bcP+hmD0O4QJw5h8SALVAYaZJiQIzBBABCAAdFiEEE/kvLVjv -y2ZpKE603LBbTPia/GYFAlm+yMUACgkQ3LBbTPia/GYgvBAAgKZffTlMvOjnmYB2 -TiG5sn9fqnU8cDmnaVLwD/XLSZ8wI3dBuLnlfEOTIAWlrAnnIXyEdH4isR3zLPuW -bXLsIy4xW5BddjnWaRpE/2kdPTxzo+tI/JjeJFmxp6MggAMV+XdaxDXTMZGwA3Gv -ZXqLiTvlCYT3YBM4MtEA7HkXjpQuvYJ2rMFLhTrf8IhWg7PQMJJKqaM2RawwJ7XX -L4HzoQyHD5iJV8H/1gtSayxHeVwPVJYlUXtpPabbPhRtrJlI39RVCWejhI0h2RU3 -U9lvVA+BP3Dv3l9kDm9XYz9/WH1sYgjatsPSFgStYg4kjvrgIuHN1ALCPv3wZUmW -0NhV26pTps667M5onEAn+0rfHYp6KF4FUX/3kPgRzuXRt+gAY2BdgFvLd+BucQxz -oaZzl3ykK9ZwbylgtX6kmaspBE/TcxKwGG8RUJZZf8VEqaIk6nZ24F+oaK9zjLgw -3eOOWsk6UefibiLGXpTRIIhmBw5ki6LJi2I/IpQ73hOZvyQKlZCKEBJL72MQbZeA -25xkO8a4ZVdmeyYTJbxL9f10t8ZNBwYJQW7MAhGRKAkg9McrK4Wh73zs8ux+jp9U -i7wM6HWRARyfbjCoJ3V7Q3FbN+H0zk8/+wvlTabpSNIyUiRp7d9Yw6fmVr/Fq2I5 -55Rlg725RwN/hJHRUvLGkoP1xSCJAhwEEAEIAAYFAlnANsUACgkQx6U8xY07H4z/ -5Q//UGyEHeDu4mm/5h57ryUR32/0NG4yBeQrn5HLaOD+bpWD+Z5ZBV3TOJHeuJMj -xA/scBHIkfnwW+e7DQxudPBhxp6+ZMyLje6en9uZY/IVGXVKe63+XzRojwJRHhbe -7YUyym0en1RBWkI/TIdx4KjZ55Xz78/Dmb6QnBCuYr2Vb6h0mZz3p8KoTaIFEWM9 -m9/84Xz2ppCcVBoaavMyo1P4/Fxluh4T51qjR1UeLIuwDdDyS1aYQ9+MXIl8tHz1 -x05HdDbdU7Y2tAg4WUZ5Lg42m9hjRPJcyuw6P+jpF/YrxyAbY962ibZNTep1urTG -/oBwSnhJ8nIK5ISwkacbyeN3Tu2sCmJceiCfOz1M9CaEffnyxP36ALZsF9jl+PWM -bGsN+ZeZMwdnPsExBrqNbPn+Ce2LNm/dxIlfrFXJXqm7BZAuOCuL9UAm5vihR/LE -ijqYWsTI32N8nz4RclU3d1N6w5KZ/XzyVfMYHhhgrncPG/21A1YlR9CBK/FBh7nu -hBLU2Q92VV47oEIG1BUVHct7SOR1fV4Auvg2d9mTPWZV2mfGjebywaALq6kpc5l0 -bUTDew8FXxXO+arsvM5ngdI/XHIAai9+L13jnsciTjQurpnhC9ZNwUz49pyJSQy4 -fWDrYe/RldGa3ggCioNCZM9oCJUYYXzJpfeCWcCw7SmwcGO0K0dyaWZmaW4gU21p -dGggPGdzbWl0aEBzZWN1cml0eXNjb3JlY2FyZC5pbz6JAWIEMAEIAEwWIQQPEamJ -h56Lu/3B4jZE71tehhwJpwUCWcAx0S4dIEkgYW0gbm8gbG9uZ2VyIGVtcGxveWVk -IGF0IFNlY3VyaXR5U2NvcmVjYXJkAAoJEETvW16GHAmnXKMH/0JpyvK92knWLcBI -fzatSWHSyTM7CYxIgB6kj6DhIUd5h0ahVx5CLMUNLlBZSdbCKzgifSbP0HLBVC7O -mn3tCwPuE2GM5dgnxxawaOqK7SdwB8nq1wFZD2uPlFdiocHXRBG7OQH/nkaJP+V/ -eO0F+2vLEER3NxdOuIE1PZVXDRVBaeRGuyG5MXW78PdnV/GizzxoKVBw+ZRIHonj -IpCozPjFzA3/ZLpQtawKZMyO0un20QEDEXJAoAsgIAyYFYjb568+VBb/8Ghe7V5q -7yekKOW1HzxBsN6/YGvOBLedKANsG1C180klDQIt6GkBk1V7RUs59DpGRlfYC7la -X/cewumJATcEEwEIACEFAlgrhmUCGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AA -CgkQRO9bXoYcCadpQggAok7C6Bm6uOANdfpNuKFiLWyU64OaSEsClMH8LYb4pNKE -D1n0KM/7K9MPyHtK1JwrksjlVF7iWUoMxToxHMJsNXQ79IbGp8rfjWd0gq/4UmrA -DjCHl0u/oci/PeBOjSiBg4tufmIaY9QBZ3grvXDqMZRF6sp1WogSW6RyMGrcAeYu -2b1M/pK0wY3+sMIC8wYtRB8OyCWIYEtWHvQP/oforq+3f+PwunAt9SIAXa/HfIjW -zIaspOuvn4XWeVXdkDuA1KuAlIBaGpDvV9/NyX/Gs0dM1yDz6YSdkKUMw7H64lE9 -CdfGz+eOrZJ8DrDWJbdVz2MJS71ypY169WJEck3T04kCMwQQAQgAHRYhBBP5Ly1Y -78tmaShOtNywW0z4mvxmBQJZvsjGAAoJENywW0z4mvxm3AwP/1qwyr5JlHndaU7K -6osZ/hCL6h+yx/m/tG6HbBCAsV7CO5PxeVZAZoJsEbiPLoQ2FCWyYh6sjKoBlw4o -n+pPDWZHw///35Y+H4/srCOAWkONpBb9ZQM5Kb943thQXNLrzpzV6itcqLM/Gr3d -lhgg74srezsculLbLXHo6glxCddEr0a21gSKHu35oTcKkwepF+AmZbjS7wj4uYZC -AvUVN0HdOhb3c4+PN7Y32qq5GuElmtiUej56GKCBD10XwNKaCABsKIaPArqO+068 -hjb5iur1mkNjdKE7Wl2aqLWwweOwrPAYIGNNh/CHHLCamcRMeapfBqJqsqPdOOuG -Xjx0JKoVSL8glu+Yj7jWBg78rdm1Uot8nx94THsTOxi7ZT4Ui8GDTc/oQBPewGBz -bWxGI+P4I7r/ZWJsiKjWXCmduTM5itzSM/zG7mMgoB+Kn9qgla5XM/auiupfHcJc -ju66rDy1xBDOVuxJ49ga9FY2lrob0aLUB9ROmh8/JlgcRLWFdTbMpTRJU+6chWFn -R6UG9MPk+H7cG/IrCRPHKtUiHSgYnhCE3E/klIIIMLTGgAbJxt1BidyL2oBCkQwk -IZwynYwiIDaundIUAoWGf/t5Ca+U9trLG8cNH7g3g7Ojd0WJbOLVMEQ0Lh5nPHdu -y4C8Ejt95R2tzw5h339GiqEqrsVZtDFHcmlmZmluIFNtaXRoIChLZXliYXNlKSA8 -Z2xpdHRlcnNoYXJrQGtleWJhc2UuaW8+iQE3BBMBCAAhBQJYK4eWAhsDBQsJCAcC -BhUICQoLAgQWAgMBAh4BAheAAAoJEETvW16GHAmnFZMH/R6FknUGOR/sC+1Zifs8 -TCvXL1oBYcuEDE01c4QzkiFeOekvmjc+JzwOidSvMNXFGw3FoZTyO8C9tClaC1Bc -kWLSqAPFLpvWF/kJKVKRyOq2RwwyrKLtcDJ1LIJevmzSxnZkGfS2uLQAo3slbhZ3 -Rpcms/9GaZc15NMBEj8sbLkSb88EWiAM9MdFbAlDm4Jp13B6/elw7M2+tK9HSbUl -cb5m0/9n5zhBADdgZ1NNLFqcrbD01dNBVOgko7wuKDeK9g2CluxwTTLCttdV+7en -MHX725NrfN30yZDRAv2ZfdGIl4TE0T5XGPmMb6QTwaFxHFcp59eSD5TB5ph+Rxfy -8QSJAjMEEAEIAB0WIQQT+S8tWO/LZmkoTrTcsFtM+Jr8ZgUCWb7IxgAKCRDcsFtM -+Jr8ZjISEAC3N0/l7M6YOhybEoa9Z8Fr9LBiN5QZ1MU0AUjrBUk/IOQyP5PUagSn -v0VBUopr9hEdNxuCCNk/DNyQpJPPpJAvTrb6A2/UwBB36i1C1GadtHKi0t4djFnv -dIcpVLeA2+92bI1q504JTR5zLGuaIGf30YpUnyVOs/tlHYRNl6vHB0ccMl6XtTZG -Nw/OaSO6zsZ7b2mtjmMmDgpa/A9cyQ6NJMSPGdd8M9wrA7CZNK4SSQABdKRCMQRp -MHC18rNm14RmJ8skIWsCw3HJYyKGOj7xupHRki9/3W1Knx2q7OSNO5KnbEFfyOmN -oyIj5NiPb/P1sd5z6qtySlzZ1fYOSQh9HtxCrxGUqW/oQHFb6/ljJA5z4XYasNrM -DViI++DicrobY4nXYoui0ZLevg/FQ05GpF2ge7z07tk0slRj3ssgZ+TrizRl0VST -81cvrdNQIUmi1p3I2OzHxu9bRyjWKwOVsklq091y5wZabEvA7JbmA8nNB8HV10OZ -8mx1IjVha3GrLHiaOk/Gkomd/1p/1gX8VDyVVMezIv0pBJZpamtg0qu3aeF7rv83 -QY44LD0cBDgtohpCu1vqaxz7154seqj3hpmxRDkRAdJqfNuVgJdJhpFZeC8XOf2u -4wD5jrIoQefLx5ExAXFwQwGDgtJzS3HWYl/q7Csz0z+CjTMsI7yQDokCHAQQAQgA -BgUCWcA2xQAKCRDHpTzFjTsfjOHSD/9GloneXphdCKAT589zMjIxuWC6pCclk3Qu -elePI9GgRUS2STkWw7tSmKZ5BFY8ywIE56D7ay/Q02rUYymIQn4oRdbpS4tH6fit -nYUOBFrHDbLPWX55KpImjY7APoaBCfvF0S+rJuMT+6S4R36UF+PxCv2z5yzkz7u6 -9PvVFRQkgMQmKo3q2PrdSt9xlFtFe9Y5KAT5/UWlz2KNK4/rw2s7FEbQBv9ONzVE -2txTe1iqUpVmNKN6TpO3hLdj0ldqiPQUsxUuhIdjFPoMXZpsO1t63T9I/jkD+d5/ -DPzVQRVgpf3Dcg5GIpy2PBmW5upSWwxh96QcplLeqN7LmmQLYHOs6mJMmqCtN6lk -eaks9heso/i2zkIixDWdDPYOlEtnH50zheLtS1J2Ic6Xmn2FmWNS61KtgTfy6MLH -19Tqz5Dsu+RB8uqGBA499YUJWvBSexW0yRb488EP5SYARhhk5roNOhPDroBXTvEV -cXVmc54Ze4/cfT2/wwNyHMqbpG8itE0L0Qw+lfET7C0lcWi0tflowIqaFbDiVbEc -7qk7FoGmTSyqfJJ0NhuDfev/wRwiE1Wak+R+sfQlqk696+vPWcIO3q/Mk9RO/oCM -7Rf9I7y3ep3zyRAr1JjHvGRiO8IPECUE2LPL9rHonC+h0rJMyERojR2VKDxLCxlm -/HtaKvUwuLQiR3JpZmZpbiBTbWl0aCA8Z3JpZmZpbkB1cmJpbnQuY29tPokBUgQw -AQgAPBYhBA8RqYmHnou7/cHiNkTvW16GHAmnBQJfxmAMHh0gTm8gbG9uZ2VyIGVt -cGxveWVkIGF0IFVyYmludAAKCRBE71tehhwJp77kB/9BmSOkTEBcG98Zk0RE6HvZ -cJwEDKZhSv+ttQCfqwGp0NAQj5dd+zA9WIMNF0wnX0IHNA0BrZXCnlw8YZTG/hbP -H6VBmH700xuTlfPiBE+VbUpf5LK2h0TBjAnO3KITLZqc55Y0zev3xCaLY0Fvj1Y4 -TcTDB+julW4qtSmCgVFwe2Viz6Z0X9TQrtzCHXA9WFzRqXjcj6RqQ/tZLhWEHvje -ZwSGDMR9Pp977OZCDwd6VTl2gmvQpPcTyRVcjOLCZyqI1sPoeMyFnyBMZxbI4sV4 -lv3MuWcRQMXscTzKIcOA8sX/0aX+YOgxI1R/1K/G2dH67CcxLhg3mzIRBkss3xsA -iQFOBBMBCAA4FiEEDxGpiYeei7v9weI2RO9bXoYcCacFAlnCi/0CGwMFCwkIBwIG -FQgJCgsCBBYCAwECHgECF4AACgkQRO9bXoYcCacWvAgAkq088Xv4eXI9dpd+Cz8M -wQELaKZcjtZTFwYnsuJZEWFDAfGPz/gzn2XhX7PoLAK+kRgdA7u93JbSBKC0ibBC -KHs8NrU9E0CVPQowHDfvUzeG2A0gb0IBg+COMR6CZzMsCljicP1qnaxaMt8AuZkX -ym0+k4vvOTZGpsTFgJ7OMlW+6U9IC8LlkPxz5dEjsWbY5iOEmd3zt1iSW6iUR+0c -suDRimxqocptCWeprJy3zRBaJO0y9fP1GZsOchBFHGoZ6mJptxHmnOVXnrHTn/jP -AXr1ESofNkeTbwedP1JzjhjfrJvgZ1R7vQw/b/9SGMgyU4c8IxIu48pAv/3X/DVV -+YkCHAQQAQgABgUCWcKOvwAKCRDHpTzFjTsfjP+XEACUACOvOZef0avzBnTfom6b -ewcZ2USnrfqNP0GpVxkDD4e4e38YDFA8zLt1nIkFPtpg28+wcR+mY9by80JGz0ZY -boNM9sqdGMQJyhJ2h91g/oZnw7jmqvSWLF3LejWLmNsEUal0Y/KG5wK6LKukn5OY -PmDbiQZPTZcZ4y4neCruzm1NDQ9pbZmGkO1UQ37TTb91hyBDFcIfNoS1LHBU2cF5 -Lsol3TftaYO0QQZ90N2AC5u0i2PpgN6IN8N6pzkQ3bRe+YgeaADaQ67WrFZ0z4zS -td17Q25OXBOQdv1IYJWFnom1nqGjfzy2MUiNM/ByGyVqrMQFSOdNi4IHyq9qk8MP -ONMvhtSVNXr+8AlfYBG3fymOKP4RKEg8W/lR+0qmBNu3kxUEjMeTZEN2BYE4Bhq9 -Li1H/j7PZ/Y/fvsXS30ORrMkOunZswd4tCT5sXAaPtIJKmdsx9B5QiN6gqOYY5kG -QdRR35UvLx1WlrAhuoGNXnL0xUZc8aNQfomLAwQMxLIMXNw6GXxI8DKrc54QFyTE -VgCd9SmTO3opW/q8dqg2TYO418SF27iiG5RFsghOAb4TrqvqTDccPgv6hy5NPFQj -G9BRyK86byc/VoXVbhCok/2oJCHDPO5fE5OJozblOyAh1aQIR/LWPUQ9wen+xD14 -tDPeJ+c7VFLSX9lYq9yzJrQfR3JpZmZpbiBTbWl0aCA8Z3JmbkB1cmJpbnQuY29t -PokBUgQwAQgAPBYhBA8RqYmHnou7/cHiNkTvW16GHAmnBQJfxmAiHh0gTm8gbG9u -Z2VyIGVtcGxveWVkIGF0IFVyYmludAAKCRBE71tehhwJp0nvB/9tYQQ5Q2dnlzBJ -hrW8/aiRRkuJjog1ZlOKVc3WsA//qWH3UwPvz2pWMMyExzXMezOmy+mwZ4BgRRzD -K42o2ICj6wqifzqVr2wGeKsO1qLu0GDdIfokwuQ4RbQqfQ3BHCBWFCJF3kkE1Iee -h81DPskpI2lhIXGgjzeOA+4JRqmhG4CijXY5BKkMNdsFxHo8qx5WupvjEbF4ziSV -Uafa2XmMywtzhALvBlHBM5hpO3AGFPC/pX9w64RTPu64jWTYC4ErOhOsjVDNCn8V -APIvM9Fcoy2JRIC9N3OLlmHBpnbPZvb7b5dv1+yBWOUg1poaRDmyyMtSmS12XXl8 -PrAgiDoHiQFOBBMBCAA4FiEEDxGpiYeei7v9weI2RO9bXoYcCacFAlnCjA0CGwMF -CwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQRO9bXoYcCafEAQf8DYC4TNjO9kf1 -MD+0Xsd7N/UOWY0osGD0qzkzuDGmvEtj9P82srWNkpQ+7ecGU4o6rK4YMeaBGBIv -mbI5LpXvT9pAla1jeG2Yv/ig74doU0Ygj1nz2o7ec5+ONz2uqzdYC2GU9gYJPqeN -fgNlNwMi3DwLOrRg6XxDTTP3iaWGbGXLHFw+kQxuwvV/TeCuT4zU1F1PVUxyD1Cg -sE4Rx146JPSR07FPxDBGwJCOe4a6ylrZGijPotUEnOQT7Y6CInUt+Q3VHOb/MRtM -LITJqLCLQkYBhZs92zLC16AxdU905Uwkli+5tRRXb0zgNhWCsX8IVJuMxdJ+Tut6 -gw06osLlj4kCHAQQAQgABgUCWcKOvwAKCRDHpTzFjTsfjM1CEAC3oxjE1GnZT66H -XzT44v19MVB4Wu5zkLrIdcb3YqszibYXWusP5B/fyqCDHIE4dkmC/kTGSsMO31UO -//yXsatpOe8785d+9/T5afRE3OUKn0y55bgFwMaMHB3jBe6edaz/dR04ggzBxmAk -LE+8PdfpZrgYCoORyapnXsh2P0VkH92uSCUhWGIx6+ag813eGBjqfJF0Q++SeRfN -n4olR1Na/LDFI8eG3Lv2ku0iuHuJoiAPSsQr2/kfFYMFIFA0KtOkJvf/p93irzjB -Doc3FhDd5iQLoU0dhivkUcTjeyuQtzuvkdb+WKEVTPGNHgtd78jRRDyBh2zLiwNM -GriD1fgE57UuNMkGg85PYJYAO5br0jxHp4ZSM+jpe3xgwMsnjw9b3eknpXgG2jtt -vYmc/HpAM11ulcMUksaehg1TryOqbAmO8Ehu0Lqdh6BpQIaSLicZlpF2pymu9SyE -B4B9ZeLC265NU3GLGDKu1gwrEYcWWOF90Q6mA8XVQoTCtSiczUoxPOjzkBpZUzgu -jh3pu/TqAYnw4V7kDYimvmnp6GbiW/nc9iugAUzu7CckzlwBKATtPNNmtLnMEr2W -aOf6JkIVV24RHT61sFhUIqFhbr8mpxRTOv3iXhTYH3VbiujXPd5pHWt0ZmyBJBbU -+uR8PsXf1Il9tzFUdV0f6gqgkkRJyrkBDQRUrIB5AQgAyBP+r0INTlvWhn386d2r -ax7QoxB1OmTjROrp5Xs+Ahh2VyGWEwGwNDZoHd3dyQO8HXdKePMISP7URBR5QQ+J -cUATd8K6ZgxVatDoki7jEgGWk161+XLWOAohyVTiCVCteus7KEBar0wVu4WE7JhZ -pdX6zma58nmA/R8o9SpJNZGlJH/ia7Z2c3H7ag9IRc2B3uuOWLC0trm/2aF65VdY -c5w3SB+uE2MJb2m7wXGUehMZ+voQcjEm3ptZzageDzdhlf3Ttjq5KJU4XLRmsVaA -oQ6GrgPr31EEVm6cczCUBwCd/z7SjCsjI79Pk00iDtc7KYtpmsiO11Mly7uX3E30 -MQARAQABiQEfBBgBCAAJBQJUrIB5AhsMAAoJEETvW16GHAmntvkH/0FifrFYRRzR -1Iz1ki9aPnUlDCL+qrHghsqIxi2cQJfc+iClJ4Ot/FzK1ZIAMtWqMvdTfh2NCD4O -OYbk71N+rhaA9h6/XXfmVX7Tt/I374oqMKrvoj7derH2an/VVEw0yabC86MYsKvs -eRWyWLdoqg6it9CckA9hDJ+S4tKrUdaIbp8UdghOW8jUQNcppNQSjA29LQx5fO3w -mOfmx2QaxtLL6sg7McStE+G6kZdIElH4VQOu8XC9Qu8BtTJrTWTPirPQHqRZcZkQ -yZ19FzXWsOz+kLSuIoC8OYUohaVWJnXxMi/VtMp+DaOD46yZ0L6wryCaiftQDcWP -R/QKwpd4hf8= -=qj6y ------END PGP PUBLIC KEY BLOCK----- diff --git a/users/aspen/web/recipes/tomato-sauce.org b/users/aspen/web/recipes/tomato-sauce.org deleted file mode 100644 index dec7468ac..000000000 --- a/users/aspen/web/recipes/tomato-sauce.org +++ /dev/null @@ -1,102 +0,0 @@ -#+TITLE: Tomato Sauce -#+OPTIONS: toc:nil num:nil -#+HTML_HEAD: - -This is a general, all-purpose framework for turning some form of tomatoes into -some form of sauce. You can use fresh tomatoes or canned (the latter are really -quite surprisingly good sometimes), and include or omit garlic, basil, or other -add-ins. The only real non-negotiable ingredients are tomatoes (duh), onion, and -some kind of fat (I prefer butter). - -* Sauce - -1. *Prep*. If starting with canned tomatoes, skip this step. if starting with - whole tomatoes (which you should really only ever do if you grew them - yourself or got them fresh at a farmers market, grocery store tomatoes are - kinda sad), first, peel the tomatoes. The easiest way to do this is to score - them with an X pattern cut as shallow as possible while still breaking the - skin, trying to cover the whole surface area of the tomato, blanch them - briefly in boiling water, then dunk into an ice bath. After this, the skins - will slip right off. After peeling, cut out the stem, core, and any green or - brown bits, and go to the next step - -2. *Base layer*. Couple of variables here, though a perfectly good (in fact, my - usual go-to) tomato sauce can also skip this entire step: - - If you want meat with your sauce (pancetta/guanciale/bacon for an - amatriciana, ground beef or pork for a bolognese) you'll start out by - sautéing that in some sort of fat (probably olive oil), less fat for meat - with a lot of fat already in it, to brown and render out fat from the meat - - If you want onion in the final sauce, you'll chop them finely and sauté - them with whatever fat you've got (either from the meat, or olive oil or - butter if you're not making a meat sauce). Remember to always add a *bit* - of salt when sautéing onion like this, not for flavor but to draw out the - moisture. If you just want onion flavor but not bits of onion in the final - sauce, it's added whole later (so ignore this bullet point). - - If you feel like it (sometimes I do, usually I don't) you can also mince - garlic here and sauté that in with everything else. Add a little after the - onion, as garlic cooks faster than onion, unless you want something - roastier (usually you don't for tomato sauce) - - The traditional (so I'm told) thing to do with amatriciana, but also nice - with all variations, is to add in a little crushed red pepper with the - fat to flavor it slightly, but do this late so it doesn't burn - - If you have tomato paste on hand and feel like using it, it's also nice to - fry that in the oil for a little bit - usually I'd do that around the same - time as the garlic - - If you're making tomato *paste* from your sauce, skip all of this - paste is - an ingredient, not a sauce on its own, so imo should be as neutral as - possible (i.e. just tomato). - -3. *Tomato layer*. Not a whole lot to do here, just add all of your tomatoes - - either your peeled and de-cored tomatoes from step 1 if you're using whole - tomatoes, or an entire can of whole, peeled san marzano tomatoes, including - the juice in the can - to a pot over medium-high heat. If you need more fat - or if you skipped step 2, this is where you'd add it - a classic and my - personal favorite is like 2/3rds to 3/4ths of a stick of butter, but you can - also go with olive oil. If you skipped the onion in step 2, add that here - too - usually that'd just be a fist-sized amount of onion or so peeled but - left with the stem on so you can fish it out from your final sauce later (and - snack on it!). Also salt here, again not to taste but primarily to draw out - moisture from the various ingredients. - -4. You can cook that for a wide variety of times, especially depending on how - hot you make your stove - there ends up being *lot* of liquid in there, so - you can go (in my experience) a reasonable amount hotter than you expect - without burning the sauce, though obviously your mileage may vary. The main - thing you're looking for is the whole chunks of tomato to break down, and the - whole sauce to get a texture that looks like it'll end up sticking to pasta - nicely. In all versions of this, stir pretty regularly with a wooden spoon, - and use the spoon to crush the big chunks of tomato occasionally. - -5. *Final layer*. Usually I don't do anything here - but if you feel - like it, usually right as you take stuff off the heat is where you'd add - basil, if you're using it. You can also add sugar to balance out too much - acidity from an especially acidic tomato here - I'm not going to tell anyone. - Also salt, but make sure to account for the extra salt you're gonna get from - the pasta water (see step 6) - -6. *Pasta*. You know how to cook pasta, I'm not going to tell you that. But, - like, salt your water until it tastes too salty, and remember to move the - pasta itself *directly* into the sauce pot from the pasta pot before it's - completely done cooking and without straining, bringing along some of the - pasta water (and a little extra for good measure) then finishing the pasta in - the sauce. You know, the thing you do for pasta. Remember the pasta water - will have salt in it, so adjust for that when salting the sauce overall (I - have made this mistake and ended up with too-salty pasta sauce). - -* Paste - -Start with the above recipe for tomato sauce, noting especially that (in my -opinion) you should skip step 2 entirely. Keep cooking the sauce until it's -*too* thick for pasta sauce (but don't burn it!), then spread it out across some -sort of lined sheet pan (like a silpat, if you've got one) and bake in the oven -at like 250-300 degrees for a *hell* of a long time - I've seen this take like -10 hours, for an especially juicy batch of tomatoes, but obviously keep a close -eye on it because it *definitely will burn* eventually. You're looking for the -end result to be the texture of tomato paste, because that's what the recipe is -for. Especially if you're using garden-grown or otherwise fresh tomatoes, -you'll notice quite a few seeds in the final product - don't worry too much -about those, they've never bothered me. Once everything's done and cooled down, -store in a jar in a fridge, topped with olive oil to seal things off and prevent -oxidation. Use in all your future endeavors, including the tomato sauce recipe -above itself. Tomato sauce is a beautiful oroborous. diff --git a/users/aspen/web/shell.nix b/users/aspen/web/shell.nix deleted file mode 100644 index 7e7fccdc9..000000000 --- a/users/aspen/web/shell.nix +++ /dev/null @@ -1,9 +0,0 @@ -with import { config.allowUnfree = true; }; -mkShell { - buildInputs = [ - awscli - gnumake - tarsnap - certbot - ]; -} diff --git a/users/aspen/web/site.nix b/users/aspen/web/site.nix deleted file mode 100644 index 057c4d3ee..000000000 --- a/users/aspen/web/site.nix +++ /dev/null @@ -1,12 +0,0 @@ -args@{ pkgs ? import { }, ... }: - -let - - orgExportHTML = import ./orgExportHTML.nix args; - -in - -{ - index = orgExportHTML ./index.org; - recipes = orgExportHTML ./recipes; -} diff --git a/users/aspen/wigglydonke.rs/.well-known/cf-2fa-verify.txt b/users/aspen/wigglydonke.rs/.well-known/cf-2fa-verify.txt deleted file mode 100644 index 1012e8282..000000000 --- a/users/aspen/wigglydonke.rs/.well-known/cf-2fa-verify.txt +++ /dev/null @@ -1 +0,0 @@ -debe85916969017 diff --git a/users/aspen/wigglydonke.rs/index.html b/users/aspen/wigglydonke.rs/index.html deleted file mode 100644 index 4fd7f25fc..000000000 --- a/users/aspen/wigglydonke.rs/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - Kids Love Wiggly Donkers! - - - - - - - - diff --git a/users/aspen/wigglydonke.rs/wd.png b/users/aspen/wigglydonke.rs/wd.png deleted file mode 100644 index 217443e2d..000000000 Binary files a/users/aspen/wigglydonke.rs/wd.png and /dev/null differ diff --git a/users/aspen/xanthous/.envrc b/users/aspen/xanthous/.envrc deleted file mode 100644 index be81feddb..000000000 --- a/users/aspen/xanthous/.envrc +++ /dev/null @@ -1 +0,0 @@ -eval "$(lorri direnv)" \ No newline at end of file diff --git a/users/aspen/xanthous/.github/actions/nix-build/Dockerfile b/users/aspen/xanthous/.github/actions/nix-build/Dockerfile deleted file mode 100644 index cfe8e35df..000000000 --- a/users/aspen/xanthous/.github/actions/nix-build/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -FROM lnl7/nix:2.1.2 - -LABEL name="Nix Build for GitHub Actions" -LABEL version="1.0" -LABEL repository="http://github.com/glittershark/xanthous" -LABEL homepage="http://github.com/glittershark/xanthous" -LABEL maintainer="Griffin Smith " - -LABEL "com.github.actions.name"="Nix Build" -LABEL "com.github.actions.description"="Runs 'nix-build'" -LABEL "com.github.actions.icon"="cpu" -LABEL "com.github.actions.color"="purple" - -RUN nix-env -iA \ - nixpkgs.gnutar nixpkgs.gzip \ - nixpkgs.gnugrep nixpkgs.git && \ - mkdir -p /etc/nix && \ - (echo "binary-caches = https://cache.nixos.org/" | tee -a /etc/nix/nix.conf) && \ - (echo "trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" | tee -a /etc/nix/nix.conf) - -COPY entrypoint.sh /entrypoint.sh -ENTRYPOINT [ "/entrypoint.sh" ] -CMD [ "--help" ] diff --git a/users/aspen/xanthous/.github/actions/nix-build/entrypoint.sh b/users/aspen/xanthous/.github/actions/nix-build/entrypoint.sh deleted file mode 100755 index cb7aca541..000000000 --- a/users/aspen/xanthous/.github/actions/nix-build/entrypoint.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -# Entrypoint that runs nix-build and, optionally, copies Docker image tarballs -# to real files. The reason this is necessary is because once a Nix container -# exits, you must copy out the artifacts to the working directory before exit. - -[ "$DEBUG" = "1" ] && set -x -[ "$QUIET" = "1" ] && QUIET_ARG="-Q" - -set -e - -# file to build (e.g. release.nix) -file="$1" - -[ "$file" = "" ] && echo "No .nix file to build specified!" && exit 1 -[ ! -e "$file" ] && echo "File $file not exist!" && exit 1 - -echo "Building all attrs in $file..." -nix-build --no-link ${QUIET_ARG} "$file" "${@:2}" - -echo "Copying build closure to $(pwd)/store..." -mapfile -t storePaths < <(nix-build ${QUIET_ARG} --no-link "$file" | grep -v cache-deps) -printf '%s\n' "${storePaths[@]}" > store.roots -nix copy --to "file://$(pwd)/store" "${storePaths[@]}" diff --git a/users/aspen/xanthous/.github/workflows/haskell.yml b/users/aspen/xanthous/.github/workflows/haskell.yml deleted file mode 100644 index df82de3e8..000000000 --- a/users/aspen/xanthous/.github/workflows/haskell.yml +++ /dev/null @@ -1,15 +0,0 @@ -name: Haskell CI - -on: [push] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Nix Build - with: - args: default.nix --arg failOnWarnings true - uses: ./.github/actions/nix-build diff --git a/users/aspen/xanthous/.gitignore b/users/aspen/xanthous/.gitignore deleted file mode 100644 index 2ad31c01d..000000000 --- a/users/aspen/xanthous/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -dist -dist-* -cabal-dev -*.o -*.hi -*.hie -*.chi -*.chs.h -*.dyn_o -*.dyn_hi -.hpc -.hsenv -.cabal-sandbox/ -cabal.sandbox.config -*.prof -*.aux -*.hp -*.eventlog -.stack-work/ -cabal.project.local -cabal.project.local~ -cabal.project.local~* -.HTF/ -.ghc.environment.* - - -# from nix-build -result - -# grr -*_flymake.hs - -# app-specific -debug.log -data -*.save -.tasty-rerun-log diff --git a/users/aspen/xanthous/LICENSE b/users/aspen/xanthous/LICENSE deleted file mode 100644 index 45644ff76..000000000 --- a/users/aspen/xanthous/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/users/aspen/xanthous/README.org b/users/aspen/xanthous/README.org deleted file mode 100644 index 7e1fedb06..000000000 --- a/users/aspen/xanthous/README.org +++ /dev/null @@ -1,36 +0,0 @@ -#+TITLE: Xanthous - -* Building - -#+BEGIN_SRC shell -$ nix build -#+END_SRC - -* Running - -#+BEGIN_SRC shell -$ ./result/bin/xanthous [--help] -#+END_SRC - -** Keyboard commands - -Keyboard commands are currently undocumented, but can be found in [[[https://github.com/glittershark/xanthous/blob/master/src/Xanthous/Command.hs#L26][this file]]. -Movement uses the nethack-esque hjklybnu. - -* Development - -Use [[https://github.com/target/lorri][lorri]], or run everything in a ~nix-shell~ - -#+BEGIN_SRC shell -# Build (for dev) -$ cabal new-build - -# Run the game -$ cabal new-run xanthous - -# Run tests -$ cabal new-run test - -# Run a repl -$ cabal new-repl -#+END_SRC diff --git a/users/aspen/xanthous/Setup.hs b/users/aspen/xanthous/Setup.hs deleted file mode 100644 index 9a994af67..000000000 --- a/users/aspen/xanthous/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/users/aspen/xanthous/app/Main.hs b/users/aspen/xanthous/app/Main.hs deleted file mode 100644 index c771a0d93..000000000 --- a/users/aspen/xanthous/app/Main.hs +++ /dev/null @@ -1,171 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Main ( main ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (finally) -import Brick -import qualified Brick.BChan -import qualified Graphics.Vty as Vty -import qualified Options.Applicative as Opt -import System.Random -import Control.Monad.Random (getRandom) -import Control.Exception (finally) -import System.Exit (die) --------------------------------------------------------------------------------- -import qualified Xanthous.Game as Game -import Xanthous.Game.Env (GameEnv(..)) -import qualified Xanthous.Game.Env as Game -import Xanthous.App -import Xanthous.Generators.Level - ( GeneratorInput - , parseGeneratorInput - , generateFromInput - , showCells - ) -import qualified Xanthous.Entities.Character as Character -import Xanthous.Generators.Level.Util (regions) -import Xanthous.Generators.Level.LevelContents -import Xanthous.Data (Dimensions, Dimensions'(Dimensions)) -import Data.Array.IArray ( amap ) --------------------------------------------------------------------------------- - -parseGameConfig :: Opt.Parser Game.Config -parseGameConfig = Game.Config - <$> Opt.switch - ( Opt.long "disable-saving" - <> Opt.help "Disallow saving games" - ) - -data RunParams = RunParams - { seed :: Maybe Int - , characterName :: Maybe Text - , gameConfig :: Game.Config - } - deriving stock (Show, Eq) - -parseRunParams :: Opt.Parser RunParams -parseRunParams = RunParams - <$> optional (Opt.option Opt.auto - ( Opt.long "seed" - <> Opt.help "Random seed for the game." - )) - <*> optional (Opt.strOption - ( Opt.short 'n' - <> Opt.long "name" - <> Opt.help - ( "Name for the character. If not set on the command line, " - <> "will be prompted for at runtime" - ) - )) - <*> parseGameConfig - -data Command - = Run RunParams - | Load FilePath - | Generate GeneratorInput Dimensions (Maybe Int) - -parseDimensions :: Opt.Parser Dimensions -parseDimensions = Dimensions - <$> Opt.option Opt.auto - ( Opt.short 'w' - <> Opt.long "width" - <> Opt.metavar "TILES" - ) - <*> Opt.option Opt.auto - ( Opt.short 'h' - <> Opt.long "height" - <> Opt.metavar "TILES" - ) - - -parseCommand :: Opt.Parser Command -parseCommand = (<|> Run <$> parseRunParams) $ Opt.subparser - $ Opt.command "run" - (Opt.info - (Run <$> parseRunParams) - (Opt.progDesc "Run the game")) - <> Opt.command "load" - (Opt.info - (Load <$> Opt.argument Opt.str (Opt.metavar "FILE")) - (Opt.progDesc "Load a saved game")) - <> Opt.command "generate" - (Opt.info - (Generate - <$> parseGeneratorInput - <*> parseDimensions - <*> optional - (Opt.option Opt.auto (Opt.long "seed")) - <**> Opt.helper - ) - (Opt.progDesc "Generate a sample level")) - -optParser :: Opt.ParserInfo Command -optParser = Opt.info - (parseCommand <**> Opt.helper) - (Opt.header "Xanthous: a WIP TUI RPG") - -thanks :: IO () -thanks = putStr "\n\n" >> putStrLn "Thanks for playing Xanthous!" - -newGame :: RunParams -> IO () -newGame rparams = do - gameSeed <- maybe getRandom pure $ seed rparams - when (isNothing $ seed rparams) - . putStrLn - $ "Seed: " <> tshow gameSeed - let initialState = Game.initialStateFromSeed gameSeed &~ do - for_ (characterName rparams) $ \cn -> - Game.character . Character.characterName ?= cn - runGame NewGame (gameConfig rparams) initialState `finally` do - thanks - when (isNothing $ seed rparams) - . putStrLn - $ "Seed: " <> tshow gameSeed - putStr "\n\n" - -loadGame :: FilePath -> IO () -loadGame saveFile = do - gameState <- maybe (die "Invalid save file!") pure . Game.loadGame . fromStrict - =<< readFile @IO saveFile - gameState `deepseq` runGame (LoadGame saveFile) Game.defaultConfig gameState - -runGame :: RunType -> Game.Config -> Game.GameState -> IO () -runGame rt _config gameState = do - _eventChan <- Brick.BChan.newBChan 10 - let gameEnv = GameEnv {..} - app <- makeApp gameEnv rt - let buildVty = Vty.mkVty Vty.defaultConfig - initialVty <- buildVty - _game' <- customMain - initialVty - buildVty - (Just _eventChan) - app - gameState - pure () - -runGenerate :: GeneratorInput -> Dimensions -> Maybe Int -> IO () -runGenerate input dims mSeed = do - putStrLn "Generating..." - genSeed <- maybe getRandom pure mSeed - let randGen = mkStdGen genSeed - res = generateFromInput input dims randGen - rs = regions $ amap not res - when (isNothing mSeed) - . putStrLn - $ "Seed: " <> tshow genSeed - putStr "num regions: " - print $ length rs - putStr "region lengths: " - print $ length <$> rs - putStr "character position: " - print =<< chooseCharacterPosition res - putStrLn $ showCells res - -runCommand :: Command -> IO () -runCommand (Run runParams) = newGame runParams -runCommand (Load saveFile) = loadGame saveFile -runCommand (Generate input dims mSeed) = runGenerate input dims mSeed - -main :: IO () -main = runCommand =<< Opt.execParser optParser diff --git a/users/aspen/xanthous/bench/Bench.hs b/users/aspen/xanthous/bench/Bench.hs deleted file mode 100644 index 5889618ee..000000000 --- a/users/aspen/xanthous/bench/Bench.hs +++ /dev/null @@ -1,12 +0,0 @@ --------------------------------------------------------------------------------- -module Main where --------------------------------------------------------------------------------- -import Bench.Prelude --------------------------------------------------------------------------------- -import qualified Xanthous.RandomBench -import qualified Xanthous.Generators.UtilBench - -main :: IO () -main = defaultMain - [ Xanthous.Generators.UtilBench.benchmark - ] diff --git a/users/aspen/xanthous/bench/Bench/Prelude.hs b/users/aspen/xanthous/bench/Bench/Prelude.hs deleted file mode 100644 index c553abd6d..000000000 --- a/users/aspen/xanthous/bench/Bench/Prelude.hs +++ /dev/null @@ -1,9 +0,0 @@ --------------------------------------------------------------------------------- -module Bench.Prelude - ( module Xanthous.Prelude - , module Criterion.Main - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Criterion.Main --------------------------------------------------------------------------------- diff --git a/users/aspen/xanthous/bench/Xanthous/Generators/UtilBench.hs b/users/aspen/xanthous/bench/Xanthous/Generators/UtilBench.hs deleted file mode 100644 index 56310e691..000000000 --- a/users/aspen/xanthous/bench/Xanthous/Generators/UtilBench.hs +++ /dev/null @@ -1,37 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Generators.UtilBench (benchmark, main) where --------------------------------------------------------------------------------- -import Bench.Prelude --------------------------------------------------------------------------------- -import Data.Array.IArray -import Data.Array.Unboxed -import System.Random (getStdGen) --------------------------------------------------------------------------------- -import Xanthous.Generators.Util -import qualified Xanthous.Generators.CaveAutomata as CaveAutomata -import Xanthous.Data (Dimensions'(..)) --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain [benchmark] - --------------------------------------------------------------------------------- - -benchmark :: Benchmark -benchmark = bgroup "Generators.Util" - [ bgroup "floodFill" - [ env (NFWrapper <$> cells) $ \(NFWrapper ir) -> - bench "checkerboard" $ nf (floodFill ir) (1,0) - ] - ] - where - cells :: IO Cells - cells = CaveAutomata.generate - CaveAutomata.defaultParams - (Dimensions 50 50) - <$> getStdGen - -newtype NFWrapper a = NFWrapper a - -instance NFData (NFWrapper a) where - rnf (NFWrapper x) = x `seq` () diff --git a/users/aspen/xanthous/bench/Xanthous/RandomBench.hs b/users/aspen/xanthous/bench/Xanthous/RandomBench.hs deleted file mode 100644 index fae4af92a..000000000 --- a/users/aspen/xanthous/bench/Xanthous/RandomBench.hs +++ /dev/null @@ -1,32 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.RandomBench (benchmark, main) where --------------------------------------------------------------------------------- -import Bench.Prelude --------------------------------------------------------------------------------- -import Control.Parallel.Strategies -import Control.Monad.Random --------------------------------------------------------------------------------- -import Xanthous.Random --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain [benchmark] - --------------------------------------------------------------------------------- - -benchmark :: Benchmark -benchmark = bgroup "Random" - [ bgroup "chooseSubset" - [ bench "serially" $ - nf (evalRand $ chooseSubset (0.5 :: Double) [1 :: Int ..1000000]) - (mkStdGen 1234) - ] - , bgroup "choose weightedBy" - [ bench "serially" $ - nf (evalRand - . choose - . weightedBy (\n -> product [n, pred n .. 1]) - $ [1 :: Int ..1000000]) - (mkStdGen 1234) - ] - ] diff --git a/users/aspen/xanthous/build/generic-arbitrary-export-garbitrary.patch b/users/aspen/xanthous/build/generic-arbitrary-export-garbitrary.patch deleted file mode 100644 index f0c936bfc..000000000 --- a/users/aspen/xanthous/build/generic-arbitrary-export-garbitrary.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/src/Test/QuickCheck/Arbitrary/Generic.hs b/src/Test/QuickCheck/Arbitrary/Generic.hs -index fed6ab3..91f59f1 100644 ---- a/src/Test/QuickCheck/Arbitrary/Generic.hs -+++ b/src/Test/QuickCheck/Arbitrary/Generic.hs -@@ -23,6 +23,7 @@ The generated 'arbitrary' method is equivalent to - - module Test.QuickCheck.Arbitrary.Generic - ( Arbitrary(..) -+ , GArbitrary - , genericArbitrary - , genericShrink - ) where diff --git a/users/aspen/xanthous/build/hgeometry-fix-haddock.patch b/users/aspen/xanthous/build/hgeometry-fix-haddock.patch deleted file mode 100644 index 748c65b3e..000000000 --- a/users/aspen/xanthous/build/hgeometry-fix-haddock.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/Data/Geometry/PlanarSubdivision/Merge.hs b/src/Data/Geometry/PlanarSubdivision/Merge.hs -index 1136114..3f4e7bb 100644 ---- a/src/Data/Geometry/PlanarSubdivision/Merge.hs -+++ b/src/Data/Geometry/PlanarSubdivision/Merge.hs -@@ -153,7 +153,7 @@ mergeWith' mergeFaces p1 p2 = PlanarSubdivision cs vd rd rf - -- we have to shift the number of the *Arcs*. Since every dart - -- consists of two arcs, we have to shift by numDarts / 2 - -- Furthermore, we take numFaces - 1 since we want the first -- -- *internal* face of p2 (the one with FaceId 1) to correspond with the first free -+ -- /internal/ face of p2 (the one with FaceId 1) to correspond with the first free - -- position (at index numFaces) - - cs = p1^.components <> p2'^.components diff --git a/users/aspen/xanthous/build/update-comonad-extras.patch b/users/aspen/xanthous/build/update-comonad-extras.patch deleted file mode 100644 index cd1dbe24d..000000000 --- a/users/aspen/xanthous/build/update-comonad-extras.patch +++ /dev/null @@ -1,92 +0,0 @@ -diff --git a/comonad-extras.cabal b/comonad-extras.cabal -index fc3745a..77a2f0d 100644 ---- a/comonad-extras.cabal -+++ b/comonad-extras.cabal -@@ -1,7 +1,7 @@ - name: comonad-extras - category: Control, Comonads --version: 4.0 -+version: 5.0 - x-revision: 1 - license: BSD3 - cabal-version: >= 1.6 - license-file: LICENSE -@@ -34,8 +34,8 @@ library - build-depends: - array >= 0.3 && < 0.6, -- base >= 4 && < 4.7, -- containers >= 0.4 && < 0.6, -- comonad >= 4 && < 5, -+ base >= 4 && < 5, -+ containers >= 0.6 && < 0.7, -+ comonad >= 5 && < 6, - distributive >= 0.3.2 && < 1, -- semigroupoids >= 4 && < 5, -- transformers >= 0.2 && < 0.4 -+ semigroupoids >= 5 && < 6, -+ transformers >= 0.5 && < 0.6 - - exposed-modules: - Control.Comonad.Store.Zipper -diff --git a/src/Control/Comonad/Store/Pointer.hs b/src/Control/Comonad/Store/Pointer.hs -index 5044a1e..8d4c62d 100644 ---- a/src/Control/Comonad/Store/Pointer.hs -+++ b/src/Control/Comonad/Store/Pointer.hs -@@ -41,7 +41,6 @@ module Control.Comonad.Store.Pointer - , module Control.Comonad.Store.Class - ) where - --import Control.Applicative - import Control.Comonad - import Control.Comonad.Hoist.Class - import Control.Comonad.Trans.Class -@@ -51,27 +50,8 @@ import Control.Comonad.Env.Class - import Data.Functor.Identity - import Data.Functor.Extend - import Data.Array -- - #ifdef __GLASGOW_HASKELL__ - import Data.Typeable --instance (Typeable i, Typeable1 w) => Typeable1 (PointerT i w) where -- typeOf1 diwa = mkTyConApp storeTTyCon [typeOf (i diwa), typeOf1 (w diwa)] -- where -- i :: PointerT i w a -> i -- i = undefined -- w :: PointerT i w a -> w a -- w = undefined -- --instance (Typeable i, Typeable1 w, Typeable a) => Typeable (PointerT i w a) where -- typeOf = typeOfDefault -- --storeTTyCon :: TyCon --#if __GLASGOW_HASKELL__ < 704 --storeTTyCon = mkTyCon "Control.Comonad.Trans.Store.Pointer.PointerT" --#else --storeTTyCon = mkTyCon3 "comonad-extras" "Control.Comonad.Trans.Store.Pointer" "PointerT" --#endif --{-# NOINLINE storeTTyCon #-} - #endif - - type Pointer i = PointerT i Identity -@@ -83,6 +63,9 @@ runPointer :: Pointer i a -> (Array i a, i) - runPointer (PointerT (Identity f) i) = (f, i) - - data PointerT i w a = PointerT (w (Array i a)) i -+#ifdef __GLASGOW_HASKELL__ -+ deriving Typeable -+#endif - - runPointerT :: PointerT i w a -> (w (Array i a), i) - runPointerT (PointerT g i) = (g, i) -diff --git a/src/Control/Comonad/Store/Zipper.hs b/src/Control/Comonad/Store/Zipper.hs -index 3b70c86..decc378 100644 ---- a/src/Control/Comonad/Store/Zipper.hs -+++ b/src/Control/Comonad/Store/Zipper.hs -@@ -15,7 +15,6 @@ - module Control.Comonad.Store.Zipper - ( Zipper, zipper, zipper1, unzipper, size) where - --import Control.Applicative - import Control.Comonad (Comonad(..)) - import Data.Functor.Extend - import Data.Foldable diff --git a/users/aspen/xanthous/default.nix b/users/aspen/xanthous/default.nix deleted file mode 100644 index 049c92fb4..000000000 --- a/users/aspen/xanthous/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ depot ? (import ../../../. { }) -, pkgs ? depot.third_party.nixpkgs -, ... -}: - -let - ignore = depot.third_party.gitignoreSource.gitignoreFilter ./.; - src = builtins.path { - name = "xanthous-source"; - path = ./.; - filter = path: type: - !(type == "directory" && builtins.baseNameOf path == "server") - && !(type == "directory" && builtins.baseNameOf path == "docs") - && (ignore path type - || builtins.baseNameOf path == "package.yaml"); - }; - # generated by cabal2nix - basePkg = pkgs.haskell.packages.ghc8107.callPackage ./pkg.nix { }; -in - -pkgs.haskell.lib.overrideCabal basePkg (default: { - inherit src; - version = "canon"; - configureFlags = [ - "--ghc-option=-Wall --ghc-option=-Werror" - ] ++ (default.configureFlags or [ ]); -}) diff --git a/users/aspen/xanthous/docs/raw-types.org b/users/aspen/xanthous/docs/raw-types.org deleted file mode 100644 index e5bcda042..000000000 --- a/users/aspen/xanthous/docs/raw-types.org +++ /dev/null @@ -1,24 +0,0 @@ -#+TITLE: Raw Types (WIP) - - -* Raw Types -** Item -*** Attributes -| name | type | commentary | -|-----------------+---------------------------+------------------------------------------------------------------| -| name | string | | -| description | string | Not capitalized, should usually start with an indefinite article | -| longDescription | string | Capitalized, should usually start with an indefinite article | -| char | [[*EntityChar][EntityChar]] | | -| wieldable | [[*EntityWieldable][EntityWieldable]] | | -| density | number , [number, number] | Density, or range for random density, in g/m³ | -| volume | number , [number, number] | Volume, or range for random volume, in m³ | -* Data Types -** EntityChar -*** Attributes -| name | type | commentary | -|-------+------+-------------------------------------------------------| -| char | char | How the entity is displayed when dropped on the floor | -| style | Attr | | -** TODO EntityWieldable -** TODO Attr diff --git a/users/aspen/xanthous/hie.yaml b/users/aspen/xanthous/hie.yaml deleted file mode 100644 index e7cf01d15..000000000 --- a/users/aspen/xanthous/hie.yaml +++ /dev/null @@ -1,10 +0,0 @@ -cradle: - cabal: - - path: './src' - component: 'lib:xanthous' - - path: './test' - component: 'test:test' - - path: './app' - component: 'exe:xanthous' - - path: './bench' - component: 'bench:benchmark' diff --git a/users/aspen/xanthous/nixpkgs.nix b/users/aspen/xanthous/nixpkgs.nix deleted file mode 100644 index 7d7c16440..000000000 --- a/users/aspen/xanthous/nixpkgs.nix +++ /dev/null @@ -1,3 +0,0 @@ -args: -let pkgs = (import ../../../. args).third_party; -in pkgs // { inherit pkgs; } diff --git a/users/aspen/xanthous/package.yaml b/users/aspen/xanthous/package.yaml deleted file mode 100644 index 15a36fe96..000000000 --- a/users/aspen/xanthous/package.yaml +++ /dev/null @@ -1,157 +0,0 @@ -name: xanthous -version: 0.1.0.0 -github: "glittershark/xanthous" -license: GPL-3 -author: "Griffin Smith" -maintainer: "root@gws.fyi" -copyright: "2019 Griffin Smith" - -extra-source-files: -- README.org - -synopsis: A WIP TUI RPG -category: Game - -description: Please see the README on GitHub at - -dependencies: -- base - -- aeson -- array -- async -- QuickCheck -- quickcheck-text -- quickcheck-instances -- brick -- bifunctors -- checkers -- classy-prelude -- comonad -- comonad-extras -- constraints -- containers -- criterion -- data-default -- data-interval -- deepseq -- directory -- fgl -- fgl-arbitrary -- file-embed -- filepath -- generic-arbitrary -- generic-lens -- groups -- hgeometry -- hgeometry-combinatorial -- JuicyPixels -- lens -- lifted-async -- linear -- megaparsec -- mmorph -- monad-control -- MonadRandom -- mtl -- optparse-applicative -- parallel -- parser-combinators -- pointed -- random -- random-fu -- random-extras -- random-source -- raw-strings-qq -- reflection -- Rasterific -- splitmix -- streams -- stache -- semigroups -- semigroupoids -- tomland -- transformers -- text -- text-zipper -- vector -- vty -- witherable -- yaml -- zlib - -default-extensions: -- BlockArguments -- ConstraintKinds -- DataKinds -- DeriveAnyClass -- DeriveGeneric -- DerivingStrategies -- DerivingVia -- FlexibleContexts -- FlexibleInstances -- FunctionalDependencies -- GADTSyntax -- GeneralizedNewtypeDeriving -- KindSignatures -- StandaloneKindSignatures -- LambdaCase -- MultiWayIf -- NoImplicitPrelude -- NoStarIsType -- OverloadedStrings -- PolyKinds -- RankNTypes -- ScopedTypeVariables -- TupleSections -- TypeApplications -- TypeFamilies -- TypeOperators -- ViewPatterns - -ghc-options: -- -Wall -- -fconstraint-solver-iterations=6 # Xanthous.Data, Xanthous.Command - -library: - source-dirs: src - -executable: - source-dirs: app - main: Main.hs - dependencies: - - xanthous - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - - -O2 - -tests: - test: - main: Spec.hs - source-dirs: test - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - - -O0 - dependencies: - - xanthous - - tasty - - tasty-hunit - - tasty-quickcheck - - tasty-rerun - - lens-properties - -benchmarks: - benchmark: - main: Bench.hs - source-dirs: bench - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - dependencies: - - xanthous - - criterion diff --git a/users/aspen/xanthous/pkg.nix b/users/aspen/xanthous/pkg.nix deleted file mode 100644 index f8364c467..000000000 --- a/users/aspen/xanthous/pkg.nix +++ /dev/null @@ -1,349 +0,0 @@ -{ mkDerivation -, aeson -, array -, async -, base -, bifunctors -, brick -, checkers -, classy-prelude -, comonad -, comonad-extras -, constraints -, containers -, criterion -, data-default -, data-interval -, deepseq -, directory -, fgl -, fgl-arbitrary -, file-embed -, filepath -, generic-arbitrary -, generic-lens -, groups -, hgeometry -, hgeometry-combinatorial -, hpack -, JuicyPixels -, lens -, lens-properties -, lib -, lifted-async -, linear -, megaparsec -, mmorph -, monad-control -, MonadRandom -, mtl -, optparse-applicative -, parallel -, parser-combinators -, pointed -, QuickCheck -, quickcheck-instances -, quickcheck-text -, random -, random-extras -, random-fu -, random-source -, Rasterific -, raw-strings-qq -, reflection -, semigroupoids -, semigroups -, splitmix -, stache -, streams -, tasty -, tasty-hunit -, tasty-quickcheck -, tasty-rerun -, text -, text-zipper -, tomland -, transformers -, vector -, vty -, witherable -, yaml -, zlib -}: -mkDerivation { - pname = "xanthous"; - version = "0.1.0.0"; - src = ./.; - isLibrary = true; - isExecutable = true; - libraryHaskellDepends = [ - aeson - array - async - base - bifunctors - brick - checkers - classy-prelude - comonad - comonad-extras - constraints - containers - criterion - data-default - data-interval - deepseq - directory - fgl - fgl-arbitrary - file-embed - filepath - generic-arbitrary - generic-lens - groups - hgeometry - hgeometry-combinatorial - JuicyPixels - lens - lifted-async - linear - megaparsec - mmorph - monad-control - MonadRandom - mtl - optparse-applicative - parallel - parser-combinators - pointed - QuickCheck - quickcheck-instances - quickcheck-text - random - random-extras - random-fu - random-source - Rasterific - raw-strings-qq - reflection - semigroupoids - semigroups - splitmix - stache - streams - text - text-zipper - tomland - transformers - vector - vty - witherable - yaml - zlib - ]; - libraryToolDepends = [ hpack ]; - executableHaskellDepends = [ - aeson - array - async - base - bifunctors - brick - checkers - classy-prelude - comonad - comonad-extras - constraints - containers - criterion - data-default - data-interval - deepseq - directory - fgl - fgl-arbitrary - file-embed - filepath - generic-arbitrary - generic-lens - groups - hgeometry - hgeometry-combinatorial - JuicyPixels - lens - lifted-async - linear - megaparsec - mmorph - monad-control - MonadRandom - mtl - optparse-applicative - parallel - parser-combinators - pointed - QuickCheck - quickcheck-instances - quickcheck-text - random - random-extras - random-fu - random-source - Rasterific - raw-strings-qq - reflection - semigroupoids - semigroups - splitmix - stache - streams - text - text-zipper - tomland - transformers - vector - vty - witherable - yaml - zlib - ]; - testHaskellDepends = [ - aeson - array - async - base - bifunctors - brick - checkers - classy-prelude - comonad - comonad-extras - constraints - containers - criterion - data-default - data-interval - deepseq - directory - fgl - fgl-arbitrary - file-embed - filepath - generic-arbitrary - generic-lens - groups - hgeometry - hgeometry-combinatorial - JuicyPixels - lens - lens-properties - lifted-async - linear - megaparsec - mmorph - monad-control - MonadRandom - mtl - optparse-applicative - parallel - parser-combinators - pointed - QuickCheck - quickcheck-instances - quickcheck-text - random - random-extras - random-fu - random-source - Rasterific - raw-strings-qq - reflection - semigroupoids - semigroups - splitmix - stache - streams - tasty - tasty-hunit - tasty-quickcheck - tasty-rerun - text - text-zipper - tomland - transformers - vector - vty - witherable - yaml - zlib - ]; - benchmarkHaskellDepends = [ - aeson - array - async - base - bifunctors - brick - checkers - classy-prelude - comonad - comonad-extras - constraints - containers - criterion - data-default - data-interval - deepseq - directory - fgl - fgl-arbitrary - file-embed - filepath - generic-arbitrary - generic-lens - groups - hgeometry - hgeometry-combinatorial - JuicyPixels - lens - lifted-async - linear - megaparsec - mmorph - monad-control - MonadRandom - mtl - optparse-applicative - parallel - parser-combinators - pointed - QuickCheck - quickcheck-instances - quickcheck-text - random - random-extras - random-fu - random-source - Rasterific - raw-strings-qq - reflection - semigroupoids - semigroups - splitmix - stache - streams - text - text-zipper - tomland - transformers - vector - vty - witherable - yaml - zlib - ]; - prePatch = "hpack"; - homepage = "https://github.com/glittershark/xanthous#readme"; - description = "A WIP TUI RPG"; - license = lib.licenses.gpl3Only; -} diff --git a/users/aspen/xanthous/server/.envrc b/users/aspen/xanthous/server/.envrc deleted file mode 100644 index 051d09d29..000000000 --- a/users/aspen/xanthous/server/.envrc +++ /dev/null @@ -1 +0,0 @@ -eval "$(lorri direnv)" diff --git a/users/aspen/xanthous/server/.gitignore b/users/aspen/xanthous/server/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/users/aspen/xanthous/server/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/users/aspen/xanthous/server/Cargo.lock b/users/aspen/xanthous/server/Cargo.lock deleted file mode 100644 index 173298b15..000000000 --- a/users/aspen/xanthous/server/Cargo.lock +++ /dev/null @@ -1,1874 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "ctr", - "opaque-debug", -] - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "0.7.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" -dependencies = [ - "memchr", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "atomic-shim" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cd4b51d303cf3501c301e8125df442128d3c6d7c69f71b27833d253de47e77" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64ct" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" - -[[package]] -name = "bcrypt-pbkdf" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c38c03b9506bd92bf1ef50665a81eda156f615438f7654bffba58907e6149d7" -dependencies = [ - "blowfish", - "crypto-mac", - "pbkdf2", - "sha2", - "zeroize", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block-modes" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" -dependencies = [ - "block-padding", - "cipher", -] - -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "blowfish" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3ff3fc1de48c1ac2e3341c4df38b0d1bfb8fdf04632a187c8b75aaa319a7ab" -dependencies = [ - "byteorder", - "cipher", - "opaque-debug", -] - -[[package]] -name = "bumpalo" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" -dependencies = [ - "iana-time-zone", - "num-integer", - "num-traits", - "winapi", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "clap" -version = "3.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750" -dependencies = [ - "atty", - "bitflags", - "clap_derive", - "clap_lex", - "indexmap", - "once_cell", - "strsim", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap_derive" -version = "3.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "color-eyre" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f1885697ee8a177096d42f158922251a41973117f6d8a234cee94b9509157b7" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6eee477a4a8a72f4addd4de416eb56d54bc307b284d6601bafdee1f4ea462d1" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "cpufeatures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "cryptovec" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc7fa13a6bbb2322d325292c57f4c8e7291595506f8289968a0eb61c3130bdf" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "ctr" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" -dependencies = [ - "cipher", -] - -[[package]] -name = "dashmap" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" -dependencies = [ - "cfg-if", - "num_cpus", -] - -[[package]] -name = "data-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - -[[package]] -name = "dirs" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" - -[[package]] -name = "eyre" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "fastrand" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] - -[[package]] -name = "flate2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "futures" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f21eda599937fba36daeb58a22e8f5cee2d14c4a17b5b7739c7c8e5e3b8230c" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdd20c28fadd505d0fd6712cdfcb0d4b5648baf45faef7f852afb2399bb050" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e5aa3de05362c3fb88de6531e6296e85cde7739cccad4b9dfeeb7f6ebce56bf" - -[[package]] -name = "futures-executor" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff63c23854bee61b6e9cd331d523909f238fc7636290b96826e9cfa5faa00ab" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf4d2a7a308fd4578637c0b17c7e1c7ba127b8f6ba00b29f717e9655d85eb68" - -[[package]] -name = "futures-macro" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cd15d1c7456c04dbdf7e88bcd69760d74f3a798d6444e16974b505b0e62f17" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b20ba5a92e727ba30e72834706623d94ac93a725410b6a6b6fbc1b07f7ba56" - -[[package]] -name = "futures-task" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6508c467c73851293f390476d4491cf4d227dbabcd4170f3bb6044959b294f1" - -[[package]] -name = "futures-util" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44fb6cb1be61cc1d2e43b262516aafcf63b241cffdb1d3fa115f91d9c7b09c90" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "gimli" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest", -] - -[[package]] -name = "http" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "hyper" -version = "0.14.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd911b35d940d2bd0bea0f9100068e5b97b51a1cbe13d13382f132e0365257a0" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "ipnet" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b" - -[[package]] -name = "itoa" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.134" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" - -[[package]] -name = "libsodium-sys" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b779387cd56adfbc02ea4a668e704f729be8d6a6abd2c27ca5ee537849a92fd" -dependencies = [ - "cc", - "libc", - "pkg-config", - "walkdir", -] - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "mach" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" -dependencies = [ - "libc", -] - -[[package]] -name = "matchers" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "md5" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "metrics" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55586aa936c35f34ba8aa5d97356d554311206e1ce1f9e68fe7b07288e5ad827" -dependencies = [ - "ahash", - "metrics-macros", -] - -[[package]] -name = "metrics-exporter-prometheus" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343a5ceb38235928e7a5687412590f07e6d281522dcd9ff51246f8856eef5fe5" -dependencies = [ - "hyper", - "ipnet", - "metrics", - "metrics-util", - "parking_lot", - "quanta", - "thiserror", - "tokio", -] - -[[package]] -name = "metrics-macros" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0daa0ab3a0ae956d0e2c1f42511422850e577d36a255357d1a7d08d45ee3a2f1" -dependencies = [ - "lazy_static", - "proc-macro2", - "quote", - "regex", - "syn", -] - -[[package]] -name = "metrics-util" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1174223789e331d9d47a4a953dac36e397db60fa8d2a111ac505388c6c7fe32e" -dependencies = [ - "ahash", - "aho-corasick", - "atomic-shim", - "crossbeam-epoch", - "crossbeam-utils", - "dashmap", - "hashbrown 0.11.2", - "indexmap", - "metrics", - "num_cpus", - "ordered-float", - "parking_lot", - "quanta", - "radix_trie", - "sketches-ddsketch", -] - -[[package]] -name = "miniz_oxide" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" -dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", -] - -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - -[[package]] -name = "nix" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "ordered-float" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" -dependencies = [ - "num-traits", -] - -[[package]] -name = "os_str_bytes" -version = "6.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" - -[[package]] -name = "owo-colors" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "password-hash" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "pbkdf2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95f5254224e617595d2cc3cc73ff0a5eaf2637519e25f03388154e9378b6ffa" -dependencies = [ - "base64ct", - "crypto-mac", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quanta" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20afe714292d5e879d8b12740aa223c6a88f118af41870e8b6196e39a02238a8" -dependencies = [ - "crossbeam-utils", - "libc", - "mach", - "once_cell", - "raw-cpuid", - "wasi 0.10.2+wasi-snapshot-preview1", - "web-sys", - "winapi", -] - -[[package]] -name = "quote" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radix_trie" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" -dependencies = [ - "endian-type", - "nibble_vec", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "raw-cpuid" -version = "10.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6823ea29436221176fe662da99998ad3b4db2c7f31e7b6f5fe43adccd6320bb" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" -dependencies = [ - "getrandom", - "redox_syscall", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "serde" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" - -[[package]] -name = "serde_derive" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer", - "cfg-if", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - -[[package]] -name = "sketches-ddsketch" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d2ecae5fcf33b122e2e6bd520a57ccf152d2dde3b38c71039df1a6867264ee" - -[[package]] -name = "slab" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" - -[[package]] -name = "socket2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16" - -[[package]] -name = "thiserror" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "thrussh" -version = "0.33.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6540238a9adf83df6e66541c182a52acf892ab335595ca965c229ade8536f8" -dependencies = [ - "bitflags", - "byteorder", - "cryptovec", - "digest", - "flate2", - "futures", - "generic-array", - "log", - "rand", - "sha2", - "thiserror", - "thrussh-keys", - "thrussh-libsodium", - "tokio", -] - -[[package]] -name = "thrussh-keys" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a72cc51a2932b18d92f7289332d8564cec4a5014063722a9d3fdca52c5d8f5ab" -dependencies = [ - "aes", - "bcrypt-pbkdf", - "bit-vec", - "block-modes", - "byteorder", - "cryptovec", - "data-encoding", - "dirs", - "futures", - "hmac", - "log", - "md5", - "num-bigint", - "num-integer", - "pbkdf2", - "rand", - "serde", - "serde_derive", - "sha2", - "thiserror", - "thrussh-libsodium", - "tokio", - "tokio-stream", - "yasna", -] - -[[package]] -name = "thrussh-libsodium" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe89c70d27b1cb92e13bc8af63493e890d0de46dae4df0e28233f62b4ed9500" -dependencies = [ - "lazy_static", - "libc", - "libsodium-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "tokio" -version = "1.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" -dependencies = [ - "autocfg", - "bytes", - "libc", - "memchr", - "mio", - "num_cpus", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "winapi", -] - -[[package]] -name = "tokio-macros" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-stream" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6edf2d6bc038a43d31353570e27270603f4648d18f5ed10c0e179abe43255af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4d7c0b83d4a500748fa5879461652b361edf5c9d51ede2a2ac03875ca185e24" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-serde" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "ansi_term", - "chrono", - "lazy_static", - "matchers", - "regex", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", - "tracing-serde", -] - -[[package]] -name = "try-lock" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "unicode-ident" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - -[[package]] -name = "xanthous-server" -version = "0.1.0" -dependencies = [ - "base64ct", - "clap", - "color-eyre", - "eyre", - "futures", - "libc", - "metrics", - "metrics-exporter-prometheus", - "nix", - "pbkdf2", - "tempfile", - "thrussh", - "thrussh-keys", - "tokio", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "yasna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e262a29d0e61ccf2b6190d7050d4b237535fc76ce4c1210d9caa316f71dffa75" -dependencies = [ - "bit-vec", - "num-bigint", -] - -[[package]] -name = "zeroize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" diff --git a/users/aspen/xanthous/server/Cargo.toml b/users/aspen/xanthous/server/Cargo.toml deleted file mode 100644 index d4a064beb..000000000 --- a/users/aspen/xanthous/server/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -name = "xanthous-server" -version = "0.1.0" -edition = "2018" - -[dependencies] -clap = { version = "3.0", features = [ "derive", "env" ] } -color-eyre = "0.5.11" -eyre = "0.6.5" -thrussh = "0.33.5" -thrussh-keys = "0.21.0" -tracing = "0.1.29" -tracing-subscriber = "0.2.25" -metrics = "0.17.0" -metrics-exporter-prometheus = "0.6.1" -futures = "0.3.17" -libc = "0.2.103" -nix = "0.23.0" - -# Pins for rust 1.55 (2018 edition) until we have 1.56 in nixpkgs-unstable -pbkdf2 = "<0.9" -base64ct = "<1.2" - -[dependencies.tokio] -version = "1.13" -features = ["rt", "rt-multi-thread", "macros", "net", "process", "fs", "signal"] - -[dev-dependencies] -tempfile = "3.2.0" diff --git a/users/aspen/xanthous/server/default.nix b/users/aspen/xanthous/server/default.nix deleted file mode 100644 index 572230a56..000000000 --- a/users/aspen/xanthous/server/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -args@{ depot ? import ../../../.. { } -, pkgs ? depot.third_party.nixpkgs -, ... -}: - -depot.third_party.naersk.buildPackage { - name = "xanthous-server"; - version = "0.0.1"; - src = depot.third_party.gitignoreSource ./.; - - # Workaround for a potential Nix bug related to restricted eval. - # See https://github.com/nix-community/naersk/issues/169 - root = depot.nix.sparseTree { - root = ./.; - paths = [ - ./Cargo.toml - ./Cargo.lock - ]; - }; - - passthru = { - docker = import ./docker.nix args; - }; -} diff --git a/users/aspen/xanthous/server/docker.nix b/users/aspen/xanthous/server/docker.nix deleted file mode 100644 index 5eaef4553..000000000 --- a/users/aspen/xanthous/server/docker.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ depot ? import ../../../.. { } -, pkgs ? depot.third_party.nixpkgs -, ... -}: - -let - inherit (depot.users.aspen) xanthous; - xanthous-server = xanthous.server; -in -pkgs.dockerTools.buildLayeredImage { - name = "xanthous-server"; - tag = "latest"; - contents = [ xanthous xanthous-server ]; - config = { - Cmd = [ - "${xanthous-server}/bin/xanthous-server" - "--xanthous-binary-path" - "${xanthous}/bin/xanthous" - ]; - }; -} diff --git a/users/aspen/xanthous/server/module.nix b/users/aspen/xanthous/server/module.nix deleted file mode 100644 index 8950f2e8d..000000000 --- a/users/aspen/xanthous/server/module.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ config, lib, pkgs, depot, ... }: - -let - cfg = config.services.xanthous-server; -in -{ - options = with lib; { - services.xanthous-server = { - enable = mkEnableOption "xanthous server"; - - port = mkOption { - type = types.int; - default = 2222; - description = "Port to listen to for SSH connections"; - }; - - metricsPort = mkOption { - type = types.int; - default = 9000; - description = "Port to listen to for prometheus metrics"; - }; - - image = mkOption { - type = types.package; - default = depot.users.aspen.xanthous.server.docker; - description = "OCI image file to run"; - }; - - ed25519SecretKeyFile = mkOption { - type = with types; uniq str; - description = "Path to the ed25519 secret key for the server"; - }; - }; - }; - - config = lib.mkIf cfg.enable { - virtualisation.oci-containers.containers."xanthous-server" = { - autoStart = true; - image = "${cfg.image.imageName}:${cfg.image.imageTag}"; - imageFile = cfg.image; - ports = [ - "${toString cfg.port}:22" - "${toString cfg.metricsPort}:9000" - ]; - environment.SECRET_KEY_FILE = "/secret-key"; - volumes = [ "/etc/secrets/xanthous-server-secret-key:/secret-key" ]; - }; - }; -} diff --git a/users/aspen/xanthous/server/shell.nix b/users/aspen/xanthous/server/shell.nix deleted file mode 100644 index e01c0316a..000000000 --- a/users/aspen/xanthous/server/shell.nix +++ /dev/null @@ -1,11 +0,0 @@ -let - depot = import ../../../.. { }; - pkgs = depot.third_party.nixpkgs; -in - -pkgs.mkShell { - buildInputs = with pkgs; [ - rustup - rust-analyzer - ]; -} diff --git a/users/aspen/xanthous/server/src/main.rs b/users/aspen/xanthous/server/src/main.rs deleted file mode 100644 index 1b2c1c104..000000000 --- a/users/aspen/xanthous/server/src/main.rs +++ /dev/null @@ -1,385 +0,0 @@ -use std::net::SocketAddr; -use std::path::PathBuf; -use std::pin::Pin; -use std::process::Command; -use std::str; -use std::sync::Arc; - -use clap::Parser; -use color_eyre::eyre::Result; -use eyre::{bail, Context}; -use futures::future::{ready, Ready}; -use futures::Future; -use metrics_exporter_prometheus::PrometheusBuilder; -use nix::pty::Winsize; -use pty::ChildHandle; -use thrussh::server::{self, Auth, Session}; -use thrussh::{ChannelId, CryptoVec}; -use thrussh_keys::decode_secret_key; -use thrussh_keys::key::KeyPair; -use tokio::fs::File; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio::net::TcpListener; -use tokio::select; -use tokio::time::Instant; -use tracing::{debug, error, info, info_span, trace, warn, Instrument}; -use tracing_subscriber::EnvFilter; - -use crate::pty::WaitPid; - -mod metrics; -mod pty; - -use crate::metrics::reported::*; -use crate::metrics::{decrement_gauge, histogram, increment_counter, increment_gauge}; - -/// SSH-compatible server for playing Xanthous -#[derive(Parser, Debug)] -struct Opts { - /// Address to bind to - #[clap(long, short = 'a', default_value = "0.0.0.0:22")] - address: String, - - /// Address to listen to for metrics - #[clap(long, default_value = "0.0.0.0:9000")] - metrics_address: SocketAddr, - - /// Format to use when emitting log events - #[clap( - long, - env = "LOG_FORMAT", - default_value = "full", - possible_values = &["compact", "full", "pretty", "json"] - )] - log_format: String, - - /// Full path to the xanthous binary - #[clap(long, env = "XANTHOUS_BINARY_PATH")] - xanthous_binary_path: String, - - /// Path to a file containing the ed25519 secret key for the server - #[clap(long, env = "SECRET_KEY_FILE")] - secret_key_file: PathBuf, - - /// Level to log at - #[clap(long, env = "LOG_LEVEL", default_value = "info")] - log_level: String, -} - -impl Opts { - async fn read_secret_key(&self) -> Result { - let mut file = File::open(&self.secret_key_file) - .await - .context("Reading secret key file")?; - let mut secret_key = Vec::with_capacity(464); - file.read_to_end(&mut secret_key).await?; - Ok(decode_secret_key(str::from_utf8(&secret_key)?, None)?) - } - - async fn ssh_server_config(&self) -> Result { - let key_pair = self.read_secret_key().await?; - - Ok(server::Config { - server_id: "SSH-2.0-xanthous".to_owned(), - keys: vec![key_pair], - ..Default::default() - }) - } - - fn init_logging(&self) -> Result<()> { - let filter = EnvFilter::try_new(&self.log_level)?; - let s = tracing_subscriber::fmt().with_env_filter(filter); - - match self.log_format.as_str() { - "compact" => s.compact().init(), - "full" => s.init(), - "pretty" => s.pretty().init(), - "json" => s.json().with_current_span(true).init(), - f => bail!("Invalid log format `{}`", f), - } - - Ok(()) - } -} - -struct Handler { - address: SocketAddr, - xanthous_binary_path: &'static str, - username: Option, - child: Option, -} - -async fn run_child( - mut child: pty::Child, - mut server_handle: server::Handle, - channel_id: ChannelId, -) -> Result<()> { - let mut buf = [0; 2048]; - loop { - select! { - r = child.tty.read(&mut buf) => { - let read_bytes = r?; - if read_bytes == 0 { - info!("EOF received from process"); - let _ = server_handle.close(channel_id).await; - return Ok(()) - } else { - trace!(?read_bytes, "read bytes from child"); - let _ = server_handle.data(channel_id, CryptoVec::from_slice(&buf[..read_bytes])).await; - } - } - status = WaitPid::new(child.pid) => { - match status { - Ok(_status) => info!("Child exited"), - Err(error) => error!(%error, "Child failed"), - } - let _ = server_handle.close(channel_id).await; - return Ok(()) - } - } - } -} - -impl Handler { - async fn spawn_shell( - &mut self, - mut handle: server::Handle, - channel_id: ChannelId, - term: String, - winsize: Winsize, - ) -> Result<()> { - let mut cmd = Command::new(self.xanthous_binary_path); - cmd.env("TERM", term); - if let Some(username) = &self.username { - cmd.args(["--name", username]); - } - cmd.arg("--disable-saving"); - - let child = pty::spawn(cmd, Some(winsize), None).await?; - info!(pid = %child.pid, "Spawned child"); - increment_gauge!(RUNNING_PROCESSES, 1.0); - self.child = Some(child.handle().await?); - tokio::spawn( - async move { - let span = info_span!("child", pid = %child.pid); - if let Err(error) = run_child(child, handle.clone(), channel_id) - .instrument(span.clone()) - .await - { - span.in_scope(|| error!(%error, "Error running child")); - let _ = handle.close(channel_id).await; - } - decrement_gauge!(RUNNING_PROCESSES, 1.0); - } - .in_current_span(), - ); - Ok(()) - } -} - -#[allow(clippy::type_complexity)] -impl server::Handler for Handler { - type Error = eyre::Error; - type FutureAuth = Ready>; - type FutureUnit = Pin> + Send + 'static>>; - type FutureBool = Ready>; - - fn finished_auth(self, auth: Auth) -> Self::FutureAuth { - ready(Ok((self, auth))) - } - - fn finished_bool(self, b: bool, session: Session) -> Self::FutureBool { - ready(Ok((self, session, b))) - } - - fn finished(self, session: Session) -> Self::FutureUnit { - Box::pin(ready(Ok((self, session)))) - } - - fn auth_none(mut self, username: &str) -> Self::FutureAuth { - info!(%username, "Accepted new connection"); - self.username = Some(username.to_owned()); - self.finished_auth(Auth::Accept) - } - - fn auth_password(mut self, username: &str, _password: &str) -> Self::FutureAuth { - info!(%username, "Accepted new connection"); - self.username = Some(username.to_owned()); - self.finished_auth(Auth::Accept) - } - - fn auth_publickey( - mut self, - username: &str, - _: &thrussh_keys::key::PublicKey, - ) -> Self::FutureAuth { - info!(%username, "Accepted new connection"); - self.username = Some(username.to_owned()); - self.finished_auth(Auth::Accept) - } - - fn pty_request( - mut self, - channel: thrussh::ChannelId, - term: &str, - col_width: u32, - row_height: u32, - pix_width: u32, - pix_height: u32, - modes: &[(thrussh::Pty, u32)], - session: Session, - ) -> Self::FutureUnit { - let term = term.to_owned(); - let modes = modes.to_vec(); - Box::pin(async move { - debug!( - %term, - %col_width, - %row_height, - %pix_width, - %pix_height, - ?modes, - "PTY Requested" - ); - - self.spawn_shell( - session.handle(), - channel, - term, - Winsize { - ws_row: row_height as _, - ws_col: col_width as _, - ws_xpixel: pix_width as _, - ws_ypixel: pix_height as _, - }, - ) - .await?; - - Ok((self, session)) - }) - } - - fn window_change_request( - mut self, - _channel: ChannelId, - col_width: u32, - row_height: u32, - pix_width: u32, - pix_height: u32, - session: Session, - ) -> Self::FutureUnit { - Box::pin(async move { - if let Some(child) = self.child.as_mut() { - trace!(%row_height, %col_width, "Window resize request received"); - child - .resize_window(Winsize { - ws_row: row_height as _, - ws_col: col_width as _, - ws_xpixel: pix_width as _, - ws_ypixel: pix_height as _, - }) - .await?; - } else { - warn!("Resize request received without child process; ignoring"); - } - - Ok((self, session)) - }) - } - - fn data( - mut self, - _channel: thrussh::ChannelId, - data: &[u8], - session: Session, - ) -> Self::FutureUnit { - trace!(data = %String::from_utf8_lossy(data), raw_data = ?data); - let data = data.to_owned(); - Box::pin(async move { - if let Some(child) = self.child.as_mut() { - child.write_all(&data).await?; - } else { - warn!("Data received without child process; ignoring"); - } - - Ok((self, session)) - }) - } -} - -#[tokio::main] -async fn main() -> Result<()> { - color_eyre::install()?; - let opts = Box::leak::<'static>(Box::new(Opts::parse())); - opts.init_logging()?; - PrometheusBuilder::new() - .listen_address(opts.metrics_address) - .install()?; - metrics::register(); - - let config = Arc::new(opts.ssh_server_config().await?); - info!(address = %opts.address, "Listening for new SSH connections"); - let listener = TcpListener::bind(&opts.address).await?; - - loop { - let (stream, address) = listener.accept().await?; - increment_counter!(CONNECTIONS_ACCEPTED); - increment_gauge!(ACTIVE_CONNECTIONS, 1.0); - let config = config.clone(); - let handler = Handler { - xanthous_binary_path: &opts.xanthous_binary_path, - address, - username: None, - child: None, - }; - tokio::spawn(async move { - let span = info_span!("client", address = %handler.address); - let start = Instant::now(); - if let Err(error) = server::run_stream(config, stream, handler) - .instrument(span.clone()) - .await - { - span.in_scope(|| error!(%error)); - } - let duration = start.elapsed(); - span.in_scope(|| info!(duration_ms = %duration.as_millis(), "Client disconnected")); - histogram!(CONNECTION_DURATION, duration); - decrement_gauge!(ACTIVE_CONNECTIONS, 1.0); - }); - } -} - -#[cfg(test)] -mod tests { - use tempfile::NamedTempFile; - - use super::*; - - #[tokio::test] - async fn read_secret_key() { - use std::io::Write; - - let mut file = NamedTempFile::new().unwrap(); - file.write_all( - b" ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACAYz80xcK7jYxZMAl6apIHKRtB0Z2U78gG39c1QaIhgMwAAAJB9vxK9fb8S -vQAAAAtzc2gtZWQyNTUxOQAAACAYz80xcK7jYxZMAl6apIHKRtB0Z2U78gG39c1QaIhgMw -AAAEDNZ0d3lLNBGU6Im4JOpr490TOjm+cB7kMVXjVg3iCowBjPzTFwruNjFkwCXpqkgcpG -0HRnZTvyAbf1zVBoiGAzAAAACHRlc3Qta2V5AQIDBAU= ------END OPENSSH PRIVATE KEY----- -", - ) - .unwrap(); - - let opts: Opts = Opts::parse_from(&[ - "xanthous-server".as_ref(), - "--xanthous-binary-path".as_ref(), - "/bin/xanthous".as_ref(), - "--secret-key-file".as_ref(), - file.path().as_os_str(), - ]); - opts.read_secret_key().await.unwrap(); - } -} diff --git a/users/aspen/xanthous/server/src/metrics.rs b/users/aspen/xanthous/server/src/metrics.rs deleted file mode 100644 index 6912cdd9c..000000000 --- a/users/aspen/xanthous/server/src/metrics.rs +++ /dev/null @@ -1,24 +0,0 @@ -pub use ::metrics::*; - -pub mod reported { - /// Counter: Connections accepted on the TCP listener - pub const CONNECTIONS_ACCEPTED: &str = "ssh.connections.accepted"; - - /// Histogram: Connection duration - pub const CONNECTION_DURATION: &str = "ssh.connections.duration"; - - /// Gauge: Currently active connections - pub const ACTIVE_CONNECTIONS: &str = "ssh.connections.active"; - - /// Gauge: Currently running xanthous processes - pub const RUNNING_PROCESSES: &str = "ssh.child.processes"; -} - -pub fn register() { - use reported::*; - - register_counter!(CONNECTIONS_ACCEPTED); - register_histogram!(CONNECTION_DURATION); - register_gauge!(ACTIVE_CONNECTIONS); - register_gauge!(RUNNING_PROCESSES); -} diff --git a/users/aspen/xanthous/server/src/pty.rs b/users/aspen/xanthous/server/src/pty.rs deleted file mode 100644 index 234ecd8f2..000000000 --- a/users/aspen/xanthous/server/src/pty.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::io::{self}; -use std::os::unix::prelude::{AsRawFd, CommandExt, FromRawFd}; -use std::pin::Pin; -use std::process::{abort, Command}; -use std::task::{Context, Poll}; - -use eyre::{bail, Result}; -use futures::Future; -use nix::pty::{forkpty, Winsize}; -use nix::sys::termios::Termios; -use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus}; -use nix::unistd::{ForkResult, Pid}; -use tokio::fs::File; -use tokio::io::{AsyncRead, AsyncWrite}; -use tokio::signal::unix::{signal, Signal, SignalKind}; -use tokio::task::spawn_blocking; - -mod ioctl { - use super::Winsize; - use libc::TIOCSWINSZ; - use nix::ioctl_write_ptr_bad; - - ioctl_write_ptr_bad!(tiocswinsz, TIOCSWINSZ, Winsize); -} - -async fn asyncify(f: F) -> Result -where - F: FnOnce() -> Result + Send + 'static, - T: Send + 'static, -{ - match spawn_blocking(f).await { - Ok(res) => res, - Err(_) => bail!("background task failed",), - } -} - -pub struct Child { - pub tty: File, - pub pid: Pid, -} - -pub struct ChildHandle { - pub tty: File, -} - -pub struct WaitPid { - pid: Pid, - signal: Signal, -} - -impl WaitPid { - pub fn new(pid: Pid) -> Self { - Self { - pid, - signal: signal(SignalKind::child()).unwrap(), - } - } -} - -impl Future for WaitPid { - type Output = nix::Result; - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let _ = self.signal.poll_recv(cx); - match waitpid(self.pid, Some(WaitPidFlag::WNOHANG)) { - Ok(WaitStatus::StillAlive) => Poll::Pending, - result => Poll::Ready(result), - } - } -} - -impl Child { - pub async fn handle(&self) -> io::Result { - Ok(ChildHandle { - tty: self.tty.try_clone().await?, - }) - } -} - -impl ChildHandle { - pub async fn resize_window(&mut self, winsize: Winsize) -> Result<()> { - let fd = self.tty.as_raw_fd(); - asyncify(move || unsafe { - ioctl::tiocswinsz(fd, &winsize as *const Winsize)?; - Ok(()) - }) - .await - } -} - -pub async fn spawn( - mut cmd: Command, - winsize: Option, - termios: Option, -) -> Result { - asyncify(move || unsafe { - let res = forkpty(winsize.as_ref(), termios.as_ref())?; - match res.fork_result { - ForkResult::Parent { child } => Ok(Child { - pid: child, - tty: File::from_raw_fd(res.master), - }), - ForkResult::Child => { - cmd.exec(); - abort(); - } - } - }) - .await -} - -impl AsyncRead for Child { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut tokio::io::ReadBuf<'_>, - ) -> Poll> { - Pin::new(&mut self.tty).poll_read(cx, buf) - } -} - -impl AsyncWrite for Child { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Pin::new(&mut self.tty).poll_write(cx, buf) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.tty).poll_flush(cx) - } - - fn poll_shutdown( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - Pin::new(&mut self.tty).poll_shutdown(cx) - } -} - -impl AsyncRead for ChildHandle { - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut tokio::io::ReadBuf<'_>, - ) -> Poll> { - Pin::new(&mut self.tty).poll_read(cx, buf) - } -} - -impl AsyncWrite for ChildHandle { - fn poll_write( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - Pin::new(&mut self.tty).poll_write(cx, buf) - } - - fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - Pin::new(&mut self.tty).poll_flush(cx) - } - - fn poll_shutdown( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - ) -> Poll> { - Pin::new(&mut self.tty).poll_shutdown(cx) - } -} diff --git a/users/aspen/xanthous/shell.nix b/users/aspen/xanthous/shell.nix deleted file mode 100644 index 2c41cb4aa..000000000 --- a/users/aspen/xanthous/shell.nix +++ /dev/null @@ -1,23 +0,0 @@ -let - depot = import ../../../. { }; - inherit (depot) third_party; - pkgs = third_party.nixpkgs; -in - -(pkgs.haskell.packages.ghc8107.extend (pkgs.haskell.lib.packageSourceOverrides { - xanthous = third_party.gitignoreSource ./.; -})).shellFor { - packages = p: [ p.xanthous ]; - withHoogle = true; - doBenchmark = true; - buildInputs = (with pkgs.haskell.packages.ghc8107; [ - cabal-install - ghc-prof-flamegraph - hp2pretty - hlint - haskell-language-server - cabal2nix - ]) ++ (with pkgs; [ - qpdf - ]); -} diff --git a/users/aspen/xanthous/src/Data/Aeson/Generic/DerivingVia.hs b/users/aspen/xanthous/src/Data/Aeson/Generic/DerivingVia.hs deleted file mode 100644 index e89fcd621..000000000 --- a/users/aspen/xanthous/src/Data/Aeson/Generic/DerivingVia.hs +++ /dev/null @@ -1,168 +0,0 @@ -{-# LANGUAGE ConstraintKinds, DataKinds, DeriveGeneric, DerivingVia #-} -{-# LANGUAGE ExplicitNamespaces, FlexibleContexts, FlexibleInstances #-} -{-# LANGUAGE GADTs, GeneralizedNewtypeDeriving, MultiParamTypeClasses #-} -{-# LANGUAGE PolyKinds, ScopedTypeVariables, StandaloneDeriving #-} -{-# LANGUAGE TypeApplications, TypeFamilies, TypeInType, TypeOperators #-} -{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -Wall #-} --- | https://gist.github.com/konn/27c00f784dd883ec2b90eab8bc84a81d -module Data.Aeson.Generic.DerivingVia - ( StrFun(..), Setting(..), SumEncoding'(..), DefaultOptions, WithOptions(..) - , -- Utility type synonyms to save ticks (') before promoted data constructors - type Drop, type CamelTo2, type UserDefined - , type TaggedObj, type UntaggedVal, type ObjWithSingleField, type TwoElemArr - , type FieldLabelModifier - , type ConstructorTagModifier - , type AllNullaryToStringTag - , type OmitNothingFields - , type SumEnc - , type UnwrapUnaryRecords - , type TagSingleConstructors - ) - where - -import Prelude -import Data.Aeson (FromJSON (..), GFromJSON, GToJSON, - ToJSON (..)) -import Data.Aeson (Options (..), Zero, camelTo2, - genericParseJSON) -import Data.Aeson (defaultOptions, genericToJSON) -import qualified Data.Aeson as Aeson -import Data.Kind (Constraint, Type) -import Data.Proxy (Proxy (..)) -import Data.Reflection (Reifies (..)) -import GHC.Generics (Generic, Rep) -import GHC.TypeLits (KnownNat, KnownSymbol, natVal, symbolVal) -import GHC.TypeLits (Nat, Symbol) - -newtype WithOptions options a = WithOptions { runWithOptions :: a } - -data StrFun = Drop Nat - | CamelTo2 Symbol - | forall p. UserDefined p - -type Drop = 'Drop -type CamelTo2 = 'CamelTo2 -type UserDefined = 'UserDefined - -type family Demoted a where - Demoted Symbol = String - Demoted StrFun = String -> String - Demoted [a] = [Demoted a] - Demoted Setting = Options -> Options - Demoted SumEncoding' = Aeson.SumEncoding - Demoted a = a - -data SumEncoding' = TaggedObj {tagFieldName' :: Symbol, contentsFieldName :: Symbol } - | UntaggedVal - | ObjWithSingleField - | TwoElemArr - -type TaggedObj = 'TaggedObj -type UntaggedVal = 'UntaggedVal -type ObjWithSingleField = 'ObjWithSingleField -type TwoElemArr = 'TwoElemArr - -data Setting = FieldLabelModifier [StrFun] - | ConstructorTagModifier [StrFun] - | AllNullaryToStringTag Bool - | OmitNothingFields Bool - | SumEnc SumEncoding' - | UnwrapUnaryRecords Bool - | TagSingleConstructors Bool - -type FieldLabelModifier = 'FieldLabelModifier -type ConstructorTagModifier = 'ConstructorTagModifier --- | If 'True' the constructors of a datatype, with all nullary constructors, --- will be encoded to just a string with the constructor tag. If 'False' the --- encoding will always follow the 'SumEncoding'. -type AllNullaryToStringTag = 'AllNullaryToStringTag -type OmitNothingFields = 'OmitNothingFields -type SumEnc = 'SumEnc --- | Hide the field name when a record constructor has only one field, like a --- newtype. -type UnwrapUnaryRecords = 'UnwrapUnaryRecords --- | Encode types with a single constructor as sums, so that --- 'AllNullaryToStringTag' and 'SumEncoding' apply. -type TagSingleConstructors = 'TagSingleConstructors - -class Demotable (a :: k) where - demote :: proxy a -> Demoted k - -type All :: (Type -> Constraint) -> [Type] -> Constraint -type family All p xs where - All p '[] = () - All p (x ': xs) = (p x, All p xs) - -instance Reifies f (String -> String) => Demotable ('UserDefined f) where - demote _ = reflect @f Proxy - -instance KnownSymbol sym => Demotable sym where - demote = symbolVal - -instance (KnownSymbol s, KnownSymbol t) => Demotable ('TaggedObj s t) where - demote _ = Aeson.TaggedObject (symbolVal @s Proxy) (symbolVal @t Proxy) - -instance Demotable 'UntaggedVal where - demote _ = Aeson.UntaggedValue - -instance Demotable 'ObjWithSingleField where - demote _ = Aeson.ObjectWithSingleField - -instance Demotable 'TwoElemArr where - demote _ = Aeson.TwoElemArray - -instance Demotable xs => Demotable ('FieldLabelModifier xs) where - demote _ o = o { fieldLabelModifier = foldr (.) id (demote (Proxy @xs)) } - -instance Demotable xs => Demotable ('ConstructorTagModifier xs) where - demote _ o = o { constructorTagModifier = foldr (.) id (demote (Proxy @xs)) } - -instance Demotable b => Demotable ('AllNullaryToStringTag b) where - demote _ o = o { allNullaryToStringTag = demote (Proxy @b) } - -instance Demotable b => Demotable ('OmitNothingFields b) where - demote _ o = o { omitNothingFields = demote (Proxy @b) } - -instance Demotable b => Demotable ('UnwrapUnaryRecords b) where - demote _ o = o { unwrapUnaryRecords = demote (Proxy @b) } - -instance Demotable b => Demotable ('TagSingleConstructors b) where - demote _ o = o { tagSingleConstructors = demote (Proxy @b) } - -instance Demotable b => Demotable ('SumEnc b) where - demote _ o = o { sumEncoding = demote (Proxy @b) } - -instance Demotable 'True where - demote _ = True - -instance Demotable 'False where - demote _ = False - -instance KnownNat n => Demotable ('Drop n) where - demote _ = drop (fromIntegral $ natVal (Proxy :: Proxy n)) - -instance KnownSymbol sym => Demotable ('CamelTo2 sym) where - demote _ = camelTo2 $ head $ symbolVal @sym Proxy - -instance {-# OVERLAPPING #-} Demotable ('[] :: [k]) where - demote _ = [] - -instance (Demotable (x :: k), Demotable (xs :: [k])) => Demotable (x ': xs) where - demote _ = demote (Proxy @x) : demote (Proxy @xs) - -type DefaultOptions = ('[] :: [Setting]) - -reflectOptions :: forall xs proxy. Demotable (xs :: [Setting]) => proxy xs -> Options -reflectOptions pxy = foldr (.) id (demote pxy) defaultOptions - -instance (Demotable (options :: [Setting])) => Reifies options Options where - reflect = reflectOptions - -instance (Generic a, GToJSON Zero (Rep a), Reifies (options :: k) Options) - => ToJSON (WithOptions options a) where - toJSON = genericToJSON (reflect (Proxy @options)) . runWithOptions - -instance (Generic a, GFromJSON Zero (Rep a), Reifies (options :: k) Options) - => FromJSON (WithOptions options a) where - parseJSON = fmap WithOptions . genericParseJSON (reflect (Proxy @options)) diff --git a/users/aspen/xanthous/src/Xanthous/AI/Gormlak.hs b/users/aspen/xanthous/src/Xanthous/AI/Gormlak.hs deleted file mode 100644 index 1f2b513ff..000000000 --- a/users/aspen/xanthous/src/Xanthous/AI/Gormlak.hs +++ /dev/null @@ -1,201 +0,0 @@ -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE UndecidableInstances #-} --------------------------------------------------------------------------------- -module Xanthous.AI.Gormlak - ( HasVisionRadius(..) - , GormlakBrain(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (lines) --------------------------------------------------------------------------------- -import Control.Monad.State -import Control.Monad.Random -import Data.Aeson (object) -import qualified Data.Aeson as A -import Data.Generics.Product.Fields --------------------------------------------------------------------------------- -import Xanthous.Data - ( Positioned(..), positioned, position, _Position - , diffPositions, stepTowards, isUnit - , Ticks, (|*|), invertedRate - ) -import Xanthous.Data.EntityMap -import Xanthous.Entities.Creature.Hippocampus -import Xanthous.Entities.Character (Character) -import qualified Xanthous.Entities.Character as Character -import qualified Xanthous.Entities.RawTypes as Raw -import Xanthous.Entities.RawTypes - ( CreatureType, HasLanguage(language), getLanguage - , HasAttacks (attacks), creatureAttackMessage - ) -import Xanthous.Entities.Common - ( wielded, Inventory, wieldedItems, WieldedItem (WieldedItem) ) -import Xanthous.Game.State -import Xanthous.Game.Lenses - ( entitiesCollision, collisionAt - , character, characterPosition, positionIsCharacterVisible - , hearingRadius - ) -import Xanthous.Data.EntityMap.Graphics (linesOfSight, canSee) -import Xanthous.Random -import Xanthous.Monad (say, message) -import Xanthous.Generators.Speech (word) -import qualified Linear.Metric as Metric -import qualified Xanthous.Messages as Messages --------------------------------------------------------------------------------- - --- TODO move the following two classes to a more central location - -class HasVisionRadius a where visionRadius :: a -> Word - -type IsCreature entity = - ( HasVisionRadius entity - , HasField "_hippocampus" entity entity Hippocampus Hippocampus - , HasField "_creatureType" entity entity CreatureType CreatureType - , HasField "_inventory" entity entity Inventory Inventory - , A.ToJSON entity - ) - --------------------------------------------------------------------------------- - -stepGormlak - :: forall entity m. - ( MonadState GameState m, MonadRandom m - , IsCreature entity - ) - => Ticks - -> Positioned entity - -> m (Positioned entity) -stepGormlak ticks pe@(Positioned pos creature) = do - canSeeCharacter <- uses entities $ canSee (entityIs @Character) pos vision - - let selectDestination pos' creature' = destinationFromPos <$> do - if canSeeCharacter - then do - charPos <- use characterPosition - if isUnit (pos' `diffPositions` charPos) - then attackCharacter $> pos' - else pure $ pos' `stepTowards` charPos - else do - lines <- map (takeWhile (isNothing . entitiesCollision . map snd . snd) - -- the first item on these lines is always the creature itself - . fromMaybe mempty . tailMay) - . linesOfSight pos' (visionRadius creature') - <$> use entities - line <- choose $ weightedBy length lines - pure $ fromMaybe pos' $ fmap fst . headMay =<< line - - pe' <- if canSeeCharacter && not (creature ^. creatureGreeted) - then yellAtCharacter $> (pe & positioned . creatureGreeted .~ True) - else pure pe - - dest <- maybe (selectDestination pos creature) pure - . mfilter (\(Destination p _) -> p /= pos) - $ creature ^. hippocampus . destination - let progress' = - dest ^. destinationProgress - + creature ^. creatureType . Raw.speed . invertedRate |*| ticks - if progress' < 1 - then pure - $ pe' - & positioned . hippocampus . destination - ?~ (dest & destinationProgress .~ progress') - else do - let newPos = dest ^. destinationPosition - remainingSpeed = progress' - 1 - newDest <- selectDestination newPos creature - <&> destinationProgress +~ remainingSpeed - let pe'' = pe' & positioned . hippocampus . destination ?~ newDest - collisionAt newPos >>= \case - Nothing -> pure $ pe'' & position .~ newPos - Just Stop -> pure pe'' - Just Combat -> do - ents <- use $ entities . atPosition newPos - when (any (entityIs @Character) ents) attackCharacter - pure pe' - where - vision = visionRadius creature - attackCharacter = do - dmg <- case creature ^? inventory . wielded . wieldedItems of - Just (WieldedItem item wi) -> do - let msg = fromMaybe - (Messages.lookup ["combat", "creatureAttack", "genericWeapon"]) - $ wi ^. creatureAttackMessage - message msg $ object [ "creature" A..= creature - , "item" A..= item - ] - pure $ wi ^. Raw.damage - Nothing -> do - attack <- choose $ creature ^. creatureType . attacks - attackDescription <- Messages.render (attack ^. Raw.description) - $ object [] - say ["combat", "creatureAttack", "natural"] - $ object [ "creature" A..= creature - , "attackDescription" A..= attackDescription - ] - pure $ attack ^. Raw.damage - - character %= Character.damage dmg - - yellAtCharacter = for_ (creature ^. creatureType . language) - $ \lang -> do - utterance <- fmap (<> "!") . word $ getLanguage lang - creatureSaysText pe utterance - - creatureGreeted :: Lens' entity Bool - creatureGreeted = hippocampus . greetedCharacter - - --- | A creature sends some text --- --- If that creature is visible to the character, its description will be --- included, otherwise if it's within earshot the character will just hear the --- sound -creatureSaysText - :: (MonadState GameState m, MonadRandom m, IsCreature entity) - => Positioned entity - -> Text - -> m () -creatureSaysText ent txt = do - let entPos = ent ^. position . _Position . to (fmap fromIntegral) - charPos <- use $ characterPosition . _Position . to (fmap fromIntegral) - let dist :: Int - dist = round $ Metric.distance @_ @Double entPos charPos - audible = dist <= fromIntegral hearingRadius - when audible $ do - visible <- positionIsCharacterVisible $ ent ^. position - let path = ["entities", "say", "creature"] - <> [if visible then "visible" else "invisible"] - params = object [ "creature" A..= (ent ^. positioned) - , "message" A..= txt - ] - say path params - -newtype GormlakBrain entity = GormlakBrain { _unGormlakBrain :: entity } - -instance (IsCreature entity) => Brain (GormlakBrain entity) where - step ticks - = fmap (fmap GormlakBrain) - . stepGormlak ticks - . fmap _unGormlakBrain - entityCanMove = const True - -hippocampus :: HasField "_hippocampus" s t a b => Lens s t a b -hippocampus = field @"_hippocampus" - -creatureType :: HasField "_creatureType" s t a b => Lens s t a b -creatureType = field @"_creatureType" - -inventory :: HasField "_inventory" s t a b => Lens s t a b -inventory = field @"_inventory" - --------------------------------------------------------------------------------- - --- instance Brain Creature where --- step = brainVia GormlakBrain --- entityCanMove = const True - --- instance Entity Creature where --- blocksVision _ = False --- description = view $ Creature.creatureType . Raw.description --- entityChar = view $ Creature.creatureType . char diff --git a/users/aspen/xanthous/src/Xanthous/App.hs b/users/aspen/xanthous/src/Xanthous/App.hs deleted file mode 100644 index 426230cdc..000000000 --- a/users/aspen/xanthous/src/Xanthous/App.hs +++ /dev/null @@ -1,647 +0,0 @@ -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -{-# OPTIONS_GHC -Wno-deferred-type-errors #-} -module Xanthous.App - ( makeApp - , RunType(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Brick hiding (App, halt, continue, raw) -import qualified Brick -import Graphics.Vty.Attributes (defAttr) -import Graphics.Vty.Input.Events (Event(EvKey)) -import Control.Monad.State (get, gets) -import Control.Monad.State.Class (modify) -import Data.Aeson (object, ToJSON) -import qualified Data.Aeson as A -import qualified Data.Vector as V -import System.Exit -import System.Directory (doesFileExist) -import Data.List.NonEmpty (NonEmpty(..)) -import Data.Vector.Lens (toVectorOf) --------------------------------------------------------------------------------- -import Xanthous.App.Common -import Xanthous.App.Time -import Xanthous.App.Prompt -import Xanthous.App.Autocommands -import Xanthous.Command -import Xanthous.Data - ( move - , Dimensions'(Dimensions) - , positioned - , position - , Position - , (|*|) - , Tiles(..), Hitpoints, fromScalar - ) -import Xanthous.Data.App (ResourceName, Panel(..), AppEvent(..)) -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Data.Levels (prevLevel, nextLevel) -import qualified Xanthous.Data.Levels as Levels -import Xanthous.Data.Entities (blocksObject) -import Xanthous.Game -import Xanthous.Game.State -import Xanthous.Game.Env -import Xanthous.Game.Draw (drawGame) -import Xanthous.Game.Prompt hiding (Fire) -import qualified Xanthous.Messages as Messages -import Xanthous.Random -import Xanthous.Util (removeVectorIndex, useListOf) -import Xanthous.Util.Inflection (toSentence) -import Xanthous.Physics (throwDistance, bluntThrowDamage) -import Xanthous.Data.EntityMap.Graphics (lineOfSight) -import Xanthous.Data.EntityMap (EntityID) --------------------------------------------------------------------------------- -import Xanthous.Entities.Common - ( InventoryPosition, describeInventoryPosition, backpack - , wieldableItem, wieldedItems, wielded, itemsWithPosition - , removeItemFromPosition, asWieldedItem - , wieldedItem, items, Hand (..), describeHand, wieldInHand - , WieldedItem, Wielded (..) - ) -import qualified Xanthous.Entities.Character as Character -import Xanthous.Entities.Character hiding (pickUpItem) -import Xanthous.Entities.Item (Item, weight) -import qualified Xanthous.Entities.Item as Item -import Xanthous.Entities.Creature (Creature) -import qualified Xanthous.Entities.Creature as Creature -import Xanthous.Entities.Environment - (Door, open, closed, locked, GroundMessage(..), Staircase(..)) -import Xanthous.Entities.RawTypes - ( edible, eatMessage, hitpointsHealed - , attackMessage - ) -import Xanthous.Generators.Level -import qualified Xanthous.Generators.Level.CaveAutomata as CaveAutomata -import qualified Xanthous.Generators.Level.Dungeon as Dungeon --------------------------------------------------------------------------------- - -type App = Brick.App GameState AppEvent ResourceName - -data RunType = NewGame | LoadGame FilePath - deriving stock (Eq) - -makeApp :: GameEnv -> RunType -> IO App -makeApp env rt = pure $ Brick.App - { appDraw = drawGame - , appChooseCursor = const headMay - , appHandleEvent = \game event -> runAppM (handleEvent event) env game - , appStartEvent = case rt of - NewGame -> runAppM (startEvent >> get) env - LoadGame save -> pure . (savefile ?~ save) - , appAttrMap = const $ attrMap defAttr [] - } - -runAppM :: AppM a -> GameEnv -> GameState -> EventM ResourceName a -runAppM appm ge = fmap fst . runAppT appm ge - -startEvent :: AppM () -startEvent = do - initLevel - modify updateCharacterVision - use (character . characterName) >>= \case - Nothing -> prompt_ @'StringPrompt ["character", "namePrompt"] Uncancellable - $ \(StringResult s) -> do - character . characterName ?= s - say ["welcome"] =<< use character - Just n -> say ["welcome"] $ object [ "characterName" A..= n ] - -initLevel :: AppM () -initLevel = do - level <- genLevel 0 - entities <>= levelToEntityMap level - characterPosition .= level ^. levelCharacterPosition - --------------------------------------------------------------------------------- - -handleEvent :: BrickEvent ResourceName AppEvent -> AppM (Next GameState) -handleEvent ev = use promptState >>= \case - NoPrompt -> handleNoPromptEvent ev - WaitingPrompt msg pr -> handlePromptEvent msg pr ev - - -handleNoPromptEvent :: BrickEvent ResourceName AppEvent -> AppM (Next GameState) -handleNoPromptEvent (VtyEvent (EvKey k mods)) - | Just command <- commandFromKey k mods - = do messageHistory %= nextTurn - cancelAutocommand - handleCommand command -handleNoPromptEvent (AppEvent AutoContinue) = do - preuse (autocommand . _ActiveAutocommand . _1) >>= traverse_ autoStep - continue -handleNoPromptEvent _ = continue - -handleCommand :: Command -> AppM (Next GameState) -handleCommand Quit = confirm_ ["quit", "confirm"] (liftIO exitSuccess) >> continue - -handleCommand Help = showPanel HelpPanel >> continue - -handleCommand (Move dir) = do - newPos <- uses characterPosition $ move dir - collisionAt newPos >>= \case - Nothing -> do - characterPosition .= newPos - stepGameBy =<< uses (character . speed) (|*| Tiles 1) - describeEntitiesAt newPos - Just Combat -> attackAt newPos - Just Stop -> pure () - continue - -handleCommand PickUp = do - pos <- use characterPosition - uses entities (entitiesAtPositionWithType @Item pos) >>= \case - [] -> say_ ["pickUp", "nothingToPickUp"] - [item] -> pickUpItem item - items' -> - menu_ ["pickUp", "menu"] Cancellable (entityMenu_ items') - $ \(MenuResult item) -> pickUpItem item - continue - where - pickUpItem (itemID, item) = do - character %= Character.pickUpItem item - entities . at itemID .= Nothing - say ["pickUp", "pickUp"] $ object [ "item" A..= item ] - stepGameBy 100 -- TODO - -handleCommand Drop = do - takeItemFromInventory_ ["drop", "menu"] Cancellable id - (say_ ["drop", "nothing"]) - $ \(MenuResult item) -> do - entitiesAtCharacter %= (SomeEntity item <|) - say ["drop", "dropped"] $ object [ "item" A..= item ] - continue - -handleCommand PreviousMessage = do - messageHistory %= previousMessage - continue - -handleCommand Open = do - prompt_ @'DirectionPrompt ["open", "prompt"] Cancellable - $ \(DirectionResult dir) -> do - pos <- move dir <$> use characterPosition - doors <- uses entities $ entitiesAtPositionWithType @Door pos - if | null doors -> say_ ["open", "nothingToOpen"] - | any (view $ _2 . locked) doors -> say_ ["open", "locked"] - | all (view $ _2 . open) doors -> say_ ["open", "alreadyOpen"] - | otherwise -> do - for_ doors $ \(eid, _) -> - entities . ix eid . positioned . _SomeEntity . open .= True - say_ ["open", "success"] - pure () - stepGame -- TODO - continue - -handleCommand Close = do - prompt_ @'DirectionPrompt ["close", "prompt"] Cancellable - $ \(DirectionResult dir) -> do - pos <- move dir <$> use characterPosition - (nonDoors, doors) <- uses entities - $ partitionEithers - . toList - . map ( (matching . aside $ _SomeEntity @Door) - . over _2 (view positioned) - ) - . EntityMap.atPositionWithIDs pos - if | null doors -> say_ ["close", "nothingToClose"] - | all (view $ _2 . closed) doors -> say_ ["close", "alreadyClosed"] - | any (view blocksObject . entityAttributes . snd) nonDoors -> - say ["close", "blocked"] - $ object [ "entityDescriptions" - A..= ( toSentence - . map description - . filter (view blocksObject . entityAttributes) - . map snd - ) nonDoors - , "blockOrBlocks" - A..= ( if length nonDoors == 1 - then "blocks" - else "block" - :: Text) - ] - | otherwise -> do - for_ doors $ \(eid, _) -> - entities . ix eid . positioned . _SomeEntity . closed .= True - for_ nonDoors $ \(eid, _) -> - entities . ix eid . position %= move dir - say_ ["close", "success"] - pure () - stepGame -- TODO - continue - -handleCommand Look = do - prompt_ @'PointOnMap ["look", "prompt"] Cancellable - $ \(PointOnMapResult pos) -> revealedEntitiesAtPosition pos >>= \case - Empty -> say_ ["look", "nothing"] - ents -> describeEntities ents - continue - -handleCommand Wait = stepGame >> continue - -handleCommand Eat = do - uses (character . inventory . backpack) - (V.mapMaybe (\item -> (item,) <$> item ^. Item.itemType . edible)) - >>= \case - Empty -> say_ ["eat", "noFood"] - food -> - let foodMenuItem idx (item, edibleItem) - = ( item ^. Item.itemType . char . char - , MenuOption (description item) (idx, item, edibleItem)) - -- TODO refactor to use entityMenu_ - menuItems = mkMenuItems $ imap foodMenuItem food - in menu_ ["eat", "menuPrompt"] Cancellable menuItems - $ \(MenuResult (idx, item, edibleItem)) -> do - character . inventory . backpack %= removeVectorIndex idx - let msg = fromMaybe (Messages.lookup ["eat", "eat"]) - $ edibleItem ^. eatMessage - character . characterHitpoints' += - edibleItem ^. hitpointsHealed . to fromIntegral - message msg $ object ["item" A..= item] - stepGame -- TODO - continue - -handleCommand Read = do - -- TODO allow reading things in the inventory (combo direction+menu prompt?) - prompt_ @'DirectionPrompt ["read", "prompt"] Cancellable - $ \(DirectionResult dir) -> do - pos <- uses characterPosition $ move dir - uses entities - (fmap snd . entitiesAtPositionWithType @GroundMessage pos) >>= \case - Empty -> say_ ["read", "nothing"] - GroundMessage msg :< Empty -> - say ["read", "result"] $ object ["message" A..= msg] - msgs -> - let readAndContinue Empty = pure () - readAndContinue (msg :< msgs') = - prompt @'Continue - ["read", "result"] - (object ["message" A..= msg]) - Cancellable - . const - $ readAndContinue msgs' - readAndContinue _ = error "this is total" - in readAndContinue msgs - continue - -handleCommand ShowInventory = showPanel InventoryPanel >> continue - -handleCommand DescribeInventory = do - selectItemFromInventory_ ["inventory", "describe", "select"] Cancellable id - (say_ ["inventory", "describe", "nothing"]) - $ \(MenuResult (invPos, item)) -> showPanel . ItemDescriptionPanel - $ Item.fullDescription item - <> "\n\n" <> describeInventoryPosition invPos - continue - - -handleCommand Wield = do - hs <- use $ character . inventory . wielded - selectItem $ \(MenuResult (invPos, (item :: WieldedItem))) -> do - selectHand hs $ \(MenuResult hand) -> do - character . inventory - %= removeItemFromPosition invPos (asWieldedItem # item) - prevItems <- character . inventory . wielded %%= wieldInHand hand item - character . inventory . backpack - <>= fromList (map (view wieldedItem) prevItems) - say ["wield", "wielded"] $ object [ "item" A..= item - , "hand" A..= describeHand hand - ] - continue - where - selectItem = - selectItemFromInventory_ ["wield", "menu"] Cancellable asWieldedItem - (say_ ["wield", "nothing"]) - selectHand hs = menu_ ["wield", "hand"] Cancellable $ handsMenu hs - itemsInHand (Hands i _) LeftHand = toList i - itemsInHand (DoubleHanded _) LeftHand = [] - itemsInHand (Hands _ i) RightHand = toList i - itemsInHand (DoubleHanded _) RightHand = [] - itemsInHand (Hands l r) BothHands = toList l <> toList r - itemsInHand (DoubleHanded i) BothHands = [i] - describeItems [] = "" - describeItems is - = " (currently holding " - <> (intercalate " and" $ map (view $ wieldedItem . to description) is) - <> ")" - handsMenu hs = mapFromList - . map (second $ \hand -> - MenuOption - ( describeHand hand - <> describeItems (itemsInHand hs hand) - ) - hand - ) - $ [ ('l', LeftHand) - , ('r', RightHand) - , ('b', BothHands) - ] - -handleCommand Fire = do - selectItemFromInventory_ ["fire", "menu"] Cancellable id - (say_ ["fire", "nothing"]) - $ \(MenuResult (invPos, item)) -> - let wt = weight item - dist = throwDistance wt - dam = bluntThrowDamage wt - in if dist < fromScalar 1 - then say_ ["fire", "zeroRange"] - else firePrompt_ ["fire", "target"] Cancellable dist $ - \(FireResult targetPos) -> do - charPos <- use characterPosition - mTarget <- uses entities $ firstEnemy . lineOfSight charPos targetPos - case mTarget of - Just target -> do - creature' <- damageCreature target dam - unless (Creature.isDead creature') $ - let msgPath = ["fire", "fired"] <> [if dam == 0 - then "noDamage" - else "someDamage"] - in say msgPath $ object [ "item" A..= item - , "creature" A..= creature' - ] - Nothing -> - say ["fire", "fired", "noTarget"] $ object [ "item" A..= item ] - character . inventory %= removeItemFromPosition invPos item - entities . EntityMap.atPosition targetPos %= (SomeEntity item <|) - stepGame -- TODO(grfn): should this be based on distance? - continue - where - firstEnemy - :: [(Position, Vector (EntityID, SomeEntity))] - -> Maybe (EntityID, Creature) - firstEnemy los = - let enemies = los >>= \(_, es) -> toList $ headMay es - in enemies ^? folded . below _SomeEntity - -handleCommand Save = - view (config . disableSaving) >>= \case - True -> say_ ["save", "disabled"] >> continue - False -> do - -- TODO default save locations / config file? - use savefile >>= \case - Just filepath -> - stringPromptWithDefault_ - ["save", "location"] - Cancellable - (pack filepath) - promptCallback - Nothing -> prompt_ @'StringPrompt ["save", "location"] Cancellable promptCallback - continue - where - promptCallback :: PromptResult 'StringPrompt -> AppM () - promptCallback (StringResult filename) = do - sf <- use savefile - exists <- liftIO . doesFileExist $ unpack filename - if exists && sf /= Just (unpack filename) - then confirm ["save", "overwrite"] (object ["filename" A..= filename]) - $ doSave filename - else doSave filename - doSave filename = do - src <- gets saveGame - lift . liftIO $ do - writeFile (unpack filename) $ toStrict src - exitSuccess - -handleCommand GoUp = do - hasStairs <- uses entitiesAtCharacter $ elem (SomeEntity UpStaircase) - if hasStairs - then uses levels prevLevel >>= \case - Just levs' -> do - cEID <- use characterEntityID - pCharacter <- entities . at cEID <<.= Nothing - levels .= levs' - charPos <- use characterPosition - entities . at cEID .= pCharacter - characterPosition .= charPos - Nothing -> - -- TODO in nethack, this leaves the game. Maybe something similar here? - say_ ["cant", "goUp"] - else say_ ["cant", "goUp"] - - continue - -handleCommand GoDown = do - hasStairs <- uses entitiesAtCharacter $ elem (SomeEntity DownStaircase) - - if hasStairs - then do - levs <- use levels - let newLevelNum = Levels.pos levs + 1 - levs' <- nextLevel (levelToGameLevel <$> genLevel newLevelNum) levs - cEID <- use characterEntityID - pCharacter <- entities . at cEID <<.= Nothing - levels .= levs' - entities . at cEID .= pCharacter - characterPosition .= extract levs' ^. upStaircasePosition - else say_ ["cant", "goDown"] - - continue - -handleCommand (StartAutoMove dir) = do - runAutocommand $ AutoMove dir - continue - -handleCommand Rest = do - say_ ["autocommands", "resting"] - runAutocommand AutoRest - continue - --- - -handleCommand ToggleRevealAll = do - val <- debugState . allRevealed <%= not - say ["debug", "toggleRevealAll"] $ object [ "revealAll" A..= val ] - continue - --------------------------------------------------------------------------------- -attackAt :: Position -> AppM () -attackAt pos = - uses entities (entitiesAtPositionWithType @Creature pos) >>= \case - Empty -> say_ ["combat", "nothingToAttack"] - (creature :< Empty) -> attackCreature creature - creatures -> - menu_ ["combat", "menu"] Cancellable (entityMenu_ creatures) - $ \(MenuResult creature) -> attackCreature creature - where - attackCreature creature = do - charDamage <- uses character characterDamage - creature' <- damageCreature creature charDamage - unless (Creature.isDead creature') $ writeAttackMessage creature' - whenM (uses character $ isNothing . weapon) handleFists - stepGame - weapon chr = chr ^? inventory . wielded . wieldedItems . wieldableItem - writeAttackMessage creature = do - let params = object ["creature" A..= creature] - attackMessages <- uses character getAttackMessages - msg <- intercalate " and " <$> for attackMessages (`Messages.render` params) - writeMessage $ "You " <> msg - getAttackMessages chr = - case chr ^.. inventory . wielded . wieldedItems . wieldableItem of - [] -> [Messages.lookup ["combat", "hit", "fists"]] - is -> - is - <&> \wi -> - fromMaybe (Messages.lookup ["combat", "hit", "generic"]) - $ wi ^. attackMessage - - - handleFists = do - damageChance <- use $ character . body . knuckles . to fistDamageChance - whenM (chance damageChance) $ do - damageAmount <- use $ character . body . knuckles . to fistfightingDamage - say_ [ "combat" , if damageAmount > 1 - then "fistExtraSelfDamage" - else "fistSelfDamage" ] - character %= Character.damage damageAmount - character . body . knuckles %= damageKnuckles - -damageCreature :: (EntityID, Creature) -> Hitpoints -> AppM Creature -damageCreature (creatureID, creature) dam = do - let creature' = Creature.damage dam creature - msgParams = object ["creature" A..= creature'] - if Creature.isDead creature' - then do - say ["combat", "killed"] msgParams - floorItems <- useListOf - $ entities - . ix creatureID - . positioned - . _SomeEntity @Creature - . inventory - . items - mCreaturePos <- preuse $ entities . ix creatureID . position - entities . at creatureID .= Nothing - for_ mCreaturePos $ \creaturePos -> - entities . EntityMap.atPosition creaturePos - %= (<> fromList (SomeEntity <$> floorItems)) - else entities . ix creatureID . positioned .= SomeEntity creature' - pure creature' - - -entityMenu_ - :: (Comonad w, Entity entity) - => [w entity] - -> Map Char (MenuOption (w entity)) -entityMenu_ = mkMenuItems @[_] . map entityMenuItem - where - entityMenuItem wentity - = let entity = extract wentity - in (entityMenuChar entity, MenuOption (description entity) wentity) - - -entityMenuChar :: Entity a => a -> Char -entityMenuChar entity - = let ec = entityChar entity ^. char - in if ec `elem` (['a'..'z'] ++ ['A'..'Z']) - then ec - else 'a' - --- | Prompt with an item to select out of the inventory and call callback with --- it -selectItemFromInventory - :: forall item params. - (ToJSON params) - => [Text] -- ^ Menu message - -> params -- ^ Menu message params - -> PromptCancellable -- ^ Is the menu cancellable? - -> Prism' Item item -- ^ Attach some extra information to the item, in a - -- recoverable fashion. Prism vs iso so we can discard - -- items. - -> AppM () -- ^ Action to take if there are no items matching - -> (PromptResult ('Menu (InventoryPosition, item)) -> AppM ()) - -> AppM () -selectItemFromInventory msgPath msgParams cancellable extraInfo onEmpty cb = do - uses (character . inventory) - (V.mapMaybe (_2 $ preview extraInfo) . toVectorOf itemsWithPosition) - >>= \case - Empty -> onEmpty - items' -> menu msgPath msgParams cancellable (itemMenu items') cb - where - itemMenu = mkMenuItems . map itemMenuItem - itemMenuItem (invPos, extraInfoItem) = - let item = extraInfo # extraInfoItem - in ( entityMenuChar item - , MenuOption - (description item <> " (" <> describeInventoryPosition invPos <> ")") - (invPos, extraInfoItem) - ) - --- | Prompt with an item to select out of the inventory and call callback with --- it -selectItemFromInventory_ - :: forall item. - [Text] -- ^ Menu message - -> PromptCancellable -- ^ Is the menu cancellable? - -> Prism' Item item -- ^ Attach some extra information to the item, in a - -- recoverable fashion. Prism vs iso so we can discard - -- items. - -> AppM () -- ^ Action to take if there are no items matching - -> (PromptResult ('Menu (InventoryPosition, item)) -> AppM ()) - -> AppM () -selectItemFromInventory_ msgPath = selectItemFromInventory msgPath () - --- | Prompt with an item to select out of the inventory, remove it from the --- inventory, and call callback with it -takeItemFromInventory - :: forall item params. - (ToJSON params) - => [Text] -- ^ Menu message - -> params -- ^ Menu message params - -> PromptCancellable -- ^ Is the menu cancellable? - -> Prism' Item item -- ^ Attach some extra information to the item, in a - -- recoverable fashion. Prism vs iso so we can discard - -- items. - -> AppM () -- ^ Action to take if there are no items matching - -> (PromptResult ('Menu item) -> AppM ()) - -> AppM () -takeItemFromInventory msgPath msgParams cancellable extraInfo onEmpty cb = - selectItemFromInventory msgPath msgParams cancellable extraInfo onEmpty - $ \(MenuResult (invPos, item)) -> do - character . inventory - %= removeItemFromPosition invPos (item ^. re extraInfo) - cb $ MenuResult item - -takeItemFromInventory_ - :: forall item. - [Text] -- ^ Menu message - -> PromptCancellable -- ^ Is the menu cancellable? - -> Prism' Item item -- ^ Attach some extra information to the item, in a - -- recoverable fashion. Prism vs iso so we can discard - -- items. - -> AppM () -- ^ Action to take if there are no items matching - -> (PromptResult ('Menu item) -> AppM ()) - -> AppM () -takeItemFromInventory_ msgPath = takeItemFromInventory msgPath () - --- entityMenu :: Entity entity => [entity] -> Map Char (MenuOption entity) --- entityMenu = map (map runIdentity) . entityMenu_ . fmap Identity - -showPanel :: Panel -> AppM () -showPanel panel = do - activePanel ?= panel - prompt_ @'Continue ["generic", "continue"] Uncancellable - . const - $ activePanel .= Nothing - --------------------------------------------------------------------------------- - -genLevel - :: Word -- ^ Level number, starting at 0 - -> AppM Level -genLevel num = do - let dims = Dimensions 80 80 - generator <- choose $ CaveAutomata :| [Dungeon] - let - doGen = case generator of - CaveAutomata -> generateLevel SCaveAutomata CaveAutomata.defaultParams - Dungeon -> generateLevel SDungeon Dungeon.defaultParams - level <- doGen dims num - pure $!! level - -levelToGameLevel :: Level -> GameLevel -levelToGameLevel level = - let _levelEntities = levelToEntityMap level - _upStaircasePosition = level ^. levelCharacterPosition - _levelRevealedPositions = mempty - in GameLevel {..} diff --git a/users/aspen/xanthous/src/Xanthous/App/Autocommands.hs b/users/aspen/xanthous/src/Xanthous/App/Autocommands.hs deleted file mode 100644 index 5d4db1a47..000000000 --- a/users/aspen/xanthous/src/Xanthous/App/Autocommands.hs +++ /dev/null @@ -1,76 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.App.Autocommands - ( runAutocommand - , autoStep - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Control.Concurrent (threadDelay) -import qualified Data.Aeson as A -import Data.Aeson (object) -import Data.List.NonEmpty (nonEmpty) -import qualified Data.List.NonEmpty as NE -import Control.Monad.State (gets) --------------------------------------------------------------------------------- -import Xanthous.App.Common -import Xanthous.App.Time -import Xanthous.Data -import Xanthous.Data.App -import Xanthous.Entities.Character (speed, isFullyHealed) -import Xanthous.Entities.Creature (Creature, creatureType) -import Xanthous.Entities.RawTypes (hostile) -import Xanthous.Game.State --------------------------------------------------------------------------------- - --- | Step the given autocommand forward once -autoStep :: Autocommand -> AppM () -autoStep (AutoMove dir) = do - newPos <- uses characterPosition $ move dir - collisionAt newPos >>= \case - Nothing -> do - characterPosition .= newPos - stepGameBy =<< uses (character . speed) (|*| (1 :: Tiles)) - describeEntitiesAt newPos - cancelIfDanger - Just _ -> cancelAutocommand - -autoStep AutoRest = do - done <- uses character isFullyHealed - if done - then say_ ["autocommands", "doneResting"] >> cancelAutocommand - else stepGame >> cancelIfDanger - --- | Cancel the autocommand if the character is in danger -cancelIfDanger :: AppM () -cancelIfDanger = do - maybeVisibleEnemies <- nonEmpty <$> enemiesInSight - for_ maybeVisibleEnemies $ \visibleEnemies -> do - say ["autocommands", "enemyInSight"] - $ object [ "firstEntity" A..= NE.head visibleEnemies ] - cancelAutocommand - where - enemiesInSight :: AppM [Creature] - enemiesInSight = do - ents <- gets characterVisibleEntities - pure $ ents - ^.. folded - . _SomeEntity @Creature - . filtered (view $ creatureType . hostile) - --------------------------------------------------------------------------------- - -autocommandIntervalμs :: Int -autocommandIntervalμs = 1000 * 50 -- 50 ms - -runAutocommand :: Autocommand -> AppM () -runAutocommand ac = do - env <- ask - tid <- liftIO . async $ runReaderT go env - autocommand .= ActiveAutocommand ac tid - where - go = everyμs autocommandIntervalμs $ sendEvent AutoContinue - --- | Perform 'act' every μs microseconds forever -everyμs :: MonadIO m => Int -> m () -> m () -everyμs μs act = act >> liftIO (threadDelay μs) >> everyμs μs act diff --git a/users/aspen/xanthous/src/Xanthous/App/Common.hs b/users/aspen/xanthous/src/Xanthous/App/Common.hs deleted file mode 100644 index 69ba6f0e0..000000000 --- a/users/aspen/xanthous/src/Xanthous/App/Common.hs +++ /dev/null @@ -1,67 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.App.Common - ( describeEntities - , describeEntitiesAt - , entitiesAtPositionWithType - - -- * Re-exports - , MonadState - , MonadRandom - , EntityMap - , module Xanthous.Game.Lenses - , module Xanthous.Monad - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.Aeson (object) -import qualified Data.Aeson as A -import Control.Monad.State (MonadState) -import Control.Monad.Random (MonadRandom) --------------------------------------------------------------------------------- -import Xanthous.Data (Position, positioned) -import Xanthous.Data.EntityMap (EntityMap) -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Game -import Xanthous.Game.Lenses -import Xanthous.Game.State -import Xanthous.Monad -import Xanthous.Entities.Character (Character) -import Xanthous.Util.Inflection (toSentence) --------------------------------------------------------------------------------- - -entitiesAtPositionWithType - :: forall a. (Entity a, Typeable a) - => Position - -> EntityMap SomeEntity - -> [(EntityMap.EntityID, a)] -entitiesAtPositionWithType pos em = - let someEnts = EntityMap.atPositionWithIDs pos em - in flip foldMap someEnts $ \(eid, view positioned -> se) -> - case downcastEntity @a se of - Just e -> [(eid, e)] - Nothing -> [] - -describeEntitiesAt :: (MonadState GameState m, MonadRandom m) => Position -> m () -describeEntitiesAt pos = - use ( entities - . EntityMap.atPosition pos - . to (filter (not . entityIs @Character)) - ) >>= \case - Empty -> pure () - ents -> describeEntities ents - -describeEntities - :: ( Entity entity - , MonadRandom m - , MonadState GameState m - , MonoFoldable (f Text) - , Functor f - , Element (f Text) ~ Text - ) - => f entity - -> m () -describeEntities ents = - let descriptions = description <$> ents - in say ["entities", "description"] - $ object ["entityDescriptions" A..= toSentence descriptions] diff --git a/users/aspen/xanthous/src/Xanthous/App/Prompt.hs b/users/aspen/xanthous/src/Xanthous/App/Prompt.hs deleted file mode 100644 index 799281a1c..000000000 --- a/users/aspen/xanthous/src/Xanthous/App/Prompt.hs +++ /dev/null @@ -1,228 +0,0 @@ -{-# LANGUAGE UndecidableInstances #-} --------------------------------------------------------------------------------- -module Xanthous.App.Prompt - ( handlePromptEvent - , clearPrompt - , prompt - , prompt_ - , stringPromptWithDefault - , stringPromptWithDefault_ - , confirm_ - , confirm - , menu - , menu_ - , firePrompt_ - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Brick (BrickEvent(..), Next) -import Brick.Widgets.Edit (handleEditorEvent) -import Data.Aeson (ToJSON, object) -import Graphics.Vty.Input.Events (Event(EvKey), Key(..)) --------------------------------------------------------------------------------- -import Xanthous.App.Common -import Xanthous.Data (move, Tiles, Position, positioned, _Position) -import qualified Xanthous.Data as Data -import Xanthous.Command (directionFromChar) -import Xanthous.Data.App (ResourceName, AppEvent) -import Xanthous.Game.Prompt -import Xanthous.Game.State -import qualified Xanthous.Messages as Messages -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Entities.Creature (creatureType, Creature) -import Xanthous.Entities.RawTypes (hostile) -import qualified Linear.Metric as Metric --------------------------------------------------------------------------------- - -handlePromptEvent - :: Text -- ^ Prompt message - -> Prompt AppM - -> BrickEvent ResourceName AppEvent - -> AppM (Next GameState) - -handlePromptEvent _ (Prompt Cancellable _ _ _ _) (VtyEvent (EvKey KEsc [])) - = clearPrompt >> continue -handlePromptEvent _ pr (VtyEvent (EvKey KEnter [])) - = clearPrompt >> submitPrompt pr >> continue - -handlePromptEvent _ pr@(Prompt _ SConfirm _ _ _) (VtyEvent (EvKey (KChar 'y') [])) - = clearPrompt >> submitPrompt pr >> continue - -handlePromptEvent _ (Prompt _ SConfirm _ _ _) (VtyEvent (EvKey (KChar 'n') [])) - = clearPrompt >> continue - -handlePromptEvent - msg - (Prompt c SStringPrompt (StringPromptState edit) pri cb) - (VtyEvent ev) - = do - edit' <- lift $ handleEditorEvent ev edit - let prompt' = Prompt c SStringPrompt (StringPromptState edit') pri cb - promptState .= WaitingPrompt msg prompt' - continue - -handlePromptEvent _ (Prompt _ SDirectionPrompt _ _ cb) - (VtyEvent (EvKey (KChar (directionFromChar -> Just dir)) [])) - = clearPrompt >> cb (DirectionResult dir) >> continue -handlePromptEvent _ (Prompt _ SDirectionPrompt _ _ _) _ = continue - -handlePromptEvent _ (Prompt _ SMenu _ items' cb) (VtyEvent (EvKey (KChar chr) [])) - | Just (MenuOption _ res) <- items' ^. at chr - = clearPrompt >> cb (MenuResult res) >> continue - | otherwise - = continue - -handlePromptEvent - msg - (Prompt c SPointOnMap (PointOnMapPromptState pos) pri cb) - (VtyEvent (EvKey (KChar (directionFromChar -> Just dir)) [])) - = let pos' = move dir pos - prompt' = Prompt c SPointOnMap (PointOnMapPromptState pos') pri cb - in promptState .= WaitingPrompt msg prompt' - >> continue -handlePromptEvent _ (Prompt _ SPointOnMap _ _ _) _ = continue - -handlePromptEvent - msg - (Prompt c SFire (FirePromptState pos) pri@(origin, range) cb) - (VtyEvent (EvKey (KChar (directionFromChar -> Just dir)) [])) - = do - let pos' = move dir pos - prompt' = Prompt c SFire (FirePromptState pos') pri cb - when (Data.distance origin pos' <= range) $ - promptState .= WaitingPrompt msg prompt' - continue - -handlePromptEvent - _ - (Prompt Cancellable _ _ _ _) - (VtyEvent (EvKey (KChar 'q') [])) - = clearPrompt >> continue -handlePromptEvent _ _ _ = continue - -clearPrompt :: AppM () -clearPrompt = promptState .= NoPrompt - -type PromptParams :: PromptType -> Type -type family PromptParams pt where - PromptParams ('Menu a) = Map Char (MenuOption a) -- Menu items - PromptParams 'Fire = Tiles -- Range - PromptParams _ = () - -prompt - :: forall (pt :: PromptType) (params :: Type). - (ToJSON params, SingPromptType pt, PromptParams pt ~ ()) - => [Text] -- ^ Message key - -> params -- ^ Message params - -> PromptCancellable - -> (PromptResult pt -> AppM ()) -- ^ Prompt promise handler - -> AppM () -prompt msgPath params cancellable cb = do - let pt = singPromptType @pt - msg <- Messages.message msgPath params - mp :: Maybe (Prompt AppM) <- case pt of - SPointOnMap -> do - charPos <- use characterPosition - pure . Just $ mkPointOnMapPrompt cancellable charPos cb - SStringPrompt -> pure . Just $ mkStringPrompt cancellable cb - SConfirm -> pure . Just $ mkPrompt cancellable pt cb - SDirectionPrompt -> pure . Just $ mkPrompt cancellable pt cb - SContinue -> pure . Just $ mkPrompt cancellable pt cb - for_ mp $ \p -> promptState .= WaitingPrompt msg p - -prompt_ - :: forall (pt :: PromptType). - (SingPromptType pt, PromptParams pt ~ ()) - => [Text] -- ^ Message key - -> PromptCancellable - -> (PromptResult pt -> AppM ()) -- ^ Prompt promise handler - -> AppM () -prompt_ msg = prompt msg $ object [] - -stringPromptWithDefault - :: forall (params :: Type). (ToJSON params) - => [Text] -- ^ Message key - -> params -- ^ Message params - -> PromptCancellable - -> Text -- ^ Prompt default - -> (PromptResult 'StringPrompt -> AppM ()) -- ^ Prompt promise handler - -> AppM () -stringPromptWithDefault msgPath params cancellable def cb = do - msg <- Messages.message msgPath params - let p = mkStringPromptWithDefault cancellable def cb - promptState .= WaitingPrompt msg p - -stringPromptWithDefault_ - :: [Text] -- ^ Message key - -> PromptCancellable - -> Text -- ^ Prompt default - -> (PromptResult 'StringPrompt -> AppM ()) -- ^ Prompt promise handler - -> AppM () -stringPromptWithDefault_ msg = stringPromptWithDefault msg $ object [] - -confirm - :: ToJSON params - => [Text] -- ^ Message key - -> params - -> AppM () - -> AppM () -confirm msgPath params - = prompt @'Confirm msgPath params Cancellable . const - -confirm_ :: [Text] -> AppM () -> AppM () -confirm_ msgPath = confirm msgPath $ object [] - -menu :: forall (a :: Type) (params :: Type). - (ToJSON params) - => [Text] -- ^ Message key - -> params -- ^ Message params - -> PromptCancellable - -> Map Char (MenuOption a) -- ^ Menu items - -> (PromptResult ('Menu a) -> AppM ()) -- ^ Menu promise handler - -> AppM () -menu msgPath params cancellable items' cb = do - msg <- Messages.message msgPath params - let p = mkMenu cancellable items' cb - promptState .= WaitingPrompt msg p - -menu_ :: forall (a :: Type). - [Text] -- ^ Message key - -> PromptCancellable - -> Map Char (MenuOption a) -- ^ Menu items - -> (PromptResult ('Menu a) -> AppM ()) -- ^ Menu promise handler - -> AppM () -menu_ msgPath = menu msgPath $ object [] - -firePrompt_ - :: [Text] -- ^ Message key - -> PromptCancellable - -> Tiles -- ^ Range - -> (PromptResult 'Fire -> AppM ()) -- ^ Promise handler - -> AppM () -firePrompt_ msgPath cancellable range cb = do - msg <- Messages.message msgPath $ object [] - initialPos <- maybe (use characterPosition) pure =<< nearestEnemyPosition - let p = mkFirePrompt cancellable initialPos range cb - promptState .= WaitingPrompt msg p - --- | Returns the position of the nearest visible hostile creature, if any -nearestEnemyPosition :: AppM (Maybe Position) -nearestEnemyPosition = do - charPos <- use characterPosition - em <- use entities - ps <- characterVisiblePositions - let candidates = toList ps >>= \p -> - let ents = EntityMap.atPositionWithIDs p em - in ents - ^.. folded - . _2 - . positioned - . _SomeEntity @Creature - . creatureType - . filtered (view hostile) - . to (const (distance charPos p, p)) - pure . headMay . fmap snd $ sortOn fst candidates - where - distance :: Position -> Position -> Double - distance = Metric.distance `on` (fmap fromIntegral . view _Position) diff --git a/users/aspen/xanthous/src/Xanthous/App/Time.hs b/users/aspen/xanthous/src/Xanthous/App/Time.hs deleted file mode 100644 index cca352858..000000000 --- a/users/aspen/xanthous/src/Xanthous/App/Time.hs +++ /dev/null @@ -1,42 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.App.Time - ( stepGame - , stepGameBy - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import System.Exit --------------------------------------------------------------------------------- -import Xanthous.Data (Ticks) -import Xanthous.App.Prompt -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Entities.Character (isDead) -import Xanthous.Game.State -import Xanthous.Game.Prompt -import Xanthous.Game.Lenses -import Control.Monad.State (modify) -import qualified Xanthous.Game.Memo as Memo --------------------------------------------------------------------------------- - - -stepGameBy :: Ticks -> AppM () -stepGameBy ticks = do - ents <- uses entities EntityMap.toEIDsAndPositioned - for_ ents $ \(eid, pEntity) -> do - pEntity' <- step ticks pEntity - entities . ix eid .= pEntity' - - clearMemo Memo.characterVisiblePositions - modify updateCharacterVision - - whenM (uses character isDead) - . prompt_ @'Continue ["dead"] Uncancellable - . const . lift . liftIO - $ exitSuccess - -ticksPerTurn :: Ticks -ticksPerTurn = 100 - -stepGame :: AppM () -stepGame = stepGameBy ticksPerTurn diff --git a/users/aspen/xanthous/src/Xanthous/Command.hs b/users/aspen/xanthous/src/Xanthous/Command.hs deleted file mode 100644 index 6e6274a02..000000000 --- a/users/aspen/xanthous/src/Xanthous/Command.hs +++ /dev/null @@ -1,145 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Command - ( -- * Commands - Command(..) - , commandIsHidden - -- * Keybindings - , Keybinding(..) - , keybindings - , commands - , commandFromKey - , directionFromChar - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (Left, Right, Down, try) --------------------------------------------------------------------------------- -import Graphics.Vty.Input (Key(..), Modifier(..)) -import qualified Data.Char as Char -import Data.Aeson (FromJSON (parseJSON), FromJSONKey, FromJSONKeyFunction (FromJSONKeyTextParser)) -import qualified Data.Aeson as A -import Data.Aeson.Generic.DerivingVia -import Text.Megaparsec (Parsec, errorBundlePretty, parse, eof, try) -import Text.Megaparsec.Char (string', char', printChar) -import Data.FileEmbed (embedFile) -import qualified Data.Yaml as Yaml -import Test.QuickCheck.Arbitrary -import Data.Aeson.Types (Parser) --------------------------------------------------------------------------------- -import Xanthous.Data (Direction(..)) -import Xanthous.Util.QuickCheck (GenericArbitrary(..)) --------------------------------------------------------------------------------- - -data Command - = Quit - | Help - | Move !Direction - | StartAutoMove !Direction - | PreviousMessage - | PickUp - | Drop - | Open - | Close - | Wait - | Eat - | Look - | Save - | Read - | ShowInventory - | DescribeInventory - | Wield - | Fire - | GoUp - | GoDown - | Rest - - -- | TODO replace with `:` commands - | ToggleRevealAll - deriving stock (Show, Eq, Generic) - deriving anyclass (Hashable, NFData) - deriving Arbitrary via GenericArbitrary Command - deriving (FromJSON) - via WithOptions '[ SumEnc UntaggedVal ] - Command - --- | Should the command be hidden from the help menu? --- --- Note that this is true for both debug commands and movement commands, as the --- latter is documented non-automatically -commandIsHidden :: Command -> Bool -commandIsHidden (Move _) = True -commandIsHidden (StartAutoMove _) = True -commandIsHidden ToggleRevealAll = True -commandIsHidden _ = False - --------------------------------------------------------------------------------- - -data Keybinding = Keybinding !Key ![Modifier] - deriving stock (Show, Eq, Generic) - deriving anyclass (Hashable, NFData) - -parseKeybindingFromText :: Text -> Parser Keybinding -parseKeybindingFromText - = either (fail . errorBundlePretty) pure - . parse keybinding "" - where - key :: Parsec Void Text Key - key = KUp <$ string' "" - <|> KDown <$ string' "" - <|> KLeft <$ string' "" - <|> KRight <$ string' "" - <|> KChar <$> printChar - - modifier :: Parsec Void Text Modifier - modifier = modf <* char' '-' - where - modf = MAlt <$ char' 'a' - <|> MMeta <$ char' 'm' - <|> MCtrl <$ char' 'c' - <|> MShift <$ char' 's' - - keybinding :: Parsec Void Text Keybinding - keybinding = do - mods <- many (try modifier) - k <- key - eof - pure $ Keybinding k mods - -instance FromJSON Keybinding where - parseJSON = A.withText "Keybinding" parseKeybindingFromText - -instance FromJSONKey Keybinding where - fromJSONKey = FromJSONKeyTextParser parseKeybindingFromText - -rawKeybindings :: ByteString -rawKeybindings = $(embedFile "src/Xanthous/keybindings.yaml") - -keybindings :: HashMap Keybinding Command -keybindings = either (error . Yaml.prettyPrintParseException) id - $ Yaml.decodeEither' rawKeybindings - -commands :: HashMap Command Keybinding -commands = mapFromList . map swap . itoList $ keybindings - -commandFromKey :: Key -> [Modifier] -> Maybe Command -commandFromKey (KChar (directionFromChar -> Just dir)) [] = Just $ Move dir -commandFromKey (KChar c) [] - | Char.isUpper c - , Just dir <- directionFromChar $ Char.toLower c - = Just $ StartAutoMove dir -commandFromKey k mods = keybindings ^. at keybinding - where keybinding = Keybinding k mods - --------------------------------------------------------------------------------- - -directionFromChar :: Char -> Maybe Direction -directionFromChar 'h' = Just Left -directionFromChar 'j' = Just Down -directionFromChar 'k' = Just Up -directionFromChar 'l' = Just Right -directionFromChar 'y' = Just UpLeft -directionFromChar 'u' = Just UpRight -directionFromChar 'b' = Just DownLeft -directionFromChar 'n' = Just DownRight -directionFromChar '.' = Just Here -directionFromChar _ = Nothing diff --git a/users/aspen/xanthous/src/Xanthous/Data.hs b/users/aspen/xanthous/src/Xanthous/Data.hs deleted file mode 100644 index 703955206..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data.hs +++ /dev/null @@ -1,822 +0,0 @@ -{-# LANGUAGE PartialTypeSignatures #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE RoleAnnotations #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE DeriveTraversable #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE NoTypeSynonymInstances #-} -{-# LANGUAGE DuplicateRecordFields #-} -{-# LANGUAGE QuantifiedConstraints #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE AllowAmbiguousTypes #-} --------------------------------------------------------------------------------- --- | Common data types for Xanthous ------------------------------------------------------------------------------ -module Xanthous.Data - ( Opposite(..) - - -- * - , Position'(..) - , Position - , x - , y - - -- ** - , Positioned(..) - , _Positioned - , position - , positioned - , loc - , _Position - , positionFromPair - , positionFromV2 - , addPositions - , diffPositions - , stepTowards - , isUnit - , distance - - -- * Boxes - , Box(..) - , topLeftCorner - , bottomRightCorner - , setBottomRightCorner - , dimensions - , inBox - , boxIntersects - , boxCenter - , boxEdge - , module Linear.V2 - - -- * Unit math - , Scalar(..) - , Per(..) - , invertRate - , invertedRate - , (|+|) - , (|*|) - , (|/|) - , (:+:) - , (:*:) - , (:/:) - , (:**:)(..) - , Ticks(..) - , Tiles(..) - , TicksPerTile - , TilesPerTick - , timesTiles - , Square(..) - , squared - , Cubic(..) - , Grams - , Meters - , Uno(..) - , Unit(..) - , UnitSymbol(..) - - -- * - , Dimensions'(..) - , Dimensions - , HasWidth(..) - , HasHeight(..) - - -- * - , Direction(..) - , move - , asPosition - , directionOf - , Cardinal(..) - - -- * - , Corner(..) - , Edge(..) - , cornerEdges - - -- * - , Neighbors(..) - , edges - , neighborDirections - , neighborPositions - , neighborCells - , arrayNeighbors - , rotations - , HasTopLeft(..) - , HasTop(..) - , HasTopRight(..) - , HasLeft(..) - , HasRight(..) - , HasBottomLeft(..) - , HasBottom(..) - , HasBottomRight(..) - - -- * - , Hitpoints(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (Left, Down, Right, (.=), elements) --------------------------------------------------------------------------------- -import Linear.V2 hiding (_x, _y) -import qualified Linear.V2 as L -import Linear.V4 hiding (_x, _y) -import Test.QuickCheck (CoArbitrary, Function, elements) -import Test.QuickCheck.Arbitrary.Generic -import Data.Group -import Brick (Location(Location), Edges(..)) -import Data.Monoid (Product(..), Sum(..)) -import Data.Array.IArray -import Data.Aeson.Generic.DerivingVia -import Data.Aeson - ( ToJSON(..), FromJSON(..), object, (.=), (.:), withObject) -import Data.Random (Distribution) -import Data.Coerce -import Data.Proxy (Proxy(Proxy)) --------------------------------------------------------------------------------- -import Xanthous.Util (EqEqProp(..), EqProp, between) -import Xanthous.Orphans () -import Xanthous.Util.Graphics -import qualified Linear.Metric as Metric --------------------------------------------------------------------------------- - --- | opposite ∘ opposite ≡ id -class Opposite x where - opposite :: x -> x - --------------------------------------------------------------------------------- - --- fromScalar ∘ scalar ≡ id -class Scalar a where - scalar :: a -> Double - fromScalar :: Double -> a - -instance Scalar Double where - scalar = id - fromScalar = id - -newtype ScalarIntegral a = ScalarIntegral a - deriving newtype (Eq, Ord, Num, Enum, Real, Integral) -instance Integral a => Scalar (ScalarIntegral a) where - scalar = fromIntegral - fromScalar = floor - -deriving via (ScalarIntegral Integer) instance Scalar Integer -deriving via (ScalarIntegral Word) instance Scalar Word - --- | Units of measure -class Unit a where - unitSuffix :: Text -type UnitSymbol :: Symbol -> Type -> Type -newtype UnitSymbol suffix a = UnitSymbol a -instance KnownSymbol suffix => Unit (UnitSymbol suffix a) where - unitSuffix = pack $ symbolVal @suffix Proxy - -newtype ShowUnitSuffix a b = ShowUnitSuffix a -instance (Show b, Unit a, Coercible a b) => Show (ShowUnitSuffix a b) where - show a = show (coerce @_ @b a) <> " " <> unpack (unitSuffix @a) - --------------------------------------------------------------------------------- - -data Position' a where - Position :: { _x :: a - , _y :: a - } -> (Position' a) - deriving stock (Show, Eq, Generic, Ord, Functor, Foldable, Traversable) - deriving anyclass (NFData, Hashable, CoArbitrary, Function) - deriving EqProp via EqEqProp (Position' a) - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - (Position' a) - -x, y :: Lens' (Position' a) a -x = lens (\(Position xx _) -> xx) (\(Position _ yy) xx -> Position xx yy) -y = lens (\(Position _ yy) -> yy) (\(Position xx _) yy -> Position xx yy) - -type Position = Position' Int - -instance (Arbitrary a) => Arbitrary (Position' a) where - arbitrary = genericArbitrary - shrink (Position px py) = Position <$> shrink px <*> shrink py - - -instance Num a => Semigroup (Position' a) where - (Position x₁ y₁) <> (Position x₂ y₂) = Position (x₁ + x₂) (y₁ + y₂) - -instance Num a => Monoid (Position' a) where - mempty = Position 0 0 - -instance Num a => Group (Position' a) where - invert (Position px py) = Position (negate px) (negate py) - --- | Positions convert to scalars by discarding their orientation and just --- measuring the length from the origin -instance (Ord a, Num a, Scalar a) => Scalar (Position' a) where - scalar = fromIntegral . length . line 0 . view _Position - fromScalar n = Position (fromScalar n) (fromScalar n) - -data Positioned a where - Positioned :: Position -> a -> Positioned a - deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable, Generic) - deriving anyclass (NFData, CoArbitrary, Function) -type role Positioned representational - -_Positioned :: Iso (Position, a) (Position, b) (Positioned a) (Positioned b) -_Positioned = iso hither yon - where - hither (pos, a) = Positioned pos a - yon (Positioned pos b) = (pos, b) - -instance Arbitrary a => Arbitrary (Positioned a) where - arbitrary = Positioned <$> arbitrary <*> arbitrary - -instance ToJSON a => ToJSON (Positioned a) where - toJSON (Positioned pos val) = object - [ "position" .= pos - , "data" .= val - ] - -instance FromJSON a => FromJSON (Positioned a) where - parseJSON = withObject "Positioned" $ \obj -> - Positioned <$> obj .: "position" <*> obj .: "data" - -position :: Lens' (Positioned a) Position -position = lens - (\(Positioned pos _) -> pos) - (\(Positioned _ a) pos -> Positioned pos a) - -positioned :: Lens (Positioned a) (Positioned b) a b -positioned = lens - (\(Positioned _ x') -> x') - (\(Positioned pos _) x' -> Positioned pos x') - -loc :: Iso' Position Location -loc = iso hither yon - where - hither (Position px py) = Location (px, py) - yon (Location (lx, ly)) = Position lx ly - -_Position :: Iso' (Position' a) (V2 a) -_Position = iso hither yon - where - hither (Position px py) = V2 px py - yon (V2 lx ly) = Position lx ly - -positionFromPair :: (Num a, Integral i, Integral j) => (i, j) -> Position' a -positionFromPair (i, j) = Position (fromIntegral i) (fromIntegral j) - -positionFromV2 :: (Num a, Integral i) => V2 i -> Position' a -positionFromV2 (V2 xx yy) = Position (fromIntegral xx) (fromIntegral yy) - --- | Add two positions --- --- Operation for the additive group on positions -addPositions :: Num a => Position' a -> Position' a -> Position' a -addPositions = (<>) - --- | Subtract two positions. --- --- diffPositions pos₁ pos₂ = pos₁ `addPositions` (invert pos₂) -diffPositions :: Num a => Position' a -> Position' a -> Position' a -diffPositions (Position x₁ y₁) (Position x₂ y₂) = Position (x₁ - x₂) (y₁ - y₂) - --- | Is this position a unit position? or: When taken as a difference, does this --- position represent a step of one tile? --- --- ∀ dir :: Direction. isUnit ('asPosition' dir) -isUnit :: (Eq a, Num a) => Position' a -> Bool -isUnit (Position px py) = - abs px `elem` [0,1] && abs py `elem` [0, 1] && (px, py) /= (0, 0) - --------------------------------------------------------------------------------- - -data Dimensions' a = Dimensions - { _width :: a - , _height :: a - } - deriving stock (Show, Eq, Functor, Generic) - deriving anyclass (CoArbitrary, Function) -makeFieldsNoPrefix ''Dimensions' - -instance Arbitrary a => Arbitrary (Dimensions' a) where - arbitrary = Dimensions <$> arbitrary <*> arbitrary - -type Dimensions = Dimensions' Word - --------------------------------------------------------------------------------- - -data Direction where - Up :: Direction - Down :: Direction - Left :: Direction - Right :: Direction - UpLeft :: Direction - UpRight :: Direction - DownLeft :: Direction - DownRight :: Direction - Here :: Direction - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (CoArbitrary, Function, NFData, ToJSON, FromJSON, Hashable) - -deriving via (GenericArbitrary Direction) instance Arbitrary Direction - -instance Opposite Direction where - opposite Up = Down - opposite Down = Up - opposite Left = Right - opposite Right = Left - opposite UpLeft = DownRight - opposite UpRight = DownLeft - opposite DownLeft = UpRight - opposite DownRight = UpLeft - opposite Here = Here - -move :: Num a => Direction -> Position' a -> Position' a -move Up = y -~ 1 -move Down = y +~ 1 -move Left = x -~ 1 -move Right = x +~ 1 -move UpLeft = move Up . move Left -move UpRight = move Up . move Right -move DownLeft = move Down . move Left -move DownRight = move Down . move Right -move Here = id - -asPosition :: Direction -> Position -asPosition dir = move dir mempty - --- | Returns the direction that a given position is from a given source position -directionOf - :: Position -- ^ Source - -> Position -- ^ Target - -> Direction -directionOf (Position x₁ y₁) (Position x₂ y₂) = - case (x₁ `compare` x₂, y₁ `compare` y₂) of - (EQ, EQ) -> Here - (EQ, LT) -> Down - (EQ, GT) -> Up - (LT, EQ) -> Right - (GT, EQ) -> Left - - (LT, LT) -> DownRight - (GT, LT) -> DownLeft - - (LT, GT) -> UpRight - (GT, GT) -> UpLeft - --- | Take one (potentially diagonal) step towards the given position --- --- ∀ src tgt. isUnit (src `diffPositions` (src `stepTowards tgt`)) -stepTowards - :: Position -- ^ Source - -> Position -- ^ Target - -> Position -stepTowards (view _Position -> p₁) (view _Position -> p₂) - | p₁ == p₂ = _Position # p₁ - | otherwise = - let (_:p:_) = line p₁ p₂ - in _Position # p - --- | Newtype controlling arbitrary generation to only include cardinal --- directions ('Up', 'Down', 'Left', 'Right') -newtype Cardinal = Cardinal { getCardinal :: Direction } - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, Function, CoArbitrary) - deriving newtype (Opposite) - -instance Arbitrary Cardinal where - arbitrary = Cardinal <$> elements [Up, Down, Left, Right] - --------------------------------------------------------------------------------- - -data Corner - = TopLeft - | TopRight - | BottomLeft - | BottomRight - deriving stock (Show, Eq, Ord, Enum, Bounded, Generic) - deriving Arbitrary via GenericArbitrary Corner - -instance Opposite Corner where - opposite TopLeft = BottomRight - opposite TopRight = BottomLeft - opposite BottomLeft = TopRight - opposite BottomRight = TopLeft - -data Edge - = TopEdge - | LeftEdge - | RightEdge - | BottomEdge - deriving stock (Show, Eq, Ord, Enum, Bounded, Generic) - deriving Arbitrary via GenericArbitrary Edge - -instance Opposite Edge where - opposite TopEdge = BottomEdge - opposite BottomEdge = TopEdge - opposite LeftEdge = RightEdge - opposite RightEdge = LeftEdge - -cornerEdges :: Corner -> (Edge, Edge) -cornerEdges TopLeft = (TopEdge, LeftEdge) -cornerEdges TopRight = (TopEdge, RightEdge) -cornerEdges BottomLeft = (BottomEdge, LeftEdge) -cornerEdges BottomRight = (BottomEdge, RightEdge) - --------------------------------------------------------------------------------- - -data Neighbors a = Neighbors - { _topLeft - , _top - , _topRight - , _left - , _right - , _bottomLeft - , _bottom - , _bottomRight :: a - } - deriving stock (Show, Eq, Ord, Functor, Foldable, Traversable, Generic) - deriving anyclass (NFData, CoArbitrary, Function, MonoFoldable) - -deriving via (GenericArbitrary (Neighbors a)) instance (Arbitrary a) => Arbitrary (Neighbors a) - -type instance Element (Neighbors a) = a - -makeFieldsNoPrefix ''Neighbors - -instance Applicative Neighbors where - pure α = Neighbors - { _topLeft = α - , _top = α - , _topRight = α - , _left = α - , _right = α - , _bottomLeft = α - , _bottom = α - , _bottomRight = α - } - nf <*> nx = Neighbors - { _topLeft = nf ^. topLeft $ nx ^. topLeft - , _top = nf ^. top $ nx ^. top - , _topRight = nf ^. topRight $ nx ^. topRight - , _left = nf ^. left $ nx ^. left - , _right = nf ^. right $ nx ^. right - , _bottomLeft = nf ^. bottomLeft $ nx ^. bottomLeft - , _bottom = nf ^. bottom $ nx ^. bottom - , _bottomRight = nf ^. bottomRight $ nx ^. bottomRight - } - -edges :: Neighbors a -> Edges a -edges neighs = Edges - { eTop = neighs ^. top - , eBottom = neighs ^. bottom - , eLeft = neighs ^. left - , eRight = neighs ^. right - } - -neighborDirections :: Neighbors Direction -neighborDirections = Neighbors - { _topLeft = UpLeft - , _top = Up - , _topRight = UpRight - , _left = Left - , _right = Right - , _bottomLeft = DownLeft - , _bottom = Down - , _bottomRight = DownRight - } - -neighborPositions :: Num a => Position' a -> Neighbors (Position' a) -neighborPositions pos = (`move` pos) <$> neighborDirections - -neighborCells :: Num a => V2 a -> Neighbors (V2 a) -neighborCells = map (view _Position) . neighborPositions . review _Position - -arrayNeighbors - :: (IArray a e, Ix i, Num i) - => a (V2 i) e - -> V2 i - -> Neighbors (Maybe e) -arrayNeighbors arr center = arrLookup <$> neighborPositions (_Position # center) - where - arrLookup (view _Position -> pos) - | inRange (bounds arr) pos = Just $ arr ! pos - | otherwise = Nothing - --- | Returns a list of all 4 90-degree rotations of the given neighbors -rotations :: Neighbors a -> V4 (Neighbors a) -rotations orig@(Neighbors tl t tr l r bl b br) = V4 - orig -- tl t tr - -- l r - -- bl b br - - (Neighbors bl l tl b t br r tr) -- bl l tl - -- b t - -- br r tr - - (Neighbors br b bl r l tr t tl) -- br b bl - -- r l - -- tr t tl - - (Neighbors tr r br t b tl l bl) -- tr r br - -- t b - -- tl l bl - --------------------------------------------------------------------------------- - -newtype Per a b = Rate Double - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (Arbitrary, Num, Ord, Enum, Real, Fractional, ToJSON, FromJSON) - via Double - deriving (Semigroup, Monoid) via Product Double - deriving Show via ShowUnitSuffix (Per a b) Double -deriving via Double - instance ( Distribution d Double - , forall xx yy. Coercible xx yy => Coercible (d xx) (d yy) - ) - => Distribution d (Per a b) - -instance (Unit a, Unit b) => Unit (a `Per` b) where - unitSuffix = unitSuffix @a <> "/" <> unitSuffix @b - -invertRate :: a `Per` b -> b `Per` a -invertRate (Rate p) = Rate $ 1 / p - -invertedRate :: Iso (a `Per` b) (b' `Per` a') (b `Per` a) (a' `Per` b') -invertedRate = iso invertRate invertRate - -type (:+:) :: Type -> Type -> Type -type family (:+:) a b where - a :+: a = a - a :+: (Uno b) = a - -infixl 6 |+| -class AddUnit a b where - (|+|) :: a -> b -> a :+: b - -instance Scalar a => AddUnit a a where - x' |+| y' = fromScalar $ scalar x' + scalar y' - -instance (Scalar a, Scalar b) => AddUnit a (Uno b) where - x' |+| y' = fromScalar $ scalar x' + scalar y' - -type (:*:) :: Type -> Type -> Type -type family (:*:) a b where - (a `Per` b) :*: b = a - (Square a) :*: a = Cubic a - a :*: a = Square a - a :*: Uno b = a - a :*: b = a :**: b - -infixl 7 |*| -class MulUnit a b where - (|*|) :: a -> b -> a :*: b - -instance (Scalar a, Scalar b) => MulUnit (a `Per` b) b where - (Rate rate) |*| b = fromScalar $ rate * scalar b - -instance forall a. (Scalar a, a :*: a ~ Square a) => MulUnit a a where - x' |*| y' = Square @a . fromScalar $ scalar x' * scalar y' - -instance forall a. (Scalar a) => MulUnit (Square a) a where - x' |*| y' = Cubic @a . fromScalar $ scalar x' * scalar y' - -instance {-# INCOHERENT #-} forall a b. - (Scalar a, Scalar b, Scalar (a :*: Uno b)) - => MulUnit a (Uno b) where - x' |*| y' = fromScalar $ scalar x' * scalar y' - -type (:/:) :: Type -> Type -> Type -type family (:/:) a b where - (Square a) :/: a = a - (Cubic a) :/: a = Square a - (Cubic a) :/: (Square a) = a - (a :**: b) :/: b = a - (a :**: b) :/: a = b - a :/: Uno b = a - a :/: b = a `Per` b - -infixl 7 |/| -class DivUnit a b where - (|/|) :: a -> b -> a :/: b - -instance Scalar a => DivUnit (Square a) a where - (Square a) |/| b = fromScalar $ scalar a / scalar b - -instance Scalar a => DivUnit (Cubic a) a where - (Cubic a) |/| b = fromScalar $ scalar a / scalar b - -instance (Scalar a, Cubic a :/: Square a ~ a) - => DivUnit (Cubic a) (Square a) where - (Cubic a) |/| (Square b) = fromScalar $ scalar a / scalar b - -instance (Scalar a, Scalar b) => DivUnit (a :**: b) b where - (Times a) |/| b = fromScalar $ scalar a / scalar b - -instance (Scalar a, Scalar b) => DivUnit (a :**: b) a where - (Times a) |/| b = fromScalar $ scalar a / scalar b - -instance {-# INCOHERENT #-} forall a b. - (Scalar a, Scalar b, Scalar (a :/: Uno b)) - => DivUnit a (Uno b) where - x' |/| y' = fromScalar $ scalar x' / scalar y' - --- | Dimensionless quantitites (mass per unit mass, radians, etc) --- --- see -newtype Uno a = Uno a - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving ( Arbitrary, Num, Ord, Enum, Real, Fractional, ToJSON, FromJSON - , Scalar, Show - ) - via a - deriving Unit via UnitSymbol "" (Uno a) - -newtype Square a = Square a - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving ( Arbitrary, Num, Ord, Enum, Real, Fractional, ToJSON, FromJSON - , Scalar - ) - via a -deriving via (a :: Type) - instance ( Distribution d a - , forall xx yy. Coercible xx yy => Coercible (d xx) (d yy) - ) - => Distribution d (Square a) - -instance Unit a => Unit (Square a) where - unitSuffix = unitSuffix @a <> "²" - -instance Show a => Show (Square a) where - show (Square n) = show n <> "²" - -squared :: (Scalar a, a :*: a ~ Square a) => a -> Square a -squared v = v |*| v - -newtype Cubic a = Cubic a - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving ( Arbitrary, Num, Ord, Enum, Real, Fractional, ToJSON, FromJSON - , Scalar - ) - via a -deriving via (a :: Type) - instance ( Distribution d a - , forall xx yy. Coercible xx yy => Coercible (d xx) (d yy) - ) - => Distribution d (Cubic a) - -instance Unit a => Unit (Cubic a) where - unitSuffix = unitSuffix @a <> "³" - -instance Show a => Show (Cubic a) where - show (Cubic n) = show n <> "³" - -newtype (:**:) a b = Times Double - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (Arbitrary, Num, Ord, Enum, Real, Fractional, ToJSON, FromJSON) - via Double - deriving (Semigroup, Monoid) via Sum Double - deriving Show via ShowUnitSuffix (a :**: b) Double -deriving via Double - instance ( Distribution d Double - , forall xx yy. Coercible xx yy => Coercible (d xx) (d yy) - ) - => Distribution d (a :**: b) - -instance (Unit a, Unit b) => Unit (a :**: b) where - unitSuffix = unitSuffix @a <> " " <> unitSuffix @b - --------------------------------------------------------------------------------- - -newtype Ticks = Ticks Word - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (Num, Ord, Bounded, Enum, Integral, Real, ToJSON, FromJSON) via Word - deriving (Semigroup, Monoid) via (Sum Word) - deriving Scalar via ScalarIntegral Ticks - deriving Arbitrary via GenericArbitrary Ticks - deriving Unit via UnitSymbol "ticks" Ticks - deriving Show via ShowUnitSuffix Ticks Word -deriving via Word - instance ( Distribution d Word - , forall xx yy. Coercible xx yy => Coercible (d xx) (d yy) - ) - => Distribution d Ticks - -newtype Tiles = Tiles Double - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (Num, Ord, Enum, Real, ToJSON, FromJSON, Scalar) via Double - deriving (Semigroup, Monoid) via (Sum Double) - deriving Arbitrary via GenericArbitrary Tiles - deriving Unit via UnitSymbol "m" Tiles - deriving Show via ShowUnitSuffix Tiles Double -deriving via Double - instance ( Distribution d Double - , forall xx yy. Coercible xx yy => Coercible (d xx) (d yy) - ) - => Distribution d Tiles - -type TicksPerTile = Ticks `Per` Tiles -type TilesPerTick = Tiles `Per` Ticks - -timesTiles :: TicksPerTile -> Tiles -> Ticks -timesTiles = (|*|) - --- | Calculate the (cartesian) distance between two 'Position's, floored and --- represented as a number of 'Tile's --- --- Note that this is imprecise, and may be different than the length of a --- bresenham's line between the points -distance :: Position -> Position -> Tiles -distance - = (fromScalar .) . (Metric.distance `on` (fmap fromIntegral . view _Position)) - --------------------------------------------------------------------------------- - -newtype Hitpoints = Hitpoints Word - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving ( Arbitrary, Num, Ord, Bounded, Enum, Integral, Real, Scalar - , ToJSON, FromJSON - ) - via Word - deriving (Semigroup, Monoid) via Sum Word - deriving Unit via UnitSymbol "hp" Hitpoints - deriving Show via ShowUnitSuffix Hitpoints Word - --------------------------------------------------------------------------------- - --- | Grams, the fundamental measure of weight in Xanthous. -newtype Grams = Grams Double - deriving stock (Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving ( Arbitrary, Num, Ord, Enum, Real, Floating, Fractional, RealFloat - , RealFrac, Scalar, ToJSON, FromJSON - ) - via Double - deriving (Semigroup, Monoid) via Sum Double - deriving Unit via UnitSymbol "g" Grams - deriving Show via ShowUnitSuffix Grams Double - --- | Every tile is 1 meter -type Meters = Tiles - --------------------------------------------------------------------------------- - -data Box a = Box - { _topLeftCorner :: V2 a - , _dimensions :: V2 a - } - deriving stock (Show, Eq, Ord, Functor, Generic) -makeFieldsNoPrefix ''Box - --- It seems to be necessary to have an `Arg (V2 a) a` constraint, as a is passed --- to V2 internally, in order to make GHC figure out this deriving via correctly. -deriving via (GenericArbitrary (Box a)) instance (Arbitrary a) => Arbitrary (Box a) - -bottomRightCorner :: Num a => Box a -> V2 a -bottomRightCorner box = - V2 (box ^. topLeftCorner . L._x + box ^. dimensions . L._x) - (box ^. topLeftCorner . L._y + box ^. dimensions . L._y) - -setBottomRightCorner :: (Num a, Ord a) => Box a -> V2 a -> Box a -setBottomRightCorner box br@(V2 brx bry) - | brx < box ^. topLeftCorner . L._x || bry < box ^. topLeftCorner . L._y - = box & topLeftCorner .~ br - & dimensions . L._x .~ ((box ^. topLeftCorner . L._x) - brx) - & dimensions . L._y .~ ((box ^. topLeftCorner . L._y) - bry) - | otherwise - = box & dimensions . L._x .~ (brx - (box ^. topLeftCorner . L._x)) - & dimensions . L._y .~ (bry - (box ^. topLeftCorner . L._y)) - -inBox :: (Ord a, Num a) => Box a -> V2 a -> Bool -inBox box pt = flip all [L._x, L._y] $ \component -> - between (box ^. topLeftCorner . component) - (box ^. to bottomRightCorner . component) - (pt ^. component) - -boxIntersects :: (Ord a, Num a) => Box a -> Box a -> Bool -boxIntersects box₁ box₂ - = any (inBox box₁) [box₂ ^. topLeftCorner, bottomRightCorner box₂] - -boxCenter :: (Fractional a) => Box a -> V2 a -boxCenter box = V2 cx cy - where - cx = box ^. topLeftCorner . L._x + (box ^. dimensions . L._x / 2) - cy = box ^. topLeftCorner . L._y + (box ^. dimensions . L._y / 2) - -boxEdge :: (Enum a, Num a) => Box a -> Edge -> [V2 a] -boxEdge box LeftEdge = - V2 (box ^. topLeftCorner . L._x) - <$> [box ^. topLeftCorner . L._y .. box ^. to bottomRightCorner . L._y] -boxEdge box RightEdge = - V2 (box ^. to bottomRightCorner . L._x) - <$> [box ^. to bottomRightCorner . L._y .. box ^. to bottomRightCorner . L._y] -boxEdge box TopEdge = - flip V2 (box ^. topLeftCorner . L._y) - <$> [box ^. topLeftCorner . L._x .. box ^. to bottomRightCorner . L._x] -boxEdge box BottomEdge = - flip V2 (box ^. to bottomRightCorner . L._y) - <$> [box ^. topLeftCorner . L._x .. box ^. to bottomRightCorner . L._x] diff --git a/users/aspen/xanthous/src/Xanthous/Data/App.hs b/users/aspen/xanthous/src/Xanthous/Data/App.hs deleted file mode 100644 index 13c4b5d61..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/App.hs +++ /dev/null @@ -1,47 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Data.App - ( Panel(..) - , ResourceName(..) - , AppEvent(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Test.QuickCheck -import Test.QuickCheck.Instances.Text () -import Data.Aeson (ToJSON, FromJSON) --------------------------------------------------------------------------------- -import Xanthous.Util.QuickCheck --------------------------------------------------------------------------------- - --- | Enum for "panels" displayed in the game's UI. -data Panel - = -- | A panel providing help with the game's commands - HelpPanel - | -- | A panel displaying the character's inventory - InventoryPanel - | -- | A panel describing an item in the inventory in detail - -- - -- The argument is the full description of the item - ItemDescriptionPanel Text - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function, ToJSON, FromJSON) - deriving Arbitrary via GenericArbitrary Panel - - -data ResourceName - = MapViewport -- ^ The main viewport where we display the game content - | Character -- ^ The character - | MessageBox -- ^ The box where we display messages to the user - | Prompt -- ^ The game's prompt - | Panel Panel -- ^ A panel in the game - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function, ToJSON, FromJSON) - deriving Arbitrary via GenericArbitrary ResourceName - -data AppEvent - = AutoContinue -- ^ Continue whatever autocommand has been requested by the - -- user - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function, ToJSON, FromJSON) - deriving Arbitrary via GenericArbitrary AppEvent diff --git a/users/aspen/xanthous/src/Xanthous/Data/Entities.hs b/users/aspen/xanthous/src/Xanthous/Data/Entities.hs deleted file mode 100644 index 39953410f..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/Entities.hs +++ /dev/null @@ -1,68 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Xanthous.Data.Entities - ( -- * Collisions - Collision(..) - , _Stop - , _Combat - -- * Entity Attributes - , EntityAttributes(..) - , blocksVision - , blocksObject - , collision - , defaultEntityAttributes - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.Aeson (ToJSON(..), FromJSON(..), (.:?), (.!=), withObject) -import Data.Aeson.Generic.DerivingVia -import Xanthous.Util.QuickCheck (GenericArbitrary(..)) -import Test.QuickCheck --------------------------------------------------------------------------------- - -data Collision - = Stop -- ^ Can't move through this - | Combat -- ^ Moving into this equates to hitting it with a stick - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Collision - deriving (ToJSON, FromJSON) - via WithOptions '[ AllNullaryToStringTag 'True ] - Collision -makePrisms ''Collision - --- | Attributes of an entity -data EntityAttributes = EntityAttributes - { _blocksVision :: Bool - -- | Does this entity block a large object from being put in the same tile as - -- it - eg a a door being closed on it - , _blocksObject :: Bool - -- | What type of collision happens when moving into this entity? - , _collision :: Collision - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary EntityAttributes - deriving (ToJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - EntityAttributes -makeLenses ''EntityAttributes - -instance FromJSON EntityAttributes where - parseJSON = withObject "EntityAttributes" $ \o -> do - _blocksVision <- o .:? "blocksVision" - .!= _blocksVision defaultEntityAttributes - _blocksObject <- o .:? "blocksObject" - .!= _blocksObject defaultEntityAttributes - _collision <- o .:? "collision" - .!= _collision defaultEntityAttributes - pure EntityAttributes {..} - -defaultEntityAttributes :: EntityAttributes -defaultEntityAttributes = EntityAttributes - { _blocksVision = False - , _blocksObject = False - , _collision = Stop - } diff --git a/users/aspen/xanthous/src/Xanthous/Data/EntityChar.hs b/users/aspen/xanthous/src/Xanthous/Data/EntityChar.hs deleted file mode 100644 index 855a3462d..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/EntityChar.hs +++ /dev/null @@ -1,56 +0,0 @@ -{-# LANGUAGE RoleAnnotations #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Data.EntityChar - ( EntityChar(..) - , HasChar(..) - , HasStyle(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding ((.=)) --------------------------------------------------------------------------------- -import qualified Graphics.Vty.Attributes as Vty -import Test.QuickCheck -import Data.Aeson --------------------------------------------------------------------------------- -import Xanthous.Orphans () -import Xanthous.Util.QuickCheck (GenericArbitrary(..)) --------------------------------------------------------------------------------- - - -class HasChar s a | s -> a where - char :: Lens' s a - {-# MINIMAL char #-} - -data EntityChar = EntityChar - { _char :: Char - , _style :: Vty.Attr - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary EntityChar -makeFieldsNoPrefix ''EntityChar - -instance FromJSON EntityChar where - parseJSON (String (chr :< Empty)) = pure $ EntityChar chr Vty.defAttr - parseJSON (Object o) = do - (EntityChar _char _) <- o .: "char" - _style <- o .:? "style" .!= Vty.defAttr - pure EntityChar {..} - parseJSON _ = fail "Invalid type, expected string or object" - -instance ToJSON EntityChar where - toJSON (EntityChar chr styl) - | styl == Vty.defAttr = String $ chr <| Empty - | otherwise = object - [ "char" .= chr - , "style" .= styl - ] - -instance IsString EntityChar where - fromString [ch] = EntityChar ch Vty.defAttr - fromString _ = error "Entity char must only be a single character" diff --git a/users/aspen/xanthous/src/Xanthous/Data/EntityMap.hs b/users/aspen/xanthous/src/Xanthous/Data/EntityMap.hs deleted file mode 100644 index 33a98f1ae..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/EntityMap.hs +++ /dev/null @@ -1,276 +0,0 @@ -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE DeriveTraversable #-} -{-# LANGUAGE TupleSections #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE DeriveFunctor #-} --------------------------------------------------------------------------------- -module Xanthous.Data.EntityMap - ( EntityMap - , _EntityMap - , EntityID - , emptyEntityMap - , insertAt - , insertAtReturningID - , fromEIDsAndPositioned - , toEIDsAndPositioned - , atPosition - , atPositionWithIDs - , positions - , lookup - , lookupWithPosition - , positionOf - -- , positionedEntities - , neighbors - , Deduplicate(..) - - -- * debug - , byID - , byPosition - , lastID - - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (lookup) -import Xanthous.Data - ( Position - , Positioned(..) - , positioned - , Neighbors(..) - , neighborPositions, position - ) -import Xanthous.Data.VectorBag -import Xanthous.Orphans () -import Xanthous.Util (EqEqProp(..)) --------------------------------------------------------------------------------- -import Data.Monoid (Endo(..)) -import Test.QuickCheck (Arbitrary(..), CoArbitrary, Function) -import Test.QuickCheck.Checkers (EqProp) -import Test.QuickCheck.Instances.UnorderedContainers () -import Test.QuickCheck.Instances.Vector () -import Text.Show (showString, showParen) -import Data.Aeson --------------------------------------------------------------------------------- - -type EntityID = Word32 -type NonNullSet a = NonNull (Set a) - -data EntityMap a where - EntityMap :: - { _byPosition :: Map Position (NonNullSet EntityID) - , _byID :: HashMap EntityID (Positioned a) - , _lastID :: EntityID - } -> EntityMap a - deriving stock (Functor, Foldable, Traversable, Generic) - deriving anyclass (NFData, CoArbitrary, Function) -deriving via (EqEqProp (EntityMap a)) instance (Eq a, Ord a) => EqProp (EntityMap a) -makeLenses ''EntityMap - -instance ToJSON a => ToJSON (EntityMap a) where - toJSON = toJSON . toEIDsAndPositioned - - -instance FromJSON a => FromJSON (EntityMap a) where - parseJSON = fmap (fromEIDsAndPositioned @[_]) . parseJSON - -byIDInvariantError :: forall a. a -byIDInvariantError = error $ "Invariant violation: All EntityIDs in byPosition " - <> "must point to entityIDs in byID" - -instance (Ord a, Eq a) => Eq (EntityMap a) where - -- em₁ == em₂ = em₁ ^. _EntityMap == em₂ ^. _EntityMap - (==) = (==) `on` view (_EntityMap . to sort) - -deriving stock instance (Ord a) => Ord (EntityMap a) - -instance Show a => Show (EntityMap a) where - showsPrec pr em - = showParen (pr > 10) - $ showString - . ("fromEIDsAndPositioned " <>) - . show - . toEIDsAndPositioned - $ em - -instance Arbitrary a => Arbitrary (EntityMap a) where - arbitrary = review _EntityMap <$> arbitrary - shrink em = review _EntityMap <$> shrink (em ^. _EntityMap) - -type instance Index (EntityMap a) = EntityID -type instance IxValue (EntityMap a) = (Positioned a) -instance Ixed (EntityMap a) where ix eid = at eid . traverse - -instance At (EntityMap a) where - at eid = lens (view $ byID . at eid) setter - where - setter :: EntityMap a -> Maybe (Positioned a) -> EntityMap a - setter m Nothing = fromMaybe m $ do - Positioned pos _ <- m ^. byID . at eid - pure $ m - & removeEIDAtPos pos - & byID . at eid .~ Nothing - setter m (Just pe@(Positioned pos _)) = m - & (case lookupWithPosition eid m of - Nothing -> id - Just (Positioned origPos _) -> removeEIDAtPos origPos - ) - & byID . at eid ?~ pe - & byPosition . at pos %~ \case - Nothing -> Just $ opoint eid - Just es -> Just $ ninsertSet eid es - removeEIDAtPos pos = - byPosition . at pos %~ (>>= fromNullable . ndeleteSet eid) - -instance Semigroup (EntityMap a) where - em₁ <> em₂ = alaf Endo foldMap (uncurry insertAt) (em₂ ^. _EntityMap) em₁ - -instance Monoid (EntityMap a) where - mempty = emptyEntityMap - -instance FunctorWithIndex EntityID EntityMap - -instance FoldableWithIndex EntityID EntityMap - -instance TraversableWithIndex EntityID EntityMap where - itraverse = itraverseOf itraversed - -type instance Element (EntityMap a) = a -instance MonoFoldable (EntityMap a) - -emptyEntityMap :: EntityMap a -emptyEntityMap = EntityMap mempty mempty 0 - -newtype Deduplicate a = Deduplicate (EntityMap a) - deriving stock (Show, Traversable, Generic) - deriving newtype (Eq, Functor, Foldable, EqProp, Arbitrary) - -instance Semigroup (Deduplicate a) where - (Deduplicate em₁) <> (Deduplicate em₂) = - let _byID = em₁ ^. byID <> em₂ ^. byID - _byPosition = mempty &~ do - ifor_ _byID $ \eid (Positioned pos _) -> - at pos %= \case - Just eids -> Just $ ninsertSet eid eids - Nothing -> Just $ opoint eid - _lastID = fromMaybe 1 $ maximumOf (ifolded . asIndex) _byID - in Deduplicate EntityMap{..} - - --------------------------------------------------------------------------------- - -_EntityMap :: Iso' (EntityMap a) [(Position, a)] -_EntityMap = iso hither yon - where - hither :: EntityMap a -> [(Position, a)] - hither em = do - (pos, eids) <- em ^. byPosition . _Wrapped - eid <- toList eids - ent <- em ^.. byID . at eid . folded . positioned - pure (pos, ent) - yon :: [(Position, a)] -> EntityMap a - yon poses = alaf Endo foldMap (uncurry insertAt) poses emptyEntityMap - - -insertAtReturningID :: forall a. Position -> a -> EntityMap a -> (EntityID, EntityMap a) -insertAtReturningID pos e em = - let (eid, em') = em & lastID <+~ 1 - in em' - & byID . at eid ?~ Positioned pos e - & byPosition . at pos %~ \case - Nothing -> Just $ opoint eid - Just es -> Just $ ninsertSet eid es - & (eid, ) - -insertAt :: forall a. Position -> a -> EntityMap a -> EntityMap a -insertAt pos e = snd . insertAtReturningID pos e - -atPosition :: forall a. (Ord a, Show a) => Position -> Lens' (EntityMap a) (VectorBag a) -atPosition pos = lens getter setter - where - getter em = - let eids :: VectorBag EntityID - eids = maybe mempty (VectorBag . toVector . toNullable) - $ em ^. byPosition . at pos - in getEIDAssume em <$> eids - setter em Empty = em & byPosition . at pos .~ Nothing - setter em (sort -> entities) = - let origEIDs = maybe Empty toNullable $ em ^. byPosition . at pos - origEntitiesWithIDs = - sortOn snd $ toList origEIDs <&> \eid -> (eid, getEIDAssume em eid) - go alles₁@((eid, e₁) :< es₁) -- orig - (e₂ :< es₂) -- new - | e₁ == e₂ - -- same, do nothing - = let (eids, lastEID, byID') = go es₁ es₂ - in (insertSet eid eids, lastEID, byID') - | otherwise - -- e₂ is new, generate a new ID for it - = let (eids, lastEID, byID') = go alles₁ es₂ - eid' = succ lastEID - in (insertSet eid' eids, eid', byID' & at eid' ?~ Positioned pos e₂) - go Empty Empty = (mempty, em ^. lastID, em ^. byID) - go orig Empty = - let byID' = foldr deleteMap (em ^. byID) $ map fst orig - in (mempty, em ^. lastID, byID') - go Empty (new :< news) = - let (eids, lastEID, byID') = go Empty news - eid' = succ lastEID - in (insertSet eid' eids, eid', byID' & at eid' ?~ Positioned pos new) - go _ _ = error "unreachable" - (eidsAtPosition, newLastID, newByID) = go origEntitiesWithIDs entities - in em & byPosition . at pos .~ fromNullable eidsAtPosition - & byID .~ newByID - & lastID .~ newLastID - -getEIDAssume :: EntityMap a -> EntityID -> a -getEIDAssume em eid = fromMaybe byIDInvariantError - $ em ^? byID . ix eid . positioned - -atPositionWithIDs :: Position -> EntityMap a -> Vector (EntityID, Positioned a) -atPositionWithIDs pos em = - let eids = maybe mempty (toVector . toNullable) - $ em ^. byPosition . at pos - in (id &&& Positioned pos . getEIDAssume em) <$> eids - -fromEIDsAndPositioned - :: forall mono a. (MonoFoldable mono, Element mono ~ (EntityID, Positioned a)) - => mono - -> EntityMap a -fromEIDsAndPositioned eps = newLastID $ alaf Endo foldMap insert' eps mempty - where - insert' (eid, pe@(Positioned pos _)) - = (byID . at eid ?~ pe) - . (byPosition . at pos %~ \case - Just eids -> Just $ ninsertSet eid eids - Nothing -> Just $ opoint eid - ) - newLastID em = em & lastID - .~ fromMaybe 1 - (maximumOf (ifolded . asIndex) (em ^. byID)) - -toEIDsAndPositioned :: EntityMap a -> [(EntityID, Positioned a)] -toEIDsAndPositioned = itoListOf $ byID . ifolded - -positions :: EntityMap a -> [Position] -positions = toListOf $ byPosition . to keys . folded - -lookupWithPosition :: EntityID -> EntityMap a -> Maybe (Positioned a) -lookupWithPosition eid = view $ byID . at eid - -lookup :: EntityID -> EntityMap a -> Maybe a -lookup eid = fmap (view positioned) . lookupWithPosition eid - --- unlawful :( --- positionedEntities :: IndexedTraversal EntityID (EntityMap a) (EntityMap b) (Positioned a) (Positioned b) --- positionedEntities = byID . itraversed - -neighbors :: (Ord a, Show a) => Position -> EntityMap a -> Neighbors (VectorBag a) -neighbors pos em = (\p -> view (atPosition p) em) <$> neighborPositions pos - --- | Traversal to the position of the entity with the given ID -positionOf :: EntityID -> Traversal' (EntityMap a) Position -positionOf eid = ix eid . position - --------------------------------------------------------------------------------- -makeWrapped ''Deduplicate diff --git a/users/aspen/xanthous/src/Xanthous/Data/EntityMap/Graphics.hs b/users/aspen/xanthous/src/Xanthous/Data/EntityMap/Graphics.hs deleted file mode 100644 index 1398c611c..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/EntityMap/Graphics.hs +++ /dev/null @@ -1,72 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Data.EntityMap.Graphics - ( visiblePositions - , visibleEntities - , lineOfSight - , linesOfSight - , canSee - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (lines) --------------------------------------------------------------------------------- -import Xanthous.Util (takeWhileInclusive) -import Xanthous.Data -import Xanthous.Data.Entities -import Xanthous.Data.EntityMap -import Xanthous.Game.State -import Xanthous.Util.Graphics (circle, line) --------------------------------------------------------------------------------- - --- | Returns a set of positions that are visible, when taking into account --- 'blocksVision', from the given position, within the given radius. -visiblePositions - :: Entity e - => Position - -> Word -- ^ Vision radius - -> EntityMap e - -> Set Position -visiblePositions pos radius - = setFromList . positions . visibleEntities pos radius - --- | Returns a list of entities on the *line of sight* from the first position --- to the second position -lineOfSight - :: forall e. Entity e - => Position -- ^ Origin - -> Position -- ^ Destination - -> EntityMap e - -> [(Position, Vector (EntityID, e))] -lineOfSight (view _Position -> origin) (view _Position -> destination) em = - takeWhileInclusive (none (view blocksVision . entityAttributes . snd) . snd) - $ getPositionedAt <$> line origin destination - where - getPositionedAt :: V2 Int -> (Position, Vector (EntityID, e)) - getPositionedAt (review _Position -> p) = - (p, over _2 (view positioned) <$> atPositionWithIDs p em) - --- | Returns a list of individual lines of sight, each of which is a list of --- entities at positions on that line of sight -linesOfSight - :: forall e. Entity e - => Position -- ^ Centerpoint - -> Word -- ^ Radius - -> EntityMap e - -> [[(Position, Vector (EntityID, e))]] -linesOfSight pos visionRadius em = - radius <&> \edge -> lineOfSight pos (_Position # edge) em - where - radius = circle (pos ^. _Position) $ fromIntegral visionRadius - --- | Given a point and a radius of vision, returns a list of all entities that --- are *visible* (eg, not blocked by an entity that obscures vision) from that --- point -visibleEntities :: Entity e => Position -> Word -> EntityMap e -> EntityMap e -visibleEntities pos visionRadius - = fromEIDsAndPositioned - . foldMap (\(p, es) -> over _2 (Positioned p) <$> es) - . fold - . linesOfSight pos visionRadius - -canSee :: Entity e => (e -> Bool) -> Position -> Word -> EntityMap e -> Bool -canSee match pos radius = any match . visibleEntities pos radius --- ^ this might be optimizable diff --git a/users/aspen/xanthous/src/Xanthous/Data/Levels.hs b/users/aspen/xanthous/src/Xanthous/Data/Levels.hs deleted file mode 100644 index 13251d8af..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/Levels.hs +++ /dev/null @@ -1,180 +0,0 @@ -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Data.Levels - ( Levels - , allLevels - , numLevels - , nextLevel - , prevLevel - , mkLevels1 - , mkLevels - , oneLevel - , current - , ComonadStore(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding ((<.>), Empty, foldMap) -import Xanthous.Util (between, EqProp, EqEqProp(..)) -import Xanthous.Util.Comonad (current) -import Xanthous.Orphans () --------------------------------------------------------------------------------- -import Control.Comonad.Store -import Control.Comonad.Store.Zipper -import Data.Aeson (ToJSON(..), FromJSON(..)) -import Data.Aeson.Generic.DerivingVia -import Data.Functor.Apply -import Data.Foldable (foldMap) -import Data.List.NonEmpty (NonEmpty) -import qualified Data.List.NonEmpty as NE -import Data.Maybe (fromJust) -import Data.Sequence (Seq((:<|), Empty)) -import Data.Semigroup.Foldable.Class -import Data.Text (replace) -import Test.QuickCheck --------------------------------------------------------------------------------- - --- | Collection of levels plus a pointer to the current level --- --- Navigation is via the 'Comonad' instance. We can get the current level with --- 'extract': --- --- extract @Levels :: Levels level -> level --- --- For access to and modification of the level, use --- 'Xanthous.Util.Comonad.current' -newtype Levels a = Levels { levelZipper :: Zipper Seq a } - deriving stock (Generic) - deriving (Functor, Comonad, Foldable) via (Zipper Seq) - -type instance Element (Levels a) = a -instance MonoFoldable (Levels a) -instance MonoFunctor (Levels a) -instance MonoTraversable (Levels a) - -instance ComonadStore Word Levels where - pos = toEnum . pos . levelZipper - peek i = peek (fromEnum i) . levelZipper - -instance Traversable Levels where - traverse f (Levels z) = Levels <$> traverse f z - -instance Foldable1 Levels - -instance Traversable1 Levels where - traverse1 f levs@(Levels z) = seek (pos levs) . partialMkLevels <$> go (unzipper z) - where - go Empty = error "empty seq, unreachable" - go (x :<| xs) = (<|) <$> f x <.> go xs - --- | Always takes the position of the latter element -instance Semigroup (Levels a) where - levs₁ <> levs₂ - = seek (pos levs₂) - . partialMkLevels - $ allLevels levs₁ <> allLevels levs₂ - --- | The number of levels stored in 'Levels' --- --- Equivalent to 'Data.Foldable.length', but likely faster -numLevels :: Levels a -> Word -numLevels = toEnum . size . levelZipper - --- | Make Levels from a Seq. Throws an error if the seq is not empty -partialMkLevels :: Seq a -> Levels a -partialMkLevels = Levels . fromJust . zipper - --- | Make Levels from a possibly-empty structure -mkLevels :: Foldable1 f => f level -> Maybe (Levels level) -mkLevels = fmap Levels . zipper . foldMap pure - --- | Make Levels from a non-empty structure -mkLevels1 :: Foldable1 f => f level -> Levels level -mkLevels1 = fromJust . mkLevels - -oneLevel :: a -> Levels a -oneLevel = mkLevels1 . Identity - --- | Get a sequence of all the levels -allLevels :: Levels a -> Seq a -allLevels = unzipper . levelZipper - --- | Step to the next level, generating a new level if necessary using the given --- applicative action -nextLevel - :: Applicative m - => m level -- ^ Generate a new level, if necessary - -> Levels level - -> m (Levels level) -nextLevel genLevel levs - | succ (pos levs) < numLevels levs - = pure $ seeks succ levs - | otherwise - = genLevel <&> \level -> - seek (pos levs + 1) . partialMkLevels $ allLevels levs |> level - --- | Go to the previous level. Returns Nothing if 'pos' is 0 -prevLevel :: Levels level -> Maybe (Levels level) -prevLevel levs | pos levs == 0 = Nothing - | otherwise = Just $ seeks pred levs - --------------------------------------------------------------------------------- - --- | alternate, slower representation of Levels we can Iso into to perform --- various operations -data AltLevels a = AltLevels - { _levels :: NonEmpty a - , _currentLevel :: Word -- ^ invariant: is within the bounds of _levels - } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - (AltLevels a) -makeLenses ''AltLevels - -alt :: Iso (Levels a) (Levels b) (AltLevels a) (AltLevels b) -alt = iso hither yon - where - hither levs = AltLevels (NE.fromList . toList $ allLevels levs) (pos levs) - yon (AltLevels levs curr) = seek curr $ mkLevels1 levs - -instance Eq a => Eq (Levels a) where - (==) = (==) `on` view alt - -deriving via EqEqProp (Levels a) instance Eq a => EqProp (Levels a) - -instance Show a => Show (Levels a) where - show = unpack . replace "AltLevels" "Levels" . pack . show . view alt - -instance NFData a => NFData (Levels a) where - rnf = rnf . view alt - -instance ToJSON a => ToJSON (Levels a) where - toJSON = toJSON . view alt - -instance FromJSON a => FromJSON (Levels a) where - parseJSON = fmap (review alt) . parseJSON - -instance Arbitrary a => Arbitrary (AltLevels a) where - arbitrary = do - _levels <- arbitrary - _currentLevel <- choose (0, pred . toEnum . length $ _levels) - pure AltLevels {..} - shrink als = do - _levels <- shrink $ als ^. levels - _currentLevel <- filter (between 0 $ pred . toEnum . length $ _levels) - $ shrink $ als ^. currentLevel - pure AltLevels {..} - - -instance Arbitrary a => Arbitrary (Levels a) where - arbitrary = review alt <$> arbitrary - shrink = fmap (review alt) . shrink . view alt - -instance CoArbitrary a => CoArbitrary (Levels a) where - coarbitrary = coarbitrary . view alt - -instance Function a => Function (Levels a) where - function = functionMap (view alt) (review alt) diff --git a/users/aspen/xanthous/src/Xanthous/Data/Memo.hs b/users/aspen/xanthous/src/Xanthous/Data/Memo.hs deleted file mode 100644 index 2b2ee0f96..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/Memo.hs +++ /dev/null @@ -1,98 +0,0 @@ --------------------------------------------------------------------------------- --- | Memoized values --------------------------------------------------------------------------------- -module Xanthous.Data.Memo - ( Memoized(UnMemoized) - , memoizeWith - , getMemoized - , runMemoized - , fillWith - , fillWithM - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Data.Aeson (FromJSON, ToJSON) -import Test.QuickCheck (Arbitrary (arbitrary), oneof, CoArbitrary, Function) -import Test.QuickCheck.Checkers (EqProp) -import Xanthous.Util (EqEqProp(EqEqProp)) -import Control.Monad.State.Class (MonadState) --------------------------------------------------------------------------------- - --- | A memoized value, keyed by a key --- --- If key is different than what is stored here, then val is invalid -data Memoized key val = Memoized key val | UnMemoized - deriving stock (Show, Eq, Generic) - deriving anyclass (Hashable, FromJSON, ToJSON, NFData, CoArbitrary, Function) - deriving EqProp via EqEqProp (Memoized key val) - -instance (Arbitrary k, Arbitrary v) => Arbitrary (Memoized k v) where - arbitrary = oneof [ pure UnMemoized - , Memoized <$> arbitrary <*> arbitrary - ] - --- | Construct a memoized value with the given key -memoizeWith :: forall key val. key -> val -> Memoized key val -memoizeWith = Memoized -{-# INLINE memoizeWith #-} - --- | Retrieve a memoized value providing the key. If the value is unmemoized or --- the keys do not match, returns Nothing. --- --- >>> getMemoized 1 (memoizeWith @Int @Int 1 2) --- Just 2 --- --- >>> getMemoized 2 (memoizeWith @Int @Int 1 2) --- Nothing --- --- >>> getMemoized 1 (UnMemoized :: Memoized Int Int) --- Nothing -getMemoized :: Eq key => key -> Memoized key val -> Maybe val -getMemoized key (Memoized key' v) - | key == key' = Just v - | otherwise = Nothing -getMemoized _ UnMemoized = Nothing -{-# INLINE getMemoized #-} - --- | Get a memoized value using an applicative action to obtain the key -runMemoized - :: (Eq key, Applicative m) - => Memoized key val - -> m key - -> m (Maybe val) -runMemoized m mk = getMemoized <$> mk <*> pure m - --- | In a monadic state containing a 'MemoState', look up the current memoized --- target of some lens keyed by k, filling it with v if not present and --- returning either the new or old value -fillWith - :: forall m s k v. - (MonadState s m, Eq k) - => Lens' s (Memoized k v) - -> k - -> v - -> m v -fillWith l k v' = do - uses l (getMemoized k) >>= \case - Just v -> pure v - Nothing -> do - l .= memoizeWith k v' - pure v' - --- | In a monadic state, look up the current memoized target of some lens keyed --- by k, filling it with the result of some monadic action v if not present and --- returning either the new or old value -fillWithM - :: forall m s k v. - (MonadState s m, Eq k) - => Lens' s (Memoized k v) - -> k - -> m v - -> m v -fillWithM l k mv = do - uses l (getMemoized k) >>= \case - Just v -> pure v - Nothing -> do - v' <- mv - l .= memoizeWith k v' - pure v' diff --git a/users/aspen/xanthous/src/Xanthous/Data/NestedMap.hs b/users/aspen/xanthous/src/Xanthous/Data/NestedMap.hs deleted file mode 100644 index 1b875d448..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/NestedMap.hs +++ /dev/null @@ -1,227 +0,0 @@ -{-# LANGUAGE PartialTypeSignatures #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE QuantifiedConstraints #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE PolyKinds #-} --------------------------------------------------------------------------------- -module Xanthous.Data.NestedMap - ( NestedMapVal(..) - , NestedMap(..) - , lookup - , lookupVal - , insert - - -- * - , (:->) - , BifunctorFunctor'(..) - , BifunctorMonad'(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (lookup, foldMap) -import qualified Xanthous.Prelude as P --------------------------------------------------------------------------------- -import Test.QuickCheck -import Data.Aeson -import Data.Function (fix) -import Data.Foldable (Foldable(..)) -import Data.List.NonEmpty (NonEmpty(..)) -import qualified Data.List.NonEmpty as NE --------------------------------------------------------------------------------- - --- | Natural transformations on bifunctors -type (:->) p q = forall a b. p a b -> q a b -infixr 0 :-> - -class (forall b. Bifunctor b => Bifunctor (t b)) => BifunctorFunctor' t where - bifmap' :: (Bifunctor p, Bifunctor q) => (p :-> q) -> t p :-> t q - -class BifunctorFunctor' t => BifunctorMonad' t where - bireturn' :: (Bifunctor p) => p :-> t p - - bibind' :: (Bifunctor p, Bifunctor q) => (p :-> t q) -> t p :-> t q - bibind' f = bijoin' . bifmap' f - - bijoin' :: (Bifunctor p) => t (t p) :-> t p - bijoin' = bibind' id - - {-# MINIMAL bireturn', (bibind' | bijoin') #-} - --------------------------------------------------------------------------------- - -data NestedMapVal m k v = Val v | Nested (NestedMap m k v) - -deriving stock instance - ( forall k' v'. (Show k', Show v') => Show (m k' v') - , Show k - , Show v - ) => Show (NestedMapVal m k v) - -deriving stock instance - ( forall k' v'. (Eq k', Eq v') => Eq (m k' v') - , Eq k - , Eq v - ) => Eq (NestedMapVal m k v) - -instance - forall m k v. - ( Arbitrary (m k v) - , Arbitrary (m k (NestedMapVal m k v)) - , Arbitrary k - , Arbitrary v - , IsMap (m k (NestedMapVal m k v)) - , MapValue (m k (NestedMapVal m k v)) ~ (NestedMapVal m k v) - , ContainerKey (m k (NestedMapVal m k v)) ~ k - ) => Arbitrary (NestedMapVal m k v) where - arbitrary = sized . fix $ \gen n -> - let nst = fmap (NestedMap . mapFromList) - . listOf - $ (,) <$> arbitrary @k <*> gen (n `div` 2) - in if n == 0 - then Val <$> arbitrary - else oneof [ Val <$> arbitrary - , Nested <$> nst] - shrink (Val v) = Val <$> shrink v - shrink (Nested mkv) = Nested <$> shrink mkv - -instance Functor (m k) => Functor (NestedMapVal m k) where - fmap f (Val v) = Val $ f v - fmap f (Nested m) = Nested $ fmap f m - -instance Bifunctor m => Bifunctor (NestedMapVal m) where - bimap _ g (Val v) = Val $ g v - bimap f g (Nested m) = Nested $ bimap f g m - -instance BifunctorFunctor' NestedMapVal where - bifmap' _ (Val v) = Val v - bifmap' f (Nested m) = Nested $ bifmap' f m - -instance (ToJSONKey k, ToJSON v, ToJSON (m k (NestedMapVal m k v))) - => ToJSON (NestedMapVal m k v) where - toJSON (Val v) = toJSON v - toJSON (Nested m) = toJSON m - -instance Foldable (m k) => Foldable (NestedMapVal m k) where - foldMap f (Val v) = f v - foldMap f (Nested m) = foldMap f m - --- _NestedMapVal --- :: forall m k v m' k' v'. --- ( IsMap (m k v), IsMap (m' k' v') --- , IsMap (m [k] v), IsMap (m' [k'] v') --- , ContainerKey (m k v) ~ k, ContainerKey (m' k' v') ~ k' --- , ContainerKey (m [k] v) ~ [k], ContainerKey (m' [k'] v') ~ [k'] --- , MapValue (m k v) ~ v, MapValue (m' k' v') ~ v' --- , MapValue (m [k] v) ~ v, MapValue (m' [k'] v') ~ v' --- ) --- => Iso (NestedMapVal m k v) --- (NestedMapVal m' k' v') --- (m [k] v) --- (m' [k'] v') --- _NestedMapVal = iso hither yon --- where --- hither :: NestedMapVal m k v -> m [k] v --- hither (Val v) = singletonMap [] v --- hither (Nested m) = bimap _ _ $ m ^. _NestedMap --- yon = _ - --------------------------------------------------------------------------------- - -newtype NestedMap m k v = NestedMap (m k (NestedMapVal m k v)) - -deriving stock instance - ( forall k' v'. (Eq k', Eq v') => Eq (m k' v') - , Eq k - , Eq v - ) => Eq (NestedMap m k v) - -deriving stock instance - ( forall k' v'. (Show k', Show v') => Show (m k' v') - , Show k - , Show v - ) => Show (NestedMap m k v) - -instance Arbitrary (m k (NestedMapVal m k v)) - => Arbitrary (NestedMap m k v) where - arbitrary = NestedMap <$> arbitrary - shrink (NestedMap m) = NestedMap <$> shrink m - -instance Functor (m k) => Functor (NestedMap m k) where - fmap f (NestedMap m) = NestedMap $ fmap (fmap f) m - -instance Bifunctor m => Bifunctor (NestedMap m) where - bimap f g (NestedMap m) = NestedMap $ bimap f (bimap f g) m - -instance BifunctorFunctor' NestedMap where - bifmap' f (NestedMap m) = NestedMap . f $ bimap id (bifmap' f) m - -instance (ToJSONKey k, ToJSON v, ToJSON (m k (NestedMapVal m k v))) - => ToJSON (NestedMap m k v) where - toJSON (NestedMap m) = toJSON m - -instance Foldable (m k) => Foldable (NestedMap m k) where - foldMap f (NestedMap m) = foldMap (foldMap f) m - --------------------------------------------------------------------------------- - -lookup - :: ( IsMap (m k (NestedMapVal m k v)) - , MapValue (m k (NestedMapVal m k v)) ~ (NestedMapVal m k v) - , ContainerKey (m k (NestedMapVal m k v)) ~ k - ) - => NonEmpty k - -> NestedMap m k v - -> Maybe (NestedMapVal m k v) -lookup (p :| []) (NestedMap vs) = P.lookup p vs -lookup (p :| (p₁ : ps)) (NestedMap vs) = P.lookup p vs >>= \case - (Val _) -> Nothing - (Nested vs') -> lookup (p₁ :| ps) vs' - -lookupVal - :: ( IsMap (m k (NestedMapVal m k v)) - , MapValue (m k (NestedMapVal m k v)) ~ (NestedMapVal m k v) - , ContainerKey (m k (NestedMapVal m k v)) ~ k - ) - => NonEmpty k - -> NestedMap m k v - -> Maybe v -lookupVal ks m - | Just (Val v) <- lookup ks m = Just v - | otherwise = Nothing - -insert - :: ( IsMap (m k (NestedMapVal m k v)) - , MapValue (m k (NestedMapVal m k v)) ~ (NestedMapVal m k v) - , ContainerKey (m k (NestedMapVal m k v)) ~ k - ) - => NonEmpty k - -> v - -> NestedMap m k v - -> NestedMap m k v -insert (k :| []) v (NestedMap m) = NestedMap $ P.insertMap k (Val v) m -insert (k₁ :| (k₂ : ks)) v (NestedMap m) = NestedMap $ alterMap upd k₁ m - where - upd (Just (Nested nm)) = Just . Nested $ insert (k₂ :| ks) v nm - upd _ = Just $ - let (kΩ :| ks') = NE.reverse (k₂ :| ks) - in P.foldl' - (\m' k -> Nested . NestedMap . singletonMap k $ m') - (Nested . NestedMap . singletonMap kΩ $ Val v) - ks' - --- _NestedMap --- :: ( IsMap (m k v), IsMap (m' k' v') --- , IsMap (m (NonEmpty k) v), IsMap (m' (NonEmpty k') v') --- , ContainerKey (m k v) ~ k, ContainerKey (m' k' v') ~ k' --- , ContainerKey (m (NonEmpty k) v) ~ (NonEmpty k) --- , ContainerKey (m' (NonEmpty k') v') ~ (NonEmpty k') --- , MapValue (m k v) ~ v, MapValue (m' k' v') ~ v' --- , MapValue (m (NonEmpty k) v) ~ v, MapValue (m' (NonEmpty k') v') ~ v' --- ) --- => Iso (NestedMap m k v) --- (NestedMap m' k' v') --- (m (NonEmpty k) v) --- (m' (NonEmpty k') v') --- _NestedMap = iso undefined yon --- where --- hither (NestedMap m) = undefined . mapToList $ m --- yon mkv = undefined diff --git a/users/aspen/xanthous/src/Xanthous/Data/VectorBag.hs b/users/aspen/xanthous/src/Xanthous/Data/VectorBag.hs deleted file mode 100644 index 2e6d48062..000000000 --- a/users/aspen/xanthous/src/Xanthous/Data/VectorBag.hs +++ /dev/null @@ -1,100 +0,0 @@ -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE DeriveTraversable #-} -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Data.VectorBag - (VectorBag(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Data.Aeson -import qualified Data.Vector as V -import Test.QuickCheck -import Test.QuickCheck.Instances.Vector () --------------------------------------------------------------------------------- - --- | Acts exactly like a Vector, except ignores order when testing for equality -newtype VectorBag a = VectorBag (Vector a) - deriving stock - ( Traversable - , Generic - ) - deriving newtype - ( Show - , Read - , Foldable - , FromJSON - , FromJSON1 - , ToJSON - , Reversing - , Applicative - , Functor - , Monad - , Monoid - , Semigroup - , Arbitrary - , CoArbitrary - , Filterable - ) -makeWrapped ''VectorBag - -instance Function a => Function (VectorBag a) where - function = functionMap (\(VectorBag v) -> v) VectorBag - -type instance Element (VectorBag a) = a -deriving via (Vector a) instance MonoFoldable (VectorBag a) -deriving via (Vector a) instance GrowingAppend (VectorBag a) -deriving via (Vector a) instance SemiSequence (VectorBag a) -deriving via (Vector a) instance MonoPointed (VectorBag a) -deriving via (Vector a) instance MonoFunctor (VectorBag a) - -instance Cons (VectorBag a) (VectorBag b) a b where - _Cons = prism (\(x, VectorBag xs) -> VectorBag $ x <| xs) $ \(VectorBag v) -> - if V.null v - then Left (VectorBag mempty) - else Right (V.unsafeHead v, VectorBag $ V.unsafeTail v) - -instance AsEmpty (VectorBag a) where - _Empty = prism' (const $ VectorBag Empty) $ \case - (VectorBag Empty) -> Just () - _ -> Nothing - -instance Witherable VectorBag where - wither f (VectorBag v) = VectorBag <$> wither f v - witherM f (VectorBag v) = VectorBag <$> witherM f v - filterA p (VectorBag v) = VectorBag <$> filterA p v - -{- - TODO: - , Ixed - , FoldableWithIndex - , FunctorWithIndex - , TraversableWithIndex - , Snoc - , Each --} - -instance Ord a => Eq (VectorBag a) where - (==) = (==) `on` (view _Wrapped . sort) - -instance Ord a => Ord (VectorBag a) where - compare = compare `on` (view _Wrapped . sort) - -instance MonoTraversable (VectorBag a) where - otraverse f (VectorBag v) = VectorBag <$> otraverse f v - -instance IsSequence (VectorBag a) where - fromList = VectorBag . fromList - break prd (VectorBag v) = bimap VectorBag VectorBag $ break prd v - span prd (VectorBag v) = bimap VectorBag VectorBag $ span prd v - dropWhile prd (VectorBag v) = VectorBag $ dropWhile prd v - takeWhile prd (VectorBag v) = VectorBag $ takeWhile prd v - splitAt idx (VectorBag v) = bimap VectorBag VectorBag $ splitAt idx v - unsafeSplitAt idx (VectorBag v) = - bimap VectorBag VectorBag $ unsafeSplitAt idx v - take n (VectorBag v) = VectorBag $ take n v - unsafeTake n (VectorBag v) = VectorBag $ unsafeTake n v - drop n (VectorBag v) = VectorBag $ drop n v - unsafeDrop n (VectorBag v) = VectorBag $ unsafeDrop n v - partition p (VectorBag v) = bimap VectorBag VectorBag $ partition p v diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Character.hs b/users/aspen/xanthous/src/Xanthous/Entities/Character.hs deleted file mode 100644 index c8153086f..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Character.hs +++ /dev/null @@ -1,241 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.Character - - ( -- * Character datatype - Character(..) - , characterName - , HasInventory(..) - , characterDamage - , characterHitpoints' - , characterHitpoints - , hitpointRecoveryRate - , speed - , body - - -- *** Body - , Body(..) - , initialBody - , knuckles - , Knuckles(..) - , fistDamageChance - , damageKnuckles - , fistfightingDamage - - -- * Character functions - , mkCharacter - , pickUpItem - , isDead - , isFullyHealed - , damage - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Brick -import Data.Aeson.Generic.DerivingVia -import Data.Aeson (ToJSON, FromJSON) -import Data.Coerce (coerce) -import Test.QuickCheck -import Test.QuickCheck.Instances.Vector () -import Test.QuickCheck.Arbitrary.Generic -import Test.QuickCheck.Gen (chooseUpTo) -import Test.QuickCheck.Checkers (EqProp) -import Control.Monad.State.Lazy (execState) -import Control.Monad.Trans.State.Lazy (execStateT) --------------------------------------------------------------------------------- -import Xanthous.Game.State -import Xanthous.Entities.Item -import Xanthous.Entities.Common -import Xanthous.Data - ( TicksPerTile, Hitpoints, Per, Ticks, (|*|), positioned ) -import qualified Xanthous.Entities.RawTypes as Raw -import Xanthous.Util (EqEqProp(EqEqProp), modifyKL) -import Xanthous.Monad (say_) --------------------------------------------------------------------------------- - --- | The status of the character's knuckles --- --- This struct is used to track the damage and then eventual build-up of --- calluses when the character is fighting with their fists -data Knuckles = Knuckles - { -- | How damaged are the knuckles currently, from 0 to 5? - -- - -- At 0, no calluses will form - -- At 1 and up, the character will form calluses after a while - -- At 5, continuing to fistfight will deal the character even more damage - _knuckleDamage :: !Word - -- | How built-up are the character's calluses, from 0 to 5? - -- - -- Each level of calluses decreases the likelihood of being damaged when - -- fistfighting by 1%, up to 5 where the character will never be damaged - -- fistfighting - , _knuckleCalluses :: !Word - - -- | Number of turns that have passed since the last time the knuckles were - -- damaged - , _ticksSinceDamaged :: Ticks - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving EqProp via EqEqProp Knuckles - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - Knuckles -makeLenses ''Knuckles - -instance Semigroup Knuckles where - (Knuckles d₁ c₁ t₁) <> (Knuckles d₂ c₂ t₂) = Knuckles - (min (d₁ + d₂) 5) - (min (c₁ + c₂) 5) - (max t₁ t₂) - -instance Monoid Knuckles where - mempty = Knuckles 0 0 0 - -instance Arbitrary Knuckles where - arbitrary = do - _knuckleDamage <- fromIntegral <$> chooseUpTo 5 - _knuckleCalluses <- fromIntegral <$> chooseUpTo 5 - _ticksSinceDamaged <- arbitrary - pure Knuckles{..} - --- | Likelihood that the character fighting with their fists will damage --- themselves -fistDamageChance :: Knuckles -> Float -fistDamageChance knuckles - | calluses == 5 = 0 - | otherwise = baseChance - (0.01 * fromIntegral calluses) - where - baseChance = 0.08 - calluses = knuckles ^. knuckleCalluses - --- | Damage the knuckles by a level (capping at the max knuckle damage) -damageKnuckles :: Knuckles -> Knuckles -damageKnuckles = execState $ do - knuckleDamage %= min 5 . succ - ticksSinceDamaged .= 0 - --- | Damage taken when fistfighting and 'fistDamageChance' has occurred -fistfightingDamage :: Knuckles -> Hitpoints -fistfightingDamage knuckles - | knuckles ^. knuckleDamage == 5 = 2 - | otherwise = 1 - -stepKnuckles :: Ticks -> Knuckles -> AppM Knuckles -stepKnuckles ticks = execStateT . whenM (uses knuckleDamage (> 0)) $ do - ticksSinceDamaged += ticks - whenM (uses ticksSinceDamaged (>= 2000)) $ do - dam <- knuckleDamage <<.= 0 - knuckleCalluses %= min 5 . (+ dam) - ticksSinceDamaged .= 0 - lift $ say_ ["character", "body", "knuckles", "calluses"] - - --- | Status of the character's body -data Body = Body - { _knuckles :: !Knuckles - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Body - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - Body -makeLenses ''Body - -initialBody :: Body -initialBody = Body { _knuckles = mempty } - --------------------------------------------------------------------------------- - -data Character = Character - { _inventory :: !Inventory - , _characterName :: !(Maybe Text) - , _characterHitpoints' :: !Double - , _speed :: !TicksPerTile - , _body :: !Body - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - Character -makeFieldsNoPrefix ''Character - -characterHitpoints :: Character -> Hitpoints -characterHitpoints = views characterHitpoints' floor - -scrollOffset :: Int -scrollOffset = 5 - -instance Draw Character where - draw _ = visibleRegion rloc rreg $ str "@" - where - rloc = Location (negate scrollOffset, negate scrollOffset) - rreg = (2 * scrollOffset, 2 * scrollOffset) - drawPriority = const maxBound -- Character should always be on top, for now - -instance Brain Character where - step ticks = execStateT $ do - positioned . characterHitpoints' %= \hp -> - if hp > fromIntegral initialHitpoints - then hp - else hp + hitpointRecoveryRate |*| ticks - modifyKL (positioned . body . knuckles) $ lift . stepKnuckles ticks - -instance Entity Character where - description _ = "yourself" - entityChar _ = "@" - -instance Arbitrary Character where - arbitrary = genericArbitrary - -initialHitpoints :: Hitpoints -initialHitpoints = 10 - -hitpointRecoveryRate :: Double `Per` Ticks -hitpointRecoveryRate = 1.0 / (15 * coerce defaultSpeed) - -defaultSpeed :: TicksPerTile -defaultSpeed = 100 - -mkCharacter :: Character -mkCharacter = Character - { _inventory = mempty - , _characterName = Nothing - , _characterHitpoints' = fromIntegral initialHitpoints - , _speed = defaultSpeed - , _body = initialBody - } - -defaultCharacterDamage :: Hitpoints -defaultCharacterDamage = 1 - --- | Returns the damage that the character currently does with an attack --- TODO use double-handed/left-hand/right-hand here -characterDamage :: Character -> Hitpoints -characterDamage - = fromMaybe defaultCharacterDamage - . filter (/= 0) - . Just - . sumOf (inventory . wielded . wieldedItems . wieldableItem . Raw.damage) - --- | Is the character fully healed up to or past their initial hitpoints? -isFullyHealed :: Character -> Bool -isFullyHealed = (>= initialHitpoints) . characterHitpoints - --- | Is the character dead? -isDead :: Character -> Bool -isDead = (== 0) . characterHitpoints - -pickUpItem :: Item -> Character -> Character -pickUpItem it = inventory . backpack %~ (it <|) - -damage :: Hitpoints -> Character -> Character -damage (fromIntegral -> amount) = characterHitpoints' %~ \case - n | n <= amount -> 0 - | otherwise -> n - amount - -{-# ANN module ("Hlint: ignore Use newtype instead of data" :: String) #-} diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Common.hs b/users/aspen/xanthous/src/Xanthous/Entities/Common.hs deleted file mode 100644 index 368b03f25..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Common.hs +++ /dev/null @@ -1,290 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- --- | --- Module : Xanthous.Entities.Common --- Description : Common data type definitions and utilities for entities --- --------------------------------------------------------------------------------- -module Xanthous.Entities.Common - ( -- * Inventory - Inventory(..) - , HasInventory(..) - , backpack - , wielded - , items - , InventoryPosition(..) - , describeInventoryPosition - , inventoryPosition - , itemsWithPosition - , removeItemFromPosition - - -- ** Wielded items - , Wielded(..) - , nothingWielded - , hands - , leftHand - , rightHand - , inLeftHand - , inRightHand - , doubleHanded - , Hand(..) - , itemsInHand - , inHand - , wieldInHand - , describeHand - , wieldedItems - , WieldedItem(..) - , wieldedItem - , wieldableItem - , asWieldedItem - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.Aeson (ToJSON, FromJSON) -import Data.Aeson.Generic.DerivingVia -import Test.QuickCheck -import Test.QuickCheck.Checkers (EqProp) --------------------------------------------------------------------------------- -import Xanthous.Data (Positioned(..), positioned) -import Xanthous.Util.QuickCheck -import Xanthous.Game.State -import Xanthous.Entities.Item -import Xanthous.Entities.RawTypes (WieldableItem, wieldable) -import Xanthous.Util (removeFirst, EqEqProp(..)) --------------------------------------------------------------------------------- - -data WieldedItem = WieldedItem - { _wieldedItem :: Item - , _wieldableItem :: WieldableItem - -- ^ Invariant: item ^. itemType . wieldable ≡ Just wieldableItem - } - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - WieldedItem -makeFieldsNoPrefix ''WieldedItem - -asWieldedItem :: Prism' Item WieldedItem -asWieldedItem = prism' hither yon - where - yon item = WieldedItem item <$> item ^. itemType . wieldable - hither (WieldedItem item _) = item - -instance Brain WieldedItem where - step ticks (Positioned p wi) = - over positioned (\i -> WieldedItem i $ wi ^. wieldableItem) - <$> step ticks (Positioned p $ wi ^. wieldedItem) - -instance Draw WieldedItem where - draw = draw . view wieldedItem - -instance Entity WieldedItem where - entityAttributes = entityAttributes . view wieldedItem - description = description . view wieldedItem - entityChar = entityChar . view wieldedItem - -instance Arbitrary WieldedItem where - arbitrary = genericArbitrary <&> \wi -> - wi & wieldedItem . itemType . wieldable ?~ wi ^. wieldableItem - -data Wielded - = DoubleHanded WieldedItem - | Hands { _leftHand :: !(Maybe WieldedItem) - , _rightHand :: !(Maybe WieldedItem) - } - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Wielded - deriving (ToJSON, FromJSON) - via WithOptions '[ 'SumEnc 'ObjWithSingleField ] - Wielded - - -nothingWielded :: Wielded -nothingWielded = Hands Nothing Nothing - -hands :: Prism' Wielded (Maybe WieldedItem, Maybe WieldedItem) -hands = prism' (uncurry Hands) $ \case - Hands l r -> Just (l, r) - _ -> Nothing - -leftHand :: Traversal' Wielded (Maybe WieldedItem) -leftHand = hands . _1 - -inLeftHand :: WieldedItem -> Wielded -inLeftHand wi = Hands (Just wi) Nothing - -rightHand :: Traversal' Wielded (Maybe WieldedItem) -rightHand = hands . _2 - -inRightHand :: WieldedItem -> Wielded -inRightHand wi = Hands Nothing (Just wi) - -doubleHanded :: Prism' Wielded WieldedItem -doubleHanded = prism' DoubleHanded $ \case - DoubleHanded i -> Just i - _ -> Nothing - -wieldedItems :: Traversal' Wielded WieldedItem -wieldedItems k (DoubleHanded wielded) = DoubleHanded <$> k wielded -wieldedItems k (Hands l r) = Hands <$> _Just k l <*> _Just k r - - -data Hand - = LeftHand - | RightHand - | BothHands - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Hand - -itemsInHand :: Hand -> Wielded -> [WieldedItem] -itemsInHand LeftHand (DoubleHanded wi) = [wi] -itemsInHand LeftHand (Hands lh _) = toList lh -itemsInHand RightHand (DoubleHanded wi) = [wi] -itemsInHand RightHand (Hands _ rh) = toList rh -itemsInHand BothHands (DoubleHanded wi) = [wi] -itemsInHand BothHands (Hands lh rh) = toList lh <> toList rh - -inHand :: Hand -> WieldedItem -> Wielded -inHand LeftHand = inLeftHand -inHand RightHand = inRightHand -inHand BothHands = review doubleHanded - -wieldInHand :: Hand -> WieldedItem -> Wielded -> ([WieldedItem], Wielded) -wieldInHand hand item w = (itemsInHand hand w, doWield) - where - doWield = case (hand, w) of - (LeftHand, Hands _ r) -> Hands (Just item) r - (LeftHand, DoubleHanded _) -> inLeftHand item - (RightHand, Hands l _) -> Hands l (Just item) - (RightHand, DoubleHanded _) -> inRightHand item - (BothHands, _) -> DoubleHanded item - -describeHand :: Hand -> Text -describeHand LeftHand = "your left hand" -describeHand RightHand = "your right hand" -describeHand BothHands = "both hands" - -data Inventory = Inventory - { _backpack :: Vector Item - , _wielded :: Wielded - } - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Inventory - deriving EqProp via EqEqProp Inventory - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - Inventory -makeFieldsNoPrefix ''Inventory - -items :: Traversal' Inventory Item -items k (Inventory bp w) = Inventory - <$> traversed k bp - <*> (wieldedItems . wieldedItem) k w - -type instance Element Inventory = Item - -instance MonoFunctor Inventory where - omap = over items - -instance MonoFoldable Inventory where - ofoldMap = foldMapOf items - ofoldr = foldrOf items - ofoldl' = foldlOf' items - otoList = toListOf items - oall = allOf items - oany = anyOf items - onull = nullOf items - ofoldr1Ex = foldr1Of items - ofoldl1Ex' = foldl1Of' items - headEx = headEx . toListOf items - lastEx = lastEx . toListOf items - -instance MonoTraversable Inventory where - otraverse = traverseOf items - -instance Semigroup Inventory where - inv₁ <> inv₂ = - let backpack' = inv₁ ^. backpack <> inv₂ ^. backpack - (wielded', backpack'') = case (inv₁ ^. wielded, inv₂ ^. wielded) of - (wielded₁, wielded₂@(DoubleHanded _)) -> - (wielded₂, backpack' <> fromList (wielded₁ ^.. wieldedItems . wieldedItem)) - (wielded₁, wielded₂@(Hands (Just _) (Just _))) -> - (wielded₂, backpack' <> fromList (wielded₁ ^.. wieldedItems . wieldedItem)) - (wielded₁, Hands Nothing Nothing) -> (wielded₁, backpack') - (Hands Nothing Nothing, wielded₂) -> (wielded₂, backpack') - (Hands (Just l₁) Nothing, Hands Nothing (Just r₂)) -> - (Hands (Just l₁) (Just r₂), backpack') - (wielded₁@(DoubleHanded _), wielded₂) -> - (wielded₁, backpack' <> fromList (wielded₂ ^.. wieldedItems . wieldedItem)) - (Hands Nothing (Just r₁), Hands Nothing (Just r₂)) -> - (Hands Nothing (Just r₂), r₁ ^. wieldedItem <| backpack') - (Hands Nothing r₁, Hands (Just l₂) Nothing) -> - (Hands (Just l₂) r₁, backpack') - (Hands (Just l₁) Nothing, Hands (Just l₂) Nothing) -> - (Hands (Just l₂) Nothing, l₁ ^. wieldedItem <| backpack') - (Hands (Just l₁) (Just r₁), Hands Nothing (Just r₂)) -> - (Hands (Just l₁) (Just r₂), r₁ ^. wieldedItem <| backpack') - (Hands (Just l₁) (Just r₁), Hands (Just l₂) Nothing) -> - (Hands (Just l₂) (Just r₁), l₁ ^. wieldedItem <| backpack') - in Inventory backpack'' wielded' - -instance Monoid Inventory where - mempty = Inventory mempty $ Hands Nothing Nothing - -class HasInventory s a | s -> a where - inventory :: Lens' s a - {-# MINIMAL inventory #-} - --- | Representation for where in the inventory an item might be -data InventoryPosition - = Backpack - | InHand Hand - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary InventoryPosition - --- | Return a human-readable description of the given 'InventoryPosition' -describeInventoryPosition :: InventoryPosition -> Text -describeInventoryPosition Backpack = "In backpack" -describeInventoryPosition (InHand hand) = "Wielded, in " <> describeHand hand - --- | Given a position in the inventory, return a traversal on the inventory over --- all the items in that position -inventoryPosition :: InventoryPosition -> Traversal' Inventory Item -inventoryPosition Backpack = backpack . traversed -inventoryPosition (InHand LeftHand) = wielded . leftHand . _Just . wieldedItem -inventoryPosition (InHand RightHand) = wielded . leftHand . _Just . wieldedItem -inventoryPosition (InHand BothHands) = wielded . doubleHanded . wieldedItem - --- | A fold over all the items in the inventory accompanied by their position in --- the inventory --- --- Invariant: This will return items in the same order as 'items' -itemsWithPosition :: Fold Inventory (InventoryPosition, Item) -itemsWithPosition = folding $ (<>) <$> backpackItems <*> handItems - where - backpackItems = toListOf $ backpack . folded . to (Backpack ,) - handItems inv = case inv ^. wielded of - DoubleHanded i -> pure (InHand BothHands, i ^. wieldedItem) - Hands l r -> (l ^.. folded . wieldedItem . to (InHand LeftHand ,)) - <> (r ^.. folded . wieldedItem . to (InHand RightHand ,)) - --- | Remove the first item equal to 'Item' from the given position in the --- inventory -removeItemFromPosition :: InventoryPosition -> Item -> Inventory -> Inventory -removeItemFromPosition Backpack item inv - = inv & backpack %~ removeFirst (== item) -removeItemFromPosition (InHand LeftHand) item inv - = inv & wielded . leftHand %~ filter ((/= item) . view wieldedItem) -removeItemFromPosition (InHand RightHand) item inv - = inv & wielded . rightHand %~ filter ((/= item) . view wieldedItem) -removeItemFromPosition (InHand BothHands) item inv - | has (wielded . doubleHanded . wieldedItem . filtered (== item)) inv - = inv & wielded .~ nothingWielded - | otherwise - = inv diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Creature.hs b/users/aspen/xanthous/src/Xanthous/Entities/Creature.hs deleted file mode 100644 index 3ea610795..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Creature.hs +++ /dev/null @@ -1,88 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.Creature - ( -- * Creature - Creature(..) - -- ** Lenses - , creatureType - , hitpoints - , hippocampus - , inventory - - -- ** Creature functions - , damage - , isDead - , visionRadius - - -- * Hippocampus - , Hippocampus(..) - -- ** Lenses - , destination - -- ** Destination - , Destination(..) - , destinationFromPos - -- *** Lenses - , destinationPosition - , destinationProgress - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Test.QuickCheck -import Data.Aeson.Generic.DerivingVia -import Data.Aeson (ToJSON, FromJSON) --------------------------------------------------------------------------------- -import Xanthous.AI.Gormlak -import Xanthous.Entities.RawTypes hiding - (Creature, description, damage) -import qualified Xanthous.Entities.RawTypes as Raw -import Xanthous.Game.State -import Xanthous.Data -import Xanthous.Data.Entities -import Xanthous.Entities.Creature.Hippocampus -import Xanthous.Util.QuickCheck (GenericArbitrary(..)) -import Xanthous.Entities.Common (Inventory, HasInventory(..)) --------------------------------------------------------------------------------- - -data Creature = Creature - { _creatureType :: !CreatureType - , _hitpoints :: !Hitpoints - , _hippocampus :: !Hippocampus - , _inventory :: !Inventory - } - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Draw via DrawRawCharPriority "_creatureType" 1000 Creature - deriving Arbitrary via GenericArbitrary Creature - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - Creature -makeFieldsNoPrefix ''Creature - -instance HasVisionRadius Creature where - visionRadius = const 50 -- TODO - -instance Brain Creature where - step = brainVia GormlakBrain - entityCanMove = const True - -instance Entity Creature where - entityAttributes _ = defaultEntityAttributes - & blocksObject .~ True - description = view $ creatureType . Raw.description - entityChar = view $ creatureType . char - entityCollision = const $ Just Combat - --------------------------------------------------------------------------------- - -damage :: Hitpoints -> Creature -> Creature -damage amount = hitpoints %~ \hp -> - if hp <= amount - then 0 - else hp - amount - -isDead :: Creature -> Bool -isDead = views hitpoints (== 0) - -{-# ANN module ("Hlint: ignore Use newtype instead of data" :: String) #-} diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Creature/Hippocampus.hs b/users/aspen/xanthous/src/Xanthous/Entities/Creature/Hippocampus.hs deleted file mode 100644 index d13ea8055..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Creature/Hippocampus.hs +++ /dev/null @@ -1,71 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.Creature.Hippocampus - (-- * Hippocampus - Hippocampus(..) - , initialHippocampus - -- ** Lenses - , destination - , greetedCharacter - -- ** Destination - , Destination(..) - , destinationFromPos - -- *** Lenses - , destinationPosition - , destinationProgress - ) -where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.Aeson.Generic.DerivingVia -import Data.Aeson (ToJSON, FromJSON) -import Test.QuickCheck -import Test.QuickCheck.Arbitrary.Generic --------------------------------------------------------------------------------- -import Xanthous.Data --------------------------------------------------------------------------------- - - -data Destination = Destination - { _destinationPosition :: !Position - -- | The progress towards the destination, tracked as an offset from the - -- creature's original position. - -- - -- When this value reaches >= 1, the creature has reached their destination - , _destinationProgress :: !Tiles - } - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - Destination -instance Arbitrary Destination where arbitrary = genericArbitrary -makeLenses ''Destination - -destinationFromPos :: Position -> Destination -destinationFromPos _destinationPosition = - let _destinationProgress = 0 - in Destination{..} - -data Hippocampus = Hippocampus - { _destination :: !(Maybe Destination) - , -- | Has this creature greeted the character in any way yet? - -- - -- Some creature types ignore this field - _greetedCharacter :: !Bool - } - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Hippocampus - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - Hippocampus -makeLenses ''Hippocampus - -initialHippocampus :: Hippocampus -initialHippocampus = Hippocampus - { _destination = Nothing - , _greetedCharacter = False - } diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Draw/Util.hs b/users/aspen/xanthous/src/Xanthous/Entities/Draw/Util.hs deleted file mode 100644 index aa6c5fa4f..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Draw/Util.hs +++ /dev/null @@ -1,31 +0,0 @@ -module Xanthous.Entities.Draw.Util where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Brick.Widgets.Border.Style -import Brick.Types (Edges(..)) --------------------------------------------------------------------------------- - -borderFromEdges :: BorderStyle -> Edges Bool -> Char -borderFromEdges bstyle edges = ($ bstyle) $ case edges of - Edges False False False False -> const '☐' - - Edges True False False False -> bsVertical - Edges False True False False -> bsVertical - Edges False False True False -> bsHorizontal - Edges False False False True -> bsHorizontal - - Edges True True False False -> bsVertical - Edges True False True False -> bsCornerBR - Edges True False False True -> bsCornerBL - - Edges False True True False -> bsCornerTR - Edges False True False True -> bsCornerTL - Edges False False True True -> bsHorizontal - - Edges False True True True -> bsIntersectT - Edges True False True True -> bsIntersectB - Edges True True False True -> bsIntersectL - Edges True True True False -> bsIntersectR - - Edges True True True True -> bsIntersectFull diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Entities.hs b/users/aspen/xanthous/src/Xanthous/Entities/Entities.hs deleted file mode 100644 index a0c037a1b..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Entities.hs +++ /dev/null @@ -1,63 +0,0 @@ -{-# LANGUAGE StandaloneDeriving #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.Entities () where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Test.QuickCheck -import qualified Test.QuickCheck.Gen as Gen -import Data.Aeson --------------------------------------------------------------------------------- -import Xanthous.Entities.Character -import Xanthous.Entities.Item -import Xanthous.Entities.Creature -import Xanthous.Entities.Environment -import Xanthous.Entities.Marker -import Xanthous.Game.State -import Xanthous.Util.QuickCheck -import Data.Aeson.Generic.DerivingVia --------------------------------------------------------------------------------- - -instance Arbitrary SomeEntity where - arbitrary = Gen.oneof - [ SomeEntity <$> arbitrary @Character - , SomeEntity <$> arbitrary @Item - , SomeEntity <$> arbitrary @Creature - , SomeEntity <$> arbitrary @Wall - , SomeEntity <$> arbitrary @Door - , SomeEntity <$> arbitrary @GroundMessage - , SomeEntity <$> arbitrary @Staircase - , SomeEntity <$> arbitrary @Marker - ] - -instance FromJSON SomeEntity where - parseJSON = withObject "Entity" $ \obj -> do - (entityType :: Text) <- obj .: "type" - case entityType of - "Character" -> SomeEntity @Character <$> obj .: "data" - "Item" -> SomeEntity @Item <$> obj .: "data" - "Creature" -> SomeEntity @Creature <$> obj .: "data" - "Wall" -> SomeEntity @Wall <$> obj .: "data" - "Door" -> SomeEntity @Door <$> obj .: "data" - "GroundMessage" -> SomeEntity @GroundMessage <$> obj .: "data" - "Staircase" -> SomeEntity @Staircase <$> obj .: "data" - "Marker" -> SomeEntity @Marker <$> obj .: "data" - _ -> fail . unpack $ "Invalid entity type \"" <> entityType <> "\"" - -deriving via WithOptions '[ FieldLabelModifier '[Drop 1] ] GameLevel - instance FromJSON GameLevel -deriving via WithOptions '[ FieldLabelModifier '[Drop 1] ] GameState - instance FromJSON GameState - -instance Entity SomeEntity where - entityAttributes (SomeEntity ent) = entityAttributes ent - description (SomeEntity ent) = description ent - entityChar (SomeEntity ent) = entityChar ent - entityCollision (SomeEntity ent) = entityCollision ent - -instance Function SomeEntity where - function = functionJSON - -instance CoArbitrary SomeEntity where - coarbitrary = coarbitrary . encode diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Entities.hs-boot b/users/aspen/xanthous/src/Xanthous/Entities/Entities.hs-boot deleted file mode 100644 index 519a862c6..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Entities.hs-boot +++ /dev/null @@ -1,14 +0,0 @@ -{-# OPTIONS_GHC -fno-warn-orphans #-} -module Xanthous.Entities.Entities where - -import Test.QuickCheck -import Data.Aeson -import Xanthous.Game.State (SomeEntity, GameState, Entity) - -instance Arbitrary SomeEntity -instance Function SomeEntity -instance CoArbitrary SomeEntity -instance FromJSON SomeEntity -instance Entity SomeEntity - -instance FromJSON GameState diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Environment.hs b/users/aspen/xanthous/src/Xanthous/Entities/Environment.hs deleted file mode 100644 index b45a91eab..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Environment.hs +++ /dev/null @@ -1,160 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -module Xanthous.Entities.Environment - ( - -- * Walls - Wall(..) - - -- * Doors - , Door(..) - , open - , closed - , locked - , unlockedDoor - - -- * Messages - , GroundMessage(..) - - -- * Stairs - , Staircase(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Test.QuickCheck -import Brick (str) -import Brick.Widgets.Border.Style (unicode) -import Brick.Types (Edges(..)) -import Data.Aeson -import Data.Aeson.Generic.DerivingVia --------------------------------------------------------------------------------- -import Xanthous.Entities.Draw.Util -import Xanthous.Data -import Xanthous.Data.Entities -import Xanthous.Game.State -import Xanthous.Util.QuickCheck --------------------------------------------------------------------------------- - -data Wall = Wall - deriving stock (Show, Eq, Ord, Generic, Enum) - deriving anyclass (NFData, CoArbitrary, Function) - -instance ToJSON Wall where - toJSON = const $ String "Wall" - -instance FromJSON Wall where - parseJSON = withText "Wall" $ \case - "Wall" -> pure Wall - _ -> fail "Invalid Wall: expected Wall" - -instance Brain Wall where step = brainVia Brainless - -instance Entity Wall where - entityAttributes _ = defaultEntityAttributes - & blocksVision .~ True - & blocksObject .~ True - description _ = "a wall" - entityChar _ = "┼" - -instance Arbitrary Wall where - arbitrary = pure Wall - -wallEdges :: (MonoFoldable mono, Element mono ~ SomeEntity) - => Neighbors mono -> Edges Bool -wallEdges neighs = any (entityIs @Wall) <$> edges neighs - -instance Draw Wall where - drawWithNeighbors neighs _wall = - str . pure . borderFromEdges unicode $ wallEdges neighs - -data Door = Door - { _open :: Bool - , _locked :: Bool - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function, ToJSON, FromJSON) - deriving Arbitrary via GenericArbitrary Door -makeLenses ''Door - -instance Draw Door where - drawWithNeighbors neighs door - = str . pure . ($ door ^. open) $ case wallEdges neighs of - Edges True False False False -> vertDoor - Edges False True False False -> vertDoor - Edges True True False False -> vertDoor - Edges False False True False -> horizDoor - Edges False False False True -> horizDoor - Edges False False True True -> horizDoor - _ -> allsidesDoor - where - horizDoor True = '␣' - horizDoor False = 'ᚔ' - vertDoor True = '[' - vertDoor False = 'ǂ' - allsidesDoor True = '+' - allsidesDoor False = '▥' - -instance Brain Door where step = brainVia Brainless - -instance Entity Door where - entityAttributes door = defaultEntityAttributes - & blocksVision .~ not (door ^. open) - description door | door ^. open = "an open door" - | otherwise = "a closed door" - entityChar _ = "d" - entityCollision door | door ^. open = Nothing - | otherwise = Just Stop - -closed :: Lens' Door Bool -closed = open . involuted not - --- | A closed, unlocked door -unlockedDoor :: Door -unlockedDoor = Door - { _open = False - , _locked = False - } - --------------------------------------------------------------------------------- - -newtype GroundMessage = GroundMessage Text - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary GroundMessage - deriving (ToJSON, FromJSON) - via WithOptions '[ 'TagSingleConstructors 'True - , 'SumEnc 'ObjWithSingleField - ] - GroundMessage - deriving Draw - via DrawStyledCharacter ('Just 'Yellow) 'Nothing "≈" - GroundMessage -instance Brain GroundMessage where step = brainVia Brainless - -instance Entity GroundMessage where - description = const "a message on the ground. Press r. to read it." - entityChar = const "≈" - entityCollision = const Nothing - --------------------------------------------------------------------------------- - -data Staircase = UpStaircase | DownStaircase - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Staircase - deriving (ToJSON, FromJSON) - via WithOptions '[ 'TagSingleConstructors 'True - , 'SumEnc 'ObjWithSingleField - ] - Staircase -instance Brain Staircase where step = brainVia Brainless - -instance Draw Staircase where - draw UpStaircase = str "<" - draw DownStaircase = str ">" - -instance Entity Staircase where - description UpStaircase = "a staircase leading upwards" - description DownStaircase = "a staircase leading downwards" - entityChar UpStaircase = "<" - entityChar DownStaircase = ">" - entityCollision = const Nothing diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Item.hs b/users/aspen/xanthous/src/Xanthous/Entities/Item.hs deleted file mode 100644 index eadd62569..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Item.hs +++ /dev/null @@ -1,76 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.Item - ( Item(..) - , itemType - , density - , volume - , newWithType - , isEdible - , weight - , fullDescription - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Test.QuickCheck (Arbitrary, CoArbitrary, Function) -import Data.Aeson (ToJSON, FromJSON) -import Data.Aeson.Generic.DerivingVia -import Control.Monad.Random (MonadRandom) --------------------------------------------------------------------------------- -import Xanthous.Entities.RawTypes (ItemType) -import qualified Xanthous.Entities.RawTypes as Raw -import Xanthous.Game.State -import Xanthous.Data (Grams, Per, Cubic, Meters, (|*|)) -import Xanthous.Util.QuickCheck (GenericArbitrary(GenericArbitrary)) -import Xanthous.Random (choose, FiniteInterval(..)) --------------------------------------------------------------------------------- - -data Item = Item - { _itemType :: ItemType - , _density :: Grams `Per` Cubic Meters - , _volume :: Cubic Meters - } - deriving stock (Eq, Show, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Draw via DrawRawChar "_itemType" Item - deriving Arbitrary via GenericArbitrary Item - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - Item -makeLenses ''Item - --- deriving via (Brainless Item) instance Brain Item -instance Brain Item where step = brainVia Brainless - -instance Entity Item where - description = view $ itemType . Raw.description - entityChar = view $ itemType . Raw.char - entityCollision = const Nothing - -newWithType :: MonadRandom m => ItemType -> m Item -newWithType _itemType = do - _density <- choose . FiniteInterval $ _itemType ^. Raw.density - _volume <- choose . FiniteInterval $ _itemType ^. Raw.volume - pure Item {..} - -isEdible :: Item -> Bool -isEdible = Raw.isEdible . view itemType - --- | The weight of this item, calculated by multiplying its volume by the --- density of its material -weight :: Item -> Grams -weight item = (item ^. density) |*| (item ^. volume) - --- | Describe the item in full detail -fullDescription :: Item -> Text -fullDescription item = unlines - [ item ^. itemType . Raw.description - , "" - , item ^. itemType . Raw.longDescription - , "" - , "volume: " <> tshow (item ^. volume) - , "density: " <> tshow (item ^. density) - , "weight: " <> tshow (weight item) - ] diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Marker.hs b/users/aspen/xanthous/src/Xanthous/Entities/Marker.hs deleted file mode 100644 index 14d02872e..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Marker.hs +++ /dev/null @@ -1,41 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Entities.Marker ( Marker(..) ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.Aeson -import Test.QuickCheck -import qualified Graphics.Vty.Attributes as Vty -import qualified Graphics.Vty.Image as Vty -import Brick.Widgets.Core (raw) --------------------------------------------------------------------------------- -import Xanthous.Game.State -import Xanthous.Data.Entities (EntityAttributes(..)) --------------------------------------------------------------------------------- - --- | Mark on the map - for use in debugging / development only. -newtype Marker = Marker Text - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (Semigroup, Monoid, ToJSON, FromJSON, Arbitrary) via Text - -instance Brain Marker where step = brainVia Brainless - -instance Entity Marker where - entityAttributes = const EntityAttributes - { _blocksVision = False - , _blocksObject = False - , _collision = Stop - } - description (Marker m) = "[M] " <> m - entityChar = const $ "X" & style .~ markerStyle - entityCollision = const Nothing - -instance Draw Marker where - draw = const . raw $ Vty.char markerStyle 'X' - drawPriority = const maxBound - -markerStyle :: Vty.Attr -markerStyle = Vty.defAttr - `Vty.withForeColor` Vty.red - `Vty.withBackColor` Vty.black diff --git a/users/aspen/xanthous/src/Xanthous/Entities/RawTypes.hs b/users/aspen/xanthous/src/Xanthous/Entities/RawTypes.hs deleted file mode 100644 index a7021d76c..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/RawTypes.hs +++ /dev/null @@ -1,286 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE DuplicateRecordFields #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.RawTypes - ( - EntityRaw(..) - , _Creature - , _Item - - -- * Creatures - , CreatureType(..) - , hostile - -- ** Generation parameters - , CreatureGenerateParams(..) - , canGenerate - -- ** Language - , LanguageName(..) - , getLanguage - -- ** Attacks - , Attack(..) - - -- * Items - , ItemType(..) - -- ** Item sub-types - -- *** Edible - , EdibleItem(..) - , isEdible - -- *** Wieldable - , WieldableItem(..) - , isWieldable - - -- * Lens classes - , HasAttackMessage(..) - , HasAttacks(..) - , HasChance(..) - , HasChar(..) - , HasCreatureAttackMessage(..) - , HasDamage(..) - , HasDensity(..) - , HasDescription(..) - , HasEatMessage(..) - , HasEdible(..) - , HasEntityName(..) - , HasEquippedItem(..) - , HasFriendly(..) - , HasGenerateParams(..) - , HasHitpointsHealed(..) - , HasLanguage(..) - , HasLevelRange(..) - , HasLongDescription(..) - , HasMaxHitpoints(..) - , HasName(..) - , HasSayVerb(..) - , HasSpeed(..) - , HasVolume(..) - , HasWieldable(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Test.QuickCheck -import Data.Aeson.Generic.DerivingVia -import Data.Aeson (ToJSON, FromJSON) -import Data.Interval (Interval, lowerBound', upperBound') -import qualified Data.Interval as Interval --------------------------------------------------------------------------------- -import Xanthous.Messages (Message(..)) -import Xanthous.Data (TicksPerTile, Hitpoints, Per, Grams, Cubic, Meters) -import Xanthous.Data.EntityChar -import Xanthous.Util.QuickCheck -import Xanthous.Generators.Speech (Language, gormlak, english) -import Xanthous.Orphans () -import Xanthous.Util (EqProp, EqEqProp(..)) --------------------------------------------------------------------------------- - --- | Identifiers for languages that creatures can speak. --- --- Non-verbal or non-sentient creatures have Nothing as their language --- --- At some point, we will likely want to make languages be defined in data files --- somewhere, and reference them that way instead. -data LanguageName = Gormlak | English - deriving stock (Show, Eq, Ord, Generic, Enum, Bounded) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary LanguageName - deriving (ToJSON, FromJSON) - via WithOptions '[ AllNullaryToStringTag 'True ] - LanguageName - --- | Resolve a 'LanguageName' into an actual 'Language' -getLanguage :: LanguageName -> Language -getLanguage Gormlak = gormlak -getLanguage English = english - --- | Natural attacks for creature types -data Attack = Attack - { -- | the @{{creature}}@ @{{description}}@ - _description :: !Message - -- | Damage dealt - , _damage :: !Hitpoints - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Attack - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] - , OmitNothingFields 'True - ] - Attack -makeFieldsNoPrefix ''Attack - --- | Description for generating an item equipped to a creature -data CreatureEquippedItem = CreatureEquippedItem - { -- | Name of the entity type to generate - _entityName :: !Text - -- | Chance of generating the item when generating the creature - -- - -- A chance of 1.0 will always generate the item - , _chance :: !Double - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary CreatureEquippedItem - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] - , OmitNothingFields 'True - ] - CreatureEquippedItem -makeFieldsNoPrefix ''CreatureEquippedItem - - -data CreatureGenerateParams = CreatureGenerateParams - { -- | Range of dungeon levels at which to generate this creature - _levelRange :: !(Interval Word) - -- | Item equipped to the creature - , _equippedItem :: !(Maybe CreatureEquippedItem) - } - deriving stock (Eq, Show, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary CreatureGenerateParams - deriving EqProp via EqEqProp CreatureGenerateParams - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - CreatureGenerateParams -makeFieldsNoPrefix ''CreatureGenerateParams - -instance Ord CreatureGenerateParams where - compare - = (compare `on` lowerBound' . _levelRange) - <> (compare `on` upperBound' . _levelRange) - <> (compare `on` _equippedItem) - --- | Can a creature with these generate params be generated on this level? -canGenerate - :: Word -- ^ Level number - -> CreatureGenerateParams - -> Bool -canGenerate levelNumber gps = Interval.member levelNumber $ gps ^. levelRange - -data CreatureType = CreatureType - { _name :: !Text - , _description :: !Text - , _char :: !EntityChar - , _maxHitpoints :: !Hitpoints - , _friendly :: !Bool - , _speed :: !TicksPerTile - , _language :: !(Maybe LanguageName) - , -- | The verb, in present tense, for when the creature says something - _sayVerb :: !(Maybe Text) - , -- | The creature's natural attacks - _attacks :: !(NonNull (Vector Attack)) - -- | Parameters for generating the creature in levels - , _generateParams :: !(Maybe CreatureGenerateParams) - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary CreatureType - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] - , OmitNothingFields 'True - ] - CreatureType -makeFieldsNoPrefix ''CreatureType - -hostile :: Lens' CreatureType Bool -hostile = friendly . involuted not - --------------------------------------------------------------------------------- - -data EdibleItem = EdibleItem - { _hitpointsHealed :: !Int - , _eatMessage :: !(Maybe Message) - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary EdibleItem - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - EdibleItem -makeFieldsNoPrefix ''EdibleItem - -data WieldableItem = WieldableItem - { _damage :: !Hitpoints - -- | Message to use when the character is using this item to attack a - -- creature. - -- - -- Grammatically, this should be of the form "slash at the - -- {{creature.creatureType.name}} with your dagger" - -- - -- = Parameters - -- - -- [@creature@ (type: 'Creature')] The creature being attacked - , _attackMessage :: !(Maybe Message) - -- | Message to use when a creature is using this item to attack the - -- character. - -- - -- Grammatically, should be of the form "The creature slashes you with its - -- dagger". - -- - -- = Parameters - -- - -- [@creature@ (type: 'Creature')] The creature doing the attacking - -- [@item@ (type: 'Item')] The item itself - , _creatureAttackMessage :: !(Maybe Message) - } - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary WieldableItem - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - WieldableItem -makeFieldsNoPrefix ''WieldableItem - --------------------------------------------------------------------------------- - -data ItemType = ItemType - { _name :: !Text - , _description :: !Text - , _longDescription :: !Text - , _char :: !EntityChar - , _density :: !(Interval (Grams `Per` Cubic Meters)) - , _volume :: !(Interval (Cubic Meters)) - , _edible :: !(Maybe EdibleItem) - , _wieldable :: !(Maybe WieldableItem) - } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary ItemType - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - ItemType -makeFieldsNoPrefix ''ItemType - -instance Ord ItemType where - compare x y - = compareOf name x y - <> compareOf description x y - <> compareOf longDescription x y - <> compareOf char x y - <> compareOf (density . to extractInterval) x y - <> compareOf (volume . to extractInterval) x y - <> compareOf edible x y - <> compareOf wieldable x y - where - compareOf l = comparing (view l) - extractInterval = lowerBound' &&& upperBound' - --- | Can this item be eaten? -isEdible :: ItemType -> Bool -isEdible = has $ edible . _Just - --- | Can this item be used as a weapon? -isWieldable :: ItemType -> Bool -isWieldable = has $ wieldable . _Just - --------------------------------------------------------------------------------- - -data EntityRaw - = Creature !CreatureType - | Item !ItemType - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData) - deriving Arbitrary via GenericArbitrary EntityRaw - deriving (FromJSON) - via WithOptions '[ SumEnc ObjWithSingleField ] - EntityRaw -makePrisms ''EntityRaw diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Raws.hs b/users/aspen/xanthous/src/Xanthous/Entities/Raws.hs deleted file mode 100644 index 10f0d8319..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Raws.hs +++ /dev/null @@ -1,49 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.Raws - ( raws - , raw - , RawType(..) - , rawsWithType - ) where --------------------------------------------------------------------------------- -import Data.FileEmbed -import qualified Data.Yaml as Yaml -import Xanthous.Prelude -import System.FilePath.Posix --------------------------------------------------------------------------------- -import Xanthous.Entities.RawTypes -import Xanthous.AI.Gormlak () --------------------------------------------------------------------------------- -rawRaws :: [(FilePath, ByteString)] -rawRaws = $(embedDir "src/Xanthous/Entities/Raws") - -raws :: HashMap Text EntityRaw -raws - = mapFromList - . map (bimap - (pack . takeBaseName) - (either (error . Yaml.prettyPrintParseException) id - . Yaml.decodeEither')) - $ rawRaws - -raw :: Text -> Maybe EntityRaw -raw n = raws ^. at n - -class RawType (a :: Type) where - _RawType :: Prism' EntityRaw a - -instance RawType CreatureType where - _RawType = prism' Creature $ \case - Creature c -> Just c - _ -> Nothing - -instance RawType ItemType where - _RawType = prism' Item $ \case - Item i -> Just i - _ -> Nothing - -rawsWithType :: forall a. RawType a => HashMap Text a -rawsWithType = mapFromList . itoListOf (ifolded . _RawType) $ raws - --------------------------------------------------------------------------------- diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Raws/broken-dagger.yaml b/users/aspen/xanthous/src/Xanthous/Entities/Raws/broken-dagger.yaml deleted file mode 100644 index 12c76fc14..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Raws/broken-dagger.yaml +++ /dev/null @@ -1,24 +0,0 @@ -Item: - name: broken dagger - description: a short, broken dagger - longDescription: A short dagger with a twisted, chipped blade - char: - char: † - style: - foreground: black - wieldable: - damage: 3 - attackMessage: - - slash at the {{creature.creatureType.name}} with your dagger - - stab the {{creature.creatureType.name}} with your dagger - creatureAttackMessage: - - The {{creature.creatureType.name}} slashes at you with its dagger. - - The {{creature.creatureType.name}} stabs you with its dagger. - # Just the steel, not the handle, for now - density: [7750 , 8050000] - # 15cm – 45cm - # × - # 2cm – 3cm - # × - # .5cm – 1cm - volume: [0.15, 1.35] diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Raws/gormlak.yaml b/users/aspen/xanthous/src/Xanthous/Entities/Raws/gormlak.yaml deleted file mode 100644 index ad3d9cb14..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Raws/gormlak.yaml +++ /dev/null @@ -1,20 +0,0 @@ -Creature: - name: gormlak - description: a gormlak - longDescription: | - A chittering imp-like creature with bright yellow horns and sharp claws. It - adores shiny objects and gathers in swarms. - char: - char: g - style: - foreground: red - maxHitpoints: 5 - speed: 125 - friendly: false - language: Gormlak - sayVerb: yells - attacks: - - description: - - claws you - - slashes you with its claws - damage: 1 diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Raws/husk.yaml b/users/aspen/xanthous/src/Xanthous/Entities/Raws/husk.yaml deleted file mode 100644 index cdfcde616..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Raws/husk.yaml +++ /dev/null @@ -1,26 +0,0 @@ -Creature: - name: husk - description: an empty husk of some humanoid creature - longDescription: | - An empty husk of a humanoid creature. All semblance of sentience has long - left its eyes; instead it shambles about aimlessly, always hungering for the - warmth of life. - char: - char: h - style: - foreground: black - maxHitpoints: 6 - speed: 110 - friendly: false - attacks: - - description: - - swings its arms at you - - elbows you - damage: 1 - - description: kicks you - damage: 2 - generateParams: - levelRange: [1, PosInf] - equippedItem: - entityName: broken-dagger - chance: 0.9 diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Raws/noodles.yaml b/users/aspen/xanthous/src/Xanthous/Entities/Raws/noodles.yaml deleted file mode 100644 index c0501a18a..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Raws/noodles.yaml +++ /dev/null @@ -1,14 +0,0 @@ -Item: - name: noodles - description: "a big bowl o' noodles" - longDescription: You know exactly what kind of noodles - char: - char: 'n' - style: - foreground: yellow - edible: - hitpointsHealed: 2 - eatMessage: - - You slurp up the noodles. Yumm! - density: 500000 - volume: 0.001 diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Raws/ooze.yaml b/users/aspen/xanthous/src/Xanthous/Entities/Raws/ooze.yaml deleted file mode 100644 index fe427c94a..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Raws/ooze.yaml +++ /dev/null @@ -1,15 +0,0 @@ -Creature: - name: ooze - description: an ooze - longDescription: | - A jiggling, amorphous, bright green caustic blob - char: - char: o - style: - foreground: green - maxHitpoints: 3 - speed: 100 - friendly: false - attacks: - - description: slams into you - damage: 1 diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Raws/rock.yaml b/users/aspen/xanthous/src/Xanthous/Entities/Raws/rock.yaml deleted file mode 100644 index 3f4e133fe..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Raws/rock.yaml +++ /dev/null @@ -1,10 +0,0 @@ -Item: - name: rock - description: a rock - longDescription: a medium-sized rock made out of some unknown stone - char: . - wieldable: - damage: 1 - attackMessage: hit the {{creature.creatureType.name}} in the head with your rock - density: [ 1500000, 2500000 ] - volume: [ 0.000125, 0.001 ] diff --git a/users/aspen/xanthous/src/Xanthous/Entities/Raws/stick.yaml b/users/aspen/xanthous/src/Xanthous/Entities/Raws/stick.yaml deleted file mode 100644 index 7f9e1faff..000000000 --- a/users/aspen/xanthous/src/Xanthous/Entities/Raws/stick.yaml +++ /dev/null @@ -1,22 +0,0 @@ -Item: - name: stick - description: a wooden stick - longDescription: A sturdy branch broken off from some sort of tree - char: - char: ∤ - style: - foreground: yellow - wieldable: - damage: 2 - attackMessage: - - bonk the {{creature.creatureType.name}} over the head with your stick - - bash the {{creature.creatureType.name}} on the noggin with your stick - - whack the {{creature.creatureType.name}} with your stick - creatureAttackMessage: - - The {{creature.creatureType.name}} bonks you over the head with its stick. - - The {{creature.creatureType.name}} bashes you on the noggin with its stick. - - The {{creature.creatureType.name}} whacks you with its stick. - # https://www.sciencedirect.com/topics/agricultural-and-biological-sciences/wood-density - # it's a hard stick. so it's dense wood. - density: 890000 # g/m³ - volume: [ 0.003, 0.006 ] # ≈3.5 cm radius × ≈1m length diff --git a/users/aspen/xanthous/src/Xanthous/Game.hs b/users/aspen/xanthous/src/Xanthous/Game.hs deleted file mode 100644 index 89c23f0de..000000000 --- a/users/aspen/xanthous/src/Xanthous/Game.hs +++ /dev/null @@ -1,73 +0,0 @@ -module Xanthous.Game - ( GameState(..) - , levels - , entities - , revealedPositions - , messageHistory - , randomGen - , promptState - , GamePromptState(..) - - , getInitialState - , initialStateFromSeed - - , positionedCharacter - , character - , characterPosition - , updateCharacterVision - , characterVisiblePositions - , entitiesAtCharacter - , revealedEntitiesAtPosition - - -- * Messages - , MessageHistory(..) - , HasMessages(..) - , HasTurn(..) - , HasDisplayedTurn(..) - , pushMessage - , previousMessage - , nextTurn - - -- * Collisions - , Collision(..) - , collisionAt - - -- * App monad - , AppT(..) - - -- * Saving the game - , saveGame - , loadGame - , saved - - -- * Debug State - , DebugState(..) - , debugState - , allRevealed - ) where --------------------------------------------------------------------------------- -import qualified Codec.Compression.Zlib as Zlib -import Codec.Compression.Zlib.Internal (DecompressError) -import qualified Data.Aeson as JSON -import System.IO.Unsafe --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Xanthous.Game.State -import Xanthous.Game.Lenses -import Xanthous.Game.Arbitrary () -import Xanthous.Entities.Entities () --------------------------------------------------------------------------------- - -saveGame :: GameState -> LByteString -saveGame = Zlib.compress . JSON.encode - -loadGame :: LByteString -> Maybe GameState -loadGame = JSON.decode <=< decompressZlibMay - where - decompressZlibMay bs - = unsafeDupablePerformIO - $ (let r = Zlib.decompress bs in r `seq` pure (Just r)) - `catch` \(_ :: DecompressError) -> pure Nothing - -saved :: Prism' LByteString GameState -saved = prism' saveGame loadGame diff --git a/users/aspen/xanthous/src/Xanthous/Game/Arbitrary.hs b/users/aspen/xanthous/src/Xanthous/Game/Arbitrary.hs deleted file mode 100644 index 679bfe545..000000000 --- a/users/aspen/xanthous/src/Xanthous/Game/Arbitrary.hs +++ /dev/null @@ -1,53 +0,0 @@ -{-# LANGUAGE UndecidableInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Xanthous.Game.Arbitrary where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (foldMap) --------------------------------------------------------------------------------- -import Test.QuickCheck -import System.Random -import Data.Foldable (foldMap) --------------------------------------------------------------------------------- -import Xanthous.Data.Levels -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Entities.Entities () -import Xanthous.Entities.Character -import Xanthous.Game.State -import Xanthous.Orphans () -import Xanthous.Util.QuickCheck (GenericArbitrary(..)) --------------------------------------------------------------------------------- - -deriving via GenericArbitrary GameLevel instance Arbitrary GameLevel - -instance Arbitrary GameState where - arbitrary = do - chr <- arbitrary @Character - _upStaircasePosition <- arbitrary - _messageHistory <- arbitrary - levs <- arbitrary @(Levels GameLevel) - _levelRevealedPositions <- - fmap setFromList - . sublistOf - . foldMap (EntityMap.positions . _levelEntities) - $ levs - let (_characterEntityID, _levelEntities) = - EntityMap.insertAtReturningID _upStaircasePosition (SomeEntity chr) - $ levs ^. current . levelEntities - _levels = levs & current .~ GameLevel {..} - _randomGen <- mkStdGen <$> arbitrary - let _promptState = NoPrompt -- TODO - _activePanel <- arbitrary - _debugState <- arbitrary - let _autocommand = NoAutocommand - _memo <- arbitrary - _savefile <- arbitrary - pure $ GameState {..} - - -instance CoArbitrary GameLevel -instance Function GameLevel -instance CoArbitrary GameState -instance Function GameState diff --git a/users/aspen/xanthous/src/Xanthous/Game/Draw.hs b/users/aspen/xanthous/src/Xanthous/Game/Draw.hs deleted file mode 100644 index 291dfd8b5..000000000 --- a/users/aspen/xanthous/src/Xanthous/Game/Draw.hs +++ /dev/null @@ -1,224 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Game.Draw - ( drawGame - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Brick hiding (loc, on) -import Brick.Widgets.Border -import Brick.Widgets.Border.Style -import Brick.Widgets.Edit -import Control.Monad.State.Lazy (evalState) -import Control.Monad.State.Class ( get, MonadState, gets ) --------------------------------------------------------------------------------- -import Xanthous.Data -import Xanthous.Data.App (ResourceName, Panel(..)) -import qualified Xanthous.Data.App as Resource -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Game.State -import Xanthous.Entities.Common (Wielded(..), wielded, backpack) -import Xanthous.Entities.Character -import Xanthous.Entities.Item (Item) -import Xanthous.Game - ( characterPosition - , character - , revealedEntitiesAtPosition - ) -import Xanthous.Game.Prompt -import Xanthous.Orphans () -import Brick.Widgets.Center (hCenter) -import Xanthous.Command (Keybinding (..), keybindings, Command, commandIsHidden) -import Graphics.Vty.Input.Events (Modifier(..)) -import Graphics.Vty.Input (Key(..)) -import Brick.Widgets.Table --------------------------------------------------------------------------------- - -cursorPosition :: GameState -> Widget ResourceName -> Widget ResourceName -cursorPosition game - | WaitingPrompt _ (Prompt _ _ (preview promptStatePosition -> Just pos) _ _) - <- game ^. promptState - = showCursor Resource.Prompt (pos ^. loc) - | otherwise - = showCursor Resource.Character (game ^. characterPosition . loc) - -drawMessages :: MessageHistory -> Widget ResourceName -drawMessages = txtWrap . (<> " ") . unwords . reverse . oextract - -drawPromptState :: GamePromptState m -> Widget ResourceName -drawPromptState NoPrompt = emptyWidget -drawPromptState (WaitingPrompt msg (Prompt _ pt ps pri _)) = - case (pt, ps, pri) of - (SStringPrompt, StringPromptState edit, mDef) -> - txt msg - <+> txt (maybe "" (\def -> "(default: " <> def <> ") ") mDef) - <+> renderEditor (txt . fold) True edit - (SDirectionPrompt, DirectionPromptState, _) -> txtWrap msg - (SMenu, _, menuItems) -> - txtWrap msg - <=> foldl' (<=>) emptyWidget (map drawMenuItem $ itoList menuItems) - _ -> txtWrap msg - where - drawMenuItem (chr, MenuOption m _) = - str ("[" <> pure chr <> "] ") <+> txtWrap m - -drawEntities - :: forall m. MonadState GameState m - => m (Widget ResourceName) -drawEntities = do - allEnts <- use entities - let entityPositions = EntityMap.positions allEnts - maxY = fromMaybe 0 $ maximumOf (folded . y) entityPositions - maxX = fromMaybe 0 $ maximumOf (folded . x) entityPositions - rows = traverse mkRow [0..maxY] - mkRow rowY = hBox <$> traverse (renderEntityAt . flip Position rowY) [0..maxX] - renderEntityAt pos - = renderTopEntity pos <$> revealedEntitiesAtPosition pos - renderTopEntity pos ents - = let neighbors = EntityMap.neighbors pos allEnts - in maybe (str " ") (drawWithNeighbors neighbors) - $ maximumBy (compare `on` drawPriority) - <$> fromNullable ents - vBox <$> rows - -drawMap :: MonadState GameState m => m (Widget ResourceName) -drawMap = do - cursorPos <- gets cursorPosition - viewport Resource.MapViewport Both . cursorPos <$> drawEntities - -bullet :: Char -bullet = '•' - -drawInventoryPanel :: GameState -> Widget ResourceName -drawInventoryPanel game - = drawWielded (game ^. character . inventory . wielded) - <=> drawBackpack (game ^. character . inventory . backpack) - where - drawWielded (Hands Nothing Nothing) = emptyWidget - drawWielded (DoubleHanded i) = - txtWrap $ "You are holding " <> description i <> " in both hands" - drawWielded (Hands l r) = drawHand "left" l <=> drawHand "right" r - drawHand side = maybe emptyWidget $ \i -> - txtWrap ( "You are holding " - <> description i - <> " in your " <> side <> " hand" - ) - <=> txt " " - - drawBackpack :: Vector Item -> Widget ResourceName - drawBackpack Empty = txtWrap "Your backpack is empty right now." - drawBackpack backpackItems - = txtWrap ( "You are currently carrying the following items in your " - <> "backpack:") - <=> txt " " - <=> foldl' (<=>) emptyWidget - (map - (txtWrap . ((bullet <| " ") <>) . description) - backpackItems) - -drawHelpPanel :: Widget ResourceName -drawHelpPanel - = txtWrap "To move in a direction or attack, use vi keys (hjklyubn):" - <=> txt " " - <=> hCenter keyStar - <=> txt " " - <=> cmds - where - keyStar - = txt "y k u" - <=> txt " \\|/" - <=> txt "h-.-l" - <=> txt " /|\\" - <=> txt "b j n" - - cmds - = renderTable - . alignRight 0 - . setDefaultRowAlignment AlignTop - . surroundingBorder False - . rowBorders False - . columnBorders False - . table $ help <&> \(key, cmd) -> [ txt $ key <> " : " - , hLimitPercent 100 $ txtWrap cmd] - - help = - extraHelp <> - keybindings - ^.. ifolded - . filtered (not . commandIsHidden) - . withIndex - . to (bimap displayKeybinding displayCommand) - extraHelp - = [("Shift-Dir", "Auto-move")] - - displayCommand = tshow @Command - displayKeybinding (Keybinding k mods) = foldMap showMod mods <> showKey k - - showMod MCtrl = "Ctrl-" - showMod MShift = "Shift-" - showMod MAlt = "Alt-" - showMod MMeta = "Meta-" - - showKey (KChar c) = pack [c] - showKey KEsc = "" - showKey KBS = "" - showKey KEnter = "" - showKey KLeft = "" - showKey KRight = "" - showKey KUp = "" - showKey KDown = "" - showKey KUpLeft = "" - showKey KUpRight = "" - showKey KDownLeft = "" - showKey KDownRight = "" - showKey KCenter = "
    " - showKey (KFun n) = " tshow n <> ">" - showKey KBackTab = "" - showKey KPrtScr = "" - showKey KPause = "" - showKey KIns = "" - showKey KHome = "" - showKey KPageUp = "" - showKey KDel = "" - showKey KEnd = "" - showKey KPageDown = "" - showKey KBegin = "" - showKey KMenu = "" - -drawPanel :: GameState -> Panel -> Widget ResourceName -drawPanel game panel - = border - . hLimit 35 - . viewport (Resource.Panel panel) Vertical - $ case panel of - HelpPanel -> drawHelpPanel - InventoryPanel -> drawInventoryPanel game - ItemDescriptionPanel desc -> txtWrap desc - -drawCharacterInfo :: Character -> Widget ResourceName -drawCharacterInfo ch = txt " " <+> charName <+> charHitpoints - where - charName | Just n <- ch ^. characterName - = txt $ n <> " " - | otherwise - = emptyWidget - charHitpoints - = txt "Hitpoints: " - <+> txt (tshow $ let Hitpoints hp = characterHitpoints ch in hp) - -drawGame :: GameState -> [Widget ResourceName] -drawGame = evalState $ do - game <- get - drawnMap <- drawMap - pure - . pure - . withBorderStyle unicode - $ case game ^. promptState of - NoPrompt -> drawMessages (game ^. messageHistory) - _ -> emptyWidget - <=> drawPromptState (game ^. promptState) - <=> - (maybe emptyWidget (drawPanel game) (game ^. activePanel) - <+> border drawnMap - ) - <=> drawCharacterInfo (game ^. character) diff --git a/users/aspen/xanthous/src/Xanthous/Game/Env.hs b/users/aspen/xanthous/src/Xanthous/Game/Env.hs deleted file mode 100644 index 5d7b275c8..000000000 --- a/users/aspen/xanthous/src/Xanthous/Game/Env.hs +++ /dev/null @@ -1,37 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Game.Env - ( Config(..) - , defaultConfig - , disableSaving - , GameEnv(..) - , eventChan - , config - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Brick.BChan (BChan) -import Xanthous.Data.App (AppEvent) --------------------------------------------------------------------------------- - -data Config = Config - { _disableSaving :: Bool - } - deriving stock (Generic, Show, Eq) -makeLenses ''Config -{-# ANN Config ("HLint: ignore Use newtype instead of data" :: String) #-} - -defaultConfig :: Config -defaultConfig = Config - { _disableSaving = False - } - --------------------------------------------------------------------------------- - -data GameEnv = GameEnv - { _eventChan :: BChan AppEvent - , _config :: Config - } - deriving stock (Generic) -makeLenses ''GameEnv diff --git a/users/aspen/xanthous/src/Xanthous/Game/Lenses.hs b/users/aspen/xanthous/src/Xanthous/Game/Lenses.hs deleted file mode 100644 index c692a3b47..000000000 --- a/users/aspen/xanthous/src/Xanthous/Game/Lenses.hs +++ /dev/null @@ -1,178 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE QuantifiedConstraints #-} -{-# LANGUAGE AllowAmbiguousTypes #-} --------------------------------------------------------------------------------- -module Xanthous.Game.Lenses - ( clearMemo - , positionedCharacter - , character - , characterPosition - , updateCharacterVision - , characterVisiblePositions - , characterVisibleEntities - , positionIsCharacterVisible - , getInitialState - , initialStateFromSeed - , entitiesAtCharacter - , revealedEntitiesAtPosition - , hearingRadius - - -- * Collisions - , Collision(..) - , entitiesCollision - , collisionAt - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import System.Random -import Control.Monad.State -import Control.Monad.Random (getRandom) --------------------------------------------------------------------------------- -import Xanthous.Game.State -import qualified Xanthous.Game.Memo as Memo -import Xanthous.Data -import Xanthous.Data.Levels -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Data.EntityMap.Graphics - (visiblePositions, visibleEntities) -import Xanthous.Data.VectorBag -import Xanthous.Entities.Character (Character, mkCharacter) -import {-# SOURCE #-} Xanthous.Entities.Entities () -import Xanthous.Game.Memo (emptyMemoState, MemoState) -import Xanthous.Data.Memo (fillWithM, Memoized) --------------------------------------------------------------------------------- - -getInitialState :: IO GameState -getInitialState = initialStateFromSeed <$> getRandom - -initialStateFromSeed :: Int -> GameState -initialStateFromSeed seed = - let _randomGen = mkStdGen seed - chr = mkCharacter - _upStaircasePosition = Position 0 0 - (_characterEntityID, _levelEntities) - = EntityMap.insertAtReturningID - _upStaircasePosition - (SomeEntity chr) - mempty - _levelRevealedPositions = mempty - level = GameLevel {..} - _levels = oneLevel level - _messageHistory = mempty - _promptState = NoPrompt - _activePanel = Nothing - _debugState = DebugState - { _allRevealed = False - } - _savefile = Nothing - _autocommand = NoAutocommand - _memo = emptyMemoState - in GameState {..} - -clearMemo :: MonadState GameState m => Lens' MemoState (Memoized k v) -> m () -clearMemo l = memo %= Memo.clear l - -positionedCharacter :: Lens' GameState (Positioned Character) -positionedCharacter = lens getPositionedCharacter setPositionedCharacter - where - setPositionedCharacter :: GameState -> Positioned Character -> GameState - setPositionedCharacter game chr - = game - & entities . at (game ^. characterEntityID) - ?~ fmap SomeEntity chr - - getPositionedCharacter :: GameState -> Positioned Character - getPositionedCharacter game - = over positioned - ( fromMaybe (error "Invariant error: Character was not a character!") - . downcastEntity - ) - . fromMaybe (error "Invariant error: Character not found!") - $ EntityMap.lookupWithPosition - (game ^. characterEntityID) - (game ^. entities) - - -character :: Lens' GameState Character -character = positionedCharacter . positioned - -characterPosition :: Lens' GameState Position -characterPosition = positionedCharacter . position - --- TODO make this dynamic -visionRadius :: Word -visionRadius = 12 - --- TODO make this dynamic -hearingRadius :: Word -hearingRadius = 12 - --- | Update the revealed entities at the character's position based on their --- vision -updateCharacterVision :: GameState -> GameState -updateCharacterVision = execState $ do - positions <- characterVisiblePositions - revealedPositions <>= positions - -characterVisiblePositions :: MonadState GameState m => m (Set Position) -characterVisiblePositions = do - charPos <- use characterPosition - fillWithM - (memo . Memo.characterVisiblePositions) - charPos - (uses entities $ visiblePositions charPos visionRadius) - -characterVisibleEntities :: GameState -> EntityMap.EntityMap SomeEntity -characterVisibleEntities game = - let charPos = game ^. characterPosition - in visibleEntities charPos visionRadius $ game ^. entities - -positionIsCharacterVisible :: MonadState GameState m => Position -> m Bool -positionIsCharacterVisible p = (p `elem`) <$> characterVisiblePositions --- ^ TODO optimize - -entitiesCollision - :: ( Functor f - , forall xx. MonoFoldable (f xx) - , Element (f SomeEntity) ~ SomeEntity - , Element (f (Maybe Collision)) ~ Maybe Collision - , Show (f (Maybe Collision)) - , Show (f SomeEntity) - ) - => f SomeEntity - -> Maybe Collision -entitiesCollision = join . maximumMay . fmap entityCollision - -collisionAt :: MonadState GameState m => Position -> m (Maybe Collision) -collisionAt p = uses (entities . EntityMap.atPosition p) entitiesCollision - -entitiesAtCharacter :: Lens' GameState (VectorBag SomeEntity) -entitiesAtCharacter = lens getter setter - where - getter gs = gs ^. entities . EntityMap.atPosition (gs ^. characterPosition) - setter gs ents = gs - & entities . EntityMap.atPosition (gs ^. characterPosition) .~ ents - --- | Returns all entities at the given position that are revealed to the --- character. --- --- Concretely, this is either entities that are *currently* visible to the --- character, or entities, that are immobile and that the character has seen --- before -revealedEntitiesAtPosition - :: MonadState GameState m - => Position - -> m (VectorBag SomeEntity) -revealedEntitiesAtPosition p = do - allRev <- use $ debugState . allRevealed - cvps <- characterVisiblePositions - entitiesAtPosition <- use $ entities . EntityMap.atPosition p - revealed <- use revealedPositions - let immobileEntitiesAtPosition = filter (not . entityCanMove) entitiesAtPosition - pure $ if | allRev || p `member` cvps - -> entitiesAtPosition - | p `member` revealed - -> immobileEntitiesAtPosition - | otherwise - -> mempty diff --git a/users/aspen/xanthous/src/Xanthous/Game/Memo.hs b/users/aspen/xanthous/src/Xanthous/Game/Memo.hs deleted file mode 100644 index 154063b5d..000000000 --- a/users/aspen/xanthous/src/Xanthous/Game/Memo.hs +++ /dev/null @@ -1,52 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- --- | Memoized versions of calculations --------------------------------------------------------------------------------- -module Xanthous.Game.Memo - ( MemoState - , emptyMemoState - , clear - -- ** Memo lenses - , characterVisiblePositions - - -- * Memoized values - , Memoized(UnMemoized) - , memoizeWith - , getMemoized - , runMemoized - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.Aeson (ToJSON, FromJSON) -import Data.Aeson.Generic.DerivingVia -import Test.QuickCheck (CoArbitrary, Function, Arbitrary) --------------------------------------------------------------------------------- -import Xanthous.Data (Position) -import Xanthous.Data.Memo -import Xanthous.Util.QuickCheck (GenericArbitrary(GenericArbitrary)) --------------------------------------------------------------------------------- - --- | Memoized calculations on the game state -data MemoState = MemoState - { -- | Memoized version of 'Xanthous.Game.Lenses.characterVisiblePositions', - -- memoized with the position of the character - _characterVisiblePositions :: Memoized Position (Set Position) - } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary MemoState - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - MemoState -makeLenses ''MemoState - -emptyMemoState :: MemoState -emptyMemoState = MemoState { _characterVisiblePositions = UnMemoized } -{-# INLINE emptyMemoState #-} - -clear :: ASetter' MemoState (Memoized key val) -> MemoState -> MemoState -clear = flip set UnMemoized -{-# INLINE clear #-} - -{-# ANN module ("Hlint: ignore Use newtype instead of data" :: String) #-} diff --git a/users/aspen/xanthous/src/Xanthous/Game/Prompt.hs b/users/aspen/xanthous/src/Xanthous/Game/Prompt.hs deleted file mode 100644 index 2d6c0a280..000000000 --- a/users/aspen/xanthous/src/Xanthous/Game/Prompt.hs +++ /dev/null @@ -1,359 +0,0 @@ -{-# LANGUAGE DeriveFunctor #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE GADTs #-} --------------------------------------------------------------------------------- -module Xanthous.Game.Prompt - ( PromptType(..) - , SPromptType(..) - , SingPromptType(..) - , PromptCancellable(..) - , PromptResult(..) - , PromptState(..) - , promptStatePosition - , MenuOption(..) - , mkMenuItems - , PromptInput - , Prompt(..) - , mkPrompt - , mkStringPrompt - , mkStringPromptWithDefault - , mkMenu - , mkPointOnMapPrompt - , mkFirePrompt - , isCancellable - , submitPrompt - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Brick.Widgets.Edit (Editor, editorText, getEditContents) -import Test.QuickCheck -import Test.QuickCheck.Arbitrary.Generic --------------------------------------------------------------------------------- -import Xanthous.Util (smallestNotIn, AlphaChar (..)) -import Xanthous.Data (Direction, Position, Tiles) -import Xanthous.Data.App (ResourceName) -import qualified Xanthous.Data.App as Resource --------------------------------------------------------------------------------- - -data PromptType where - StringPrompt :: PromptType - Confirm :: PromptType - Menu :: Type -> PromptType - DirectionPrompt :: PromptType - PointOnMap :: PromptType - -- | Throw an item or fire a projectile weapon. Prompt is to select the - -- direction - Fire :: PromptType - Continue :: PromptType - deriving stock (Generic) - -instance Show PromptType where - show StringPrompt = "StringPrompt" - show Confirm = "Confirm" - show (Menu _) = "Menu" - show DirectionPrompt = "DirectionPrompt" - show PointOnMap = "PointOnMap" - show Continue = "Continue" - show Fire = "Fire" - -data SPromptType :: PromptType -> Type where - SStringPrompt :: SPromptType 'StringPrompt - SConfirm :: SPromptType 'Confirm - SMenu :: SPromptType ('Menu a) - SDirectionPrompt :: SPromptType 'DirectionPrompt - SPointOnMap :: SPromptType 'PointOnMap - SContinue :: SPromptType 'Continue - SFire :: SPromptType 'Fire - -instance NFData (SPromptType pt) where - rnf SStringPrompt = () - rnf SConfirm = () - rnf SMenu = () - rnf SDirectionPrompt = () - rnf SPointOnMap = () - rnf SContinue = () - rnf SFire = () - -class SingPromptType pt where singPromptType :: SPromptType pt -instance SingPromptType 'StringPrompt where singPromptType = SStringPrompt -instance SingPromptType 'Confirm where singPromptType = SConfirm -instance SingPromptType 'DirectionPrompt where singPromptType = SDirectionPrompt -instance SingPromptType 'PointOnMap where singPromptType = SPointOnMap -instance SingPromptType 'Continue where singPromptType = SContinue -instance SingPromptType 'Fire where singPromptType = SFire - -instance Show (SPromptType pt) where - show SStringPrompt = "SStringPrompt" - show SConfirm = "SConfirm" - show SMenu = "SMenu" - show SDirectionPrompt = "SDirectionPrompt" - show SPointOnMap = "SPointOnMap" - show SContinue = "SContinue" - show SFire = "SFire" - -data PromptCancellable - = Cancellable - | Uncancellable - deriving stock (Show, Eq, Ord, Enum, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - -instance Arbitrary PromptCancellable where - arbitrary = genericArbitrary - -data PromptResult (pt :: PromptType) where - StringResult :: Text -> PromptResult 'StringPrompt - ConfirmResult :: Bool -> PromptResult 'Confirm - MenuResult :: forall a. a -> PromptResult ('Menu a) - DirectionResult :: Direction -> PromptResult 'DirectionPrompt - PointOnMapResult :: Position -> PromptResult 'PointOnMap - FireResult :: Position -> PromptResult 'Fire - ContinueResult :: PromptResult 'Continue - -instance Arbitrary (PromptResult 'StringPrompt) where - arbitrary = StringResult <$> arbitrary - -instance Arbitrary (PromptResult 'Confirm) where - arbitrary = ConfirmResult <$> arbitrary - -instance Arbitrary a => Arbitrary (PromptResult ('Menu a)) where - arbitrary = MenuResult <$> arbitrary - -instance Arbitrary (PromptResult 'DirectionPrompt) where - arbitrary = DirectionResult <$> arbitrary - -instance Arbitrary (PromptResult 'PointOnMap) where - arbitrary = PointOnMapResult <$> arbitrary - -instance Arbitrary (PromptResult 'Continue) where - arbitrary = pure ContinueResult - -instance Arbitrary (PromptResult 'Fire) where - arbitrary = FireResult <$> arbitrary - --------------------------------------------------------------------------------- - -data PromptState pt where - StringPromptState - :: Editor Text ResourceName -> PromptState 'StringPrompt - DirectionPromptState :: PromptState 'DirectionPrompt - ContinuePromptState :: PromptState 'Continue - ConfirmPromptState :: PromptState 'Confirm - MenuPromptState :: forall a. PromptState ('Menu a) - PointOnMapPromptState :: Position -> PromptState 'PointOnMap - FirePromptState :: Position -> PromptState 'Fire - -instance NFData (PromptState pt) where - rnf sps@(StringPromptState ed) = sps `deepseq` ed `deepseq` () - rnf DirectionPromptState = () - rnf ContinuePromptState = () - rnf ConfirmPromptState = () - rnf MenuPromptState = () - rnf pomps@(PointOnMapPromptState pos) = pomps `deepseq` pos `deepseq` () - rnf fps@(FirePromptState pos) = fps `deepseq` pos `deepseq` () - -instance Arbitrary (PromptState 'StringPrompt) where - arbitrary = StringPromptState <$> arbitrary - -instance Arbitrary (PromptState 'DirectionPrompt) where - arbitrary = pure DirectionPromptState - -instance Arbitrary (PromptState 'Continue) where - arbitrary = pure ContinuePromptState - -instance Arbitrary (PromptState ('Menu a)) where - arbitrary = pure MenuPromptState - -instance Arbitrary (PromptState 'Fire) where - arbitrary = FirePromptState <$> arbitrary - -instance CoArbitrary (PromptState 'StringPrompt) where - coarbitrary (StringPromptState ed) = coarbitrary ed - -instance CoArbitrary (PromptState 'DirectionPrompt) where - coarbitrary DirectionPromptState = coarbitrary () - -instance CoArbitrary (PromptState 'Continue) where - coarbitrary ContinuePromptState = coarbitrary () - -instance CoArbitrary (PromptState ('Menu a)) where - coarbitrary MenuPromptState = coarbitrary () - -instance CoArbitrary (PromptState 'Fire) where - coarbitrary (FirePromptState pos) = coarbitrary pos - -deriving stock instance Show (PromptState pt) - --- | Traversal over the position for the prompt types with positions in their --- prompt state (currently 'Fire' and 'PointOnMap') -promptStatePosition :: forall pt. Traversal' (PromptState pt) Position -promptStatePosition _ ps@(StringPromptState _) = pure ps -promptStatePosition _ DirectionPromptState = pure DirectionPromptState -promptStatePosition _ ContinuePromptState = pure ContinuePromptState -promptStatePosition _ ConfirmPromptState = pure ConfirmPromptState -promptStatePosition _ MenuPromptState = pure MenuPromptState -promptStatePosition f (PointOnMapPromptState p) = PointOnMapPromptState <$> f p -promptStatePosition f (FirePromptState p) = FirePromptState <$> f p - -data MenuOption a = MenuOption Text a - deriving stock (Eq, Generic, Functor) - deriving anyclass (NFData, CoArbitrary, Function) - -instance Comonad MenuOption where - extract (MenuOption _ x) = x - extend cok mo@(MenuOption text _) = MenuOption text (cok mo) - -mkMenuItems :: (MonoFoldable f, Element f ~ (Char, MenuOption a)) - => f - -> Map Char (MenuOption a) -mkMenuItems = flip foldl' mempty $ \items (chr, option) -> - let chr' = if has (ix chr) items - then getAlphaChar . smallestNotIn . map AlphaChar $ keys items - else chr - in items & at chr' ?~ option - -instance Show (MenuOption a) where - show (MenuOption m _) = show m - -type family PromptInput (pt :: PromptType) :: Type where - PromptInput ('Menu a) = Map Char (MenuOption a) - PromptInput 'PointOnMap = Position -- Character pos - PromptInput 'Fire = (Position, Tiles) -- Nearest enemy, range - PromptInput 'StringPrompt = Maybe Text -- Default value - PromptInput _ = () - -data Prompt (m :: Type -> Type) where - Prompt - :: forall (pt :: PromptType) - (m :: Type -> Type). - PromptCancellable - -> SPromptType pt - -> PromptState pt - -> PromptInput pt - -> (PromptResult pt -> m ()) - -> Prompt m - -instance Show (Prompt m) where - show (Prompt c pt ps pri _) - = "(Prompt " - <> show c <> " " - <> show pt <> " " - <> show ps <> " " - <> showPri - <> " )" - where showPri = case pt of - SMenu -> show pri - _ -> "()" - -instance NFData (Prompt m) where - rnf (Prompt c SMenu ps pri cb) - = c - `deepseq` ps - `deepseq` pri - `seq` cb - `seq` () - rnf (Prompt c spt ps pri cb) - = c - `deepseq` spt - `deepseq` ps - `deepseq` pri - `seq` cb - `seq` () - -instance CoArbitrary (m ()) => CoArbitrary (Prompt m) where - coarbitrary (Prompt c SStringPrompt ps pri cb) = - variant @Int 1 . coarbitrary (c, ps, pri, cb) - coarbitrary (Prompt c SConfirm _ pri cb) = -- TODO fill in prompt state - variant @Int 2 . coarbitrary (c, pri, cb) - coarbitrary (Prompt c SMenu _ps _pri _cb) = - variant @Int 3 . coarbitrary c {-, ps, pri, cb -} - coarbitrary (Prompt c SDirectionPrompt ps pri cb) = - variant @Int 4 . coarbitrary (c, ps, pri, cb) - coarbitrary (Prompt c SPointOnMap _ pri cb) = -- TODO fill in prompt state - variant @Int 5 . coarbitrary (c, pri, cb) - coarbitrary (Prompt c SContinue ps pri cb) = - variant @Int 6 . coarbitrary (c, ps, pri, cb) - coarbitrary (Prompt c SFire ps pri cb) = - variant @Int 7 . coarbitrary (c, ps, pri, cb) - --- instance Function (Prompt m) where --- function = functionMap toTuple _fromTuple --- where --- toTuple (Prompt c pt ps pri cb) = (c, pt, ps, pri, cb) - - -mkPrompt - :: (PromptInput pt ~ ()) - => PromptCancellable -- ^ Is the prompt cancellable or not? - -> SPromptType pt -- ^ The type of the prompt - -> (PromptResult pt -> m ()) -- ^ Function to call when the prompt is complete - -> Prompt m -mkPrompt c pt@SDirectionPrompt cb = Prompt c pt DirectionPromptState () cb -mkPrompt c pt@SContinue cb = Prompt c pt ContinuePromptState () cb -mkPrompt c pt@SConfirm cb = Prompt c pt ConfirmPromptState () cb - -mkStringPrompt - :: PromptCancellable -- ^ Is the prompt cancellable or not? - -> (PromptResult 'StringPrompt -> m ()) -- ^ Function to call when the prompt is complete - -> Prompt m -mkStringPrompt c = - let ps = StringPromptState $ editorText Resource.Prompt (Just 1) "" - in Prompt c SStringPrompt ps Nothing - -mkStringPromptWithDefault - :: PromptCancellable -- ^ Is the prompt cancellable or not? - -> Text -- ^ Default value for the prompt - -> (PromptResult 'StringPrompt -> m ()) -- ^ Function to call when the prompt is complete - -> Prompt m -mkStringPromptWithDefault c def = - let ps = StringPromptState $ editorText Resource.Prompt (Just 1) "" - in Prompt c SStringPrompt ps (Just def) - -mkMenu - :: forall a m. - PromptCancellable - -> Map Char (MenuOption a) -- ^ Menu items - -> (PromptResult ('Menu a) -> m ()) - -> Prompt m -mkMenu c = Prompt c SMenu MenuPromptState - -mkPointOnMapPrompt - :: PromptCancellable - -> Position - -> (PromptResult 'PointOnMap -> m ()) - -> Prompt m -mkPointOnMapPrompt c pos = Prompt c SPointOnMap (PointOnMapPromptState pos) pos - -mkFirePrompt - :: PromptCancellable - -> Position -- ^ Initial position - -> Tiles -- ^ Range - -> (PromptResult 'Fire -> m ()) - -> Prompt m -mkFirePrompt c pos range = Prompt c SFire (FirePromptState pos) (pos, range) - -isCancellable :: Prompt m -> Bool -isCancellable (Prompt Cancellable _ _ _ _) = True -isCancellable (Prompt Uncancellable _ _ _ _) = False - -submitPrompt :: Applicative m => Prompt m -> m () -submitPrompt (Prompt _ pt ps pri cb) = - case (pt, ps, pri) of - (SStringPrompt, StringPromptState edit, mDef) -> - let inputVal = mconcat . getEditContents $ edit - val | null inputVal, Just def <- mDef = def - | otherwise = inputVal - in cb $ StringResult val - (SDirectionPrompt, DirectionPromptState, _) -> - pure () -- Don't use submit with a direction prompt - (SContinue, ContinuePromptState, _) -> - cb ContinueResult - (SMenu, MenuPromptState, _) -> - pure () -- Don't use submit with a menu prompt - (SPointOnMap, PointOnMapPromptState pos, _) -> - cb $ PointOnMapResult pos - (SConfirm, ConfirmPromptState, _) -> - cb $ ConfirmResult True - (SFire, FirePromptState pos, _) -> - cb $ FireResult pos diff --git a/users/aspen/xanthous/src/Xanthous/Game/State.hs b/users/aspen/xanthous/src/Xanthous/Game/State.hs deleted file mode 100644 index 13b1ba158..000000000 --- a/users/aspen/xanthous/src/Xanthous/Game/State.hs +++ /dev/null @@ -1,572 +0,0 @@ -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE AllowAmbiguousTypes #-} --------------------------------------------------------------------------------- -module Xanthous.Game.State - ( GameState(..) - , entities - , levels - , revealedPositions - , messageHistory - , randomGen - , activePanel - , promptState - , characterEntityID - , autocommand - , savefile - , memo - , GamePromptState(..) - - -- * Game Level - , GameLevel(..) - , levelEntities - , upStaircasePosition - , levelRevealedPositions - - -- * Messages - , MessageHistory(..) - , HasMessages(..) - , HasTurn(..) - , HasDisplayedTurn(..) - , pushMessage - , previousMessage - , nextTurn - - -- * Autocommands - , Autocommand(..) - , AutocommandState(..) - , _NoAutocommand - , _ActiveAutocommand - - -- * App monad - , AppT(..) - , AppM - , runAppT - - -- * Entities - , Draw(..) - , Brain(..) - , Brainless(..) - , brainVia - , Collision(..) - , Entity(..) - , SomeEntity(..) - , downcastEntity - , _SomeEntity - , entityIs - , entityTypeName - - -- ** Vias - , Color(..) - , DrawNothing(..) - , DrawRawChar(..) - , DrawRawCharPriority(..) - , DrawCharacter(..) - , DrawStyledCharacter(..) - , DeriveEntity(..) - -- ** Field classes - , HasChar(..) - , HasStyle(..) - - -- * Debug State - , DebugState(..) - , debugState - , allRevealed - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.List.NonEmpty ( NonEmpty((:|))) -import qualified Data.List.NonEmpty as NonEmpty -import Data.Typeable -import Data.Coerce -import System.Random -import Test.QuickCheck -import Test.QuickCheck.Arbitrary.Generic -import Control.Monad.Random.Class -import Control.Monad.State -import Control.Monad.Trans.Control (MonadTransControl(..)) -import Control.Monad.Trans.Compose -import Control.Monad.Morph (MFunctor(..)) -import Brick (EventM, Widget, raw, str, emptyWidget) -import Data.Aeson (ToJSON(..), FromJSON(..), Value(Null)) -import qualified Data.Aeson as JSON -import Data.Aeson.Generic.DerivingVia -import Data.Generics.Product.Fields -import qualified Graphics.Vty.Attributes as Vty -import qualified Graphics.Vty.Image as Vty --------------------------------------------------------------------------------- -import Xanthous.Util (KnownBool(..)) -import Xanthous.Data -import Xanthous.Data.App -import Xanthous.Data.Levels -import Xanthous.Data.EntityMap (EntityMap, EntityID) -import Xanthous.Data.EntityChar -import Xanthous.Data.VectorBag -import Xanthous.Data.Entities -import Xanthous.Orphans () -import Xanthous.Game.Prompt -import Xanthous.Game.Env -import Xanthous.Game.Memo (MemoState) --------------------------------------------------------------------------------- - -data MessageHistory - = MessageHistory - { _messages :: Map Word (NonEmpty Text) - , _turn :: Word - , _displayedTurn :: Maybe Word - } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary MessageHistory - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - MessageHistory -makeFieldsNoPrefix ''MessageHistory - -instance Semigroup MessageHistory where - (MessageHistory msgs₁ turn₁ dt₁) <> (MessageHistory msgs₂ turn₂ dt₂) = - MessageHistory (msgs₁ <> msgs₂) (max turn₁ turn₂) $ case (dt₁, dt₂) of - (_, Nothing) -> Nothing - (Just t, _) -> Just t - (Nothing, Just t) -> Just t - -instance Monoid MessageHistory where - mempty = MessageHistory mempty 0 Nothing - -type instance Element MessageHistory = [Text] -instance MonoFunctor MessageHistory where - omap f mh@(MessageHistory _ t _) = - mh & messages . at t %~ (NonEmpty.nonEmpty . f . toList =<<) - -instance MonoComonad MessageHistory where - oextract (MessageHistory ms t dt) = maybe [] toList $ ms ^. at (fromMaybe t dt) - oextend cok mh@(MessageHistory _ t dt) = - mh & messages . at (fromMaybe t dt) .~ NonEmpty.nonEmpty (cok mh) - -pushMessage :: Text -> MessageHistory -> MessageHistory -pushMessage msg mh@(MessageHistory _ turn' _) = - mh - & messages . at turn' %~ \case - Nothing -> Just $ msg :| mempty - Just msgs -> Just $ msg <| msgs - & displayedTurn .~ Nothing - -nextTurn :: MessageHistory -> MessageHistory -nextTurn = (turn +~ 1) . (displayedTurn .~ Nothing) - -previousMessage :: MessageHistory -> MessageHistory -previousMessage mh = mh & displayedTurn .~ maximumOf - (messages . ifolded . asIndex . filtered (< mh ^. turn)) - mh - - --------------------------------------------------------------------------------- - -data GamePromptState m where - NoPrompt :: GamePromptState m - WaitingPrompt :: Text -> Prompt m -> GamePromptState m - deriving stock (Show, Generic) - deriving anyclass (NFData) - --- | Non-injective! We never try to serialize waiting prompts, since: --- --- * they contain callback functions --- * we can't save the game when in a prompt anyway -instance ToJSON (GamePromptState m) where - toJSON _ = Null - --- | Always expects Null -instance FromJSON (GamePromptState m) where - parseJSON Null = pure NoPrompt - parseJSON _ = fail "Invalid GamePromptState; expected null" - -instance CoArbitrary (GamePromptState m) where - coarbitrary NoPrompt = variant @Int 1 - coarbitrary (WaitingPrompt txt _) = variant @Int 2 . coarbitrary txt - -instance Function (GamePromptState m) where - function = functionMap onlyNoPrompt (const NoPrompt) - where - onlyNoPrompt NoPrompt = () - onlyNoPrompt (WaitingPrompt _ _) = - error "Can't handle prompts in Function!" - --------------------------------------------------------------------------------- - -newtype AppT m a - = AppT { unAppT :: ReaderT GameEnv (StateT GameState m) a } - deriving ( Functor - , Applicative - , Monad - , MonadState GameState - , MonadReader GameEnv - , MonadIO - ) - via (ReaderT GameEnv (StateT GameState m)) - deriving ( MonadTrans - , MFunctor - ) - via (ReaderT GameEnv `ComposeT` StateT GameState) - -type AppM = AppT (EventM ResourceName) - --------------------------------------------------------------------------------- - -class Draw a where - drawWithNeighbors :: Neighbors (VectorBag SomeEntity) -> a -> Widget n - drawWithNeighbors = const draw - - draw :: a -> Widget n - draw = drawWithNeighbors $ pure mempty - - -- | higher priority gets drawn on top - drawPriority :: a -> Word - drawPriority = const minBound - -instance Draw a => Draw (Positioned a) where - drawWithNeighbors ns (Positioned _ a) = drawWithNeighbors ns a - draw (Positioned _ a) = draw a - -newtype DrawCharacter (char :: Symbol) (a :: Type) where - DrawCharacter :: a -> DrawCharacter char a - -instance KnownSymbol char => Draw (DrawCharacter char a) where - draw _ = str $ symbolVal @char Proxy - -data Color = Black | Red | Green | Yellow | Blue | Magenta | Cyan | White - -class KnownColor (color :: Color) where - colorVal :: forall proxy. proxy color -> Vty.Color - -instance KnownColor 'Black where colorVal _ = Vty.black -instance KnownColor 'Red where colorVal _ = Vty.red -instance KnownColor 'Green where colorVal _ = Vty.green -instance KnownColor 'Yellow where colorVal _ = Vty.yellow -instance KnownColor 'Blue where colorVal _ = Vty.blue -instance KnownColor 'Magenta where colorVal _ = Vty.magenta -instance KnownColor 'Cyan where colorVal _ = Vty.cyan -instance KnownColor 'White where colorVal _ = Vty.white - -class KnownMaybeColor (maybeColor :: Maybe Color) where - maybeColorVal :: forall proxy. proxy maybeColor -> Maybe Vty.Color - -instance KnownMaybeColor 'Nothing where maybeColorVal _ = Nothing -instance KnownColor color => KnownMaybeColor ('Just color) where - maybeColorVal _ = Just $ colorVal @color Proxy - -newtype DrawStyledCharacter (fg :: Maybe Color) (bg :: Maybe Color) (char :: Symbol) (a :: Type) where - DrawStyledCharacter :: a -> DrawStyledCharacter fg bg char a - -instance - ( KnownMaybeColor fg - , KnownMaybeColor bg - , KnownSymbol char - ) - => Draw (DrawStyledCharacter fg bg char a) where - draw _ = raw $ Vty.string attr $ symbolVal @char Proxy - where attr = Vty.Attr - { Vty.attrStyle = Vty.Default - , Vty.attrForeColor = maybe Vty.Default Vty.SetTo - $ maybeColorVal @fg Proxy - , Vty.attrBackColor = maybe Vty.Default Vty.SetTo - $ maybeColorVal @bg Proxy - , Vty.attrURL = Vty.Default - } - -instance Draw EntityChar where - draw EntityChar{..} = raw $ Vty.string _style [_char] - --------------------------------------------------------------------------------- - -newtype DrawNothing (a :: Type) = DrawNothing a - -instance Draw (DrawNothing a) where - draw = const emptyWidget - drawPriority = const 0 - -newtype DrawRawChar (rawField :: Symbol) (a :: Type) = DrawRawChar a - -instance - forall rawField a raw. - ( HasField rawField a a raw raw - , HasChar raw EntityChar - ) => Draw (DrawRawChar rawField a) where - draw (DrawRawChar e) = draw $ e ^. field @rawField . char - -newtype DrawRawCharPriority - (rawField :: Symbol) - (priority :: Nat) - (a :: Type) - = DrawRawCharPriority a - -instance - forall rawField priority a raw. - ( HasField rawField a a raw raw - , KnownNat priority - , HasChar raw EntityChar - ) => Draw (DrawRawCharPriority rawField priority a) where - draw (DrawRawCharPriority e) = draw $ e ^. field @rawField . char - drawPriority = const . fromIntegral $ natVal @priority Proxy - - --------------------------------------------------------------------------------- - -class Brain a where - step :: Ticks -> Positioned a -> AppM (Positioned a) - -- | Does this entity ever move on its own? - entityCanMove :: a -> Bool - entityCanMove = const False - -newtype Brainless a = Brainless a - -instance Brain (Brainless a) where - step = const pure - --- | Workaround for the inability to use DerivingVia on Brain due to the lack of --- higher-order roles (specifically AppT not having its last type argument have --- role representational bc of StateT) -brainVia - :: forall brain entity. (Coercible entity brain, Brain brain) - => (entity -> brain) -- ^ constructor, ignored - -> (Ticks -> Positioned entity -> AppM (Positioned entity)) -brainVia _ ticks = fmap coerce . step ticks . coerce @_ @(Positioned brain) - --------------------------------------------------------------------------------- - -class ( Show a, Eq a, Ord a, NFData a - , ToJSON a, FromJSON a - , Draw a, Brain a - ) => Entity a where - entityAttributes :: a -> EntityAttributes - entityAttributes = const defaultEntityAttributes - description :: a -> Text - entityChar :: a -> EntityChar - entityCollision :: a -> Maybe Collision - entityCollision = const $ Just Stop - -data SomeEntity where - SomeEntity :: forall a. (Entity a, Typeable a) => a -> SomeEntity - -instance Show SomeEntity where - show (SomeEntity e) = "SomeEntity (" <> show e <> ")" - -instance Eq SomeEntity where - (SomeEntity (a :: ea)) == (SomeEntity (b :: eb)) = case eqT @ea @eb of - Just Refl -> a == b - _ -> False - -instance Ord SomeEntity where - compare (SomeEntity (a :: ea)) (SomeEntity (b :: eb)) = case eqT @ea @eb of - Just Refl -> compare a b - _ -> compare (typeRep $ Proxy @ea) (typeRep $ Proxy @eb) - - -instance NFData SomeEntity where - rnf (SomeEntity ent) = ent `deepseq` () - -instance ToJSON SomeEntity where - toJSON (SomeEntity ent) = entityToJSON ent - where - entityToJSON :: forall entity. (Entity entity, Typeable entity) - => entity -> JSON.Value - entityToJSON entity = JSON.object - [ "type" JSON..= tshow (typeRep @_ @entity Proxy) - , "data" JSON..= toJSON entity - ] - -instance Draw SomeEntity where - drawWithNeighbors ns (SomeEntity ent) = drawWithNeighbors ns ent - drawPriority (SomeEntity ent) = drawPriority ent - -instance Brain SomeEntity where - step ticks (Positioned p (SomeEntity ent)) = - fmap SomeEntity <$> step ticks (Positioned p ent) - entityCanMove (SomeEntity ent) = entityCanMove ent - -downcastEntity :: forall (a :: Type). (Typeable a) => SomeEntity -> Maybe a -downcastEntity (SomeEntity e) = cast e - -entityIs :: forall (a :: Type). (Typeable a) => SomeEntity -> Bool -entityIs = isJust . downcastEntity @a - -_SomeEntity :: forall a. (Entity a, Typeable a) => Prism' SomeEntity a -_SomeEntity = prism' SomeEntity downcastEntity - --- | Get the name of the type of 'SomeEntity' as a string -entityTypeName :: SomeEntity -> Text -entityTypeName (SomeEntity e) = pack . tyConName . typeRepTyCon $ typeOf e - -newtype DeriveEntity - (blocksVision :: Bool) - (description :: Symbol) - (entityChar :: Symbol) - (entity :: Type) - = DeriveEntity entity - deriving newtype (Show, Eq, Ord, NFData, ToJSON, FromJSON, Draw) - -instance Brain entity => Brain (DeriveEntity b d c entity) where - step = brainVia $ \(DeriveEntity e) -> e - -instance - ( KnownBool blocksVision - , KnownSymbol description - , KnownSymbol entityChar - , Show entity, Eq entity, Ord entity, NFData entity - , ToJSON entity, FromJSON entity - , Draw entity, Brain entity - ) - => Entity (DeriveEntity blocksVision description entityChar entity) where - entityAttributes _ = defaultEntityAttributes - & blocksVision .~ boolVal @blocksVision - description _ = pack . symbolVal $ Proxy @description - entityChar _ = fromString . symbolVal $ Proxy @entityChar - --------------------------------------------------------------------------------- - -data GameLevel = GameLevel - { _levelEntities :: !(EntityMap SomeEntity) - , _upStaircasePosition :: !Position - , _levelRevealedPositions :: !(Set Position) - } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData) - deriving (ToJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - GameLevel - --------------------------------------------------------------------------------- - -data Autocommand - = AutoMove Direction - | AutoRest - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (NFData, Hashable, ToJSON, FromJSON, CoArbitrary, Function) - deriving Arbitrary via GenericArbitrary Autocommand -{-# ANN module ("HLint: ignore Use newtype instead of data" :: String) #-} - -data AutocommandState - = NoAutocommand - | ActiveAutocommand Autocommand (Async ()) - deriving stock (Eq, Ord, Generic) - deriving anyclass (Hashable) - -instance Show AutocommandState where - show NoAutocommand = "NoAutocommand" - show (ActiveAutocommand ac _) = - "(ActiveAutocommand " <> show ac <> " )" - -instance ToJSON AutocommandState where - toJSON = const Null - -instance FromJSON AutocommandState where - parseJSON Null = pure NoAutocommand - parseJSON _ = fail "Invalid AutocommandState; expected null" - -instance NFData AutocommandState where - rnf NoAutocommand = () - rnf (ActiveAutocommand ac t) = ac `deepseq` t `seq` () - -instance CoArbitrary AutocommandState where - coarbitrary NoAutocommand = variant @Int 1 - coarbitrary (ActiveAutocommand ac t) - = variant @Int 2 - . coarbitrary ac - . coarbitrary (hash t) - -instance Function AutocommandState where - function = functionMap onlyNoAC (const NoAutocommand) - where - onlyNoAC NoAutocommand = () - onlyNoAC _ = error "Can't handle autocommands in Function" - --------------------------------------------------------------------------------- - - -data DebugState = DebugState - { _allRevealed :: !Bool - } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving (ToJSON, FromJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - DebugState -{-# ANN DebugState ("HLint: ignore Use newtype instead of data" :: String) #-} - -instance Arbitrary DebugState where - arbitrary = genericArbitrary - -data GameState = GameState - { _levels :: !(Levels GameLevel) - , _characterEntityID :: !EntityID - , _messageHistory :: !MessageHistory - , _randomGen :: !StdGen - - -- | The active panel displayed in the UI, if any - , _activePanel :: !(Maybe Panel) - - , _promptState :: !(GamePromptState AppM) - , _debugState :: !DebugState - , _autocommand :: !AutocommandState - - -- | The path to the savefile that was loaded for this game, if any - , _savefile :: !(Maybe FilePath) - - , _memo :: MemoState - } - deriving stock (Show, Generic) - deriving anyclass (NFData) - deriving (ToJSON) - via WithOptions '[ FieldLabelModifier '[Drop 1] ] - GameState - -makeLenses ''GameLevel -makeLenses ''GameState - -entities :: Lens' GameState (EntityMap SomeEntity) -entities = levels . current . levelEntities - -revealedPositions :: Lens' GameState (Set Position) -revealedPositions = levels . current . levelRevealedPositions - -instance Eq GameState where - (==) = (==) `on` \gs -> - ( gs ^. entities - , gs ^. revealedPositions - , gs ^. characterEntityID - , gs ^. messageHistory - , gs ^. activePanel - , gs ^. debugState - ) - --------------------------------------------------------------------------------- - -runAppT :: Monad m => AppT m a -> GameEnv -> GameState -> m (a, GameState) -runAppT appt env initialState - = flip runStateT initialState - . flip runReaderT env - . unAppT - $ appt - -instance (Monad m) => MonadRandom (AppT m) where - getRandomR rng = randomGen %%= randomR rng - getRandom = randomGen %%= random - getRandomRs rng = uses randomGen $ randomRs rng - getRandoms = uses randomGen randoms - -instance MonadTransControl AppT where - type StT AppT a = (a, GameState) - liftWith f - = AppT - . ReaderT $ \e - -> StateT $ \s - -> (,s) <$> f (\action -> runAppT action e s) - restoreT = AppT . ReaderT . const . StateT . const - --------------------------------------------------------------------------------- - -makeLenses ''DebugState -makePrisms ''AutocommandState diff --git a/users/aspen/xanthous/src/Xanthous/Generators/Level.hs b/users/aspen/xanthous/src/Xanthous/Generators/Level.hs deleted file mode 100644 index fc57402e7..000000000 --- a/users/aspen/xanthous/src/Xanthous/Generators/Level.hs +++ /dev/null @@ -1,172 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE GADTs #-} -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Generators.Level - ( generate - , Generator(..) - , SGenerator(..) - , GeneratorInput(..) - , generateFromInput - , parseGeneratorInput - , showCells - , Level(..) - , levelWalls - , levelItems - , levelCreatures - , levelDoors - , levelCharacterPosition - , levelTutorialMessage - , levelExtra - , generateLevel - , levelToEntityMap - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Data.Array.Unboxed -import qualified Options.Applicative as Opt -import Control.Monad.Random --------------------------------------------------------------------------------- -import qualified Xanthous.Generators.Level.CaveAutomata as CaveAutomata -import qualified Xanthous.Generators.Level.Dungeon as Dungeon -import Xanthous.Generators.Level.Util -import Xanthous.Generators.Level.LevelContents -import Xanthous.Generators.Level.Village as Village -import Xanthous.Data (Dimensions, Position'(Position), Position) -import Xanthous.Data.EntityMap (EntityMap, _EntityMap) -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Entities.Environment -import Xanthous.Entities.Item (Item) -import Xanthous.Entities.Creature (Creature) -import Xanthous.Game.State (SomeEntity(..)) -import Linear.V2 --------------------------------------------------------------------------------- - -data Generator - = CaveAutomata - | Dungeon - deriving stock (Show, Eq) - -data SGenerator (gen :: Generator) where - SCaveAutomata :: SGenerator 'CaveAutomata - SDungeon :: SGenerator 'Dungeon - -type family Params (gen :: Generator) :: Type where - Params 'CaveAutomata = CaveAutomata.Params - Params 'Dungeon = Dungeon.Params - -generate - :: RandomGen g - => SGenerator gen - -> Params gen - -> Dimensions - -> g - -> Cells -generate SCaveAutomata = CaveAutomata.generate -generate SDungeon = Dungeon.generate - -data GeneratorInput where - GeneratorInput :: forall gen. SGenerator gen -> Params gen -> GeneratorInput - -generateFromInput :: RandomGen g => GeneratorInput -> Dimensions -> g -> Cells -generateFromInput (GeneratorInput sg ps) = generate sg ps - -parseGeneratorInput :: Opt.Parser GeneratorInput -parseGeneratorInput = Opt.subparser - $ generatorCommand SCaveAutomata - "cave" - "Cellular-automata based cave generator" - CaveAutomata.parseParams - <> generatorCommand SDungeon - "dungeon" - "Classic dungeon map generator" - Dungeon.parseParams - where - generatorCommand sgen name desc parseParams = - Opt.command name - (Opt.info - (GeneratorInput sgen <$> parseParams) - (Opt.progDesc desc) - ) - - -showCells :: Cells -> Text -showCells arr = - let (V2 minX minY, V2 maxX maxY) = bounds arr - showCellVal True = "x" - showCellVal False = " " - showCell = showCellVal . (arr !) - row r = foldMap (showCell . (`V2` r)) [minX..maxX] - rows = row <$> [minY..maxY] - in intercalate "\n" rows - -cellsToWalls :: Cells -> EntityMap Wall -cellsToWalls cells = foldl' maybeInsertWall mempty . assocs $ cells - where - maybeInsertWall em (pos@(V2 x y), True) - | not (surroundedOnAllSides pos) = - let x' = fromIntegral x - y' = fromIntegral y - in EntityMap.insertAt (Position x' y') Wall em - maybeInsertWall em _ = em - surroundedOnAllSides pos = numAliveNeighbors cells pos == 8 - --------------------------------------------------------------------------------- - -data Level = Level - { _levelWalls :: !(EntityMap Wall) - , _levelDoors :: !(EntityMap Door) - , _levelItems :: !(EntityMap Item) - , _levelCreatures :: !(EntityMap Creature) - , _levelTutorialMessage :: !(EntityMap GroundMessage) - , _levelStaircases :: !(EntityMap Staircase) - , _levelExtra :: !(EntityMap SomeEntity) -- ^ TODO this is a bit of a hack... - , _levelCharacterPosition :: !Position - } - deriving stock (Generic) - deriving anyclass (NFData) -makeLenses ''Level - -generateLevel - :: MonadRandom m - => SGenerator gen - -> Params gen - -> Dimensions - -> Word -- ^ Level number, starting at 0 - -> m Level -generateLevel gen ps dims num = do - rand <- mkStdGen <$> getRandom - let cells = generate gen ps dims rand - _levelWalls = cellsToWalls cells - village <- generateVillage cells gen - let _levelExtra = village - _levelItems <- randomItems cells - _levelCreatures <- randomCreatures num cells - _levelDoors <- randomDoors cells - _levelCharacterPosition <- chooseCharacterPosition cells - let upStaircase = _EntityMap # [(_levelCharacterPosition, UpStaircase)] - downStaircase <- placeDownStaircase cells - let _levelStaircases = upStaircase <> downStaircase - _levelTutorialMessage <- - if num == 0 - then tutorialMessage cells _levelCharacterPosition - else pure mempty - pure Level {..} - -levelToEntityMap :: Level -> EntityMap SomeEntity -levelToEntityMap level - = (SomeEntity <$> level ^. levelWalls) - <> (SomeEntity <$> level ^. levelDoors) - <> (SomeEntity <$> level ^. levelItems) - <> (SomeEntity <$> level ^. levelCreatures) - <> (SomeEntity <$> level ^. levelTutorialMessage) - <> (SomeEntity <$> level ^. levelStaircases) - <> (level ^. levelExtra) - -generateVillage - :: MonadRandom m - => Cells -- ^ Wall positions - -> SGenerator gen - -> m (EntityMap SomeEntity) -generateVillage wallPositions SCaveAutomata = Village.fromCave wallPositions -generateVillage _ _ = pure mempty diff --git a/users/aspen/xanthous/src/Xanthous/Generators/Level/CaveAutomata.hs b/users/aspen/xanthous/src/Xanthous/Generators/Level/CaveAutomata.hs deleted file mode 100644 index 03d534ca3..000000000 --- a/users/aspen/xanthous/src/Xanthous/Generators/Level/CaveAutomata.hs +++ /dev/null @@ -1,112 +0,0 @@ -{-# LANGUAGE MultiWayIf #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Generators.Level.CaveAutomata - ( Params(..) - , defaultParams - , parseParams - , generate - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Control.Monad.Random (RandomGen, runRandT) -import Data.Array.ST -import Data.Array.Unboxed -import qualified Options.Applicative as Opt --------------------------------------------------------------------------------- -import Xanthous.Util (between) -import Xanthous.Util.Optparse -import Xanthous.Data (Dimensions, width, height) -import Xanthous.Generators.Level.Util -import Linear.V2 --------------------------------------------------------------------------------- - -data Params = Params - { _aliveStartChance :: Double - , _birthLimit :: Word - , _deathLimit :: Word - , _steps :: Word - } - deriving stock (Show, Eq, Generic) -makeLenses ''Params - -defaultParams :: Params -defaultParams = Params - { _aliveStartChance = 0.6 - , _birthLimit = 3 - , _deathLimit = 4 - , _steps = 4 - } - -parseParams :: Opt.Parser Params -parseParams = Params - <$> Opt.option parseChance - ( Opt.long "alive-start-chance" - <> Opt.value (defaultParams ^. aliveStartChance) - <> Opt.showDefault - <> Opt.help ( "Chance for each cell to start alive at the beginning of " - <> "the cellular automata" - ) - <> Opt.metavar "CHANCE" - ) - <*> Opt.option parseNeighbors - ( Opt.long "birth-limit" - <> Opt.value (defaultParams ^. birthLimit) - <> Opt.showDefault - <> Opt.help "Minimum neighbor count required for birth of a cell" - <> Opt.metavar "NEIGHBORS" - ) - <*> Opt.option parseNeighbors - ( Opt.long "death-limit" - <> Opt.value (defaultParams ^. deathLimit) - <> Opt.showDefault - <> Opt.help "Maximum neighbor count required for death of a cell" - <> Opt.metavar "NEIGHBORS" - ) - <*> Opt.option Opt.auto - ( Opt.long "steps" - <> Opt.value (defaultParams ^. steps) - <> Opt.showDefault - <> Opt.help "Number of generations to run the automata for" - <> Opt.metavar "STEPS" - ) - <**> Opt.helper - where - parseChance = readWithGuard - (between 0 1) - $ \res -> "Chance must be in the range [0,1], got: " <> show res - - parseNeighbors = readWithGuard - (between 0 8) - $ \res -> "Neighbors must be in the range [0,8], got: " <> show res - -generate :: RandomGen g => Params -> Dimensions -> g -> Cells -generate params dims gen - = runSTUArray - $ fmap fst - $ flip runRandT gen - $ generate' params dims - -generate' :: RandomGen g => Params -> Dimensions -> CellM g s (MCells s) -generate' params dims = do - cells <- randInitialize dims $ params ^. aliveStartChance - let steps' = params ^. steps - when (steps' > 0) - $ for_ [0 .. pred steps'] . const $ stepAutomata cells dims params - -- Remove all but the largest contiguous region of unfilled space - (_: smallerRegions) <- lift $ regions @UArray . amap not <$> freeze cells - lift $ fillAllM (fold smallerRegions) cells - lift $ fillOuterEdgesM cells - pure cells - -stepAutomata :: forall s g. MCells s -> Dimensions -> Params -> CellM g s () -stepAutomata cells dims params = do - origCells <- lift $ cloneMArray @_ @(STUArray s) cells - for_ (range (0, V2 (dims ^. width) (dims ^. height))) $ \pos -> do - neighs <- lift $ numAliveNeighborsM origCells pos - origValue <- lift $ readArray origCells pos - lift . writeArray cells pos - $ if origValue - then neighs >= params ^. deathLimit - else neighs > params ^. birthLimit diff --git a/users/aspen/xanthous/src/Xanthous/Generators/Level/Dungeon.hs b/users/aspen/xanthous/src/Xanthous/Generators/Level/Dungeon.hs deleted file mode 100644 index 0be7c0435..000000000 --- a/users/aspen/xanthous/src/Xanthous/Generators/Level/Dungeon.hs +++ /dev/null @@ -1,190 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Generators.Level.Dungeon - ( Params(..) - , defaultParams - , parseParams - , generate - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding ((:>)) --------------------------------------------------------------------------------- -import Control.Monad.Random -import Data.Array.ST -import Data.Array.IArray (amap) -import Data.Stream.Infinite (Stream(..)) -import qualified Data.Stream.Infinite as Stream -import qualified Data.Graph.Inductive.Graph as Graph -import Data.Graph.Inductive.PatriciaTree -import qualified Data.List.NonEmpty as NE -import Data.Maybe (fromJust) -import Linear.V2 -import Linear.Metric -import qualified Options.Applicative as Opt --------------------------------------------------------------------------------- -import Xanthous.Random -import Xanthous.Data hiding (x, y, _x, _y, edges, distance) -import Xanthous.Generators.Level.Util -import Xanthous.Util.Graphics (delaunay, straightLine) -import Xanthous.Util.Graph (mstSubGraph) --------------------------------------------------------------------------------- - -data Params = Params - { _numRoomsRange :: (Word, Word) - , _roomDimensionRange :: (Word, Word) - , _connectednessRatioRange :: (Double, Double) - } - deriving stock (Show, Eq, Ord, Generic) -makeLenses ''Params - -defaultParams :: Params -defaultParams = Params - { _numRoomsRange = (6, 8) - , _roomDimensionRange = (3, 12) - , _connectednessRatioRange = (0.1, 0.15) - } - -parseParams :: Opt.Parser Params -parseParams = Params - <$> parseRange - "num-rooms" - "number of rooms to generate in the dungeon" - "ROOMS" - (defaultParams ^. numRoomsRange) - <*> parseRange - "room-size" - "size in tiles of one of the sides of a room" - "TILES" - (defaultParams ^. roomDimensionRange) - <*> parseRange - "connectedness-ratio" - ( "ratio of edges from the delaunay triangulation to re-add to the " - <> "minimum-spanning-tree") - "RATIO" - (defaultParams ^. connectednessRatioRange) - <**> Opt.helper - where - parseRange name desc metavar (defMin, defMax) = - (,) - <$> Opt.option Opt.auto - ( Opt.long ("min-" <> name) - <> Opt.value defMin - <> Opt.showDefault - <> Opt.help ("Minimum " <> desc) - <> Opt.metavar metavar - ) - <*> Opt.option Opt.auto - ( Opt.long ("max-" <> name) - <> Opt.value defMax - <> Opt.showDefault - <> Opt.help ("Maximum " <> desc) - <> Opt.metavar metavar - ) - -generate :: RandomGen g => Params -> Dimensions -> g -> Cells -generate params dims gen - = amap not - $ runSTUArray - $ fmap fst - $ flip runRandT gen - $ generate' params dims - --------------------------------------------------------------------------------- - -generate' :: RandomGen g => Params -> Dimensions -> CellM g s (MCells s) -generate' params dims = do - cells <- initializeEmpty dims - rooms <- genRooms params dims - for_ rooms $ fillRoom cells - - let fullRoomGraph = delaunayRoomGraph rooms - mst = mstSubGraph fullRoomGraph - mstEdges = Graph.edges mst - nonMSTEdges = filter (\(n₁, n₂, _) -> (n₁, n₂) `notElem` mstEdges) - $ Graph.labEdges fullRoomGraph - - reintroEdgeCount <- floor . (* fromIntegral (length nonMSTEdges)) - <$> getRandomR (params ^. connectednessRatioRange) - let reintroEdges = take reintroEdgeCount nonMSTEdges - corridorGraph = Graph.insEdges reintroEdges mst - - corridors <- traverse - ( uncurry corridorBetween - . over both (fromJust . Graph.lab corridorGraph) - ) $ Graph.edges corridorGraph - - for_ (join corridors) $ \pt -> lift $ writeArray cells pt True - - pure cells - -type Room = Box Word - -genRooms :: MonadRandom m => Params -> Dimensions -> m [Room] -genRooms params dims = do - numRooms <- fromIntegral <$> getRandomR (params ^. numRoomsRange) - subRand . fmap (Stream.take numRooms . removeIntersecting []) . infinitely $ do - roomWidth <- getRandomR $ params ^. roomDimensionRange - roomHeight <- getRandomR $ params ^. roomDimensionRange - xPos <- getRandomR (0, dims ^. width - roomWidth) - yPos <- getRandomR (0, dims ^. height - roomHeight) - pure Box - { _topLeftCorner = V2 xPos yPos - , _dimensions = V2 roomWidth roomHeight - } - where - removeIntersecting seen (room :> rooms) - | any (boxIntersects room) seen - = removeIntersecting seen rooms - | otherwise - = room :> removeIntersecting (room : seen) rooms - streamRepeat x = x :> streamRepeat x - infinitely = sequence . streamRepeat - -delaunayRoomGraph :: [Room] -> Gr Room Double -delaunayRoomGraph rooms = - Graph.insEdges edges . Graph.insNodes nodes $ Graph.empty - where - edges = map (\((n₁, room₁), (n₂, room₂)) -> (n₁, n₂, roomDist room₁ room₂)) - . over (mapped . both) snd - . delaunay @Double - . NE.fromList - . map (\p@(_, room) -> (boxCenter $ fromIntegral <$> room, p)) - $ nodes - nodes = zip [0..] rooms - roomDist = distance `on` (boxCenter . fmap fromIntegral) - -fillRoom :: MCells s -> Room -> CellM g s () -fillRoom cells room = - let V2 posx posy = room ^. topLeftCorner - V2 dimx dimy = room ^. dimensions - in for_ [posx .. posx + dimx] $ \x -> - for_ [posy .. posy + dimy] $ \y -> - lift $ writeArray cells (V2 x y) True - -corridorBetween :: MonadRandom m => Room -> Room -> m [V2 Word] -corridorBetween originRoom destinationRoom - = straightLine <$> origin <*> destination - where - origin = choose . NE.fromList =<< originEdge - destination = choose . NE.fromList =<< destinationEdge - originEdge = pickEdge originRoom originCorner - destinationEdge = pickEdge destinationRoom destinationCorner - pickEdge room corner = choose . over both (boxEdge room) $ cornerEdges corner - originCorner = - case ( compare (originRoom ^. topLeftCorner . _x) - (destinationRoom ^. topLeftCorner . _x) - , compare (originRoom ^. topLeftCorner . _y) - (destinationRoom ^. topLeftCorner . _y) - ) of - (LT, LT) -> BottomRight - (LT, GT) -> TopRight - (GT, LT) -> BottomLeft - (GT, GT) -> TopLeft - - (EQ, LT) -> BottomLeft - (EQ, GT) -> TopRight - (GT, EQ) -> TopLeft - (LT, EQ) -> BottomRight - (EQ, EQ) -> TopLeft -- should never happen - - destinationCorner = opposite originCorner diff --git a/users/aspen/xanthous/src/Xanthous/Generators/Level/LevelContents.hs b/users/aspen/xanthous/src/Xanthous/Generators/Level/LevelContents.hs deleted file mode 100644 index 4f8a2f42e..000000000 --- a/users/aspen/xanthous/src/Xanthous/Generators/Level/LevelContents.hs +++ /dev/null @@ -1,182 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Xanthous.Generators.Level.LevelContents - ( chooseCharacterPosition - , randomItems - , randomCreatures - , randomDoors - , placeDownStaircase - , tutorialMessage - , entityFromRaw - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (any, toList) --------------------------------------------------------------------------------- -import Control.Monad.Random -import Data.Array.IArray (amap, bounds, rangeSize, (!)) -import qualified Data.Array.IArray as Arr -import Data.Foldable (any, toList) -import Linear.V2 --------------------------------------------------------------------------------- -import Xanthous.Generators.Level.Util -import Xanthous.Random hiding (chance) -import qualified Xanthous.Random as Random -import Xanthous.Data - ( positionFromV2, Position, _Position - , rotations, arrayNeighbors, Neighbors(..) - , neighborPositions - ) -import Xanthous.Data.EntityMap (EntityMap, _EntityMap) -import Xanthous.Entities.Raws (rawsWithType, RawType, raw) -import qualified Xanthous.Entities.Item as Item -import Xanthous.Entities.Item (Item) -import qualified Xanthous.Entities.Creature as Creature -import Xanthous.Entities.Creature (Creature) -import Xanthous.Entities.Environment - (GroundMessage(..), Door(..), unlockedDoor, Staircase(..)) -import Xanthous.Messages (message_) -import Xanthous.Util.Graphics (circle) -import Xanthous.Entities.RawTypes -import Xanthous.Entities.Creature.Hippocampus (initialHippocampus) -import Xanthous.Entities.Common (inRightHand, asWieldedItem, wielded) -import Xanthous.Game.State (SomeEntity(SomeEntity)) --------------------------------------------------------------------------------- - -chooseCharacterPosition :: MonadRandom m => Cells -> m Position -chooseCharacterPosition = randomPosition - -randomItems :: MonadRandom m => Cells -> m (EntityMap Item) -randomItems = randomEntities (fmap Identity . Item.newWithType) (0.0004, 0.001) - -placeDownStaircase :: MonadRandom m => Cells -> m (EntityMap Staircase) -placeDownStaircase cells = do - pos <- randomPosition cells - pure $ _EntityMap # [(pos, DownStaircase)] - -randomDoors :: MonadRandom m => Cells -> m (EntityMap Door) -randomDoors cells = do - doorRatio <- getRandomR subsetRange - let numDoors = floor $ doorRatio * fromIntegral (length candidateCells) - doorPositions = - removeAdjacent . fmap positionFromV2 . take numDoors $ candidateCells - doors = zip doorPositions $ repeat unlockedDoor - pure $ _EntityMap # doors - where - removeAdjacent = - foldr (\pos acc -> - if pos `elem` (acc >>= toList . neighborPositions) - then acc - else pos : acc - ) [] - candidateCells = filter doorable $ Arr.indices cells - subsetRange = (0.8 :: Double, 1.0) - doorable pos = - not (fromMaybe True $ cells ^? ix pos) - && any (teeish . fmap (fromMaybe True)) - (rotations $ arrayNeighbors cells pos) - -- only generate doors at the *ends* of hallways, eg (where O is walkable, - -- X is a wall, and D is a door): - -- - -- O O O - -- X D X - -- O - teeish (fmap not -> (Neighbors tl t tr l r _ b _ )) = - and [tl, t, tr, b] && (and . fmap not) [l, r] - -randomCreatures - :: MonadRandom m - => Word -- ^ Level number, starting at 0 - -> Cells - -> m (EntityMap Creature) -randomCreatures levelNumber - = randomEntities maybeNewCreature (0.0007, 0.002) - where - maybeNewCreature cType - | maybe True (canGenerate levelNumber) $ cType ^. generateParams - = Just <$> newCreatureWithType cType - | otherwise - = pure Nothing - -newCreatureWithType :: MonadRandom m => CreatureType -> m Creature -newCreatureWithType _creatureType = do - let _hitpoints = _creatureType ^. maxHitpoints - _hippocampus = initialHippocampus - - equipped <- fmap join - . traverse genEquipped - $ _creatureType - ^.. generateParams . _Just . equippedItem . _Just - let _inventory = maybe id (\ei -> wielded .~ inRightHand ei) (headMay equipped) mempty - pure Creature.Creature {..} - where - genEquipped cei = do - doGen <- Random.chance $ cei ^. chance - let entName = cei ^. entityName - itemType = - fromMaybe (error $ "raw \"" <> unpack entName <> "\" not of type Item") - . preview _Item - . fromMaybe (error $ "Could not find raw: " <> unpack entName) - $ raw entName - item <- Item.newWithType itemType - if doGen - then pure [fromMaybe (error $ "raw \"" <> unpack entName <> "\" not wieldable") - $ preview asWieldedItem item] - else pure [] - - -tutorialMessage :: MonadRandom m - => Cells - -> Position -- ^ CharacterPosition - -> m (EntityMap GroundMessage) -tutorialMessage cells characterPosition = do - let distance = 2 - pos <- fmap (fromMaybe (error "No valid positions for tutorial message?")) - . choose . ChooseElement - $ accessiblePositionsWithin distance cells characterPosition - msg <- message_ ["tutorial", "message1"] - pure $ _EntityMap # [(pos, GroundMessage msg)] - where - accessiblePositionsWithin :: Int -> Cells -> Position -> [Position] - accessiblePositionsWithin dist valid pos = - review _Position - <$> filter - (\pt -> not $ valid ! (fromIntegral <$> pt)) - (circle (pos ^. _Position) dist) - -randomEntities - :: forall entity raw m t. (MonadRandom m, RawType raw, Functor t, Foldable t) - => (raw -> m (t entity)) - -> (Float, Float) - -> Cells - -> m (EntityMap entity) -randomEntities newWithType sizeRange cells = - case fromNullable $ rawsWithType @raw of - Nothing -> pure mempty - Just raws -> do - let len = rangeSize $ bounds cells - (numEntities :: Int) <- - floor . (* fromIntegral len) <$> getRandomR sizeRange - entities <- for [0..numEntities] $ const $ do - pos <- randomPosition cells - r <- choose raws - entities <- newWithType r - pure $ (pos, ) <$> entities - pure $ _EntityMap # (entities >>= toList) - -randomPosition :: MonadRandom m => Cells -> m Position -randomPosition = fmap positionFromV2 . choose . impureNonNull . cellCandidates - --- cellCandidates :: Cells -> Cells -cellCandidates :: Cells -> Set (V2 Word) -cellCandidates - -- find the largest contiguous region of cells in the cave. - = maximumBy (compare `on` length) - . fromMaybe (error "No regions generated! this should never happen.") - . fromNullable - . regions - -- cells ends up with true = wall, we want true = can put an item here - . amap not - -entityFromRaw :: MonadRandom m => EntityRaw -> m SomeEntity -entityFromRaw (Creature ct) = SomeEntity <$> newCreatureWithType ct -entityFromRaw (Item it) = SomeEntity <$> Item.newWithType it diff --git a/users/aspen/xanthous/src/Xanthous/Generators/Level/Util.hs b/users/aspen/xanthous/src/Xanthous/Generators/Level/Util.hs deleted file mode 100644 index 0008eb965..000000000 --- a/users/aspen/xanthous/src/Xanthous/Generators/Level/Util.hs +++ /dev/null @@ -1,236 +0,0 @@ -{-# LANGUAGE QuantifiedConstraints #-} -{-# LANGUAGE AllowAmbiguousTypes #-} --------------------------------------------------------------------------------- -module Xanthous.Generators.Level.Util - ( MCells - , Cells - , CellM - , randInitialize - , initializeEmpty - , numAliveNeighborsM - , numAliveNeighbors - , fillOuterEdgesM - , cloneMArray - , floodFill - , regions - , fillAll - , fillAllM - , fromPoints - , fromPointsM - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (Foldable, toList, for_) --------------------------------------------------------------------------------- -import Data.Array.ST -import Data.Array.Unboxed -import Control.Monad.ST -import Control.Monad.Random -import Data.Monoid -import Data.Foldable (Foldable, toList, for_) -import qualified Data.Set as Set -import Data.Semigroup.Foldable -import Linear.V2 --------------------------------------------------------------------------------- -import Xanthous.Util (foldlMapM', maximum1, minimum1) -import Xanthous.Data (Dimensions, width, height) --------------------------------------------------------------------------------- - -type MCells s = STUArray s (V2 Word) Bool -type Cells = UArray (V2 Word) Bool -type CellM g s a = RandT g (ST s) a - -randInitialize :: RandomGen g => Dimensions -> Double -> CellM g s (MCells s) -randInitialize dims aliveChance = do - res <- initializeEmpty dims - for_ [0..dims ^. width] $ \i -> - for_ [0..dims ^. height] $ \j -> do - val <- (>= aliveChance) <$> getRandomR (0, 1) - lift $ writeArray res (V2 i j) val - pure res - -initializeEmpty :: RandomGen g => Dimensions -> CellM g s (MCells s) -initializeEmpty dims = - lift $ newArray (0, V2 (dims ^. width) (dims ^. height)) False - --- | Returns the number of neighbors of the given point in the given array that --- are True. --- --- Behavior if point is out-of-bounds for the array is undefined, but will not --- error -numAliveNeighborsM - :: forall a i m - . (MArray a Bool m, Ix i, Integral i) - => a (V2 i) Bool - -> V2 i - -> m Word -numAliveNeighborsM cells pt@(V2 x y) = do - cellBounds <- getBounds cells - getSum <$> foldlMapM' - (fmap (Sum . fromIntegral . fromEnum) . boundedGet cellBounds) - neighborPositions - - where - boundedGet :: (V2 i, V2 i) -> (Int, Int) -> m Bool - boundedGet bnds _ - | not (inRange bnds pt) - = pure True - boundedGet (V2 minX minY, V2 maxX maxY) (i, j) - | (x <= minX && i < 0) - || (y <= minY && j < 0) - || (x >= maxX && i > 0) - || (y >= maxY && j > 0) - = pure True - | otherwise = - let nx = fromIntegral $ fromIntegral x + i - ny = fromIntegral $ fromIntegral y + j - in readArray cells $ V2 nx ny - --- | Returns the number of neighbors of the given point in the given array that --- are True. --- --- Behavior if point is out-of-bounds for the array is undefined, but will not --- error -numAliveNeighbors - :: forall a i - . (IArray a Bool, Ix i, Integral i) - => a (V2 i) Bool - -> V2 i - -> Word -numAliveNeighbors cells pt@(V2 x y) = - let cellBounds = bounds cells - in getSum $ foldMap - (Sum . fromIntegral . fromEnum . boundedGet cellBounds) - neighborPositions - - where - boundedGet :: (V2 i, V2 i) -> (Int, Int) -> Bool - boundedGet bnds _ - | not (inRange bnds pt) - = True - boundedGet (V2 minX minY, V2 maxX maxY) (i, j) - | (x <= minX && i < 0) - || (y <= minY && j < 0) - || (x >= maxX && i > 0) - || (y >= maxY && j > 0) - = True - | otherwise = - let nx = fromIntegral $ fromIntegral x + i - ny = fromIntegral $ fromIntegral y + j - in cells ! V2 nx ny - -neighborPositions :: [(Int, Int)] -neighborPositions = [(i, j) | i <- [-1..1], j <- [-1..1], (i, j) /= (0, 0)] - -fillOuterEdgesM :: (MArray a Bool m, Ix i) => a (V2 i) Bool -> m () -fillOuterEdgesM arr = do - (V2 minX minY, V2 maxX maxY) <- getBounds arr - for_ (range (minX, maxX)) $ \x -> do - writeArray arr (V2 x minY) True - writeArray arr (V2 x maxY) True - for_ (range (minY, maxY)) $ \y -> do - writeArray arr (V2 minX y) True - writeArray arr (V2 maxX y) True - -cloneMArray - :: forall a a' i e m. - ( Ix i - , MArray a e m - , MArray a' e m - , IArray UArray e - ) - => a i e - -> m (a' i e) -cloneMArray = thaw @_ @UArray <=< freeze - --------------------------------------------------------------------------------- - --- | Flood fill a cell array starting at a point, returning a list of all the --- (true) cell locations reachable from that point -floodFill :: forall a i. - ( IArray a Bool - , Ix i - , Enum i - , Bounded i - , Eq i - ) - => a (V2 i) Bool -- ^ array - -> (V2 i) -- ^ position - -> Set (V2 i) -floodFill = go mempty - where - go :: Set (V2 i) -> a (V2 i) Bool -> (V2 i) -> Set (V2 i) - go res arr@(bounds -> arrBounds) idx@(V2 x y) - | not (inRange arrBounds idx) = res - | not (arr ! idx) = res - | otherwise = - let neighbors - = filter (inRange arrBounds) - . filter (/= idx) - . filter (`notMember` res) - $ V2 - <$> [(if x == minBound then x else pred x) - .. - (if x == maxBound then x else succ x)] - <*> [(if y == minBound then y else pred y) - .. - (if y == maxBound then y else succ y)] - in foldl' (\r idx' -> - if arr ! idx' - then r <> (let r' = r & contains idx' .~ True - in r' `seq` go r' arr idx') - else r) - (res & contains idx .~ True) neighbors -{-# SPECIALIZE floodFill :: UArray (V2 Word) Bool -> (V2 Word) -> Set (V2 Word) #-} - --- | Gives a list of all the disconnected regions in a cell array, represented --- each as lists of points -regions :: forall a i. - ( IArray a Bool - , Ix i - , Enum i - , Bounded i - , Eq i - ) - => a (V2 i) Bool - -> [Set (V2 i)] -regions arr - | Just firstPoint <- findFirstPoint arr = - let region = floodFill arr firstPoint - arr' = fillAll region arr - in region : regions arr' - | otherwise = [] - where - findFirstPoint :: a (V2 i) Bool -> Maybe (V2 i) - findFirstPoint = fmap fst . headMay . filter snd . assocs -{-# SPECIALIZE regions :: UArray (V2 Word) Bool -> [Set (V2 Word)] #-} - -fillAll :: (IArray a Bool, Ix i, Foldable f) => f i -> a i Bool -> a i Bool -fillAll ixes a = accum (const fst) a $ (, (False, ())) <$> toList ixes - -fillAllM :: (MArray a Bool m, Ix i, Foldable f) => f i -> a i Bool -> m () -fillAllM ixes a = for_ ixes $ \i -> writeArray a i False - -fromPoints - :: forall a f i. - ( IArray a Bool - , Ix i - , Functor f - , Foldable1 f - ) - => f (i, i) - -> a (i, i) Bool -fromPoints points = - let pts = Set.fromList $ toList points - dims = ( (minimum1 $ fst <$> points, minimum1 $ snd <$> points) - , (maximum1 $ fst <$> points, maximum1 $ snd <$> points) - ) - in array dims $ range dims <&> \i -> (i, i `member` pts) - -fromPointsM - :: (MArray a Bool m, Ix i, Element f ~ i, MonoFoldable f) - => NonNull f - -> m (a i Bool) -fromPointsM points = do - arr <- newArray (minimum points, maximum points) False - fillAllM (otoList points) arr - pure arr diff --git a/users/aspen/xanthous/src/Xanthous/Generators/Level/Village.hs b/users/aspen/xanthous/src/Xanthous/Generators/Level/Village.hs deleted file mode 100644 index ab7de95e6..000000000 --- a/users/aspen/xanthous/src/Xanthous/Generators/Level/Village.hs +++ /dev/null @@ -1,126 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Generators.Level.Village - ( fromCave - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (any, failing, toList) --------------------------------------------------------------------------------- -import Control.Monad.Random (MonadRandom) -import Control.Monad.State (execStateT, MonadState, modify) -import Control.Monad.Trans.Maybe -import Control.Parallel.Strategies -import Data.Array.IArray -import Data.Foldable (any, toList) --------------------------------------------------------------------------------- -import Xanthous.Data -import Xanthous.Data.EntityMap (EntityMap) -import qualified Xanthous.Data.EntityMap as EntityMap -import Xanthous.Entities.Environment -import Xanthous.Generators.Level.Util -import Xanthous.Game.State (SomeEntity(..)) -import Xanthous.Random --------------------------------------------------------------------------------- - -fromCave :: MonadRandom m - => Cells -- ^ The positions of all the walls - -> m (EntityMap SomeEntity) -fromCave wallPositions = execStateT (fromCave' wallPositions) mempty - -fromCave' :: forall m. (MonadRandom m, MonadState (EntityMap SomeEntity) m) - => Cells - -> m () -fromCave' wallPositions = failing (pure ()) $ do - Just villageRegion <- - choose - . (`using` parTraversable rdeepseq) - . weightedBy (\reg -> let circSize = length $ circumference reg - in if circSize == 50 - then (1.0 :: Double) - else 1.0 / (fromIntegral . abs $ circSize - 50)) - $ regions closedHallways - - let circ = setFromList . circumference $ villageRegion - - centerPoints <- chooseSubset (0.1 :: Double) $ toList circ - - roomTiles <- foldM - (flip $ const $ stepOut circ) - (map pure centerPoints) - [0 :: Int ..2] - - let roomWalls = circumference . setFromList @(Set _) <$> roomTiles - allWalls = join roomWalls - - doorPositions <- fmap join . for roomWalls $ \room -> - let candidates = filter (`notMember` circ) room - in fmap toList . choose $ ChooseElement candidates - - let entryways = - filter (\pt -> - let ncs = neighborCells pt - in any ((&&) <$> (not . (wallPositions !)) - <*> (`notMember` villageRegion)) ncs - && any ((&&) <$> (`member` villageRegion) - <*> (`notElem` allWalls)) ncs) - $ toList villageRegion - - Just entryway <- choose $ ChooseElement entryways - - for_ (filter ((&&) <$> (`notElem` doorPositions) <*> (/= entryway)) allWalls) - $ insertEntity Wall - for_ (filter (/= entryway) doorPositions) $ insertEntity unlockedDoor - insertEntity unlockedDoor entryway - - - where - insertEntity e pt = modify $ EntityMap.insertAt (ptToPos pt) $ SomeEntity e - ptToPos pt = _Position # (fromIntegral <$> pt) - - stepOut :: Set (V2 Word) -> [[V2 Word]] -> MaybeT m [[V2 Word]] - stepOut circ rooms = for rooms $ \room -> - let nextLevels = hashNub $ toList . neighborCells =<< room - in pure - . (<> room) - $ filter ((&&) <$> (`notMember` circ) <*> (`notElem` join rooms)) - nextLevels - - circumference pts = - filter (any (`notMember` pts) . neighborCells) $ toList pts - closedHallways = closeHallways livePositions - livePositions = amap not wallPositions - --------------------------------------------------------------------------------- - -closeHallways :: Cells -> Cells -closeHallways livePositions = - livePositions // mapMaybe closeHallway (assocs livePositions) - where - closeHallway (_, False) = Nothing - closeHallway (pos, _) - | isHallway pos = Just (pos, False) - | otherwise = Nothing - isHallway pos = any ((&&) <$> not . view left <*> not . view right) - . rotations - . fmap (fromMaybe False) - $ arrayNeighbors livePositions pos - -failing :: Monad m => m a -> MaybeT m a -> m a -failing result = (maybe result pure =<<) . runMaybeT - -{- - -import Xanthous.Generators.Village -import Xanthous.Generators -import Xanthous.Data -import System.Random -import qualified Data.Text -import qualified Xanthous.Generators.CaveAutomata as CA -let gi = GeneratorInput SCaveAutomata CA.defaultParams -wallPositions <- generateFromInput gi (Dimensions 80 50) <$> getStdGen -putStrLn . Data.Text.unpack $ showCells wallPositions - -import Data.Array.IArray -let closedHallways = closeHallways . amap not $ wallPositions -putStrLn . Data.Text.unpack . showCells $ amap not closedHallways - --} diff --git a/users/aspen/xanthous/src/Xanthous/Generators/Speech.hs b/users/aspen/xanthous/src/Xanthous/Generators/Speech.hs deleted file mode 100644 index 8abc00b6a..000000000 --- a/users/aspen/xanthous/src/Xanthous/Generators/Speech.hs +++ /dev/null @@ -1,181 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE OverloadedLists #-} --------------------------------------------------------------------------------- -module Xanthous.Generators.Speech - ( -- * Language definition - Language(..) - -- ** Lenses - , phonotactics - , syllablesPerWord - - -- ** Phonotactics - , Phonotactics(..) - -- *** Lenses - , onsets - , nuclei - , codas - , numOnsets - , numNuclei - , numCodas - - -- * Language generation - , syllable - , word - - -- * Languages - , english - , gormlak - - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (replicateM) -import Data.Interval (Interval, (<=..<=)) -import qualified Data.Interval as Interval -import Control.Monad.Random.Class (MonadRandom) -import Xanthous.Random (chooseRange, choose, ChooseElement (..), Weighted (Weighted)) -import Control.Monad (replicateM) -import Test.QuickCheck (Arbitrary, CoArbitrary, Function) -import Test.QuickCheck.Instances.Text () -import Data.List.NonEmpty (NonEmpty) --------------------------------------------------------------------------------- - -newtype Phoneme = Phoneme Text - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData, CoArbitrary, Function) - deriving newtype (IsString, Semigroup, Monoid, Arbitrary) - --- | The phonotactics of a language --- --- The phonotactics of a language represent the restriction on the phonemes in --- the syllables of a language. --- --- Syllables in a language consist of an onset, a nucleus, and a coda (the --- nucleus and the coda together representing the "rhyme" of the syllable). -data Phonotactics = Phonotactics - { _onsets :: [Phoneme] -- ^ The permissible onsets, or consonant clusters - -- at the beginning of a syllable - , _nuclei :: [Phoneme] -- ^ The permissible nuclei, or vowel clusters in - -- the middle of a syllable - , _codas :: [Phoneme] -- ^ The permissible codas, or consonant clusters at - -- the end of a syllable - , _numOnsets :: Interval Word -- ^ The range of number of allowable onsets - , _numNuclei :: Interval Word -- ^ The range of number of allowable nuclei - , _numCodas :: Interval Word -- ^ The range of number of allowable codas - } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData) -makeLenses ''Phonotactics - --- | Randomly generate a syllable with the given 'Phonotactics' -syllable :: MonadRandom m => Phonotactics -> m Text -syllable phonotactics = do - let genPart num choices = do - n <- fromIntegral . fromMaybe 0 <$> chooseRange (phonotactics ^. num) - fmap (fromMaybe mempty . mconcat) - . replicateM n - . choose . ChooseElement - $ phonotactics ^. choices - - (Phoneme onset) <- genPart numOnsets onsets - (Phoneme nucleus) <- genPart numNuclei nuclei - (Phoneme coda) <- genPart numCodas codas - - pure $ onset <> nucleus <> coda - --- | A definition for a language --- --- Currently this provides enough information to generate multi-syllabic words, --- but in the future will likely also include grammar-related things. -data Language = Language - { _phonotactics :: Phonotactics - , _syllablesPerWord :: Weighted Int NonEmpty Int - } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData) -makeLenses ''Language - -word :: MonadRandom m => Language -> m Text -word lang = do - numSyllables <- choose $ lang ^. syllablesPerWord - mconcat <$> replicateM numSyllables (syllable $ lang ^. phonotactics) - --------------------------------------------------------------------------------- - --- -englishPhonotactics :: Phonotactics -englishPhonotactics = Phonotactics - { _onsets = [ "pl" , "bl" , "kl" , "gl" , "pr" , "br" , "tr" , "dr" , "kr" - , "gr" , "tw" , "dw" , "gw" , "kw" , "pw" - - , "fl" , "sl" , {- "thl", -} "shl" {- , "vl" -} - , "p", "b", "t", "d", "k", "ɡ", "m", "n", "f", "v", "th", "s" - , "z", "h", "l", "w" - - , "sp", "st", "sk" - - , "sm", "sn" - - , "sf", "sth" - - , "spl", "skl", "spr", "str", "skr", "skw", "sm", "sp", "st", "sk" - ] - , _nuclei = [ "a", "e", "i", "o", "u", "ur", "ar", "or", "ear", "are", "ure" - , "oa", "ee", "oo", "ei", "ie", "oi", "ou" - ] - , _codas = [ "m", "n", "ng", "p", "t", "tsh", "k", "f", "sh", "s", "th", "x" - , "v", "z", "zh", "l", "r", "w" - - , "lk", "lb", "lt", "ld", "ltsh", "ldsh", "lk" - , "rp", "rb", "rt", "rd", "rtsh", "rdsh", "rk", "rɡ" - , "lf", "lv", "lth", "ls", "lz", "lsh", "lth" - , "rf", "rv", "rth", "rs", "rz", "rth" - , "lm", "ln" - , "rm", "rn", "rl" - , "mp", "nt", "nd", "nth", "nsh", "nk" - , "mf", "ms", "mth", "nf", "nth", "ns", "nz", "nth" - , "ft", "sp", "st", "sk" - , "fth" - , "pt", "kt" - , "pth", "ps", "th", "ts", "dth", "dz", "ks" - , "lpt", "lps", "lfth", "lts", "lst", "lkt", "lks" - , "rmth", "rpt", "rps", "rts", "rst", "rkt" - , "mpt", "mps", "ndth", "nkt", "nks", "nkth" - , "ksth", "kst" - ] - , _numOnsets = 0 <=..<= 1 - , _numNuclei = Interval.singleton 1 - , _numCodas = 0 <=..<= 1 - } - -english :: Language -english = Language - { _phonotactics = englishPhonotactics - , _syllablesPerWord = Weighted [(20, 1), - (7, 2), - (2, 3), - (1, 4)] - } - -gormlakPhonotactics :: Phonotactics -gormlakPhonotactics = Phonotactics - { _onsets = [ "h", "l", "g", "b", "m", "n", "ng" - , "gl", "bl", "fl" - ] - , _numOnsets = Interval.singleton 1 - , _nuclei = [ "a", "o", "aa", "u" ] - , _numNuclei = Interval.singleton 1 - , _codas = [ "r", "l", "g", "m", "n" - , "rl", "gl", "ml", "rm" - , "n", "k" - ] - , _numCodas = Interval.singleton 1 - } - -gormlak :: Language -gormlak = Language - { _phonotactics = gormlakPhonotactics - , _syllablesPerWord = Weighted [ (5, 2) - , (5, 1) - , (1, 3) - ] - } diff --git a/users/aspen/xanthous/src/Xanthous/Messages.hs b/users/aspen/xanthous/src/Xanthous/Messages.hs deleted file mode 100644 index c273d6508..000000000 --- a/users/aspen/xanthous/src/Xanthous/Messages.hs +++ /dev/null @@ -1,114 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} --------------------------------------------------------------------------------- -module Xanthous.Messages - ( Message(..) - , resolve - , MessageMap(..) - , lookupMessage - - -- * Game messages - , messages - , render - , render_ - , lookup - , message - , message_ - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (lookup) --------------------------------------------------------------------------------- -import Control.Monad.Random.Class (MonadRandom) -import Data.Aeson (FromJSON, ToJSON, toJSON, object) -import qualified Data.Aeson as JSON -import Data.Aeson.Generic.DerivingVia -import Data.FileEmbed -import Data.List.NonEmpty -import Test.QuickCheck hiding (choose) -import Test.QuickCheck.Instances.UnorderedContainers () -import Text.Mustache -import qualified Data.Yaml as Yaml --------------------------------------------------------------------------------- -import Xanthous.Random -import Xanthous.Orphans () --------------------------------------------------------------------------------- - -data Message = Single Template | Choice (NonEmpty Template) - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (CoArbitrary, Function, NFData) - deriving (ToJSON, FromJSON) - via WithOptions '[ SumEnc UntaggedVal ] - Message - -instance Arbitrary Message where - arbitrary = - frequency [ (10, Single <$> arbitrary) - , (1, Choice <$> arbitrary) - ] - shrink = genericShrink - -resolve :: MonadRandom m => Message -> m Template -resolve (Single t) = pure t -resolve (Choice ts) = choose ts - -data MessageMap = Direct Message | Nested (HashMap Text MessageMap) - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (CoArbitrary, Function, NFData) - deriving (ToJSON, FromJSON) - via WithOptions '[ SumEnc UntaggedVal ] - MessageMap - -instance Arbitrary MessageMap where - arbitrary = frequency [ (10, Direct <$> arbitrary) - , (1, Nested <$> arbitrary) - ] - -lookupMessage :: [Text] -> MessageMap -> Maybe Message -lookupMessage [] (Direct msg) = Just msg -lookupMessage (k:ks) (Nested m) = lookupMessage ks =<< m ^. at k -lookupMessage _ _ = Nothing - -type instance Index MessageMap = [Text] -type instance IxValue MessageMap = Message -instance Ixed MessageMap where - ix [] f (Direct msg) = Direct <$> f msg - ix (k:ks) f (Nested m) = case m ^. at k of - Just m' -> ix ks f m' <&> \m'' -> - Nested $ m & at k ?~ m'' - Nothing -> pure $ Nested m - ix _ _ m = pure m - --------------------------------------------------------------------------------- - -rawMessages :: ByteString -rawMessages = $(embedFile "src/Xanthous/messages.yaml") - -messages :: MessageMap -messages - = either (error . Yaml.prettyPrintParseException) id - $ Yaml.decodeEither' rawMessages - -render :: (MonadRandom m, ToJSON params) => Message -> params -> m Text -render msg params = do - tpl <- resolve msg - pure . toStrict . renderMustache tpl $ toJSON params - --- | Render a message with an empty set of params -render_ :: (MonadRandom m) => Message -> m Text -render_ msg = render msg $ object [] - -lookup :: [Text] -> Message -lookup path = fromMaybe notFound $ messages ^? ix path - where notFound - = Single - $ compileMustacheText "template" "Message not found" - ^?! _Right - -message :: (MonadRandom m, ToJSON params) => [Text] -> params -> m Text -message path params = maybe notFound (`render` params) $ messages ^? ix path - where - notFound = pure "Message not found" - -message_ :: (MonadRandom m) => [Text] -> m Text -message_ path = maybe notFound (`render` JSON.object []) $ messages ^? ix path - where - notFound = pure "Message not found" diff --git a/users/aspen/xanthous/src/Xanthous/Messages/Template.hs b/users/aspen/xanthous/src/Xanthous/Messages/Template.hs deleted file mode 100644 index 517688035..000000000 --- a/users/aspen/xanthous/src/Xanthous/Messages/Template.hs +++ /dev/null @@ -1,275 +0,0 @@ -{-# LANGUAGE DeriveDataTypeable #-} --------------------------------------------------------------------------------- -module Xanthous.Messages.Template - ( -- * Template AST - Template(..) - , Substitution(..) - , Filter(..) - - -- ** Template AST transformations - , reduceTemplate - - -- * Template parser - , template - , runParser - , errorBundlePretty - - -- * Template pretty-printer - , ppTemplate - - -- * Rendering templates - , TemplateVar(..) - , nested - , TemplateVars(..) - , vars - , RenderError - , render - ) -where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding - (many, concat, try, elements, some, parts) --------------------------------------------------------------------------------- -import Test.QuickCheck hiding (label) -import Test.QuickCheck.Instances.Text () -import Test.QuickCheck.Instances.Semigroup () -import Test.QuickCheck.Checkers (EqProp) -import Control.Monad.Combinators.NonEmpty -import Data.List.NonEmpty (NonEmpty(..)) -import Data.Data -import Text.Megaparsec hiding (sepBy1, some) -import Text.Megaparsec.Char -import qualified Text.Megaparsec.Char.Lexer as L -import Data.Function (fix) --------------------------------------------------------------------------------- -import Xanthous.Util (EqEqProp(..)) --------------------------------------------------------------------------------- - -genIdentifier :: Gen Text -genIdentifier = pack <$> listOf1 (elements identifierChars) - -identifierChars :: String -identifierChars = ['a'..'z'] <> ['A'..'Z'] <> ['-', '_'] - -newtype Filter = FilterName Text - deriving stock (Show, Eq, Ord, Generic, Data) - deriving anyclass (NFData) - deriving (IsString) via Text - -instance Arbitrary Filter where - arbitrary = FilterName <$> genIdentifier - shrink (FilterName fn) = fmap FilterName . filter (not . null) $ shrink fn - -data Substitution - = SubstPath (NonEmpty Text) - | SubstFilter Substitution Filter - deriving stock (Show, Eq, Ord, Generic, Data) - deriving anyclass (NFData) - -instance Arbitrary Substitution where - arbitrary = sized . fix $ \gen n -> - let leaves = - [ SubstPath <$> ((:|) <$> genIdentifier <*> listOf genIdentifier)] - subtree = gen $ n `div` 2 - in if n == 0 - then oneof leaves - else oneof $ leaves <> [ SubstFilter <$> subtree <*> arbitrary ] - shrink (SubstPath pth) = - fmap SubstPath - . filter (not . any ((||) <$> null <*> any (`notElem` identifierChars))) - $ shrink pth - shrink (SubstFilter s f) - = shrink s - <> (uncurry SubstFilter <$> shrink (s, f)) - -data Template - = Literal Text - | Subst Substitution - | Concat Template Template - deriving stock (Show, Generic, Data) - deriving anyclass (NFData) - deriving EqProp via EqEqProp Template - -instance Plated Template where - plate _ tpl@(Literal _) = pure tpl - plate _ tpl@(Subst _) = pure tpl - plate f (Concat tpl₁ tpl₂) = Concat <$> f tpl₁ <*> f tpl₂ - -reduceTemplate :: Template -> Template -reduceTemplate = transform $ \case - (Concat (Literal t₁) (Literal t₂)) -> Literal (t₁ <> t₂) - (Concat (Literal "") t) -> t - (Concat t (Literal "")) -> t - (Concat t₁ (Concat t₂ t₃)) -> Concat (Concat t₁ t₂) t₃ - (Concat (Concat t₁ (Literal t₂)) (Literal t₃)) -> (Concat t₁ (Literal $ t₂ <> t₃)) - t -> t - -instance Eq Template where - tpl₁ == tpl₂ = case (reduceTemplate tpl₁, reduceTemplate tpl₂) of - (Literal t₁, Literal t₂) -> t₁ == t₂ - (Subst s₁, Subst s₂) -> s₁ == s₂ - (Concat ta₁ ta₂, Concat tb₁ tb₂) -> ta₁ == tb₁ && ta₂ == tb₂ - _ -> False - -instance Arbitrary Template where - arbitrary = sized . fix $ \gen n -> - let leaves = [ Literal . pack . filter (`notElem` ['\\', '{']) <$> arbitrary - , Subst <$> arbitrary - ] - subtree = gen $ n `div` 2 - genConcat = Concat <$> subtree <*> subtree - in if n == 0 - then oneof leaves - else oneof $ genConcat : leaves - shrink (Literal t) = Literal <$> shrink t - shrink (Subst s) = Subst <$> shrink s - shrink (Concat t₁ t₂) - = shrink t₁ - <> shrink t₂ - <> (Concat <$> shrink t₁ <*> shrink t₂) - -instance Semigroup Template where - (<>) = Concat - -instance Monoid Template where - mempty = Literal "" - --------------------------------------------------------------------------------- - -type Parser = Parsec Void Text - -sc :: Parser () -sc = L.space space1 empty empty - -lexeme :: Parser a -> Parser a -lexeme = L.lexeme sc - -symbol :: Text -> Parser Text -symbol = L.symbol sc - -identifier :: Parser Text -identifier = lexeme . label "identifier" $ do - firstChar <- letterChar <|> oneOf ['-', '_'] - restChars <- many $ alphaNumChar <|> oneOf ['-', '_'] - pure $ firstChar <| pack restChars - -filterName :: Parser Filter -filterName = FilterName <$> identifier - -substitutionPath :: Parser Substitution -substitutionPath = SubstPath <$> sepBy1 identifier (char '.') - -substitutionFilter :: Parser Substitution -substitutionFilter = do - path <- substitutionPath - fs <- some $ symbol "|" *> filterName - pure $ foldl' SubstFilter path fs - -- pure $ SubstFilter path f - -substitutionContents :: Parser Substitution -substitutionContents - = try substitutionFilter - <|> substitutionPath - -substitution :: Parser Substitution -substitution = between (string "{{") (string "}}") substitutionContents - -literal :: Parser Template -literal = Literal <$> - ( (string "\\{" $> "{") - <|> takeWhile1P Nothing (`notElem` ['\\', '{']) - ) - -subst :: Parser Template -subst = Subst <$> substitution - -template' :: Parser Template -template' = do - parts <- many $ literal <|> subst - pure $ foldr Concat (Literal "") parts - - -template :: Parser Template -template = reduceTemplate <$> template' <* eof - --------------------------------------------------------------------------------- - -ppSubstitution :: Substitution -> Text -ppSubstitution (SubstPath substParts) = intercalate "." substParts -ppSubstitution (SubstFilter s (FilterName f)) = ppSubstitution s <> " | " <> f - -ppTemplate :: Template -> Text -ppTemplate (Literal txt) = txt -ppTemplate (Subst s) = "{{" <> ppSubstitution s <> "}}" -ppTemplate (Concat tpl₁ tpl₂) = ppTemplate tpl₁ <> ppTemplate tpl₂ - --------------------------------------------------------------------------------- - -data TemplateVar - = Val Text - | Nested (Map Text TemplateVar) - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData) - -nested :: [(Text, TemplateVar)] -> TemplateVar -nested = Nested . mapFromList - -instance Arbitrary TemplateVar where - arbitrary = sized . fix $ \gen n -> - let nst = fmap mapFromList . listOf $ (,) <$> arbitrary <*> gen (n `div` 2) - in if n == 0 - then Val <$> arbitrary - else oneof [ Val <$> arbitrary - , Nested <$> nst] - -newtype TemplateVars = Vars { getTemplateVars :: Map Text TemplateVar } - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData) - deriving (Arbitrary) via (Map Text TemplateVar) - -type instance Index TemplateVars = Text -type instance IxValue TemplateVars = TemplateVar -instance Ixed TemplateVars where - ix k f (Vars vs) = Vars <$> ix k f vs -instance At TemplateVars where - at k f (Vars vs) = Vars <$> at k f vs - -vars :: [(Text, TemplateVar)] -> TemplateVars -vars = Vars . mapFromList - -lookupVar :: TemplateVars -> NonEmpty Text -> Maybe TemplateVar -lookupVar vs (p :| []) = vs ^. at p -lookupVar vs (p :| (p₁ : ps)) = vs ^. at p >>= \case - (Val _) -> Nothing - (Nested vs') -> lookupVar (Vars vs') $ p₁ :| ps - -data RenderError - = NoSuchVariable (NonEmpty Text) - | NestedFurther (NonEmpty Text) - | NoSuchFilter Filter - deriving stock (Show, Eq, Generic) - deriving anyclass (NFData) - -renderSubst - :: Map Filter (Text -> Text) -- ^ Filters - -> TemplateVars - -> Substitution - -> Either RenderError Text -renderSubst _ vs (SubstPath pth) = - case lookupVar vs pth of - Just (Val v) -> Right v - Just (Nested _) -> Left $ NestedFurther pth - Nothing -> Left $ NoSuchVariable pth -renderSubst fs vs (SubstFilter s fn) = - case fs ^. at fn of - Just filterFn -> filterFn <$> renderSubst fs vs s - Nothing -> Left $ NoSuchFilter fn - -render - :: Map Filter (Text -> Text) -- ^ Filters - -> TemplateVars -- ^ Template variables - -> Template -- ^ Template - -> Either RenderError Text -render _ _ (Literal s) = pure s -render fs vs (Concat t₁ t₂) = (<>) <$> render fs vs t₁ <*> render fs vs t₂ -render fs vs (Subst s) = renderSubst fs vs s diff --git a/users/aspen/xanthous/src/Xanthous/Monad.hs b/users/aspen/xanthous/src/Xanthous/Monad.hs deleted file mode 100644 index db602de56..000000000 --- a/users/aspen/xanthous/src/Xanthous/Monad.hs +++ /dev/null @@ -1,76 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Monad - ( AppT(..) - , AppM - , runAppT - , continue - , halt - - -- * Messages - , say - , say_ - , message - , message_ - , writeMessage - - -- * Autocommands - , cancelAutocommand - - -- * Events - , sendEvent - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Control.Monad.Random -import Control.Monad.State -import qualified Brick -import Brick (EventM, Next) -import Brick.BChan (writeBChan) -import Data.Aeson (ToJSON, object) --------------------------------------------------------------------------------- -import Xanthous.Data.App (AppEvent) -import Xanthous.Game.State -import Xanthous.Game.Env -import Xanthous.Messages (Message) -import qualified Xanthous.Messages as Messages --------------------------------------------------------------------------------- - -halt :: AppT (EventM n) (Next GameState) -halt = lift . Brick.halt =<< get - -continue :: AppT (EventM n) (Next GameState) -continue = lift . Brick.continue =<< get - --------------------------------------------------------------------------------- - -say :: (MonadRandom m, ToJSON params, MonadState GameState m) - => [Text] -> params -> m () -say msgPath = writeMessage <=< Messages.message msgPath - -say_ :: (MonadRandom m, MonadState GameState m) => [Text] -> m () -say_ msgPath = say msgPath $ object [] - -message :: (MonadRandom m, ToJSON params, MonadState GameState m) - => Message -> params -> m () -message msg = writeMessage <=< Messages.render msg - -message_ :: (MonadRandom m, MonadState GameState m) - => Message -> m () -message_ msg = message msg $ object [] - -writeMessage :: MonadState GameState m => Text -> m () -writeMessage m = messageHistory %= pushMessage m - --- | Cancel the currently active autocommand, if any -cancelAutocommand :: (MonadState GameState m, MonadIO m) => m () -cancelAutocommand = do - traverse_ (liftIO . cancel . snd) =<< preuse (autocommand . _ActiveAutocommand) - autocommand .= NoAutocommand - --------------------------------------------------------------------------------- - --- | Send an event to the app in an environment where the game env is available -sendEvent :: (MonadReader GameEnv m, MonadIO m) => AppEvent -> m () -sendEvent evt = do - ec <- view eventChan - liftIO $ writeBChan ec evt diff --git a/users/aspen/xanthous/src/Xanthous/Orphans.hs b/users/aspen/xanthous/src/Xanthous/Orphans.hs deleted file mode 100644 index 66004163f..000000000 --- a/users/aspen/xanthous/src/Xanthous/Orphans.hs +++ /dev/null @@ -1,495 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE PackageImports #-} -{-# OPTIONS_GHC -Wno-orphans #-} -{-# OPTIONS_GHC -Wno-type-defaults #-} --------------------------------------------------------------------------------- -module Xanthous.Orphans - ( ppTemplate - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (elements, (.=)) --------------------------------------------------------------------------------- -import Data.Aeson hiding (Key) -import qualified Data.Aeson.KeyMap as KM -import Data.Aeson.Types (typeMismatch) -import Data.List.NonEmpty (NonEmpty(..)) -import qualified Graphics.Vty.Input -import Graphics.Vty.Attributes -import Brick.Widgets.Edit -import Data.Text.Zipper.Generic (GenericTextZipper) -import Brick.Widgets.Core (getName) -import System.Random.Internal (StdGen (..)) -import System.Random.SplitMix (SMGen ()) -import Test.QuickCheck --- import Test.QuickCheck.Arbitrary.Generic (Arg ()) -import "quickcheck-instances" Test.QuickCheck.Instances () -import Text.Megaparsec (errorBundlePretty) -import Text.Megaparsec.Pos -import Text.Mustache -import Text.Mustache.Type ( showKey ) -import Control.Monad.State -import Linear -import qualified Data.Interval as Interval -import Data.Interval ( Interval, Extended (..), Boundary (..) - , lowerBound', upperBound', (<=..<), (<=..<=) - , interval) -import Test.QuickCheck.Checkers (EqProp ((=-=))) --------------------------------------------------------------------------------- -import Xanthous.Util.JSON -import Xanthous.Util.QuickCheck -import Xanthous.Util (EqEqProp(EqEqProp)) -import qualified Graphics.Vty.Input.Events --------------------------------------------------------------------------------- - -instance forall s a. - ( Cons s s a a - , IsSequence s - , Element s ~ a - ) => Cons (NonNull s) (NonNull s) a a where - _Cons = prism hither yon - where - hither :: (a, NonNull s) -> NonNull s - hither (a, ns) = - let s = toNullable ns - in impureNonNull $ a <| s - - yon :: NonNull s -> Either (NonNull s) (a, NonNull s) - yon ns = case nuncons ns of - (_, Nothing) -> Left ns - (x, Just xs) -> Right (x, xs) - -instance forall a. Cons (NonEmpty a) (NonEmpty a) a a where - _Cons = prism hither yon - where - hither :: (a, NonEmpty a) -> NonEmpty a - hither (a, x :| xs) = a :| (x : xs) - - yon :: NonEmpty a -> Either (NonEmpty a) (a, NonEmpty a) - yon ns@(x :| xs) = case xs of - (y : ys) -> Right (x, y :| ys) - [] -> Left ns - - -instance Arbitrary PName where - arbitrary = PName . pack <$> listOf1 (elements ['a'..'z']) - -instance Arbitrary Key where - arbitrary = Key <$> listOf1 arbSafeText - where arbSafeText = pack <$> listOf1 (elements ['a'..'z']) - shrink (Key []) = error "unreachable" - shrink k@(Key [_]) = pure k - shrink (Key (p:ps)) = Key . (p :) <$> shrink ps - -instance Arbitrary Pos where - arbitrary = mkPos . succ . abs <$> arbitrary - shrink (unPos -> 1) = [] - shrink (unPos -> x) = mkPos <$> [x..1] - -instance Arbitrary Node where - arbitrary = scale (`div` 10) $ sized node - where - node n | n > 0 = oneof $ leaves ++ branches (n `div` 4) - node _ = oneof leaves - branches n = - [ Section <$> arbitrary <*> subnodes n - , InvertedSection <$> arbitrary <*> subnodes n - ] - subnodes = fmap concatTextBlocks . listOf . node - leaves = - [ TextBlock . pack <$> listOf1 (elements ['a'..'z']) - , EscapedVar <$> arbitrary - , UnescapedVar <$> arbitrary - -- TODO fix pretty-printing of mustache partials - -- , Partial <$> arbitrary <*> arbitrary - ] - shrink = genericShrink - -concatTextBlocks :: [Node] -> [Node] -concatTextBlocks [] = [] -concatTextBlocks [x] = [x] -concatTextBlocks (TextBlock txt₁ : TextBlock txt₂ : xs) - = concatTextBlocks $ TextBlock (txt₁ <> txt₂) : concatTextBlocks xs -concatTextBlocks (x : xs) = x : concatTextBlocks xs - -instance Arbitrary Template where - arbitrary = scale (`div` 8) $ do - template <- concatTextBlocks <$> arbitrary - -- templateName <- arbitrary - -- rest <- arbitrary - let templateName = "template" - rest = mempty - pure $ Template - { templateActual = templateName - , templateCache = rest & at templateName ?~ template - } - shrink (Template actual cache) = - let Just tpl = cache ^. at actual - in do - cache' <- shrink cache - tpl' <- shrink tpl - actual' <- shrink actual - pure $ Template - { templateActual = actual' - , templateCache = cache' & at actual' ?~ tpl' - } - -instance CoArbitrary Template where - coarbitrary = coarbitrary . ppTemplate - -instance Function Template where - function = functionMap ppTemplate parseTemplatePartial - where - parseTemplatePartial txt - = compileMustacheText "template" txt ^?! _Right - -ppNode :: Map PName [Node] -> Node -> Text -ppNode _ (TextBlock txt) = txt -ppNode _ (EscapedVar k) = "{{" <> showKey k <> "}}" -ppNode ctx (Section k body) = - let sk = showKey k - in "{{#" <> sk <> "}}" <> foldMap (ppNode ctx) body <> "{{/" <> sk <> "}}" -ppNode _ (UnescapedVar k) = "{{{" <> showKey k <> "}}}" -ppNode ctx (InvertedSection k body) = - let sk = showKey k - in "{{^" <> sk <> "}}" <> foldMap (ppNode ctx) body <> "{{/" <> sk <> "}}" -ppNode _ (Partial n _) = "{{> " <> unPName n <> "}}" - -ppTemplate :: Template -> Text -ppTemplate (Template actual cache) = - case cache ^. at actual of - Nothing -> error "Template not found?" - Just nodes -> foldMap (ppNode cache) nodes - -instance ToJSON Template where - toJSON = String . ppTemplate - -instance FromJSON Template where - parseJSON - = withText "Template" - $ either (fail . errorBundlePretty) pure - . compileMustacheText "template" - -deriving anyclass instance NFData Node -deriving anyclass instance NFData Template - -instance FromJSON Color where - parseJSON (String "black") = pure black - parseJSON (String "red") = pure red - parseJSON (String "green") = pure green - parseJSON (String "yellow") = pure yellow - parseJSON (String "blue") = pure blue - parseJSON (String "magenta") = pure magenta - parseJSON (String "cyan") = pure cyan - parseJSON (String "white") = pure white - parseJSON (String "brightBlack") = pure brightBlack - parseJSON (String "brightRed") = pure brightRed - parseJSON (String "brightGreen") = pure brightGreen - parseJSON (String "brightYellow") = pure brightYellow - parseJSON (String "brightBlue") = pure brightBlue - parseJSON (String "brightMagenta") = pure brightMagenta - parseJSON (String "brightCyan") = pure brightCyan - parseJSON (String "brightWhite") = pure brightWhite - parseJSON n@(Number _) = Color240 <$> parseJSON n - parseJSON x = typeMismatch "Color" x - -instance ToJSON Color where - toJSON color - | color == black = "black" - | color == red = "red" - | color == green = "green" - | color == yellow = "yellow" - | color == blue = "blue" - | color == magenta = "magenta" - | color == cyan = "cyan" - | color == white = "white" - | color == brightBlack = "brightBlack" - | color == brightRed = "brightRed" - | color == brightGreen = "brightGreen" - | color == brightYellow = "brightYellow" - | color == brightBlue = "brightBlue" - | color == brightMagenta = "brightMagenta" - | color == brightCyan = "brightCyan" - | color == brightWhite = "brightWhite" - | Color240 num <- color = toJSON num - | otherwise = error $ "unimplemented: " <> show color - -instance (Eq a, Show a, Read a, FromJSON a) => FromJSON (MaybeDefault a) where - parseJSON Null = pure Default - parseJSON (String "keepCurrent") = pure KeepCurrent - parseJSON x = SetTo <$> parseJSON x - -instance ToJSON a => ToJSON (MaybeDefault a) where - toJSON Default = Null - toJSON KeepCurrent = String "keepCurrent" - toJSON (SetTo x) = toJSON x - --------------------------------------------------------------------------------- - -instance Arbitrary Color where - arbitrary = oneof [ Color240 <$> choose (0, 239) - , ISOColor <$> choose (0, 15) - ] - -deriving anyclass instance CoArbitrary Color -deriving anyclass instance Function Color - -instance (Eq a, Show a, Read a, Arbitrary a) => Arbitrary (MaybeDefault a) where - arbitrary = oneof [ pure Default - , pure KeepCurrent - , SetTo <$> arbitrary - ] - -instance CoArbitrary a => CoArbitrary (MaybeDefault a) where - coarbitrary Default = variant @Int 1 - coarbitrary KeepCurrent = variant @Int 2 - coarbitrary (SetTo x) = variant @Int 3 . coarbitrary x - -instance (Eq a, Show a, Read a, Function a) => Function (MaybeDefault a) where - function = functionShow - -deriving via (EqEqProp Attr) instance EqProp Attr - -instance Arbitrary Attr where - arbitrary = do - attrStyle <- arbitrary - attrForeColor <- arbitrary - attrBackColor <- arbitrary - attrURL <- arbitrary - pure Attr {..} - -deriving anyclass instance CoArbitrary Attr -deriving anyclass instance Function Attr - -instance ToJSON Attr where - toJSON Attr{..} = object - [ "style" .= maybeDefaultToJSONWith styleToJSON attrStyle - , "foreground" .= attrForeColor - , "background" .= attrBackColor - , "url" .= attrURL - ] - where - maybeDefaultToJSONWith _ Default = Null - maybeDefaultToJSONWith _ KeepCurrent = String "keepCurrent" - maybeDefaultToJSONWith tj (SetTo x) = tj x - styleToJSON style - | style == standout = "standout" - | style == underline = "underline" - | style == reverseVideo = "reverseVideo" - | style == blink = "blink" - | style == dim = "dim" - | style == bold = "bold" - | style == italic = "italic" - | otherwise = toJSON style - -instance FromJSON Attr where - parseJSON = withObject "Attr" $ \obj -> do - attrStyle <- parseStyle =<< obj .:? "style" .!= Default - attrForeColor <- obj .:? "foreground" .!= Default - attrBackColor <- obj .:? "background" .!= Default - attrURL <- obj .:? "url" .!= Default - pure Attr{..} - - where - parseStyle (SetTo (String "standout")) = pure (SetTo standout) - parseStyle (SetTo (String "underline")) = pure (SetTo underline) - parseStyle (SetTo (String "reverseVideo")) = pure (SetTo reverseVideo) - parseStyle (SetTo (String "blink")) = pure (SetTo blink) - parseStyle (SetTo (String "dim")) = pure (SetTo dim) - parseStyle (SetTo (String "bold")) = pure (SetTo bold) - parseStyle (SetTo (String "italic")) = pure (SetTo italic) - parseStyle (SetTo n@(Number _)) = SetTo <$> parseJSON n - parseStyle (SetTo v) = typeMismatch "Style" v - parseStyle Default = pure Default - parseStyle KeepCurrent = pure KeepCurrent - -deriving stock instance Ord Color -deriving stock instance Ord a => Ord (MaybeDefault a) -deriving stock instance Ord Attr - -deriving anyclass instance Hashable Graphics.Vty.Input.Events.Key -deriving anyclass instance Hashable Graphics.Vty.Input.Events.Modifier - --------------------------------------------------------------------------------- - -instance (SemiSequence a, Arbitrary (Element a), Arbitrary a) - => Arbitrary (NonNull a) where - arbitrary = ncons <$> arbitrary <*> arbitrary - -instance ToJSON a => ToJSON (NonNull a) where - toJSON = toJSON . toNullable - -instance (FromJSON a, MonoFoldable a) => FromJSON (NonNull a) where - parseJSON = maybe (fail "Found empty list") pure . fromNullable <=< parseJSON - -instance NFData a => NFData (NonNull a) where - rnf xs = xs `seq` toNullable xs `deepseq` () - --------------------------------------------------------------------------------- - -instance forall t name. (NFData t, Monoid t, NFData name) - => NFData (Editor t name) where - rnf ed = getName @_ @name ed `deepseq` getEditContents ed `deepseq` () - -deriving via (ReadShowJSON SMGen) instance ToJSON SMGen -deriving via (ReadShowJSON SMGen) instance FromJSON SMGen - -instance ToJSON StdGen where - toJSON = toJSON . unStdGen - toEncoding = toEncoding . unStdGen - -instance FromJSON StdGen where - parseJSON = fmap StdGen . parseJSON - --------------------------------------------------------------------------------- - -instance CoArbitrary a => CoArbitrary (NonNull a) where - coarbitrary = coarbitrary . toNullable - -instance (MonoFoldable a, Function a) => Function (NonNull a) where - function = functionMap toNullable $ fromMaybe (error "null") . fromNullable - -instance (Arbitrary t, Arbitrary n, GenericTextZipper t) - => Arbitrary (Editor t n) where - arbitrary = editor <$> arbitrary <*> arbitrary <*> arbitrary - -instance forall t n. (CoArbitrary t, CoArbitrary n, Monoid t) - => CoArbitrary (Editor t n) where - coarbitrary ed = coarbitrary (getName @_ @n ed, getEditContents ed) - -instance CoArbitrary StdGen where - coarbitrary = coarbitrary . show - -instance Function StdGen where - function = functionMap unStdGen StdGen - -instance Function SMGen where - function = functionShow - --------------------------------------------------------------------------------- - -deriving newtype instance (Arbitrary s, CoArbitrary (m (a, s))) - => CoArbitrary (StateT s m a) - --------------------------------------------------------------------------------- - -deriving via (GenericArbitrary (V2 a)) instance (Arbitrary a) => Arbitrary (V2 a) -instance CoArbitrary a => CoArbitrary (V2 a) -instance Function a => Function (V2 a) - --------------------------------------------------------------------------------- - -instance CoArbitrary Boundary -instance Function Boundary - -instance Arbitrary a => Arbitrary (Extended a) where - arbitrary = oneof [ pure NegInf - , pure PosInf - , Finite <$> arbitrary - ] - -instance CoArbitrary a => CoArbitrary (Extended a) where - coarbitrary NegInf = variant 1 - coarbitrary PosInf = variant 2 - coarbitrary (Finite x) = variant 3 . coarbitrary x - -instance (Function a) => Function (Extended a) where - function = functionMap g h - where - g NegInf = Left True - g (Finite a) = Right a - g PosInf = Left False - h (Left False) = PosInf - h (Left True) = NegInf - h (Right a) = Finite a - -instance ToJSON a => ToJSON (Extended a) where - toJSON NegInf = String "NegInf" - toJSON PosInf = String "PosInf" - toJSON (Finite x) = toJSON x - -instance FromJSON a => FromJSON (Extended a) where - parseJSON (String "NegInf") = pure NegInf - parseJSON (String "PosInf") = pure PosInf - parseJSON val = Finite <$> parseJSON val - -instance (EqProp a, Show a) => EqProp (Extended a) where - NegInf =-= NegInf = property True - PosInf =-= PosInf = property True - (Finite x) =-= (Finite y) = x =-= y - x =-= y = counterexample (show x <> " /= " <> show y) False - -instance Arbitrary Interval.Boundary where - arbitrary = elements [ Interval.Open , Interval.Closed ] - -instance (Ord r, Arbitrary r) => Arbitrary (Interval r) where - arbitrary = do - lower <- arbitrary - upper <- arbitrary - pure $ (if upper < lower then flip else id) - Interval.interval - lower - upper - -instance CoArbitrary a => CoArbitrary (Interval a) where - coarbitrary int = coarbitrary (lowerBound' int) . coarbitrary (upperBound' int) - -instance (Function a, Ord a) => Function (Interval a) where - function = functionMap g h - where - g = lowerBound' &&& upperBound' - h = uncurry interval - -deriving via (EqEqProp (Interval a)) instance Eq a => (EqProp (Interval a)) - -instance ToJSON a => ToJSON (Interval a) where - toJSON x = Array . fromList $ - [ object [ lowerKey .= lowerVal ] - , object [ upperKey .= upperVal ] - ] - where - (lowerVal, lowerBoundary) = lowerBound' x - (upperVal, upperBoundary) = upperBound' x - upperKey = boundaryToKey upperBoundary - lowerKey = boundaryToKey lowerBoundary - boundaryToKey Open = "Excluded" - boundaryToKey Closed = "Included" - -instance forall a. (FromJSON a, Ord a) => FromJSON (Interval a) where - parseJSON x = - boundPairWithBoundary x - <|> boundPairWithoutBoundary x - <|> singleVal x - where - boundPairWithBoundary = withArray "Bound pair" $ \arr -> do - checkLength arr - lower <- parseBound $ arr ^?! ix 0 - upper <- parseBound $ arr ^?! ix 1 - pure $ interval lower upper - parseBound = withObject "Bound" $ \obj -> do - when (KM.size obj /= 1) $ fail "Expected an object with a single key" - let [(k, v)] = obj ^@.. ifolded - boundary <- case k of - "Excluded" -> pure Open - "Open" -> pure Open - "Included" -> pure Closed - "Closed" -> pure Closed - _ -> fail "Invalid boundary specification" - val <- parseJSON v - pure (val, boundary) - boundPairWithoutBoundary = withArray "Bound pair" $ \arr -> do - checkLength arr - lower <- parseJSON $ arr ^?! ix 0 - upper <- parseJSON $ arr ^?! ix 1 - pure $ lower <=..< upper - singleVal v = do - val <- parseJSON v - pure $ val <=..<= val - checkLength arr = - when (length arr /= 2) $ fail "Expected array of length 2" - --------------------------------------------------------------------------------- - -deriving anyclass instance NFData Graphics.Vty.Input.Key -deriving anyclass instance NFData Graphics.Vty.Input.Modifier diff --git a/users/aspen/xanthous/src/Xanthous/Physics.hs b/users/aspen/xanthous/src/Xanthous/Physics.hs deleted file mode 100644 index 37530cbbc..000000000 --- a/users/aspen/xanthous/src/Xanthous/Physics.hs +++ /dev/null @@ -1,71 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Physics - ( throwDistance - , bluntThrowDamage - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Xanthous.Data - ( Meters - , (:**:)(..) - , Square - , Grams - , (|*|) - , (|/|) - , Hitpoints - , Per (..) - , squared - , Uno(..), (|+|) - ) --------------------------------------------------------------------------------- - --- university shotputter can put a 16 lb shot about 14 meters --- ≈ 7.25 kg 14 meters --- 14m = x / (7.25kg × y + z)² --- 14m = x / (7250g × y + z)² --- --- we don't want to scale down too much: --- --- 10 kg 10 meters --- = 10000 g 10 meters --- --- 15 kg w meters --- = 15000 g w meters --- --- 14m = x / (7250g × y + z)² --- 10m = x / (10000g × y + z)² --- wm = x / (15000g × y + z)² --- --- w≈0.527301 ∧ y≈0.000212178 sqrt(x) ∧ z≈1.80555 sqrt(x) ∧ 22824.1 sqrt(x)!=0 --- --- x = 101500 --- y = 0.0675979 --- z = 575.231 --- - --- TODO make this dynamic -strength :: Meters :**: Square Grams -strength = Times 10150000 - -yCoeff :: Uno Double -yCoeff = Uno 0.0675979 - -zCoeff :: Uno Double -zCoeff = Uno 575.231 - --- | Calculate the maximum distance an object with the given weight can be --- thrown -throwDistance - :: Grams -- ^ Weight of the object - -> Meters -- ^ Max distance thrown -throwDistance weight = strength |/| squared (weight |*| yCoeff |+| zCoeff) - --- | Returns the damage dealt by a blunt object with the given weight when --- thrown -bluntThrowDamage - :: Grams - -> Hitpoints -bluntThrowDamage weight = throwDamageRatio |*| weight - where - throwDamageRatio :: Hitpoints `Per` Grams - throwDamageRatio = Rate $ 1 / 5000 diff --git a/users/aspen/xanthous/src/Xanthous/Prelude.hs b/users/aspen/xanthous/src/Xanthous/Prelude.hs deleted file mode 100644 index 2cb429930..000000000 --- a/users/aspen/xanthous/src/Xanthous/Prelude.hs +++ /dev/null @@ -1,48 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Prelude - ( module ClassyPrelude - , Type - , Constraint - , module GHC.TypeLits - , module Control.Lens - , module Data.Void - , module Control.Comonad - , module Witherable - , fail - - , (&!) - - -- * Classy-Prelude addons - , ninsertSet - , ndeleteSet - , toVector - ) where --------------------------------------------------------------------------------- -import ClassyPrelude hiding - ( return, (<|), unsnoc, uncons, cons, snoc, index, (<.>), Index, say - , catMaybes, filter, mapMaybe, hashNub, ordNub - , Memoized, runMemoized - ) -import Data.Kind -import GHC.TypeLits hiding (Text) -import Control.Lens hiding (levels, Level) -import Data.Void -import Control.Comonad -import Witherable -import Control.Monad.Fail (fail) --------------------------------------------------------------------------------- - -ninsertSet - :: (IsSet set, MonoPointed set) - => Element set -> NonNull set -> NonNull set -ninsertSet x xs = impureNonNull $ opoint x `union` toNullable xs - -ndeleteSet :: IsSet b => Element b -> NonNull b -> b -ndeleteSet x = deleteSet x . toNullable - -toVector :: (MonoFoldable (f a), Element (f a) ~ a) => f a -> Vector a -toVector = fromList . toList - -infixl 1 &! -(&!) :: a -> (a -> b) -> b -(&!) = flip ($!) diff --git a/users/aspen/xanthous/src/Xanthous/Random.hs b/users/aspen/xanthous/src/Xanthous/Random.hs deleted file mode 100644 index 329b321b8..000000000 --- a/users/aspen/xanthous/src/Xanthous/Random.hs +++ /dev/null @@ -1,186 +0,0 @@ --------------------------------------------------------------------------------- -{-# LANGUAGE UndecidableInstances #-} -{-# LANGUAGE StandaloneDeriving #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} --------------------------------------------------------------------------------- -module Xanthous.Random - ( Choose(..) - , ChooseElement(..) - , Weighted(..) - , evenlyWeighted - , weightedBy - , subRand - , chance - , chooseSubset - , chooseRange - , FiniteInterval(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.List.NonEmpty (NonEmpty(..)) -import Control.Monad.Random.Class (MonadRandom(getRandomR, getRandom)) -import Control.Monad.Random (Rand, evalRand, mkStdGen, StdGen) -import Data.Functor.Compose -import Data.Random.Shuffle.Weighted -import Data.Random.Distribution -import Data.Random.Distribution.Uniform -import Data.Random.Distribution.Uniform.Exclusive -import Data.Random.Sample -import qualified Data.Random.Source as DRS -import Data.Interval ( Interval, lowerBound', Extended (Finite) - , upperBound', Boundary (Closed), lowerBound, upperBound - ) --------------------------------------------------------------------------------- - -instance {-# INCOHERENT #-} (Monad m, MonadRandom m) => DRS.MonadRandom m where - getRandomWord8 = getRandom - getRandomWord16 = getRandom - getRandomWord32 = getRandom - getRandomWord64 = getRandom - getRandomDouble = getRandom - getRandomNByteInteger n = getRandomR (0, 256 ^ n) - -class Choose a where - type RandomResult a - choose :: MonadRandom m => a -> m (RandomResult a) - -newtype ChooseElement a = ChooseElement a - -instance MonoFoldable a => Choose (ChooseElement a) where - type RandomResult (ChooseElement a) = Maybe (Element a) - choose (ChooseElement xs) = do - chosenIdx <- getRandomR (0, olength xs - 1) - let pick _ (Just x) = Just x - pick (x, i) Nothing - | i == chosenIdx = Just x - | otherwise = Nothing - pure $ ofoldr pick Nothing $ zip (toList xs) [0..] - -instance MonoFoldable a => Choose (NonNull a) where - type RandomResult (NonNull a) = Element a - choose - = fmap (fromMaybe (error "unreachable")) -- why not lol - . choose - . ChooseElement - . toNullable - -instance Choose (NonEmpty a) where - type RandomResult (NonEmpty a) = a - choose = choose . fromNonEmpty @[_] - -instance Choose (a, a) where - type RandomResult (a, a) = a - choose (x, y) = choose (x :| [y]) - -newtype Weighted w t a = Weighted (t (w, a)) - deriving (Functor, Foldable) via (t `Compose` (,) w) - -deriving newtype instance Eq (t (w, a)) => Eq (Weighted w t a) -deriving newtype instance Show (t (w, a)) => Show (Weighted w t a) -deriving newtype instance NFData (t (w, a)) => NFData (Weighted w t a) - -instance Traversable t => Traversable (Weighted w t) where - traverse f (Weighted twa) = Weighted <$> (traverse . traverse) f twa - -evenlyWeighted :: [a] -> Weighted Int [] a -evenlyWeighted = Weighted . itoList - --- | Weight the elements of some functor by a function. Larger values of 'w' per --- its 'Ord' instance will be more likely to be generated -weightedBy :: Functor t => (a -> w) -> t a -> Weighted w t a -weightedBy weighting xs = Weighted $ (weighting &&& id) <$> xs - -instance (Num w, Ord w, Distribution Uniform w, Excludable w) - => Choose (Weighted w [] a) where - type RandomResult (Weighted w [] a) = Maybe a - choose (Weighted ws) = sample $ headMay <$> weightedSample 1 ws - -instance (Num w, Ord w, Distribution Uniform w, Excludable w) - => Choose (Weighted w NonEmpty a) where - type RandomResult (Weighted w NonEmpty a) = a - choose (Weighted ws) = - sample - $ fromMaybe (error "unreachable") . headMay - <$> weightedSample 1 (toList ws) - -subRand :: MonadRandom m => Rand StdGen a -> m a -subRand sub = evalRand sub . mkStdGen <$> getRandom - --- | Has a @n@ chance of returning 'True' --- --- eg, chance 0.5 will return 'True' half the time -chance - :: (Num w, Ord w, Distribution Uniform w, Excludable w, MonadRandom m) - => w - -> m Bool -chance n = choose $ weightedBy (bool 1 (n * 2)) bools - --- | Choose a random subset of *about* @w@ of the elements of the given --- 'Witherable' structure -chooseSubset :: ( Num w, Ord w, Distribution Uniform w, Excludable w - , Witherable t - , MonadRandom m - ) => w -> t a -> m (t a) -chooseSubset = filterA . const . chance - --- | Choose a random @n@ in the given interval -chooseRange - :: ( MonadRandom m - , Distribution Uniform n - , Enum n - , Bounded n - , Ord n - ) - => Interval n - -> m (Maybe n) -chooseRange int = traverse sample distribution - where - (lower, lowerBoundary) = lowerBound' int - lowerR = case lower of - Finite x -> if lowerBoundary == Closed - then x - else succ x - _ -> minBound - (upper, upperBoundary) = upperBound' int - upperR = case upper of - Finite x -> if upperBoundary == Closed - then x - else pred x - _ -> maxBound - distribution - | lowerR <= upperR = Just $ Uniform lowerR upperR - | otherwise = Nothing - -instance ( Distribution Uniform n - , Enum n - , Bounded n - , Ord n - ) - => Choose (Interval n) where - type RandomResult (Interval n) = n - choose = fmap (fromMaybe $ error "Invalid interval") . chooseRange - -newtype FiniteInterval a - = FiniteInterval { unwrapFiniteInterval :: (Interval a) } - -instance ( Distribution Uniform n - , Ord n - ) - => Choose (FiniteInterval n) where - type RandomResult (FiniteInterval n) = n - -- TODO broken with open/closed right now - choose - = sample - . uncurry Uniform - . over both getFinite - . (lowerBound &&& upperBound) - . unwrapFiniteInterval - where - getFinite (Finite x) = x - getFinite _ = error "Infinite value" - --------------------------------------------------------------------------------- - -bools :: NonEmpty Bool -bools = True :| [False] diff --git a/users/aspen/xanthous/src/Xanthous/Util.hs b/users/aspen/xanthous/src/Xanthous/Util.hs deleted file mode 100644 index f918340f0..000000000 --- a/users/aspen/xanthous/src/Xanthous/Util.hs +++ /dev/null @@ -1,351 +0,0 @@ -{-# LANGUAGE BangPatterns #-} -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE QuantifiedConstraints #-} --------------------------------------------------------------------------------- -module Xanthous.Util - ( EqEqProp(..) - , EqProp(..) - , foldlMapM - , foldlMapM' - , between - - , appendVia - - -- * Foldable - -- ** Uniqueness - -- *** Predicates on uniqueness - , isUniqueOf - , isUnique - -- *** Removing all duplicate elements in n * log n time - , uniqueOf - , unique - -- *** Removing sequentially duplicate elements in linear time - , uniqOf - , uniq - -- ** Bag sequence algorithms - , takeWhileInclusive - , smallestNotIn - , removeVectorIndex - , removeFirst - , maximum1 - , minimum1 - - -- * Combinators - , times, times_, endoTimes - - -- * State utilities - , modifyK, modifyKL, useListOf - - -- * Type-level programming utils - , KnownBool(..) - - -- * - , AlphaChar(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (foldr) --------------------------------------------------------------------------------- -import Test.QuickCheck.Checkers -import Data.Foldable (foldr) -import Data.Monoid -import Data.Proxy -import qualified Data.Vector as V -import Data.Semigroup (Max(..), Min(..)) -import Data.Semigroup.Foldable -import Control.Monad.State.Class -import Control.Monad.State (evalState) --------------------------------------------------------------------------------- - -newtype EqEqProp a = EqEqProp a - deriving newtype Eq - -instance Eq a => EqProp (EqEqProp a) where - (=-=) = eq - -foldlMapM :: forall g b a m. (Foldable g, Monoid b, Applicative m) => (a -> m b) -> g a -> m b -foldlMapM f = foldr f' (pure mempty) - where - f' :: a -> m b -> m b - f' x = liftA2 mappend (f x) - --- Strict in the monoidal accumulator. For monads strict --- in the left argument of bind, this will run in constant --- space. -foldlMapM' :: forall g b a m. (Foldable g, Monoid b, Monad m) => (a -> m b) -> g a -> m b -foldlMapM' f xs = foldr f' pure xs mempty - where - f' :: a -> (b -> m b) -> b -> m b - f' x k bl = do - br <- f x - let !b = mappend bl br - k b - --- | Returns whether the third argument is in the range given by the first two --- arguments, inclusive --- --- >>> between (0 :: Int) 2 2 --- True --- --- >>> between (0 :: Int) 2 3 --- False -between - :: Ord a - => a -- ^ lower bound - -> a -- ^ upper bound - -> a -- ^ scrutinee - -> Bool -between lower upper x = x >= lower && x <= upper - --- | --- >>> appendVia Sum 1 2 --- 3 -appendVia :: (Rewrapping s t, Semigroup s) => (Unwrapped s -> s) -> Unwrapped s -> Unwrapped s -> Unwrapped s -appendVia wrap x y = op wrap $ wrap x <> wrap y - --------------------------------------------------------------------------------- - --- | Returns True if the targets of the given 'Fold' are unique per the 'Ord' instance for @a@ --- --- >>> isUniqueOf (folded . _1) ([(1, 2), (2, 2), (3, 2)] :: [(Int, Int)]) --- True --- --- >>> isUniqueOf (folded . _2) ([(1, 2), (2, 2), (3, 2)] :: [(Int, Int)]) --- False --- --- @ --- 'isUniqueOf' :: Ord a => 'Getter' s a -> s -> 'Bool' --- 'isUniqueOf' :: Ord a => 'Fold' s a -> s -> 'Bool' --- 'isUniqueOf' :: Ord a => 'Lens'' s a -> s -> 'Bool' --- 'isUniqueOf' :: Ord a => 'Iso'' s a -> s -> 'Bool' --- 'isUniqueOf' :: Ord a => 'Traversal'' s a -> s -> 'Bool' --- 'isUniqueOf' :: Ord a => 'Prism'' s a -> s -> 'Bool' --- @ -isUniqueOf :: Ord a => Getting (Endo (Set a, Bool)) s a -> s -> Bool -isUniqueOf aFold = orOf _2 . foldrOf aFold rejectUnique (mempty, True) - where - rejectUnique x (seen, acc) - | seen ^. contains x = (seen, False) - | otherwise = (seen & contains x .~ True, acc) - --- | Returns true if the given 'Foldable' container contains only unique --- elements, as determined by the 'Ord' instance for @a@ --- --- >>> isUnique ([3, 1, 2] :: [Int]) --- True --- --- >>> isUnique ([1, 1, 2, 2, 3, 1] :: [Int]) --- False -isUnique :: (Foldable f, Ord a) => f a -> Bool -isUnique = isUniqueOf folded - - --- | O(n * log n). Returns a monoidal, 'Cons'able container (a list, a Set, --- etc.) consisting of the unique (per the 'Ord' instance for @a@) targets of --- the given 'Fold' --- --- >>> uniqueOf (folded . _2) ([(1, 2), (2, 2), (3, 2), (4, 3)] :: [(Int, Int)]) :: [Int] --- [2,3] --- --- @ --- 'uniqueOf' :: Ord a => 'Getter' s a -> s -> [a] --- 'uniqueOf' :: Ord a => 'Fold' s a -> s -> [a] --- 'uniqueOf' :: Ord a => 'Lens'' s a -> s -> [a] --- 'uniqueOf' :: Ord a => 'Iso'' s a -> s -> [a] --- 'uniqueOf' :: Ord a => 'Traversal'' s a -> s -> [a] --- 'uniqueOf' :: Ord a => 'Prism'' s a -> s -> [a] --- @ -uniqueOf - :: (Monoid c, Ord w, Cons c c w w) => Getting (Endo (Set w, c)) a w -> a -> c -uniqueOf aFold = snd . foldrOf aFold rejectUnique (mempty, mempty) - where - rejectUnique x (seen, acc) - | seen ^. contains x = (seen, acc) - | otherwise = (seen & contains x .~ True, cons x acc) - --- | Returns a monoidal, 'Cons'able container (a list, a Set, etc.) consisting --- of the unique (per the 'Ord' instance for @a@) contents of the given --- 'Foldable' container --- --- >>> unique [1, 1, 2, 2, 3, 1] :: [Int] --- [2,3,1] - --- >>> unique [1, 1, 2, 2, 3, 1] :: Set Int --- fromList [3,2,1] -unique :: (Foldable f, Cons c c a a, Ord a, Monoid c) => f a -> c -unique = uniqueOf folded - --------------------------------------------------------------------------------- - --- | O(n). Returns a monoidal, 'Cons'able container (a list, a Vector, etc.) --- consisting of the targets of the given 'Fold' with sequential duplicate --- elements removed --- --- This function (sorry for the confusing name) differs from 'uniqueOf' in that --- it only compares /sequentially/ duplicate elements (and thus operates in --- linear time). --- cf 'Data.Vector.uniq' and POSIX @uniq@ for the name --- --- >>> uniqOf (folded . _2) ([(1, 2), (2, 2), (3, 1), (4, 2)] :: [(Int, Int)]) :: [Int] --- [2,1,2] --- --- @ --- 'uniqOf' :: Eq a => 'Getter' s a -> s -> [a] --- 'uniqOf' :: Eq a => 'Fold' s a -> s -> [a] --- 'uniqOf' :: Eq a => 'Lens'' s a -> s -> [a] --- 'uniqOf' :: Eq a => 'Iso'' s a -> s -> [a] --- 'uniqOf' :: Eq a => 'Traversal'' s a -> s -> [a] --- 'uniqOf' :: Eq a => 'Prism'' s a -> s -> [a] --- @ -uniqOf :: (Monoid c, Cons c c w w, Eq w) => Getting (Endo (Maybe w, c)) a w -> a -> c -uniqOf aFold = snd . foldrOf aFold rejectSeen (Nothing, mempty) - where - rejectSeen x (Nothing, acc) = (Just x, x <| acc) - rejectSeen x tup@(Just a, acc) - | x == a = tup - | otherwise = (Just x, x <| acc) - --- | O(n). Returns a monoidal, 'Cons'able container (a list, a Vector, etc.) --- consisting of the targets of the given 'Foldable' container with sequential --- duplicate elements removed --- --- This function (sorry for the confusing name) differs from 'unique' in that --- it only compares /sequentially/ unique elements (and thus operates in linear --- time). --- cf 'Data.Vector.uniq' and POSIX @uniq@ for the name --- --- >>> uniq [1, 1, 1, 2, 2, 2, 3, 3, 1] :: [Int] --- [1,2,3,1] --- --- >>> uniq [1, 1, 1, 2, 2, 2, 3, 3, 1] :: Vector Int --- [1,2,3,1] --- -uniq :: (Foldable f, Eq a, Cons c c a a, Monoid c) => f a -> c -uniq = uniqOf folded - --- | Like 'takeWhile', but inclusive -takeWhileInclusive :: (a -> Bool) -> [a] -> [a] -takeWhileInclusive _ [] = [] -takeWhileInclusive p (x:xs) = x : if p x then takeWhileInclusive p xs else [] - --- | Returns the smallest value not in a list -smallestNotIn :: (Ord a, Bounded a, Enum a) => [a] -> a -smallestNotIn xs = case uniq $ sort xs of - [] -> minBound - xs'@(x : _) - | x > minBound -> minBound - | otherwise - -> snd . headEx . filter (uncurry (/=)) $ zip (xs' ++ [minBound]) [minBound..] - --- | Remove the element at the given index, if any, from the given vector -removeVectorIndex :: Int -> Vector a -> Vector a -removeVectorIndex idx vect = - let (before, after) = V.splitAt idx vect - in before <> fromMaybe Empty (tailMay after) - --- | Remove the first element in a sequence that matches a given predicate -removeFirst :: IsSequence seq => (Element seq -> Bool) -> seq -> seq -removeFirst p - = flip evalState False - . filterM (\x -> do - found <- get - let matches = p x - when matches $ put True - pure $ found || not matches) - -maximum1 :: (Ord a, Foldable1 f) => f a -> a -maximum1 = getMax . foldMap1 Max - -minimum1 :: (Ord a, Foldable1 f) => f a -> a -minimum1 = getMin . foldMap1 Min - -times :: (Applicative f, Num n, Enum n) => n -> (n -> f b) -> f [b] -times n f = traverse f [1..n] - -times_ :: (Applicative f, Num n, Enum n) => n -> f a -> f [a] -times_ n fa = times n (const fa) - --- | Multiply an endomorphism by an integral --- --- >>> endoTimes (4 :: Int) succ (5 :: Int) --- 9 -endoTimes :: Integral n => n -> (a -> a) -> a -> a -endoTimes n f = appEndo $ stimes n (Endo f) - --------------------------------------------------------------------------------- - --- | This class gives a boolean associated with a type-level bool, a'la --- 'KnownSymbol', 'KnownNat' etc. -class KnownBool (bool :: Bool) where - boolVal' :: forall proxy. proxy bool -> Bool - boolVal' _ = boolVal @bool - - boolVal :: Bool - boolVal = boolVal' $ Proxy @bool - -instance KnownBool 'True where boolVal = True -instance KnownBool 'False where boolVal = False - --------------------------------------------------------------------------------- - --- | Modify some monadic state via the application of a kleisli endomorphism on --- the state itself --- --- Note that any changes made to the state during execution of @k@ will be --- overwritten --- --- @@ --- modifyK pure === pure () --- @@ -modifyK :: MonadState s m => (s -> m s) -> m () -modifyK k = get >>= k >>= put - --- | Modify some monadic state via the application of a kleisli endomorphism on --- the target of a lens --- --- Note that any changes made to the state during execution of @k@ will be --- overwritten --- --- @@ --- modifyKL id pure === pure () --- @@ -modifyKL :: MonadState s m => LensLike m s s a b -> (a -> m b) -> m () -modifyKL l k = get >>= traverseOf l k >>= put - --- | Use a list of all the targets of a 'Fold' in the current state --- --- @@ --- evalState (useListOf folded) === toList --- @@ -useListOf :: MonadState s m => Getting (Endo [a]) s a -> m [a] -useListOf = gets . toListOf - --------------------------------------------------------------------------------- - --- | A newtype wrapper around 'Char' whose 'Enum' and 'Bounded' instances only --- include the characters @[a-zA-Z]@ --- --- >>> succ (AlphaChar 'z') --- 'A' -newtype AlphaChar = AlphaChar { getAlphaChar :: Char } - deriving stock Show - deriving (Eq, Ord) via Char - -instance Enum AlphaChar where - toEnum n - | between 0 25 n - = AlphaChar . toEnum $ n + fromEnum 'a' - | between 26 51 n - = AlphaChar . toEnum $ n - 26 + fromEnum 'A' - | otherwise - = error $ "Tag " <> show n <> " out of range [0, 51] for enum AlphaChar" - fromEnum (AlphaChar chr) - | between 'a' 'z' chr - = fromEnum chr - fromEnum 'a' - | between 'A' 'Z' chr - = fromEnum chr - fromEnum 'A' - | otherwise - = error $ "Invalid value for alpha char: " <> show chr - -instance Bounded AlphaChar where - minBound = AlphaChar 'a' - maxBound = AlphaChar 'Z' diff --git a/users/aspen/xanthous/src/Xanthous/Util/Comonad.hs b/users/aspen/xanthous/src/Xanthous/Util/Comonad.hs deleted file mode 100644 index 9e158cc8e..000000000 --- a/users/aspen/xanthous/src/Xanthous/Util/Comonad.hs +++ /dev/null @@ -1,24 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Util.Comonad - ( -- * Store comonad utils - replace - , current - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Control.Comonad.Store.Class --------------------------------------------------------------------------------- - --- | Replace the current position of a store comonad with a new value by --- comparing positions -replace :: (Eq i, ComonadStore i w) => w a -> a -> w a -replace w x = w =>> \w' -> if pos w' == pos w then x else extract w' -{-# INLINE replace #-} - --- | Lens into the current position of a store comonad. --- --- current = lens extract replace -current :: (Eq i, ComonadStore i w) => Lens' (w a) a -current = lens extract replace -{-# INLINE current #-} diff --git a/users/aspen/xanthous/src/Xanthous/Util/Graph.hs b/users/aspen/xanthous/src/Xanthous/Util/Graph.hs deleted file mode 100644 index 8e5c04f4b..000000000 --- a/users/aspen/xanthous/src/Xanthous/Util/Graph.hs +++ /dev/null @@ -1,33 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Util.Graph where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.Graph.Inductive.Query.MST (msTree) -import qualified Data.Graph.Inductive.Graph as Graph -import Data.Graph.Inductive.Graph -import Data.Graph.Inductive.Basic (undir) -import Data.Set (isSubsetOf) --------------------------------------------------------------------------------- - -mstSubGraph - :: forall gr node edge. (DynGraph gr, Real edge, Show edge) - => gr node edge -> gr node edge -mstSubGraph graph = insEdges mstEdges . insNodes (labNodes graph) $ Graph.empty - where - mstEdges = ordNub $ do - LP path <- msTree $ undir graph - case path of - [] -> [] - [_] -> [] - ((n₂, edgeWeight) : (n₁, _) : _) -> - pure (n₁, n₂, edgeWeight) - -isSubGraphOf - :: (Graph gr1, Graph gr2, Ord node, Ord edge) - => gr1 node edge - -> gr2 node edge - -> Bool -isSubGraphOf graph₁ graph₂ - = setFromList (labNodes graph₁) `isSubsetOf` setFromList (labNodes graph₂) - && setFromList (labEdges graph₁) `isSubsetOf` setFromList (labEdges graph₂) diff --git a/users/aspen/xanthous/src/Xanthous/Util/Graphics.hs b/users/aspen/xanthous/src/Xanthous/Util/Graphics.hs deleted file mode 100644 index 0cb009f45..000000000 --- a/users/aspen/xanthous/src/Xanthous/Util/Graphics.hs +++ /dev/null @@ -1,177 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} --- | Graphics algorithms and utils for rendering things in 2D space --------------------------------------------------------------------------------- -module Xanthous.Util.Graphics - ( circle - , filledCircle - , line - , straightLine - , delaunay - - -- * Debugging and testing tools - , renderBooleanGraphics - , showBooleanGraphics - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- --- https://github.com/noinia/hgeometry/issues/28 --- import qualified Algorithms.Geometry.DelaunayTriangulation.DivideAndConquer --- as Geometry -import qualified Algorithms.Geometry.DelaunayTriangulation.Naive - as Geometry -import qualified Algorithms.Geometry.DelaunayTriangulation.Types as Geometry -import Control.Monad.State (execState, State) -import qualified Data.Geometry.Point as Geometry -import Data.Ext ((:+)(..)) -import Data.List (unfoldr) -import Data.List.NonEmpty (NonEmpty((:|))) -import qualified Data.List.NonEmpty as NE -import Data.Ix (Ix) -import Linear.V2 --------------------------------------------------------------------------------- - - --- | Generate a circle centered at the given point and with the given radius --- using the . --- --- Code taken from -circle :: (Num i, Ord i) - => V2 i -- ^ center - -> i -- ^ radius - -> [V2 i] -circle (V2 x₀ y₀) radius - -- Four initial points, plus the generated points - = V2 x₀ (y₀ + radius) - : V2 x₀ (y₀ - radius) - : V2 (x₀ + radius) y₀ - : V2 (x₀ - radius) y₀ - : points - where - -- Creates the (x, y) octet offsets, then maps them to absolute points in all octets. - points = concatMap generatePoints $ unfoldr step initialValues - - generatePoints (V2 x y) - = [ V2 (x₀ `xop` x') (y₀ `yop` y') - | (x', y') <- [(x, y), (y, x)] - , xop <- [(+), (-)] - , yop <- [(+), (-)] - ] - - initialValues = (1 - radius, 1, (-2) * radius, 0, radius) - - step (f, ddf_x, ddf_y, x, y) - | x >= y = Nothing - | otherwise = Just (V2 x' y', (f', ddf_x', ddf_y', x', y')) - where - (f', ddf_y', y') | f >= 0 = (f + ddf_y' + ddf_x', ddf_y + 2, y - 1) - | otherwise = (f + ddf_x, ddf_y, y) - ddf_x' = ddf_x + 2 - x' = x + 1 - - -data FillState i - = FillState - { _inCircle :: Bool - , _result :: NonEmpty (V2 i) - } -makeLenses ''FillState - -runFillState :: NonEmpty (V2 i) -> State (FillState i) a -> [V2 i] -runFillState circumference s - = toList - . view result - . execState s - $ FillState False circumference - --- | Generate a *filled* circle centered at the given point and with the given --- radius by filling a circle generated with 'circle' -filledCircle :: (Num i, Integral i, Ix i) - => V2 i -- ^ center - -> i -- ^ radius - -> [V2 i] -filledCircle center radius = - case NE.nonEmpty (circle center radius) of - Nothing -> [] - Just circumference -> runFillState circumference $ - -- the first and last lines of all circles are solid, so the whole "in the - -- circle, out of the circle" thing doesn't work... but that's fine since - -- we don't need to fill them. So just skip them - for_ [succ minX..pred maxX] $ \x -> - for_ [minY..maxY] $ \y -> do - let pt = V2 x y - next = V2 x $ succ y - whenM (use inCircle) $ result %= NE.cons pt - - when (pt `elem` circumference && next `notElem` circumference) - $ inCircle %= not - - where - (V2 minX minY, V2 maxX maxY) = minmaxes circumference - --- | Draw a line between two points using Bresenham's line drawing algorithm --- --- Code taken from -line :: (Num i, Ord i) => V2 i -> V2 i -> [V2 i] -line pa@(V2 xa ya) pb@(V2 xb yb) - = (if maySwitch pa < maySwitch pb then id else reverse) points - where - points = map maySwitch . unfoldr go $ (x₁, y₁, 0) - steep = abs (yb - ya) > abs (xb - xa) - maySwitch = if steep then view _yx else id - [V2 x₁ y₁, V2 x₂ y₂] = sort [maySwitch pa, maySwitch pb] - δx = x₂ - x₁ - δy = abs (y₂ - y₁) - ystep = if y₁ < y₂ then 1 else -1 - go (xTemp, yTemp, err) - | xTemp > x₂ = Nothing - | otherwise = Just (V2 xTemp yTemp, (xTemp + 1, newY, newError)) - where - tempError = err + δy - (newY, newError) = if (2 * tempError) >= δx - then (yTemp + ystep, tempError - δx) - else (yTemp, tempError) -{-# SPECIALIZE line :: V2 Int -> V2 Int -> [V2 Int] #-} -{-# SPECIALIZE line :: V2 Word -> V2 Word -> [V2 Word] #-} - -straightLine :: (Num i, Ord i) => V2 i -> V2 i -> [V2 i] -straightLine pa@(V2 xa _) pb@(V2 _ yb) = line pa midpoint ++ line midpoint pb - where midpoint = V2 xa yb - -delaunay - :: (Ord n, Fractional n) - => NonEmpty (V2 n, p) - -> [((V2 n, p), (V2 n, p))] -delaunay - = map (over both fromPoint) - . Geometry.edgesAsPoints - . Geometry.delaunayTriangulation - . map toPoint - where - toPoint (V2 px py, pid) = Geometry.Point2 px py :+ pid - fromPoint (Geometry.Point2 px py :+ pid) = (V2 px py, pid) - --------------------------------------------------------------------------------- - -renderBooleanGraphics :: forall i. (Num i, Ord i, Enum i) => [V2 i] -> String -renderBooleanGraphics [] = "" -renderBooleanGraphics (pt : pts') = intercalate "\n" rows - where - rows = row <$> [minX..maxX] - row x = [minY..maxY] <&> \y -> if V2 x y `member` ptSet then 'X' else ' ' - (V2 minX minY, V2 maxX maxY) = minmaxes pts - pts = pt :| pts' - ptSet :: Set (V2 i) - ptSet = setFromList $ toList pts - -showBooleanGraphics :: forall i. (Num i, Ord i, Enum i) => [V2 i] -> IO () -showBooleanGraphics = putStrLn . pack . renderBooleanGraphics - -minmaxes :: forall i. (Ord i) => NonEmpty (V2 i) -> (V2 i, V2 i) -minmaxes xs = - ( V2 (minimum1Of (traverse1 . _x) xs) - (minimum1Of (traverse1 . _y) xs) - , V2 (maximum1Of (traverse1 . _x) xs) - (maximum1Of (traverse1 . _y) xs) - ) diff --git a/users/aspen/xanthous/src/Xanthous/Util/Inflection.hs b/users/aspen/xanthous/src/Xanthous/Util/Inflection.hs deleted file mode 100644 index 724f2339d..000000000 --- a/users/aspen/xanthous/src/Xanthous/Util/Inflection.hs +++ /dev/null @@ -1,14 +0,0 @@ - -module Xanthous.Util.Inflection - ( toSentence - ) where - -import Xanthous.Prelude - -toSentence :: (MonoFoldable mono, Element mono ~ Text) => mono -> Text -toSentence xs = case reverse . toList $ xs of - [] -> "" - [x] -> x - [b, a] -> a <> " and " <> b - (final : butlast) -> - intercalate ", " (reverse butlast) <> ", and " <> final diff --git a/users/aspen/xanthous/src/Xanthous/Util/JSON.hs b/users/aspen/xanthous/src/Xanthous/Util/JSON.hs deleted file mode 100644 index 91d1328e4..000000000 --- a/users/aspen/xanthous/src/Xanthous/Util/JSON.hs +++ /dev/null @@ -1,19 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Util.JSON - ( ReadShowJSON(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import Data.Aeson --------------------------------------------------------------------------------- - -newtype ReadShowJSON a = ReadShowJSON a - deriving newtype (Read, Show) - -instance Show a => ToJSON (ReadShowJSON a) where - toJSON = toJSON . show - -instance Read a => FromJSON (ReadShowJSON a) where - parseJSON = withText "readable" - $ maybe (fail "Could not read") pure . readMay diff --git a/users/aspen/xanthous/src/Xanthous/Util/Optparse.hs b/users/aspen/xanthous/src/Xanthous/Util/Optparse.hs deleted file mode 100644 index dfa653723..000000000 --- a/users/aspen/xanthous/src/Xanthous/Util/Optparse.hs +++ /dev/null @@ -1,21 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Util.Optparse - ( readWithGuard - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude --------------------------------------------------------------------------------- -import qualified Options.Applicative as Opt --------------------------------------------------------------------------------- - -readWithGuard - :: Read b - => (b -> Bool) - -> (b -> String) - -> Opt.ReadM b -readWithGuard predicate errmsg = do - res <- Opt.auto - unless (predicate res) - $ Opt.readerError - $ errmsg res - pure res diff --git a/users/aspen/xanthous/src/Xanthous/Util/QuickCheck.hs b/users/aspen/xanthous/src/Xanthous/Util/QuickCheck.hs deleted file mode 100644 index aa881b322..000000000 --- a/users/aspen/xanthous/src/Xanthous/Util/QuickCheck.hs +++ /dev/null @@ -1,32 +0,0 @@ -{-# LANGUAGE UndecidableInstances #-} -module Xanthous.Util.QuickCheck - ( functionShow - , FunctionShow(..) - , functionJSON - , FunctionJSON(..) - , genericArbitrary - , GenericArbitrary(..) - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude -import Test.QuickCheck -import Test.QuickCheck.Function -import Test.QuickCheck.Instances.ByteString () -import Test.QuickCheck.Arbitrary.Generic -import Data.Aeson --------------------------------------------------------------------------------- - -newtype FunctionShow a = FunctionShow a - deriving newtype (Show, Read) - -instance (Show a, Read a) => Function (FunctionShow a) where - function = functionShow - -functionJSON :: (ToJSON a, FromJSON a) => (a -> c) -> a :-> c -functionJSON = functionMap encode (headEx . decode) - -newtype FunctionJSON a = FunctionJSON a - deriving newtype (ToJSON, FromJSON) - -instance (ToJSON a, FromJSON a) => Function (FunctionJSON a) where - function = functionJSON diff --git a/users/aspen/xanthous/src/Xanthous/keybindings.yaml b/users/aspen/xanthous/src/Xanthous/keybindings.yaml deleted file mode 100644 index cffb27cb0..000000000 --- a/users/aspen/xanthous/src/Xanthous/keybindings.yaml +++ /dev/null @@ -1,22 +0,0 @@ -q: Quit -?: Help -.: Wait -C-p: PreviousMessage -',': PickUp -d: Drop -o: Open -c: Close -;: Look -e: Eat -S: Save -r: Read -i: ShowInventory -I: DescribeInventory -w: Wield -f: Fire -'<': GoUp -'>': GoDown -R: Rest - -# Debug commands -M-r: ToggleRevealAll diff --git a/users/aspen/xanthous/src/Xanthous/messages.yaml b/users/aspen/xanthous/src/Xanthous/messages.yaml deleted file mode 100644 index bc08ec1ad..000000000 --- a/users/aspen/xanthous/src/Xanthous/messages.yaml +++ /dev/null @@ -1,161 +0,0 @@ -welcome: Welcome to Xanthous, {{characterName}}! It's dangerous out there, why not stay inside? Press ? for help. -dead: - - You have died... - - You die... - - You perish... - - You have perished... - -generic: - continue: Press enter to continue... - -save: - disabled: "Sorry, saving is currently disabled" - location: "Enter filename to save to: " - overwrite: "A file named {{filename}} already exists. Would you like to overwrite it? " - -quit: - confirm: Really quit without saving? - -entities: - description: You see here {{entityDescriptions}} - say: - creature: - visible: The {{creature.creatureType.name}} {{creature.creatureType.sayVerb}} "{{message}}" - invisible: You hear something yell "{{message}}" in the distance - -pickUp: - menu: What would you like to pick up? - pickUp: You pick up the {{item.itemType.name}}. - nothingToPickUp: "There's nothing here to pick up" - -cant: - goUp: - - You can't go up here - - There's nothing here that would let you go up - goDown: - - You can't go down here - - There's nothing here that would let you go down - -open: - prompt: Direction to open (hjklybnu.)? - success: "You open the door." - locked: "That door is locked" - nothingToOpen: "There's nothing to open there." - alreadyOpen: "That door is already open." - -close: - prompt: Direction to close (hjklybnu.)? - success: - - You close the door. - - You shut the door. - nothingToClose: "There's nothing to close there." - alreadyClosed: "That door is already closed." - blocked: "The {{entityDescriptions}} {{blockOrBlocks}} the door!" - -look: - prompt: Select a position on the map to describe (use Enter to confirm) - nothing: There's nothing there - -character: - namePrompt: "What's your name? " - body: - knuckles: - calluses: - - You've started developing calluses on your knuckles from all the punching you've been doing. - - You've been fighting with your fists so much they're starting to develop calluses. - -combat: - nothingToAttack: There's nothing to attack there. - menu: Which creature would you like to attack? - fistSelfDamage: - - You hit so hard with your fists you hurt yourself! - - The punch leaves your knuckles bloody! - fistExtraSelfDamage: - - You hurt your already-bloody fists with the strike! - - Ouch! Your fists were already bleeding! - hit: - fists: - - You punch the {{creature.creatureType.name}} with your bare fists! It hurts. A lot. - - You strike the {{creature.creatureType.name}} with your bare fists! It leaves a bit of a bruise on your knuckles. - generic: - - You hit the {{creature.creatureType.name}}. - - You attack the {{creature.creatureType.name}}. - creatureAttack: - natural: The {{creature.creatureType.name}} {{attackDescription}}. - genericWeapon: The {{creature.creatureType.name}} attacks you with its {{item.itemType.name}}. - killed: - - You kill the {{creature.creatureType.name}}! - - You've killed the {{creature.creatureType.name}}! - -debug: - toggleRevealAll: revealAll now set to {{revealAll}} - -eat: - noFood: - - You have nothing edible. - - You don't have any food. - - You don't have anything to eat. - - You search your pockets for something edible, and come up short. - menuPrompt: What would you like to eat? - eat: You eat the {{item.itemType.name}}. - -read: - prompt: Direction to read (hjklybnu.)? - nothing: "There's nothing there to read" - result: "\"{{message}}\"" - -inventory: - describe: - select: Select an item in your inventory to describe - nothing: You aren't carrying anything - -wield: - nothing: - - You aren't carrying anything you can wield - - You can't wield anything in your backpack - - You can't wield anything currently in your backpack - menu: What would you like to wield? - hand: Wield in which hand? - wielded: You wield the {{item.wieldedItem.itemType.name}} in {{hand}} - -fire: - nothing: - - You don't currently have anything you can throw - - You don't have anything to throw - zeroRange: - - That item is too heavy to throw! - - That's too heavy to throw - - You're not strong enough to throw that any meaningful distance - menu: What would you like to throw? - target: Choose a target - atRange: - - It's too heavy for you to throw any further than this - fired: - noTarget: - - You throw the {{item.itemType.name}} at the ground - noDamage: - - You throw the {{item.itemType.name}} at the {{creature.creatureType.name}}. It doesn't seem to care. - - You throw the {{item.itemType.name}} at the {{creature.creatureType.name}}. It doesn't seem to do anything. - - You throw the {{item.itemType.name}} at the {{creature.creatureType.name}}. It doesn't seem to hurt it. - someDamage: - - You throw the {{item.itemType.name}} at the {{creature.creatureType.name}}. It hits it on the head!. - -drop: - nothing: You aren't carrying anything - menu: What would you like to drop? - # TODO: use actual hands - dropped: - - You drop the {{item.itemType.name}}. - - You drop the {{item.itemType.name}} on the ground. - - You put the {{item.itemType.name}} on the ground. - - You take the {{item.itemType.name}} out of your backpack and put it on the ground. - - You take the {{item.itemType.name}} out of your backpack and drop it on the ground. - -autocommands: - enemyInSight: There's a {{firstEntity.creatureType.name}} nearby! - resting: Resting... - doneResting: Done resting -### - -tutorial: - message1: The caves are dark and full of nightmarish creatures - and you are likely to perish without food. Seek out sustenance! You can pick items up with ,. diff --git a/users/aspen/xanthous/test/Spec.hs b/users/aspen/xanthous/test/Spec.hs deleted file mode 100644 index 51758d6a2..000000000 --- a/users/aspen/xanthous/test/Spec.hs +++ /dev/null @@ -1,61 +0,0 @@ --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import qualified Xanthous.CommandSpec -import qualified Xanthous.Data.EntitiesSpec -import qualified Xanthous.Data.EntityCharSpec -import qualified Xanthous.Data.EntityMap.GraphicsSpec -import qualified Xanthous.Data.EntityMapSpec -import qualified Xanthous.Data.LevelsSpec -import qualified Xanthous.Data.MemoSpec -import qualified Xanthous.Data.NestedMapSpec -import qualified Xanthous.DataSpec -import qualified Xanthous.Entities.CommonSpec -import qualified Xanthous.Entities.RawsSpec -import qualified Xanthous.Entities.RawTypesSpec -import qualified Xanthous.Entities.CharacterSpec -import qualified Xanthous.GameSpec -import qualified Xanthous.Game.StateSpec -import qualified Xanthous.Game.PromptSpec -import qualified Xanthous.Generators.Level.UtilSpec -import qualified Xanthous.MessageSpec -import qualified Xanthous.Messages.TemplateSpec -import qualified Xanthous.OrphansSpec -import qualified Xanthous.RandomSpec -import qualified Xanthous.Util.GraphSpec -import qualified Xanthous.Util.GraphicsSpec -import qualified Xanthous.Util.InflectionSpec -import qualified Xanthous.UtilSpec --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMainWithRerun test - -test :: TestTree -test = testGroup "Xanthous" - [ Xanthous.CommandSpec.test - , Xanthous.Data.EntitiesSpec.test - , Xanthous.Data.EntityMap.GraphicsSpec.test - , Xanthous.Data.EntityMapSpec.test - , Xanthous.Data.LevelsSpec.test - , Xanthous.Data.MemoSpec.test - , Xanthous.Data.NestedMapSpec.test - , Xanthous.DataSpec.test - , Xanthous.Entities.CommonSpec.test - , Xanthous.Entities.RawsSpec.test - , Xanthous.Entities.CharacterSpec.test - , Xanthous.Entities.RawTypesSpec.test - , Xanthous.GameSpec.test - , Xanthous.Game.StateSpec.test - , Xanthous.Game.PromptSpec.test - , Xanthous.Generators.Level.UtilSpec.test - , Xanthous.MessageSpec.test - , Xanthous.Messages.TemplateSpec.test - , Xanthous.OrphansSpec.test - , Xanthous.RandomSpec.test - , Xanthous.Util.GraphSpec.test - , Xanthous.Util.GraphicsSpec.test - , Xanthous.Util.InflectionSpec.test - , Xanthous.UtilSpec.test - , Xanthous.Data.EntityCharSpec.test - ] diff --git a/users/aspen/xanthous/test/Test/Prelude.hs b/users/aspen/xanthous/test/Test/Prelude.hs deleted file mode 100644 index 75c1ebf5e..000000000 --- a/users/aspen/xanthous/test/Test/Prelude.hs +++ /dev/null @@ -1,34 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} --------------------------------------------------------------------------------- -module Test.Prelude - ( module Xanthous.Prelude - , module Test.Tasty - , module Test.Tasty.HUnit - , module Test.Tasty.QuickCheck - , module Test.Tasty.Ingredients.Rerun - , module Test.QuickCheck.Classes - , testBatch - , jsonRoundTrip - ) where --------------------------------------------------------------------------------- -import Xanthous.Prelude hiding (assert, elements) --------------------------------------------------------------------------------- -import Test.Tasty -import Test.Tasty.QuickCheck -import Test.Tasty.HUnit -import Test.Tasty.Ingredients.Rerun -import Test.QuickCheck.Classes -import Test.QuickCheck.Checkers (TestBatch, EqProp ((=-=))) -import Test.QuickCheck.Instances.ByteString () --------------------------------------------------------------------------------- -import qualified Data.Aeson as JSON -import Data.Aeson (ToJSON, FromJSON) --------------------------------------------------------------------------------- - -testBatch :: TestBatch -> TestTree -testBatch (name, tests) = testGroup name $ uncurry testProperty <$> tests - -jsonRoundTrip - :: forall a. (ToJSON a, FromJSON a, EqProp a, Arbitrary a, Show a) => TestTree -jsonRoundTrip = testProperty "JSON round trip" $ \(x :: a) -> - JSON.decode (JSON.encode x) =-= Just x diff --git a/users/aspen/xanthous/test/Xanthous/CommandSpec.hs b/users/aspen/xanthous/test/Xanthous/CommandSpec.hs deleted file mode 100644 index 13f69a808..000000000 --- a/users/aspen/xanthous/test/Xanthous/CommandSpec.hs +++ /dev/null @@ -1,40 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.CommandSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Xanthous.Command --------------------------------------------------------------------------------- -import Data.Aeson (fromJSON, Value(String)) -import qualified Data.Aeson as A -import Graphics.Vty.Input (Key(..), Modifier(..)) --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.CommandSpec" - [ testGroup "keybindings" - [ testCase "all are valid" $ keybindings `deepseq` pure () - , testProperty "all non-move commands are bound" $ \cmd -> - let isn'tMove = case cmd of - Move _ -> False - StartAutoMove _ -> False - _ -> True - in isn'tMove ==> member cmd commands - ] - , testGroup "instance FromJSON Keybinding" $ - [ ("q", Keybinding (KChar 'q') []) - , ("", Keybinding KUp []) - , ("", Keybinding KLeft []) - , ("", Keybinding KRight []) - , ("", Keybinding KDown []) - , ("S-q", Keybinding (KChar 'q') [MShift]) - , ("C-S-q", Keybinding (KChar 'q') [MCtrl, MShift]) - , ("m-", Keybinding KUp [MMeta]) - , ("S", Keybinding (KChar 'S') []) - ] <&> \(s, kb) -> - testCase (fromString $ unpack s <> " -> " <> show kb) - $ fromJSON (String s) @?= A.Success kb - ] diff --git a/users/aspen/xanthous/test/Xanthous/Data/EntitiesSpec.hs b/users/aspen/xanthous/test/Xanthous/Data/EntitiesSpec.hs deleted file mode 100644 index e40350374..000000000 --- a/users/aspen/xanthous/test/Xanthous/Data/EntitiesSpec.hs +++ /dev/null @@ -1,28 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Data.EntitiesSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import qualified Data.Aeson as JSON --------------------------------------------------------------------------------- -import Xanthous.Data.Entities --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Data.Entities" - [ testGroup "Collision" - [ testProperty "JSON round-trip" $ \(c :: Collision) -> - JSON.decode (JSON.encode c) === Just c - , testGroup "JSON encoding examples" - [ testCase "Stop" $ JSON.encode Stop @?= "\"Stop\"" - , testCase "Combat" $ JSON.encode Combat @?= "\"Combat\"" - ] - ] - , testGroup "EntityAttributes" - [ testProperty "JSON round-trip" $ \(ea :: EntityAttributes) -> - JSON.decode (JSON.encode ea) === Just ea - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Data/EntityCharSpec.hs b/users/aspen/xanthous/test/Xanthous/Data/EntityCharSpec.hs deleted file mode 100644 index 9e8024c9d..000000000 --- a/users/aspen/xanthous/test/Xanthous/Data/EntityCharSpec.hs +++ /dev/null @@ -1,18 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Data.EntityCharSpec where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import qualified Data.Aeson as JSON --------------------------------------------------------------------------------- -import Xanthous.Data.EntityChar --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Data.EntityChar" - [ testProperty "JSON round-trip" $ \(ec :: EntityChar) -> - JSON.decode (JSON.encode ec) === Just ec - ] diff --git a/users/aspen/xanthous/test/Xanthous/Data/EntityMap/GraphicsSpec.hs b/users/aspen/xanthous/test/Xanthous/Data/EntityMap/GraphicsSpec.hs deleted file mode 100644 index fd37548ce..000000000 --- a/users/aspen/xanthous/test/Xanthous/Data/EntityMap/GraphicsSpec.hs +++ /dev/null @@ -1,57 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Data.EntityMap.GraphicsSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude -import Data.Aeson --------------------------------------------------------------------------------- -import Xanthous.Game.State -import Xanthous.Data -import Xanthous.Data.EntityMap -import Xanthous.Data.EntityMap.Graphics -import Xanthous.Entities.Environment (Wall(..)) --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Data.EntityMap.Graphics" - [ testGroup "visiblePositions" - [ testProperty "one step in each cardinal direction is always visible" - $ \pos (Cardinal dir) (Positive r) (wallPositions :: Set Position)-> - pos `notMember` wallPositions ==> - let em = review _EntityMap . map (, Wall) . toList $ wallPositions - em' = em & atPosition (move dir pos) %~ (Wall <|) - poss = visiblePositions pos r em' - in counterexample ("visiblePositions: " <> show poss) - $ move dir pos `member` poss - , testGroup "bugs" - [ testCase "non-contiguous bug 1" - $ let charPos = Position 20 20 - gormlakPos = Position 17 19 - em = insertAt gormlakPos TestEntity - . insertAt charPos TestEntity - $ mempty - visPositions = visiblePositions charPos 12 em - in (gormlakPos `member` visPositions) @? - ( "not (" - <> show gormlakPos <> " `member` " - <> show visPositions - <> ")" - ) - ] - ] - ] - --------------------------------------------------------------------------------- - -data TestEntity = TestEntity - deriving stock (Show, Eq, Ord, Generic) - deriving anyclass (ToJSON, FromJSON, NFData) - -instance Brain TestEntity where - step _ = pure -instance Draw TestEntity -instance Entity TestEntity where - description _ = "" - entityChar _ = "e" diff --git a/users/aspen/xanthous/test/Xanthous/Data/EntityMapSpec.hs b/users/aspen/xanthous/test/Xanthous/Data/EntityMapSpec.hs deleted file mode 100644 index 7c5cad019..000000000 --- a/users/aspen/xanthous/test/Xanthous/Data/EntityMapSpec.hs +++ /dev/null @@ -1,69 +0,0 @@ -{-# LANGUAGE ApplicativeDo #-} --------------------------------------------------------------------------------- -module Xanthous.Data.EntityMapSpec where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import qualified Data.Aeson as JSON --------------------------------------------------------------------------------- -import Xanthous.Data.EntityMap -import Xanthous.Data (Positioned(..)) --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = localOption (QuickCheckTests 20) - $ testGroup "Xanthous.Data.EntityMap" - [ testBatch $ monoid @(EntityMap Int) mempty - , testGroup "Deduplicate" - [ testGroup "Semigroup laws" - [ testProperty "associative" $ \(a :: Deduplicate (EntityMap Int)) b c -> - a <> (b <> c) === (a <> b) <> c - ] - ] - , testGroup "Eq laws" - [ testProperty "reflexivity" $ \(em :: EntityMap Int) -> - em == em - , testProperty "symmetric" $ \(em₁ :: EntityMap Int) em₂ -> - (em₁ == em₂) == (em₂ == em₁) - , testProperty "transitive" $ \(em₁ :: EntityMap Int) em₂ em₃ -> - if (em₁ == em₂ && em₂ == em₃) - then (em₁ == em₃) - else True - ] - , testGroup "JSON encoding/decoding" - [ testProperty "round-trips" $ \(em :: EntityMap Int) -> - let em' = JSON.decode (JSON.encode em) - in counterexample (show (em' ^? _Just . lastID, em ^. lastID - , em' ^? _Just . byID == em ^. byID . re _Just - , em' ^? _Just . byPosition == em ^. byPosition . re _Just - , em' ^? _Just . _EntityMap == em ^. _EntityMap . re _Just - )) - $ em' === Just em - , testProperty "Preserves IDs" $ \(em :: EntityMap Int) -> - let Just em' = JSON.decode $ JSON.encode em - in toEIDsAndPositioned em' === toEIDsAndPositioned em - ] - - , localOption (QuickCheckTests 50) - $ testGroup "atPosition" - [ testProperty "setget" $ \pos (em :: EntityMap Int) es -> - view (atPosition pos) (set (atPosition pos) es em) === es - , testProperty "getset" $ \pos (em :: EntityMap Int) -> - set (atPosition pos) (view (atPosition pos) em) em === em - , testProperty "setset" $ \pos (em :: EntityMap Int) es -> - (set (atPosition pos) es . set (atPosition pos) es) em - === - set (atPosition pos) es em - -- testProperty "lens laws" $ \pos -> isLens $ atPosition @Int pos - , testProperty "preserves IDs" $ \(em :: EntityMap Int) e1 e2 p -> - let (eid, em') = insertAtReturningID p e1 em - em'' = em' & atPosition p %~ (e2 <|) - in - counterexample ("em': " <> show em') - . counterexample ("em'': " <> show em'') - $ em'' ^. at eid === Just (Positioned p e1) - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Data/LevelsSpec.hs b/users/aspen/xanthous/test/Xanthous/Data/LevelsSpec.hs deleted file mode 100644 index a75283316..000000000 --- a/users/aspen/xanthous/test/Xanthous/Data/LevelsSpec.hs +++ /dev/null @@ -1,66 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Data.LevelsSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import qualified Data.Aeson as JSON --------------------------------------------------------------------------------- -import Xanthous.Util (between) -import Xanthous.Data.Levels --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Data.Levels" - [ testGroup "current" - [ testProperty "view is extract" $ \(levels :: Levels Int) -> - levels ^. current === extract levels - , testProperty "set replaces current" $ \(levels :: Levels Int) new -> - extract (set current new levels) === new - , testProperty "set extract is id" $ \(levels :: Levels Int) -> - set current (extract levels) levels === levels - , testProperty "set y ∘ set x ≡ set y" $ \(levels :: Levels Int) x y -> - set current y (set current x levels) === set current y levels - ] - , localOption (QuickCheckTests 20) - $ testBatch $ semigroup @(Levels Int) (error "unused", 1 :: Int) - , testGroup "next/prev" - [ testGroup "nextLevel" - [ testProperty "seeks forwards" $ \(levels :: Levels Int) genned -> - (pos . runIdentity . nextLevel (Identity genned) $ levels) - === pos levels + 1 - , testProperty "maintains the invariant" $ \(levels :: Levels Int) genned -> - let levels' = runIdentity . nextLevel (Identity genned) $ levels - in between 0 (toEnum $ length levels') $ pos levels' - , testProperty "extract is total" $ \(levels :: Levels Int) genned -> - let levels' = runIdentity . nextLevel (Identity genned) $ levels - in total $ extract levels' - , testProperty "uses the generated level as the next level" - $ \(levels :: Levels Int) genned -> - let levels' = seek (toEnum $ length levels - 1) levels - levels'' = runIdentity . nextLevel (Identity genned) $ levels' - in counterexample (show levels'') - $ extract levels'' === genned - ] - , testGroup "prevLevel" - [ testProperty "seeks backwards" $ \(levels :: Levels Int) -> - case prevLevel levels of - Nothing -> property Discard - Just levels' -> pos levels' === pos levels - 1 - , testProperty "maintains the invariant" $ \(levels :: Levels Int) -> - case prevLevel levels of - Nothing -> property Discard - Just levels' -> property $ between 0 (toEnum $ length levels') $ pos levels' - , testProperty "extract is total" $ \(levels :: Levels Int) -> - case prevLevel levels of - Nothing -> property Discard - Just levels' -> total $ extract levels' - ] - ] - , testGroup "JSON" - [ testProperty "toJSON/parseJSON round-trip" $ \(levels :: Levels Int) -> - JSON.decode (JSON.encode levels) === Just levels - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Data/MemoSpec.hs b/users/aspen/xanthous/test/Xanthous/Data/MemoSpec.hs deleted file mode 100644 index ad81f1984..000000000 --- a/users/aspen/xanthous/test/Xanthous/Data/MemoSpec.hs +++ /dev/null @@ -1,19 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Data.MemoSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude -import Test.QuickCheck.Instances.Text () --------------------------------------------------------------------------------- -import Xanthous.Data.Memo --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Data.MemoSpec" - [ testGroup "getMemoized" - [ testProperty "when key matches" $ \k v -> - getMemoized @Int @Int k (memoizeWith k v) === Just v - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Data/NestedMapSpec.hs b/users/aspen/xanthous/test/Xanthous/Data/NestedMapSpec.hs deleted file mode 100644 index acf7a6726..000000000 --- a/users/aspen/xanthous/test/Xanthous/Data/NestedMapSpec.hs +++ /dev/null @@ -1,20 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Data.NestedMapSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Test.QuickCheck.Instances.Semigroup () --------------------------------------------------------------------------------- -import qualified Xanthous.Data.NestedMap as NM --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Data.NestedMap" - [ testProperty "insert/lookup" $ \nm ks v -> - let nm' = NM.insert ks v nm - in counterexample ("inserted: " <> show nm') - $ NM.lookup @Map @Int @Int ks nm' === Just (NM.Val v) - ] diff --git a/users/aspen/xanthous/test/Xanthous/DataSpec.hs b/users/aspen/xanthous/test/Xanthous/DataSpec.hs deleted file mode 100644 index 9e67505ba..000000000 --- a/users/aspen/xanthous/test/Xanthous/DataSpec.hs +++ /dev/null @@ -1,109 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.DataSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude hiding (Right, Left, Down, toList, all) -import Data.Group -import Data.Foldable (toList, all) --------------------------------------------------------------------------------- -import Xanthous.Data --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Data" - [ testGroup "Position" - [ testBatch $ monoid @Position mempty - , testProperty "group laws" $ \(pos :: Position) -> - pos <> invert pos == mempty && invert pos <> pos == mempty - , testGroup "stepTowards laws" - [ testProperty "takes only one step" $ \src tgt -> - src /= tgt ==> - isUnit (src `diffPositions` (src `stepTowards` tgt)) - -- , testProperty "moves in the right direction" $ \src tgt -> - -- stepTowards src tgt == move (directionOf src tgt) src - ] - , testProperty "directionOf laws" $ \pos dir -> - directionOf pos (move dir pos) == dir - , testProperty "diffPositions is add inverse" $ \(pos₁ :: Position) pos₂ -> - diffPositions pos₁ pos₂ == addPositions pos₁ (invert pos₂) - , testGroup "isUnit" - [ testProperty "double direction is never unit" $ \dir -> - not . isUnit $ move dir (asPosition dir) - , testCase "examples" $ do - isUnit (Position @Int 1 1) @? "not . isUnit $ Position 1 1" - isUnit (Position @Int 0 (-1)) @? "not . isUnit $ Position 0 (-1)" - (not . isUnit) (Position @Int 1 13) @? "isUnit $ Position 1 13" - ] - ] - - , testGroup "Direction" - [ testProperty "opposite is involutive" $ \(dir :: Direction) -> - opposite (opposite dir) == dir - , testProperty "opposite provides inverse" $ \dir -> - invert (asPosition dir) === asPosition (opposite dir) - , testProperty "asPosition isUnit" $ \dir -> - dir /= Here ==> isUnit (asPosition dir) - , testGroup "Move" - [ testCase "Up" $ move Up mempty @?= Position @Int 0 (-1) - , testCase "Down" $ move Down mempty @?= Position @Int 0 1 - , testCase "Left" $ move Left mempty @?= Position @Int (-1) 0 - , testCase "Right" $ move Right mempty @?= Position @Int 1 0 - , testCase "UpLeft" $ move UpLeft mempty @?= Position @Int (-1) (-1) - , testCase "UpRight" $ move UpRight mempty @?= Position @Int 1 (-1) - , testCase "DownLeft" $ move DownLeft mempty @?= Position @Int (-1) 1 - , testCase "DownRight" $ move DownRight mempty @?= Position @Int 1 1 - ] - ] - - , testGroup "Corner" - [ testGroup "instance Opposite" - [ testProperty "involutive" $ \(corner :: Corner) -> - opposite (opposite corner) === corner - ] - ] - - , testGroup "Edge" - [ testGroup "instance Opposite" - [ testProperty "involutive" $ \(edge :: Edge) -> - opposite (opposite edge) === edge - ] - ] - - , testGroup "Box" - [ testGroup "boxIntersects" - [ testProperty "True" $ \dims -> - boxIntersects (Box @Word (V2 1 1) (V2 2 2)) - (Box (V2 2 2) dims) - , testProperty "False" $ \dims -> - not $ boxIntersects (Box @Word (V2 1 1) (V2 2 2)) - (Box (V2 4 2) dims) - ] - ] - - , testGroup "Neighbors" - [ testGroup "rotations" - [ testProperty "always has the same members" - $ \(neighs :: Neighbors Int) -> - all (\ns -> sort (toList ns) == sort (toList neighs)) - $ rotations neighs - , testProperty "all rotations have the same rotations" - $ \(neighs :: Neighbors Int) -> - let rots = rotations neighs - in all (\ns -> sort (toList $ rotations ns) == sort (toList rots)) - rots - ] - ] - - , testGroup "units" - [ testGroup "unit suffixes" - [ testCase "density" - $ tshow (10000 :: Grams `Per` Cubic Meters) @?= "10000.0 g/m³" - , testCase "volume" - $ tshow (5 :: Cubic Meters) @?= "5.0 m³" - , testCase "area" - $ tshow (5 :: Square Meters) @?= "5.0 m²" - ] - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Entities/CharacterSpec.hs b/users/aspen/xanthous/test/Xanthous/Entities/CharacterSpec.hs deleted file mode 100644 index 734cce1ef..000000000 --- a/users/aspen/xanthous/test/Xanthous/Entities/CharacterSpec.hs +++ /dev/null @@ -1,24 +0,0 @@ -{-# OPTIONS_GHC -Wno-type-defaults #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.CharacterSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Xanthous.Entities.Character -import Xanthous.Util (endoTimes) --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Entities.CharacterSpec" - [ testGroup "Knuckles" - [ testBatch $ monoid @Knuckles mempty - , testGroup "damageKnuckles" - [ testCase "caps at 5" $ - let knuckles' = endoTimes 6 damageKnuckles mempty - in _knuckleDamage knuckles' @?= 5 - ] - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Entities/CommonSpec.hs b/users/aspen/xanthous/test/Xanthous/Entities/CommonSpec.hs deleted file mode 100644 index a6f8401cf..000000000 --- a/users/aspen/xanthous/test/Xanthous/Entities/CommonSpec.hs +++ /dev/null @@ -1,65 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Entities.CommonSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude -import Data.Vector.Lens (toVectorOf) --------------------------------------------------------------------------------- -import Xanthous.Entities.Common --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -newtype OneHand = OneHand Hand - deriving stock Show - -instance Arbitrary OneHand where - arbitrary = OneHand <$> elements [LeftHand, RightHand] - -otherHand :: Hand -> Hand -otherHand LeftHand = RightHand -otherHand RightHand = LeftHand -otherHand BothHands = error "OtherHand BothHands" - -test :: TestTree -test = testGroup "Xanthous.Entities.CommonSpec" - [ testGroup "Inventory" - [ testProperty "items === itemsWithPosition . _2" $ \inv -> - inv ^.. items === inv ^.. itemsWithPosition . _2 - , testGroup "removeItemFromPosition" $ - let rewield w inv = - let (old, inv') = inv & wielded <<.~ w - in inv' & backpack <>~ toVectorOf (wieldedItems . wieldedItem) old - in [ (Backpack, \item -> backpack %~ (item ^. wieldedItem <|)) - , (InHand LeftHand, rewield . inLeftHand) - , (InHand RightHand, rewield . inRightHand) - , (InHand BothHands, rewield . review doubleHanded) - ] <&> \(pos, addItem) -> - testProperty (show pos) $ \inv item -> - let inv' = addItem item inv - inv'' = removeItemFromPosition pos (item ^. wieldedItem) inv' - in inv'' ^.. items === inv ^.. items - ] - , testGroup "Wielded items" - [ testGroup "wieldInHand" - [ testProperty "puts the item in the hand" $ \w hand item -> - let (_, w') = wieldInHand hand item w - in itemsInHand hand w' === [item] - , testProperty "returns items in both hands when wielding double-handed" - $ \lh rh newItem -> - let w = Hands (Just lh) (Just rh) - (prevItems, _) = wieldInHand BothHands newItem w - in prevItems === [lh, rh] - , testProperty "wielding in one hand leaves the item in the other hand" - $ \(OneHand h) existingItem newItem -> - let (_, w) = wieldInHand h existingItem nothingWielded - (prevItems, w') = wieldInHand (otherHand h) newItem w - in prevItems === [] - .&&. sort (w' ^.. wieldedItems) === sort [existingItem, newItem] - , testProperty "always leaves the same items overall" $ \w hand item -> - let (prevItems, w') = wieldInHand hand item w - in sort (prevItems <> (w' ^.. wieldedItems)) - === sort (item : w ^.. wieldedItems) - ] - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Entities/RawTypesSpec.hs b/users/aspen/xanthous/test/Xanthous/Entities/RawTypesSpec.hs deleted file mode 100644 index e23f7faba..000000000 --- a/users/aspen/xanthous/test/Xanthous/Entities/RawTypesSpec.hs +++ /dev/null @@ -1,45 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Xanthous.Entities.RawTypesSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Data.Interval (Extended(..), (<=..<=)) --------------------------------------------------------------------------------- -import Xanthous.Entities.RawTypes --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Entities.RawTypesSpec" - [ testGroup "CreatureGenerateParams" - [ testGroup "Ord laws" - [ testProperty "comparability" $ \(a :: CreatureGenerateParams) b -> - a <= b || b <= a - , testProperty "transitivity" $ \(a :: CreatureGenerateParams) b c -> - a <= b && b <= c ==> a <= c - , testProperty "reflexivity" $ \(a :: CreatureGenerateParams) -> - a <= a - , testProperty "antisymmetry" $ \(a :: CreatureGenerateParams) b -> - (a <= b && b <= a) == (a == b) - ] - , testGroup "canGenerate" $ - let makeParams minB maxB = - let _levelRange = maybe NegInf Finite minB <=..<= maybe PosInf Finite maxB - _equippedItem = Nothing - in CreatureGenerateParams {..} - in - [ testProperty "no bounds" $ \level -> - let gps = makeParams Nothing Nothing - in canGenerate level gps - , testProperty "min bound" $ \level minB -> - let gps = makeParams (Just minB) Nothing - in canGenerate level gps === (level >= minB) - , testProperty "max bound" $ \level maxB -> - let gps = makeParams Nothing (Just maxB) - in canGenerate level gps === (level <= maxB) - ] - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Entities/RawsSpec.hs b/users/aspen/xanthous/test/Xanthous/Entities/RawsSpec.hs deleted file mode 100644 index b6c80be51..000000000 --- a/users/aspen/xanthous/test/Xanthous/Entities/RawsSpec.hs +++ /dev/null @@ -1,30 +0,0 @@ --- | - -module Xanthous.Entities.RawsSpec (main, test) where - -import Test.Prelude -import Xanthous.Entities.Raws -import Xanthous.Entities.RawTypes - (_Creature, entityName, generateParams, HasEquippedItem (equippedItem)) - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Entities.Raws" - [ testGroup "raws" - [ testCase "are all valid" $ raws `deepseq` pure () - , testCase "all CreatureEquippedItems reference existent entity names" $ - let notFound - = raws - ^.. folded - . _Creature - . generateParams - . _Just - . equippedItem - . _Just - . entityName - . filtered (isNothing . raw) - in null notFound @? ("Some entities weren't found: " <> show notFound) - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Game/PromptSpec.hs b/users/aspen/xanthous/test/Xanthous/Game/PromptSpec.hs deleted file mode 100644 index d7a3df4ac..000000000 --- a/users/aspen/xanthous/test/Xanthous/Game/PromptSpec.hs +++ /dev/null @@ -1,19 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Game.PromptSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Xanthous.Game.Prompt --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Game.PromptSpec" - [ testGroup "mkMenuItems" - [ testCase "with duplicate items" - $ mkMenuItems @[_] [('a', MenuOption @Int "a" 1), ('a', MenuOption "a" 2)] - @?= mapFromList [('a', MenuOption "a" 1), ('b', MenuOption "a" 2)] - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Game/StateSpec.hs b/users/aspen/xanthous/test/Xanthous/Game/StateSpec.hs deleted file mode 100644 index 34584f73b..000000000 --- a/users/aspen/xanthous/test/Xanthous/Game/StateSpec.hs +++ /dev/null @@ -1,30 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Game.StateSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Xanthous.Game.State -import Xanthous.Entities.Raws (raws) -import Xanthous.Generators.Level.LevelContents (entityFromRaw) -import Control.Monad.Random (evalRandT) -import System.Random (getStdGen) --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Game.StateSpec" - [ testGroup "entityTypeName" - [ testCase "for a creature" $ do - let gormlakRaw = raws ^?! ix "gormlak" - creature <- runRand $ entityFromRaw gormlakRaw - entityTypeName creature @?= "Creature" - , testCase "for an item" $ do - let stickRaw = raws ^?! ix "stick" - item <- runRand $ entityFromRaw stickRaw - entityTypeName item @?= "Item" - ] - ] - where - runRand x = evalRandT x =<< getStdGen diff --git a/users/aspen/xanthous/test/Xanthous/GameSpec.hs b/users/aspen/xanthous/test/Xanthous/GameSpec.hs deleted file mode 100644 index 2fa8527d0..000000000 --- a/users/aspen/xanthous/test/Xanthous/GameSpec.hs +++ /dev/null @@ -1,55 +0,0 @@ -module Xanthous.GameSpec where - -import Test.Prelude hiding (Down) -import Xanthous.Game -import Xanthous.Game.State -import Control.Lens.Properties -import Xanthous.Data (move, Direction(Down)) -import Xanthous.Data.EntityMap (atPosition) - -main :: IO () -main = defaultMain test - -test :: TestTree -test - = localOption (QuickCheckTests 10) - . localOption (QuickCheckMaxSize 10) - $ testGroup "Xanthous.Game" - [ testGroup "positionedCharacter" - [ testProperty "lens laws" $ isLens positionedCharacter - , testCase "updates the position of the character" $ do - initialGame <- getInitialState - let initialPos = initialGame ^. characterPosition - updatedGame = initialGame & characterPosition %~ move Down - updatedPos = updatedGame ^. characterPosition - updatedPos @?= move Down initialPos - updatedGame ^. entities . atPosition initialPos @?= fromList [] - updatedGame ^. entities . atPosition updatedPos - @?= fromList [SomeEntity $ initialGame ^. character] - ] - , testGroup "characterPosition" - [ testProperty "lens laws" $ isLens characterPosition - ] - , testGroup "character" - [ testProperty "lens laws" $ isLens character - ] - , testGroup "MessageHistory" - [ testGroup "MonoComonad laws" - [ testProperty "oextend oextract ≡ id" - $ \(mh :: MessageHistory) -> oextend oextract mh === mh - , testProperty "oextract ∘ oextend f ≡ f" - $ \(mh :: MessageHistory) f -> (oextract . oextend f) mh === f mh - , testProperty "oextend f ∘ oextend g ≡ oextend (f . oextend g)" - $ \(mh :: MessageHistory) f g -> - (oextend f . oextend g) mh === oextend (f . oextend g) mh - ] - ] - , testGroup "Saving the game" - [ testProperty "forms a prism" $ isPrism saved - , testProperty "round-trips" $ \gs -> - loadGame (saveGame gs) === Just gs - , testProperty "preserves the character ID" $ \gs -> - let Just gs' = loadGame $ saveGame gs - in gs' ^. character === gs ^. character - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Generators/Level/UtilSpec.hs b/users/aspen/xanthous/test/Xanthous/Generators/Level/UtilSpec.hs deleted file mode 100644 index b53c657f7..000000000 --- a/users/aspen/xanthous/test/Xanthous/Generators/Level/UtilSpec.hs +++ /dev/null @@ -1,127 +0,0 @@ -{-# LANGUAGE PackageImports #-} --------------------------------------------------------------------------------- -module Xanthous.Generators.Level.UtilSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude -import System.Random (mkStdGen) -import Control.Monad.Random (runRandT) -import Data.Array.ST (STUArray, runSTUArray, thaw) -import Data.Array.IArray (bounds, array) -import Data.Array.MArray (newArray, readArray, writeArray) -import Data.Array (Array, range, listArray, Ix) -import Control.Monad.ST (ST, runST) -import "checkers" Test.QuickCheck.Instances.Array () -import Linear.V2 --------------------------------------------------------------------------------- -import Xanthous.Util -import Xanthous.Data (width, height) --------------------------------------------------------------------------------- -import Xanthous.Generators.Level.Util --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - --------------------------------------------------------------------------------- - -newtype GenArray a b = GenArray (Array a b) - deriving stock (Show, Eq) - -instance (Ix a, Arbitrary a, CoArbitrary a, Arbitrary b) - => Arbitrary (GenArray a b) where - arbitrary = GenArray <$> do - (mkElem :: a -> b) <- arbitrary - minDims <- arbitrary - maxDims <- arbitrary - let bnds = (minDims, maxDims) - pure $ listArray bnds $ mkElem <$> range bnds - -test :: TestTree -test = testGroup "Xanthous.Generators.Util" - [ testGroup "randInitialize" - [ testProperty "returns an array of the correct dimensions" - $ \dims seed aliveChance -> - let gen = mkStdGen seed - res = runSTUArray - $ fmap fst - $ flip runRandT gen - $ randInitialize dims aliveChance - in bounds res === (0, V2 (dims ^. width) (dims ^. height)) - ] - , testGroup "numAliveNeighborsM" - [ testProperty "maxes out at 8" - $ \(GenArray (arr :: Array (V2 Word) Bool)) loc -> - let - act :: forall s. ST s Word - act = do - mArr <- thaw @_ @_ @_ @(STUArray s) arr - numAliveNeighborsM mArr loc - res = runST act - in counterexample (show res) $ between 0 8 res - , testCase "on the outer x edge" $ - let act :: forall s. ST s Word - act = do - cells <- thaw @_ @_ @_ @(STUArray s) $ array @Array @Bool @(V2 Word) - (V2 0 0, V2 2 2) - [ (V2 0 0, True), (V2 1 0, True), (V2 2 0, True) - , (V2 0 1, False), (V2 1 1, False), (V2 2 1, True) - , (V2 0 2, True), (V2 1 2, True), (V2 2 2, True) - ] - numAliveNeighborsM cells (V2 0 1) - res = runST act - in res @?= 7 - , testCase "on the outer y edge" $ - let act :: forall s. ST s Word - act = do - cells <- thaw @_ @_ @_ @(STUArray s) $ array @Array @Bool @(V2 Word) - (V2 0 0, V2 2 2) - [ (V2 0 0, True), (V2 1 0, True), (V2 2 0, True) - , (V2 0 1, False), (V2 1 1, False), (V2 2 1, True) - , (V2 0 2, True), (V2 1 2, True), (V2 2 2, True) - ] - numAliveNeighborsM cells (V2 1 0) - res = runST act - in res @?= 6 - ] - , testGroup "numAliveNeighbors" - [ testProperty "is equivalient to runST . numAliveNeighborsM . thaw" $ - \(GenArray (arr :: Array (V2 Word) Bool)) loc -> - let - act :: forall s. ST s Word - act = do - mArr <- thaw @_ @_ @_ @(STUArray s) arr - numAliveNeighborsM mArr loc - res = runST act - in numAliveNeighbors arr loc === res - , testCase "on the outer x edge" $ - let cells = - array @Array @Bool @(V2 Word) - (V2 0 0, V2 2 2) - [ (V2 0 0, True), (V2 1 0, True), (V2 2 0, True) - , (V2 0 1, False), (V2 1 1, False), (V2 2 1, True) - , (V2 0 2, True), (V2 1 2, True), (V2 2 2, True) - ] - in numAliveNeighbors cells (V2 0 1) @?= 7 - , testCase "on the outer y edge" $ - let cells = - array @Array @Bool @(V2 Word) - (V2 0 0, V2 2 2) - [ (V2 0 0, True), (V2 1 0, True), (V2 2 0, True) - , (V2 0 1, False), (V2 1 1, False), (V2 2 1, True) - , (V2 0 2, True), (V2 1 2, True), (V2 2 2, True) - ] - in numAliveNeighbors cells (V2 1 0) @?= 6 - ] - , testGroup "cloneMArray" - [ testCase "clones the array" $ runST $ - let - go :: forall s. ST s Assertion - go = do - arr <- newArray @(STUArray s) (0 :: Int, 5) (1 :: Int) - arr' <- cloneMArray @_ @(STUArray s) arr - writeArray arr' 0 1234 - x <- readArray arr 0 - pure $ x @?= 1 - in go - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/MessageSpec.hs b/users/aspen/xanthous/test/Xanthous/MessageSpec.hs deleted file mode 100644 index 2068e338b..000000000 --- a/users/aspen/xanthous/test/Xanthous/MessageSpec.hs +++ /dev/null @@ -1,59 +0,0 @@ -{-# LANGUAGE OverloadedLists #-} -module Xanthous.MessageSpec ( main, test ) where - -import Test.Prelude -import Xanthous.Messages -import Data.Aeson -import Text.Mustache -import Control.Lens.Properties - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Messages" - [ testGroup "Message" - [ testGroup "JSON decoding" - [ testCase "Single" - $ decode "\"Test Single Template\"" - @?= Just (Single - $ compileMustacheText "template" "Test Single Template" - ^?! _Right) - , testCase "Choice" - $ decode "[\"Choice 1\", \"Choice 2\"]" - @?= Just - (Choice - [ compileMustacheText "template" "Choice 1" ^?! _Right - , compileMustacheText "template" "Choice 2" ^?! _Right - ]) - ] - ] - , localOption (QuickCheckTests 50) - . localOption (QuickCheckMaxSize 10) - $ testGroup "MessageMap" - [ testGroup "instance Ixed" - [ testProperty "traversal laws" $ \k -> - isTraversal $ ix @MessageMap k - , testCase "preview when exists" $ - let - Right tpl = compileMustacheText "foo" "bar" - msg = Single tpl - mm = Nested [("foo", Direct msg)] - in mm ^? ix ["foo"] @?= Just msg - ] - , testGroup "lookupMessage" - [ testProperty "is equivalent to preview ix" $ \msgMap path -> - lookupMessage path msgMap === msgMap ^? ix path - ] - ] - - , testGroup "Messages" - [ testCase "are all valid" $ messages `deepseq` pure () - ] - - , testGroup "Template" - [ testGroup "eq" - [ testProperty "reflexive" $ \(tpl :: Template) -> tpl == tpl - ] - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Messages/TemplateSpec.hs b/users/aspen/xanthous/test/Xanthous/Messages/TemplateSpec.hs deleted file mode 100644 index 2a3873c3b..000000000 --- a/users/aspen/xanthous/test/Xanthous/Messages/TemplateSpec.hs +++ /dev/null @@ -1,80 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.Messages.TemplateSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude -import Test.QuickCheck.Instances.Text () -import Data.List.NonEmpty (NonEmpty(..)) -import Data.Function (fix) --------------------------------------------------------------------------------- -import Xanthous.Messages.Template --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Messages.Template" - [ testGroup "parsing" - [ testProperty "literals" $ forAll genLiteral $ \s -> - testParse template s === Right (Literal s) - , parseCase "escaped curlies" - "foo\\{" - $ Literal "foo{" - , parseCase "simple substitution" - "foo {{bar}}" - $ Literal "foo " `Concat` Subst (SubstPath $ "bar" :| []) - , parseCase "substitution with filters" - "foo {{bar | baz}}" - $ Literal "foo " - `Concat` Subst (SubstFilter (SubstPath $ "bar" :| []) - (FilterName "baz")) - , parseCase "substitution with multiple filters" - "foo {{bar | baz | qux}}" - $ Literal "foo " - `Concat` Subst (SubstFilter (SubstFilter (SubstPath $ "bar" :| []) - (FilterName "baz")) - (FilterName "qux")) - , parseCase "two substitutions and a literal" - "{{a}}{{b}}c" - $ Subst (SubstPath $ "a" :| []) - `Concat` Subst (SubstPath $ "b" :| []) - `Concat` Literal "c" - , localOption (QuickCheckTests 10) - $ testProperty "round-trips with ppTemplate" $ \tpl -> - testParse template (ppTemplate tpl) === Right tpl - ] - , testBatch $ monoid @Template mempty - , testGroup "rendering" - [ testProperty "rendering literals renders literally" - $ forAll genLiteral $ \s fs vs -> - render fs vs (Literal s) === Right s - , testProperty "rendering substitutions renders substitutions" - $ forAll genPath $ \ident val fs -> - let tpl = Subst (SubstPath ident) - tvs = varsWith ident val - in render fs tvs tpl === Right val - , testProperty "filters filter" $ forAll genPath - $ \ident filterName filterFn val -> - let tpl = Subst (SubstFilter (SubstPath ident) filterName) - fs = mapFromList [(filterName, filterFn)] - vs = varsWith ident val - in render fs vs tpl === Right (filterFn val) - ] - ] - where - genLiteral = pack . filter (`notElem` ['\\', '{']) <$> arbitrary - parseCase name input expected = - testCase name $ testParse template input @?= Right expected - testParse p = over _Left errorBundlePretty . runParser p "" - genIdentifier = pack @Text <$> listOf1 (elements identifierChars) - identifierChars = ['a'..'z'] <> ['A'..'Z'] <> ['-', '_'] - - varsWith (p :| []) val = vars [(p, Val val)] - varsWith (phead :| ps) val = vars . pure . (phead ,) . flip fix ps $ - \next pth -> case pth of - [] -> Val val - p : ps' -> nested [(p, next ps')] - - genPath = (:|) <$> genIdentifier <*> listOf genIdentifier - --- diff --git a/users/aspen/xanthous/test/Xanthous/OrphansSpec.hs b/users/aspen/xanthous/test/Xanthous/OrphansSpec.hs deleted file mode 100644 index 0d800e8a9..000000000 --- a/users/aspen/xanthous/test/Xanthous/OrphansSpec.hs +++ /dev/null @@ -1,72 +0,0 @@ -{-# LANGUAGE BlockArguments #-} -{-# LANGUAGE OverloadedLists #-} --------------------------------------------------------------------------------- -module Xanthous.OrphansSpec where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Text.Mustache -import Text.Megaparsec (errorBundlePretty) -import Graphics.Vty.Attributes -import qualified Data.Aeson as JSON -import Data.Interval (Interval, (<=..<=), (<=..<), (<..<=)) -import Data.Aeson ( ToJSON(toJSON), object, Value(Array) ) -import Data.Aeson.Types (fromJSON) -import Data.IntegerInterval (Extended(Finite)) --------------------------------------------------------------------------------- -import Xanthous.Orphans --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Orphans" - [ localOption (QuickCheckTests 50) - . localOption (QuickCheckMaxSize 10) - $ testGroup "Template" - [ testProperty "ppTemplate / compileMustacheText " \tpl -> - let src = ppTemplate tpl - res :: Either String Template - res = over _Left errorBundlePretty - $ compileMustacheText (templateActual tpl) src - expected = templateCache tpl ^?! at (templateActual tpl) - in - counterexample (unpack src) - $ Right expected === do - (Template actual cache) <- res - maybe (Left "Template not found") Right $ cache ^? at actual - , testProperty "JSON round trip" $ \(tpl :: Template) -> - counterexample (unpack $ ppTemplate tpl) - $ JSON.decode (JSON.encode tpl) === Just tpl - ] - , testGroup "Attr" - [ jsonRoundTrip @Attr ] - , testGroup "Extended" - [ jsonRoundTrip @(Extended Int) ] - , testGroup "Interval" - [ testGroup "JSON" - [ jsonRoundTrip @(Interval Int) - , testCase "parses a single value as a length-1 interval" $ - getSuccess (fromJSON $ toJSON (1 :: Int)) - @?= Just (Finite (1 :: Int) <=..<= Finite 1) - , testCase "parses a pair of values as a single-ended interval" $ - getSuccess (fromJSON $ toJSON ([1, 2] :: [Int])) - @?= Just (Finite (1 :: Int) <=..< Finite (2 :: Int)) - , testCase "parses the full included/excluded syntax" $ - getSuccess (fromJSON $ Array [ object [ "Excluded" JSON..= (1 :: Int) ] - , object [ "Included" JSON..= (4 :: Int) ] - ]) - @?= Just (Finite (1 :: Int) <..<= Finite (4 :: Int)) - , testCase "parses open/closed as aliases" $ - getSuccess (fromJSON $ Array [ object [ "Open" JSON..= (1 :: Int) ] - , object [ "Closed" JSON..= (4 :: Int) ] - ]) - @?= Just (Finite (1 :: Int) <..<= Finite (4 :: Int)) - ] - ] - ] - where - getSuccess :: JSON.Result a -> Maybe a - getSuccess (JSON.Error _) = Nothing - getSuccess (JSON.Success r) = Just r diff --git a/users/aspen/xanthous/test/Xanthous/RandomSpec.hs b/users/aspen/xanthous/test/Xanthous/RandomSpec.hs deleted file mode 100644 index c88bd9562..000000000 --- a/users/aspen/xanthous/test/Xanthous/RandomSpec.hs +++ /dev/null @@ -1,45 +0,0 @@ --------------------------------------------------------------------------------- -module Xanthous.RandomSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Control.Monad.Random --------------------------------------------------------------------------------- -import Xanthous.Random -import Xanthous.Orphans () -import qualified Data.Interval as Interval -import Data.Interval (Interval, Extended (Finite), (<=..<=)) --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Random" - [ testGroup "chooseSubset" - [ testProperty "chooses a subset" - $ \(l :: [Int]) (Positive (r :: Double)) -> randomTest $ do - ss <- chooseSubset r l - pure $ all (`elem` l) ss - ] - , testGroup "chooseRange" - [ testProperty "chooses in the range" - $ \(rng :: Interval Int) -> - not (Interval.null rng) - ==> randomTest ( do - chooseRange rng >>= \case - Just r -> pure - . counterexample (show r) - $ r `Interval.member` rng - Nothing -> pure $ property Discard - ) - , testProperty "nonEmpty range is never empty" - $ \ (lower :: Int) (NonZero diff) -> randomTest $ do - let upper = lower + diff - r <- chooseRange (Finite lower <=..<= Finite upper) - pure $ isJust r - - ] - ] - where - randomTest prop = evalRandT prop . mkStdGen =<< arbitrary diff --git a/users/aspen/xanthous/test/Xanthous/Util/GraphSpec.hs b/users/aspen/xanthous/test/Xanthous/Util/GraphSpec.hs deleted file mode 100644 index 35ff090b2..000000000 --- a/users/aspen/xanthous/test/Xanthous/Util/GraphSpec.hs +++ /dev/null @@ -1,39 +0,0 @@ -module Xanthous.Util.GraphSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude --------------------------------------------------------------------------------- -import Xanthous.Util.Graph -import Data.Graph.Inductive.Basic -import Data.Graph.Inductive.Graph (labNodes, size, order) -import Data.Graph.Inductive.PatriciaTree -import Data.Graph.Inductive.Arbitrary --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Util.Graph" - [ testGroup "mstSubGraph" - [ testProperty "always produces a subgraph" - $ \(CG _ (graph :: Gr Int Int)) -> - let msg = mstSubGraph $ undir graph - in counterexample (show msg) - $ msg `isSubGraphOf` undir graph - , testProperty "returns a graph with the same nodes" - $ \(CG _ (graph :: Gr Int Int)) -> - let msg = mstSubGraph graph - in counterexample (show msg) - $ labNodes msg === labNodes graph - , testProperty "has nodes - 1 edges" - $ \(CG _ (graph :: Gr Int Int)) -> - order graph > 1 ==> - let msg = mstSubGraph graph - in counterexample (show msg) - $ size msg === order graph - 1 - , testProperty "always produces a simple graph" - $ \(CG _ (graph :: Gr Int Int)) -> - let msg = mstSubGraph graph - in counterexample (show msg) $ isSimple msg - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/Util/GraphicsSpec.hs b/users/aspen/xanthous/test/Xanthous/Util/GraphicsSpec.hs deleted file mode 100644 index 61e589280..000000000 --- a/users/aspen/xanthous/test/Xanthous/Util/GraphicsSpec.hs +++ /dev/null @@ -1,72 +0,0 @@ -module Xanthous.Util.GraphicsSpec (main, test) where --------------------------------------------------------------------------------- -import Test.Prelude hiding (head) --------------------------------------------------------------------------------- -import Data.List (nub, head) -import Data.Set (isSubsetOf) -import Linear.V2 --------------------------------------------------------------------------------- -import Xanthous.Util.Graphics -import Xanthous.Util -import Xanthous.Orphans () --------------------------------------------------------------------------------- - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Util.Graphics" - [ testGroup "circle" - [ testCase "radius 1, origin 2,2" - {- - | | 0 | 1 | 2 | 3 | - |---+---+---+---+---| - | 0 | | | | | - | 1 | | | x | | - | 2 | | x | | x | - | 3 | | | x | | - -} - $ (sort . unique @[] @[_]) (circle @Int (V2 2 2) 1) - @?= [ V2 1 2 - , V2 2 1, V2 2 3 - , V2 3 2 - ] - , testCase "radius 12, origin 0" - $ (sort . nub) (circle @Int 0 12) - @?= (sort . nub) - [ V2 (-12) (-4), V2 (-12) (-3), V2 (-12) (-2), V2 (-12) (-1) - , V2 (-12) 0, V2 (-12) 1, V2 (-12) 2, V2 (-12) 3, V2 (-12) 4 - , V2 (-11) (-6), V2 (-11) (-5), V2 (-11) 5, V2 (-11) 6, V2 (-10) (-7) - , V2 (-10) 7, V2 (-9) (-9), V2 (-9) (-8), V2 (-9) 8, V2 (-9) 9 - , V2 (-8) (-9), V2 (-8) 9, V2 (-7) (-10), V2 (-7) 10, V2 (-6) (-11) - , V2 (-6) 11, V2 (-5) (-11), V2 (-5) 11, V2 (-4) (-12), V2 (-4) 12 - , V2 (-3) (-12), V2 (-3) 12, V2 (-2) (-12), V2 (-2) 12, V2 (-1) (-12) - , V2 (-1) 12, V2 0 (-12), V2 0 12, V2 1 (-12), V2 1 12, V2 2 (-12) - , V2 2 12, V2 3 (-12), V2 3 12, V2 4 (-12), V2 4 12, V2 5 (-11) - , V2 5 11, V2 6 (-11), V2 6 11, V2 7 (-10), V2 7 10, V2 8 (-9), V2 8 9 - , V2 9 (-9), V2 9 (-8), V2 9 8, V2 9 9, V2 10 (-7), V2 10 7 - , V2 11 (-6), V2 11 (-5), V2 11 5, V2 11 6, V2 12 (-4), V2 12 (-3) - , V2 12 (-2), V2 12 (-1), V2 12 0, V2 12 1, V2 12 2, V2 12 3, V2 12 4 - ] - ] - , testGroup "filledCircle" - [ testProperty "is a superset of circle" $ \center radius -> - let circ = circle @Int center radius - filledCirc = filledCircle center radius - in counterexample ( "circle: " <> show circ - <> "\nfilledCircle: " <> show filledCirc) - $ setFromList circ `isSubsetOf` setFromList filledCirc - -- TODO later - -- , testProperty "is always contiguous" $ \center radius -> - -- let filledCirc = filledCircle center radius - -- in counterexample (renderBooleanGraphics filledCirc) $ - ] - , testGroup "line" - [ testProperty "starts and ends at the start and end points" $ \start end -> - let ℓ = line @Int start end - in counterexample ("line: " <> show ℓ) - $ length ℓ > 2 ==> (head ℓ === start) .&&. (head (reverse ℓ) === end) - ] - ] - --------------------------------------------------------------------------------- diff --git a/users/aspen/xanthous/test/Xanthous/Util/InflectionSpec.hs b/users/aspen/xanthous/test/Xanthous/Util/InflectionSpec.hs deleted file mode 100644 index fad841043..000000000 --- a/users/aspen/xanthous/test/Xanthous/Util/InflectionSpec.hs +++ /dev/null @@ -1,18 +0,0 @@ -module Xanthous.Util.InflectionSpec (main, test) where - -import Test.Prelude -import Xanthous.Util.Inflection - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Util.Inflection" - [ testGroup "toSentence" - [ testCase "empty" $ toSentence [] @?= "" - , testCase "single" $ toSentence ["x"] @?= "x" - , testCase "two" $ toSentence ["x", "y"] @?= "x and y" - , testCase "three" $ toSentence ["x", "y", "z"] @?= "x, y, and z" - , testCase "four" $ toSentence ["x", "y", "z", "w"] @?= "x, y, z, and w" - ] - ] diff --git a/users/aspen/xanthous/test/Xanthous/UtilSpec.hs b/users/aspen/xanthous/test/Xanthous/UtilSpec.hs deleted file mode 100644 index 684a03b2c..000000000 --- a/users/aspen/xanthous/test/Xanthous/UtilSpec.hs +++ /dev/null @@ -1,46 +0,0 @@ -module Xanthous.UtilSpec (main, test) where - -import Test.Prelude -import Xanthous.Util -import Control.Monad.State.Lazy (execState) - -main :: IO () -main = defaultMain test - -test :: TestTree -test = testGroup "Xanthous.Util" - [ testGroup "smallestNotIn" - [ testCase "examples" $ do - smallestNotIn [7 :: Word, 3, 7] @?= 0 - smallestNotIn [7 :: Word, 0, 1, 3, 7] @?= 2 - , testProperty "returns an element not in the list" $ \(xs :: [Word]) -> - smallestNotIn xs `notElem` xs - , testProperty "pred return is in the list" $ \(xs :: [Word]) -> - let res = smallestNotIn xs - in res /= 0 ==> pred res `elem` xs - , testProperty "ignores order" $ \(xs :: [Word]) -> - forAll (shuffle xs) $ \shuffledXs -> - smallestNotIn xs === smallestNotIn shuffledXs - ] - , testGroup "takeWhileInclusive" - [ testProperty "takeWhileInclusive (const True) ≡ id" - $ \(xs :: [Int]) -> takeWhileInclusive (const True) xs === xs - ] - , testGroup "endoTimes" - [ testCase "endoTimes 4 succ 5" - $ endoTimes (4 :: Int) succ (5 :: Int) @?= 9 - ] - , testGroup "modifyKL" - [ testCase "_1 += 1" - $ execState (modifyKL _1 $ pure . succ) (1 :: Int, 2 :: Int) @?= (2, 2) - ] - , testGroup "removeFirst" - [ testCase "example" $ - removeFirst @[Int] (> 5) [1..10] @?= [1, 2, 3, 4, 5, 7, 8, 9, 10] - , testProperty "the result is the right length" $ \(xs :: [Int]) p -> - length (removeFirst p xs) `elem` [length xs, length xs - 1] - ] - , testGroup "AlphaChar" - [ testCase "succ 'z'" $ succ (AlphaChar 'z') @?= AlphaChar 'A' - ] - ] diff --git a/users/aspen/xanthous/xanthous.cabal b/users/aspen/xanthous/xanthous.cabal deleted file mode 100644 index 12222c267..000000000 --- a/users/aspen/xanthous/xanthous.cabal +++ /dev/null @@ -1,529 +0,0 @@ -cabal-version: 1.12 - --- This file has been generated from package.yaml by hpack version 0.35.0. --- --- see: https://github.com/sol/hpack --- --- hash: b3bf8e65d621856081832c9d3c8e8ad38799e23a7f5084dc4f972daa654a0ff3 - -name: xanthous -version: 0.1.0.0 -synopsis: A WIP TUI RPG -description: Please see the README on GitHub at -category: Game -homepage: https://github.com/glittershark/xanthous#readme -bug-reports: https://github.com/glittershark/xanthous/issues -author: Griffin Smith -maintainer: root@gws.fyi -copyright: 2019 Griffin Smith -license: GPL-3 -license-file: LICENSE -build-type: Simple -extra-source-files: - README.org - -source-repository head - type: git - location: https://github.com/glittershark/xanthous - -library - exposed-modules: - Data.Aeson.Generic.DerivingVia - Xanthous.AI.Gormlak - Xanthous.App - Xanthous.App.Autocommands - Xanthous.App.Common - Xanthous.App.Prompt - Xanthous.App.Time - Xanthous.Command - Xanthous.Data - Xanthous.Data.App - Xanthous.Data.Entities - Xanthous.Data.EntityChar - Xanthous.Data.EntityMap - Xanthous.Data.EntityMap.Graphics - Xanthous.Data.Levels - Xanthous.Data.Memo - Xanthous.Data.NestedMap - Xanthous.Data.VectorBag - Xanthous.Entities.Character - Xanthous.Entities.Common - Xanthous.Entities.Creature - Xanthous.Entities.Creature.Hippocampus - Xanthous.Entities.Draw.Util - Xanthous.Entities.Entities - Xanthous.Entities.Environment - Xanthous.Entities.Item - Xanthous.Entities.Marker - Xanthous.Entities.Raws - Xanthous.Entities.RawTypes - Xanthous.Game - Xanthous.Game.Arbitrary - Xanthous.Game.Draw - Xanthous.Game.Env - Xanthous.Game.Lenses - Xanthous.Game.Memo - Xanthous.Game.Prompt - Xanthous.Game.State - Xanthous.Generators.Level - Xanthous.Generators.Level.CaveAutomata - Xanthous.Generators.Level.Dungeon - Xanthous.Generators.Level.LevelContents - Xanthous.Generators.Level.Util - Xanthous.Generators.Level.Village - Xanthous.Generators.Speech - Xanthous.Messages - Xanthous.Messages.Template - Xanthous.Monad - Xanthous.Orphans - Xanthous.Physics - Xanthous.Prelude - Xanthous.Random - Xanthous.Util - Xanthous.Util.Comonad - Xanthous.Util.Graph - Xanthous.Util.Graphics - Xanthous.Util.Inflection - Xanthous.Util.JSON - Xanthous.Util.Optparse - Xanthous.Util.QuickCheck - other-modules: - Paths_xanthous - hs-source-dirs: - src - default-extensions: - BlockArguments - ConstraintKinds - DataKinds - DeriveAnyClass - DeriveGeneric - DerivingStrategies - DerivingVia - FlexibleContexts - FlexibleInstances - FunctionalDependencies - GADTSyntax - GeneralizedNewtypeDeriving - KindSignatures - StandaloneKindSignatures - LambdaCase - MultiWayIf - NoImplicitPrelude - NoStarIsType - OverloadedStrings - PolyKinds - RankNTypes - ScopedTypeVariables - TupleSections - TypeApplications - TypeFamilies - TypeOperators - ViewPatterns - ghc-options: -Wall -fconstraint-solver-iterations=6 - build-depends: - JuicyPixels - , MonadRandom - , QuickCheck - , Rasterific - , aeson - , array - , async - , base - , bifunctors - , brick - , checkers - , classy-prelude - , comonad - , comonad-extras - , constraints - , containers - , criterion - , data-default - , data-interval - , deepseq - , directory - , fgl - , fgl-arbitrary - , file-embed - , filepath - , generic-arbitrary - , generic-lens - , groups - , hgeometry - , hgeometry-combinatorial - , lens - , lifted-async - , linear - , megaparsec - , mmorph - , monad-control - , mtl - , optparse-applicative - , parallel - , parser-combinators - , pointed - , quickcheck-instances - , quickcheck-text - , random - , random-extras - , random-fu - , random-source - , raw-strings-qq - , reflection - , semigroupoids - , semigroups - , splitmix - , stache - , streams - , text - , text-zipper - , tomland - , transformers - , vector - , vty - , witherable - , yaml - , zlib - default-language: Haskell2010 - -executable xanthous - main-is: Main.hs - other-modules: - Paths_xanthous - hs-source-dirs: - app - default-extensions: - BlockArguments - ConstraintKinds - DataKinds - DeriveAnyClass - DeriveGeneric - DerivingStrategies - DerivingVia - FlexibleContexts - FlexibleInstances - FunctionalDependencies - GADTSyntax - GeneralizedNewtypeDeriving - KindSignatures - StandaloneKindSignatures - LambdaCase - MultiWayIf - NoImplicitPrelude - NoStarIsType - OverloadedStrings - PolyKinds - RankNTypes - ScopedTypeVariables - TupleSections - TypeApplications - TypeFamilies - TypeOperators - ViewPatterns - ghc-options: -Wall -fconstraint-solver-iterations=6 -threaded -rtsopts -with-rtsopts=-N -O2 - build-depends: - JuicyPixels - , MonadRandom - , QuickCheck - , Rasterific - , aeson - , array - , async - , base - , bifunctors - , brick - , checkers - , classy-prelude - , comonad - , comonad-extras - , constraints - , containers - , criterion - , data-default - , data-interval - , deepseq - , directory - , fgl - , fgl-arbitrary - , file-embed - , filepath - , generic-arbitrary - , generic-lens - , groups - , hgeometry - , hgeometry-combinatorial - , lens - , lifted-async - , linear - , megaparsec - , mmorph - , monad-control - , mtl - , optparse-applicative - , parallel - , parser-combinators - , pointed - , quickcheck-instances - , quickcheck-text - , random - , random-extras - , random-fu - , random-source - , raw-strings-qq - , reflection - , semigroupoids - , semigroups - , splitmix - , stache - , streams - , text - , text-zipper - , tomland - , transformers - , vector - , vty - , witherable - , xanthous - , yaml - , zlib - default-language: Haskell2010 - -test-suite test - type: exitcode-stdio-1.0 - main-is: Spec.hs - other-modules: - Test.Prelude - Xanthous.CommandSpec - Xanthous.Data.EntitiesSpec - Xanthous.Data.EntityCharSpec - Xanthous.Data.EntityMap.GraphicsSpec - Xanthous.Data.EntityMapSpec - Xanthous.Data.LevelsSpec - Xanthous.Data.MemoSpec - Xanthous.Data.NestedMapSpec - Xanthous.DataSpec - Xanthous.Entities.CharacterSpec - Xanthous.Entities.CommonSpec - Xanthous.Entities.RawsSpec - Xanthous.Entities.RawTypesSpec - Xanthous.Game.PromptSpec - Xanthous.Game.StateSpec - Xanthous.GameSpec - Xanthous.Generators.Level.UtilSpec - Xanthous.Messages.TemplateSpec - Xanthous.MessageSpec - Xanthous.OrphansSpec - Xanthous.RandomSpec - Xanthous.Util.GraphicsSpec - Xanthous.Util.GraphSpec - Xanthous.Util.InflectionSpec - Xanthous.UtilSpec - Paths_xanthous - hs-source-dirs: - test - default-extensions: - BlockArguments - ConstraintKinds - DataKinds - DeriveAnyClass - DeriveGeneric - DerivingStrategies - DerivingVia - FlexibleContexts - FlexibleInstances - FunctionalDependencies - GADTSyntax - GeneralizedNewtypeDeriving - KindSignatures - StandaloneKindSignatures - LambdaCase - MultiWayIf - NoImplicitPrelude - NoStarIsType - OverloadedStrings - PolyKinds - RankNTypes - ScopedTypeVariables - TupleSections - TypeApplications - TypeFamilies - TypeOperators - ViewPatterns - ghc-options: -Wall -fconstraint-solver-iterations=6 -threaded -rtsopts -with-rtsopts=-N -O0 - build-depends: - JuicyPixels - , MonadRandom - , QuickCheck - , Rasterific - , aeson - , array - , async - , base - , bifunctors - , brick - , checkers - , classy-prelude - , comonad - , comonad-extras - , constraints - , containers - , criterion - , data-default - , data-interval - , deepseq - , directory - , fgl - , fgl-arbitrary - , file-embed - , filepath - , generic-arbitrary - , generic-lens - , groups - , hgeometry - , hgeometry-combinatorial - , lens - , lens-properties - , lifted-async - , linear - , megaparsec - , mmorph - , monad-control - , mtl - , optparse-applicative - , parallel - , parser-combinators - , pointed - , quickcheck-instances - , quickcheck-text - , random - , random-extras - , random-fu - , random-source - , raw-strings-qq - , reflection - , semigroupoids - , semigroups - , splitmix - , stache - , streams - , tasty - , tasty-hunit - , tasty-quickcheck - , tasty-rerun - , text - , text-zipper - , tomland - , transformers - , vector - , vty - , witherable - , xanthous - , yaml - , zlib - default-language: Haskell2010 - -benchmark benchmark - type: exitcode-stdio-1.0 - main-is: Bench.hs - other-modules: - Bench.Prelude - Xanthous.Generators.UtilBench - Xanthous.RandomBench - Paths_xanthous - hs-source-dirs: - bench - default-extensions: - BlockArguments - ConstraintKinds - DataKinds - DeriveAnyClass - DeriveGeneric - DerivingStrategies - DerivingVia - FlexibleContexts - FlexibleInstances - FunctionalDependencies - GADTSyntax - GeneralizedNewtypeDeriving - KindSignatures - StandaloneKindSignatures - LambdaCase - MultiWayIf - NoImplicitPrelude - NoStarIsType - OverloadedStrings - PolyKinds - RankNTypes - ScopedTypeVariables - TupleSections - TypeApplications - TypeFamilies - TypeOperators - ViewPatterns - ghc-options: -Wall -fconstraint-solver-iterations=6 -threaded -rtsopts -with-rtsopts=-N - build-depends: - JuicyPixels - , MonadRandom - , QuickCheck - , Rasterific - , aeson - , array - , async - , base - , bifunctors - , brick - , checkers - , classy-prelude - , comonad - , comonad-extras - , constraints - , containers - , criterion - , data-default - , data-interval - , deepseq - , directory - , fgl - , fgl-arbitrary - , file-embed - , filepath - , generic-arbitrary - , generic-lens - , groups - , hgeometry - , hgeometry-combinatorial - , lens - , lifted-async - , linear - , megaparsec - , mmorph - , monad-control - , mtl - , optparse-applicative - , parallel - , parser-combinators - , pointed - , quickcheck-instances - , quickcheck-text - , random - , random-extras - , random-fu - , random-source - , raw-strings-qq - , reflection - , semigroupoids - , semigroups - , splitmix - , stache - , streams - , text - , text-zipper - , tomland - , transformers - , vector - , vty - , witherable - , xanthous - , yaml - , zlib - default-language: Haskell2010 diff --git a/users/azahi/OWNERS b/users/azahi/OWNERS deleted file mode 100644 index 73bc1ebcc..000000000 --- a/users/azahi/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -azahi diff --git a/users/azahi/pkgs/bruh/default.nix b/users/azahi/pkgs/bruh/default.nix deleted file mode 100644 index 5eecf94b6..000000000 --- a/users/azahi/pkgs/bruh/default.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ pkgs -, lib -, ... -}: - -let - inherit (pkgs) - alsa-utils - fetchFromGitHub - stdenv - ; -in - -stdenv.mkDerivation (finalAttrs: { - pname = "bruh"; - version = "2.1"; - - src = - with finalAttrs; - fetchFromGitHub { - owner = "kejpies"; - repo = pname; - rev = version; - hash = "sha256-Uw6Qes0IZkkfBchFnvnX9l1ZG5T5pyExmV7yUJLPOJ0="; - }; - - postPatch = '' - substituteInPlace bruh.c \ - --replace-fail "aplay" "${alsa-utils}/bin/aplay" - ''; - - makeFlags = [ "PREFIX=$(out)" ]; - - meta = with lib; { - description = "Bruh sound, but as a program"; - inherit (finalAttrs.src.meta) homepage; - license = licenses.gpl3Only; - platforms = platforms.linux; - maintainers = with maintainers; [ azahi ]; - mainProgram = "bruh"; - }; -}) diff --git a/users/cynthia/OWNERS b/users/cynthia/OWNERS deleted file mode 100644 index 762a4ec9e..000000000 --- a/users/cynthia/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -cynthia diff --git a/users/cynthia/keys.nix b/users/cynthia/keys.nix deleted file mode 100644 index e2f4ce488..000000000 --- a/users/cynthia/keys.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ ... }: - -{ - all = [ - "cert-authority ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICsj3W6QczgxE3s5GGT8qg0aLrCM+QeRnSq9RkiZtKvz meow" - ]; -} diff --git a/users/edef/depot-scan/default.nix b/users/edef/depot-scan/default.nix deleted file mode 100644 index a9c0f382f..000000000 --- a/users/edef/depot-scan/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, ... }: - -pkgs.writeShellScriptBin "depot-scan" '' - set -euo pipefail - - path="''${1:-$(git rev-parse --show-prefix)}" - path="''${path%%/}" - attr="''${path//\//.}" - root="$(git rev-parse --show-toplevel)" - echo "scanning //$path" >&2 - nix-instantiate -E "import ${./wrap.nix} $root" -A "$attr" -vv 2> >(${pkgs.perl}/bin/perl ${./depot-scan.pl}) >&2 -'' diff --git a/users/edef/depot-scan/depot-scan.pl b/users/edef/depot-scan/depot-scan.pl deleted file mode 100755 index 8808e2eb0..000000000 --- a/users/edef/depot-scan/depot-scan.pl +++ /dev/null @@ -1,11 +0,0 @@ -#! /usr/bin/env -S perl -ln -use strict; - -if (/^evaluating file '(.*)'$/ or - /^copied source '(.*)' -> '.*'$/ or - /^trace: depot-scan '(.*)'$/) { - print $1; - next; -} - -print STDERR unless /^instantiated '.*' -> '.*'$/; diff --git a/users/edef/depot-scan/wrap.nix b/users/edef/depot-scan/wrap.nix deleted file mode 100644 index 77362b3f6..000000000 --- a/users/edef/depot-scan/wrap.nix +++ /dev/null @@ -1,16 +0,0 @@ -# this wraps import to override readFile and readDir to trace the files it touches -# technique inspired by lorri -let - - global = { - import = global.scopedImport { }; - scopedImport = x: builtins.scopedImport (global // x); - builtins = builtins // { - inherit (global) import scopedImport; - readFile = path: builtins.trace "depot-scan '${toString path}'" (builtins.readFile path); - readDir = path: builtins.trace "depot-scan '${toString path}'" (builtins.readDir path); - }; - }; - -in -global.import diff --git a/users/emery/OWNERS b/users/emery/OWNERS deleted file mode 100644 index 9e052507d..000000000 --- a/users/emery/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -emery diff --git a/users/emery/eaglemode/default.nix b/users/emery/eaglemode/default.nix deleted file mode 100644 index 471e8eda6..000000000 --- a/users/emery/eaglemode/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -# Derivation for my fully configured Eagle Mode. -{ depot, ... }: - -let - config = depot.tools.eaglemode.etcDir { - extraPaths = [ - depot.tools.eaglemode.commands.B - depot.tools.eaglemode.plugins.avif - depot.tools.eaglemode.plugins.qoi - ]; - }; -in -depot.tools.eaglemode.withConfig { inherit config; } diff --git a/users/emery/pkgs/syndicate-server.nix b/users/emery/pkgs/syndicate-server.nix deleted file mode 100644 index e8bf73836..000000000 --- a/users/emery/pkgs/syndicate-server.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ pkgs, ... }: - -let - inherit (pkgs) - rustPlatform - rust-bin - fetchFromGitea - pkg-config - openssl - ; -in - -rustPlatform.buildRustPackage rec { - pname = "syndicate-server"; - version = "0.46.0"; - src = fetchFromGitea { - domain = "git.syndicate-lang.org"; - owner = "syndicate-lang"; - repo = "syndicate-rs"; - rev = "${pname}-v${version}"; - sha256 = "sha256-bTteZIlBSoQ1o5shgd9NeKVvEhZTyG3i2zbeVojWiO8="; - }; - cargoHash = "sha256-SIpdFXTk6MC/drjCLaaa49BbGsvCMNbPGCfTxAlCo9c="; - nativeBuildInputs = [ pkg-config ]; - buildInputs = [ openssl ]; - - RUSTC_BOOTSTRAP = 1; - - meta = { - description = "Syndicate broker server"; - homepage = "https://git.syndicate-lang.org/syndicate-lang/syndicate-rs/"; - mainProgram = "syndicate-server"; - }; -} diff --git a/users/emery/workman-cyrillic.xkb b/users/emery/workman-cyrillic.xkb deleted file mode 100644 index f6783bab7..000000000 --- a/users/emery/workman-cyrillic.xkb +++ /dev/null @@ -1,118 +0,0 @@ -# Workman with phonetic transliteration layer for Cyrllic. -# Switch layers using Shift+CapsLock. - -partial alphanumeric_keys -xkb_symbols "workman-emery" { - - name[Group1]= "Emery"; - - include "us(euro)" - - // Alphanumeric section - key { [ 1, exclam ] }; - key { [ 2, at ] }; - key { [ 3, numbersign ] }; - key { [ 4, dollar ] }; - key { [ 5, percent ] }; - key { [ 6, asciicircum ] }; - key { [ 7, ampersand ] }; - key { [ 8, asterisk ] }; - key { [ 9, parenleft ] }; - key { [ 0, parenright ] }; - - key { - [ q, Q, adiaeresis, Adiaeresis ], - [ U044B, U042B, U044c, U042C ] }; # ы Ы ь Ь - key { - [ d, D, U0111, U0111 ], # d D đ đ - [ U0434, U0414, U0452, U0402 ] }; # д Д ђ Ђ - key { - [ r, R, U20AC, U20AC ], - [ U0440, U0420, U20AC, U20AC ] }; # р Р - key { - [ w, W, aring, Aring ], - [ U0447, U0427, U045B, U040B ] }; # ч Ч ћ Ћ - key { - [ b, B, b, B ], - [ U0431, U0411 ]}; # б Б - key { - [ j, J, U0135, U0134 ], # j J ĵ Ĵ - [ U0458, U0408 ]}; # ј Ј - key { - [ f, F, 0x1002200, F ], # f F ∀ F - [ U0444, U0424, U0473, U0472 ]}; # ф Ф ѳ Ѳ - key { - [ u, U, U016D, U016C ], - [ U0443, U0423, U045E, U040E ] }; # у У ў Ў - key { - [ p, P, sterling, sterling ], - [ U043F, U041F, sterling, sterling ] }; # п П - key { - [ semicolon, colon, paragraph, degree ] }; - - key { - [ a, A, adiaeresis, Adiaeresis ], - [ U0430, U0410, U2248, U00B6 ] # а А ≈ ¶ - }; - key { - [ s, S, U0161, U0160 ], - [ U0441, U0421, U0448, U0428 ] # с С ш Ш - }; - key { - [ h, H, U010D, U010C ], - [ U0445, U0425 , U044B, U042B ] }; # х Х - key { - [ t, T, thorn, THORN ], - [ U0442, U0422] }; # т Т - key { - [ g, G, U011D, U011C ], - [ U0433, U0413 ] }; # г Г - key { - [ y, Y, udiaeresis, Udiaeresis ], - [ U044f, U042f, U044D, U042D ] }; # я Я э Э - key { - [ n, N, ntilde, Ntilde ], - [ U043D, U041D, U045A, U040A ] }; # н Н њ Њ - key { - [ e, E, ediaeresis, Ediaeresis ], - [ U0435, U0415, U0451, U0401 ] }; # е Е ё Ё - key { - [ o, O, odiaeresis, Odiaeresis ], - [ U043E, U041E, U044E, U042E ] }; # о О ю Ю - key { - [ i, I, idiaeresis, Idiaeresis ], - [ U0438, U0418, U0439, U0419 ] }; # и И й - key { - [], - [ U0447, U0427, U045B, U040B ] }; # ч Ч ћ Ћ - - key { - [ z, Z, U017E, U017D ], - [ U0437, U0417, U0436, U0416 ] }; # з З ж Ж - key { - [ x, X, x, X ], - [ U045F, U040F ] }; # џ Џ - key { - [ m, M, mu, mu ], - [ U043C, U041C, mu, mu ] }; # м М - key { - [ c, C, U0107, U0106 ], - [ U0446, U0426, U00A9, U2103 ] }; # ц Ц © ℃ - key { - [ v, V, v, V ], - [ U0432, U0412 ]}; # в В - key { - [ k, K, oe, OE ], - [ U043A, U041A ] }; # к К - key { - [ l, L, U01C9, U01C8 ], - [ U043B, U041B, U0459, U0409 ] }; # л Л љ Љ - key { [ comma, less, ellipsis, guillemotleft ] }; - key { [ period, greater, ellipsis, guillemotright ] }; - // End alphanumeric section - - key { [ BackSpace, ISO_Next_Group ] }; - - key { [ space, minus, space, space ] }; - include "level3(ralt_switch)" -}; diff --git a/users/ericvolp12/OWNERS b/users/ericvolp12/OWNERS deleted file mode 100644 index a43910023..000000000 --- a/users/ericvolp12/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -ericvolp12 diff --git a/users/espes/OWNERS b/users/espes/OWNERS deleted file mode 100644 index 257a1b820..000000000 --- a/users/espes/OWNERS +++ /dev/null @@ -1 +0,0 @@ -espes diff --git a/users/eta/OWNERS b/users/eta/OWNERS deleted file mode 100644 index 59e5e2120..000000000 --- a/users/eta/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -eta diff --git a/users/eta/keys.nix b/users/eta/keys.nix deleted file mode 100644 index ebdc8479a..000000000 --- a/users/eta/keys.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ ... }: - -let - keys = { - yubikey4 = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD6E1wuWaXQARNoLnmlOJndwI7/ms3Ga7MJxsUvFtaSiy3g8h/hz4WgyR7YT+hUYjFihh/YkGS9Zy9aEqAa5zBGLcZtgj1O0qOl2joynm679zdlcwAart74fXSJYYupT9tFeXXeWLO1g054lVJ5xZ9KLpBBk+6yzlmmm5KuoitKBqBbadzsqAeKhNn1Nq9ITPU4vxTFk+sXp/nxk/JoUOM8S2N4YuoX9OVenDHKh9DtOcvDZhlosGmunO33/YaU2XB95ZE6cNhEtVlkbyR3a2SsAYz1qGgfH0HSyoK3LJoAM4Aiz99ktuKiI/zMy4k4TV00OCi1sCPEjzUoijZRZt5FMH/TVr9dJROVjHcL9g9//fW3jwqojf7uuJFlTJb47RxjTk4Jb4F6K7HhOs7bgh3WuOjvhyRYbCYcg+RfnwjJk+hfM5GcjZ8J4UZdNc5LyIcfH8W1v9DADBCgz7QcmfrfMloYtEgjK/5XVrtBtiMtUOgpfKujawF55d1Vj26+CxeID8NHMXzZYEMeyRpi/WXlC+lq1Wx4Fj8gvideOw/3gAdj2G3SJWdSPk8XpIFQ1fm3tXB0ltyV5TszIJhfMnmsKJeEm3YlTCR1sMW7nr3wEdMqa6mpcWZTWU+dppmAGr2c+OGSnXkCi7Z2h/YJE6X+izrOrqRspG2fCM8GlfRFWw== cardno:000607469311"; - yubikey5 = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKCJx23px0Vknw1NlD+arcqeVXxcogPUMJgF/PGp6wA/tg7hHUKs2udC+gDMYlxQ9IpnWOwZ/9yvqzTDwUU3R/4= YubiKey #15026444 PIV Slot 9a"; - }; - configs = { - whitby = [ keys.yubikey4 keys.yubikey5 ]; - }; -in -configs diff --git a/users/firefly/OWNERS b/users/firefly/OWNERS deleted file mode 100644 index 1b7dd7189..000000000 --- a/users/firefly/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -firefly diff --git a/users/firefly/keys.nix b/users/firefly/keys.nix deleted file mode 100644 index 1d7467a07..000000000 --- a/users/firefly/keys.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ ... }: - -rec { - as = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN9i8fs10/BjNEqFXD+3fQeQ0SuHnQx4WpuqUg4caeed firefly@as"; - - whitby = [ as ]; -} diff --git a/users/flokli/OWNERS b/users/flokli/OWNERS index a70f5eeff..36d9cb265 100644 --- a/users/flokli/OWNERS +++ b/users/flokli/OWNERS @@ -1,3 +1 @@ set noparent - -flokli diff --git a/users/flokli/keyboards/0001-custom_config-define-MIRYOKU_KLUDGE_MOUSEKEYSPR.patch b/users/flokli/keyboards/0001-custom_config-define-MIRYOKU_KLUDGE_MOUSEKEYSPR.patch deleted file mode 100644 index 8d9089eae..000000000 --- a/users/flokli/keyboards/0001-custom_config-define-MIRYOKU_KLUDGE_MOUSEKEYSPR.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 9414e9bfe9aad3a87d34cb8e1cdbef081d38a37c Mon Sep 17 00:00:00 2001 -From: Florian Klink -Date: Fri, 15 Nov 2024 16:29:17 +0200 -Subject: [PATCH] custom_config: #define MIRYOKU_KLUDGE_MOUSEKEYSPR - ---- - miryoku/custom_config.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/miryoku/custom_config.h b/miryoku/custom_config.h -index 1097bcb..48a1b5f 100644 ---- a/miryoku/custom_config.h -+++ b/miryoku/custom_config.h -@@ -1,3 +1,4 @@ - // Copyright 2021 Manna Harbour - // https://github.com/manna-harbour/miryoku - -+#define MIRYOKU_KLUDGE_MOUSEKEYSPR --- -2.46.1 - diff --git a/users/flokli/keyboards/0001-miryoku_behaviors-add-quick-tap-ms-require-prior-idl.patch b/users/flokli/keyboards/0001-miryoku_behaviors-add-quick-tap-ms-require-prior-idl.patch deleted file mode 100644 index fc86c0627..000000000 --- a/users/flokli/keyboards/0001-miryoku_behaviors-add-quick-tap-ms-require-prior-idl.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 9ed3e8ee2aad704fcfef2490617e2fd22902b2c4 Mon Sep 17 00:00:00 2001 -From: Florian Klink -Date: Sun, 27 Oct 2024 12:01:13 +0100 -Subject: [PATCH] miryoku_behaviors: add quick-tap-ms, require-prior-idle-ms - ---- - miryoku/miryoku_behaviors.dtsi | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/miryoku/miryoku_behaviors.dtsi b/miryoku/miryoku_behaviors.dtsi -index 473df49..73211da 100644 ---- a/miryoku/miryoku_behaviors.dtsi -+++ b/miryoku/miryoku_behaviors.dtsi -@@ -14,6 +14,8 @@ - compatible = "zmk,behavior-hold-tap"; - #binding-cells = <2>; - tapping-term-ms = ; -+ quick-tap-ms = <200>; -+ require-prior-idle-ms = <125>; - flavor = "tap-preferred"; - bindings = <&mo>, <&kp>; - }; --- -2.46.1 - diff --git a/users/flokli/keyboards/0001-miryoku_layer_alternatives.h-expose-alt-gr-on-G-and-.patch b/users/flokli/keyboards/0001-miryoku_layer_alternatives.h-expose-alt-gr-on-G-and-.patch deleted file mode 100644 index 540ecb162..000000000 --- a/users/flokli/keyboards/0001-miryoku_layer_alternatives.h-expose-alt-gr-on-G-and-.patch +++ /dev/null @@ -1,25 +0,0 @@ -From a852a9738cc7510f6d3b80d1befb3c88ef8f08f7 Mon Sep 17 00:00:00 2001 -From: Florian Klink -Date: Sun, 27 Oct 2024 11:14:30 +0100 -Subject: [PATCH] miryoku_layer_alternatives.h: expose alt-gr on G and M - ---- - miryoku/miryoku_babel/miryoku_layer_alternatives.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/miryoku/miryoku_babel/miryoku_layer_alternatives.h b/miryoku/miryoku_babel/miryoku_layer_alternatives.h -index 8044fdd..07ed9b6 100644 ---- a/miryoku/miryoku_babel/miryoku_layer_alternatives.h -+++ b/miryoku/miryoku_babel/miryoku_layer_alternatives.h -@@ -86,7 +86,7 @@ U_NP, U_NP, U_LT(U_MEDIA, ESC),U_LT(U_NAV, SPACE),U_LT - - #define MIRYOKU_ALTERNATIVES_BASE_COLEMAKDH \ - &kp Q, &kp W, &kp F, &kp P, &kp B, &kp J, &kp L, &kp U, &kp Y, &kp SQT, \ --U_MT(LGUI, A), U_MT(LALT, R), U_MT(LCTRL, S), U_MT(LSHFT, T), &kp G, &kp M, U_MT(LSHFT, N), U_MT(LCTRL, E), U_MT(LALT, I), U_MT(LGUI, O), \ -+U_MT(LGUI, A), U_MT(LALT, R), U_MT(LCTRL, S), U_MT(LSHFT, T), U_MT(RALT, G), U_MT(RALT, M), U_MT(LSHFT, N), U_MT(LCTRL, E), U_MT(LALT, I), U_MT(LGUI, O), \ - U_LT(U_BUTTON, Z), U_MT(RALT, X), &kp C, &kp D, &kp V, &kp K, &kp H, &kp COMMA, U_MT(RALT, DOT), U_LT(U_BUTTON, SLASH),\ - U_NP, U_NP, U_LT(U_MEDIA, ESC),U_LT(U_NAV, SPACE),U_LT(U_MOUSE, TAB),U_LT(U_SYM, RET), U_LT(U_NUM, BSPC), U_LT(U_FUN, DEL), U_NP, U_NP - --- -2.46.1 - diff --git a/users/flokli/keyboards/chocofi/default.nix b/users/flokli/keyboards/chocofi/default.nix deleted file mode 100644 index f48341582..000000000 --- a/users/flokli/keyboards/chocofi/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ pkgs, depot, ... }: -rec { - firmware = depot.users.flokli.keyboards.buildSplitKeyboard { - name = "nice_nano_v2"; - board = "nice_nano_v2"; - shield = "corne_%PART% nice_view_adapter nice_view"; - zephyrDepsHash = "sha256:1hr304xhj596a85mmy3zl2y0bl9w143h9bj5qk7wmqx46mbs4kb0"; - src = depot.users.flokli.keyboards.miryoku_config; - extraCmakeFlags = [ - "-DCONFIG_ZMK_POINTING=y" - "-DCONFIG_ZMK_POINTING_SMOOTH_SCROLLING=y" - ]; - }; - - config-flat = depot.users.flokli.keyboards.mkFlatConfig "corne"; - - flash-left = pkgs.writeShellScript "flash.sh" '' - cp ${firmware}/zmk_left.uf2 /run/media/$USER/NICENANO/ - ''; - - flash-right = pkgs.writeShellScript "flash.sh" '' - cp ${firmware}/zmk_right.uf2 /run/media/$USER/NICENANO/ - ''; - - meta.ci.targets = [ - "config-flat" - "firmware" - ]; -} diff --git a/users/flokli/keyboards/corneish_zen/default.nix b/users/flokli/keyboards/corneish_zen/default.nix deleted file mode 100644 index 703359bd4..000000000 --- a/users/flokli/keyboards/corneish_zen/default.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ pkgs, depot, ... }: -rec { - firmware = depot.users.flokli.keyboards.buildSplitKeyboard { - name = "corneish_zen_v1"; - board = "corneish_zen_v1_%PART%"; - zephyrDepsHash = "sha256-Qe9G5YLEi9iG5QdmJCxcmQTpzUCBYkfa84zk7SVRSgQ="; - src = depot.users.flokli.keyboards.miryoku_config; - extraCmakeFlags = [ - "-DCONFIG_ZMK_MOUSE=y" - "-DCONFIG_ZMK_MOUSE_SMOOTH_SCROLLING=y" - ]; - }; - - config-flat = depot.users.flokli.keyboards.mkFlatConfig "corneish_zen"; - - flash-left = pkgs.writeShellScript "flash.sh" '' - cp ${firmware}/zmk_left.uf2 /run/media/$USER/CORNEISHZEN/ - ''; - - flash-right = pkgs.writeShellScript "flash.sh" '' - cp ${firmware}/zmk_right.uf2 /run/media/$USER/CORNEISHZEN/ - ''; - - meta.ci.targets = [ - "config-flat" - "firmware" - ]; -} diff --git a/users/flokli/keyboards/default.nix b/users/flokli/keyboards/default.nix deleted file mode 100644 index 4e207863a..000000000 --- a/users/flokli/keyboards/default.nix +++ /dev/null @@ -1,54 +0,0 @@ -{ pkgs, ... }: - - -let - zmk-nix = pkgs.fetchFromGitHub { - owner = "lilyinstarlight"; - repo = "zmk-nix"; - rev = "1d7d7aeef7c62d3a80a688b26c6484123c26cde6"; - hash = "sha256-7W+slivoV0zSfDxXlhMVL3yPodrhCiYQiFbtbco1r5U="; - }; - - zmk_builders = pkgs.callPackage (import (zmk-nix + "/nix/builders.nix")) { }; - - miryoku_zmk = pkgs.fetchFromGitHub { - owner = "manna-harbour"; - repo = "miryoku_zmk"; - rev = "a1f1eae0666b7b33ad789b10822297169754a349"; - hash = "sha256-4jYz5fudTW45hbwhRRGBdiAbu596X9zSiCio/tS85d0="; - }; - - miryoku_zmk_patched = pkgs.runCommand "miryoku_zmk_patched" { } '' - mkdir -p $out - cp -r ${miryoku_zmk}/. $out/ - cd $out - chmod -R +w $out - patch -p1 < ${./0001-miryoku_layer_alternatives.h-expose-alt-gr-on-G-and-.patch} - patch -p1 < ${./0001-miryoku_behaviors-add-quick-tap-ms-require-prior-idl.patch} - patch -p1 < ${./0001-custom_config-define-MIRYOKU_KLUDGE_MOUSEKEYSPR.patch} - ''; - - miryoku_config = pkgs.runCommand "config" { } '' - mkdir -p $out/config - cp -r ${miryoku_zmk_patched}/miryoku $out/ - cp ${./west.yml} $out/config/west.yml - cp ${miryoku_zmk_patched}/config/*.keymap $out/config/ - ''; - - # helpful for debugging a resulting keymap config - mkFlatConfig = name: pkgs.runCommand "config-flat" - { - nativeBuildInputs = [ pkgs.python3.pkgs.pcpp ]; - } '' - mkdir -p $out/config - cp ${./west.yml} $out/config/west.yml - pcpp --passthru-unfound-includes -o $out/config/${name}.keymap ${miryoku_zmk_patched}/config/${name}.keymap - ''; - -in - -{ - miryoku_zmk = miryoku_zmk_patched; - inherit (zmk_builders) buildSplitKeyboard; - inherit miryoku_config mkFlatConfig; -} diff --git a/users/flokli/keyboards/dilemma/default.nix b/users/flokli/keyboards/dilemma/default.nix deleted file mode 100644 index 115f7aa08..000000000 --- a/users/flokli/keyboards/dilemma/default.nix +++ /dev/null @@ -1,71 +0,0 @@ -{ pkgs, ... }: - -rec { - qmk_firmware_src = pkgs.fetchFromGitHub { - owner = "bastardkb"; - repo = "bastardkb-qmk"; - rev = "60f5e5ae3da7cbc724a587642b2ad36fe5fcb591"; # bkb-develop - hash = "sha256-FRlxOdxxNAf7QYlAnD4OJ68k04oog0r9UYBmaANDFsU="; - fetchSubmodules = true; - }; - - qmk_userspace = pkgs.fetchFromGitHub { - owner = "bastardkb"; - repo = "qmk_userspace"; - rev = "722fe10ae9f1249245af4852209694749207eb70"; # develop - hash = "sha256-FY5zyM6G6DEdSWowNADrHr9P5G4mqioTDK/KM10z6t0="; - fetchSubmodules = true; - }; - - firmware = pkgs.stdenv.mkDerivation { - name = "bastardkb-dilemma-firmware"; - - src = qmk_firmware_src; - - patches = [ ./enable-taps.patch ]; - - postPatch = '' - patchShebangs util/uf2conv.py - ''; - - nativeBuildInputs = [ - pkgs.python3 - pkgs.qmk - ]; - - env.QMK_HOME = qmk_firmware_src; - env.QMK_USERSPACE = "/tmp/qmk_userspace"; - env.HOME = "/tmp/qmk"; - env.SKIP_GIT = "true"; - - buildPhase = '' - mkdir -p /tmp/qmk_userspace - cp -r ${qmk_userspace}/. /tmp/qmk_userspace/ - chmod +w /tmp/qmk_userspace/ --recursive - - mkdir -p /tmp/qmk_userspace/keyboards/bastardkb/dilemma/3x5_3{,_procyon}/keymaps/flokli - cp ${./keymap.c} /tmp/qmk_userspace/keyboards/bastardkb/dilemma/3x5_3/keymaps/flokli/keymap.c - cp ${./rules.mk} /tmp/qmk_userspace/keyboards/bastardkb/dilemma/3x5_3/keymaps/flokli/rules.mk - cp ${./keymap.c} /tmp/qmk_userspace/keyboards/bastardkb/dilemma/3x5_3_procyon/keymaps/flokli/keymap.c - cp ${./rules.mk} /tmp/qmk_userspace/keyboards/bastardkb/dilemma/3x5_3_procyon/keymaps/flokli/rules.mk - - qmk compile -c -kb bastardkb/dilemma/3x5_3 -km flokli - qmk compile -c -kb bastardkb/dilemma/3x5_3_procyon -km flokli - ''; - - installPhase = '' - mkdir -p $out - cp bastardkb_dilemma_*.uf2 $out/ - ''; - }; - - flash-v2 = pkgs.writeShellScript "flash.sh" '' - QMK_HOME=${qmk_firmware_src} ${pkgs.qmk}/bin/qmk flash ${firmware}/bastardkb_dilemma_3x5_3_flokli.uf2 - ''; - flash-v3 = pkgs.writeShellScript "flash.sh" '' - QMK_HOME=${qmk_firmware_src} ${pkgs.qmk}/bin/qmk flash ${firmware}/bastardkb_dilemma_3x5_3_procyon_flokli.uf2 - ''; - - meta.ci.skip = true; - meta.ci.targets = [ "firmware" ]; -} diff --git a/users/flokli/keyboards/dilemma/enable-taps.patch b/users/flokli/keyboards/dilemma/enable-taps.patch deleted file mode 100644 index afded8549..000000000 --- a/users/flokli/keyboards/dilemma/enable-taps.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 32a1b9a189c13bec03c6b0f258121c47185db0ad Mon Sep 17 00:00:00 2001 -From: Florian Klink -Date: Tue, 23 Jan 2024 11:26:10 +0200 -Subject: [PATCH] bastardkb dilemma: enable taps - ---- - keyboards/bastardkb/dilemma/3x5_3/config.h | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/keyboards/bastardkb/dilemma/3x5_3/config.h b/keyboards/bastardkb/dilemma/3x5_3/config.h -index ccbc4e2f58..bf17dc7e02 100644 ---- a/keyboards/bastardkb/dilemma/3x5_3/config.h -+++ b/keyboards/bastardkb/dilemma/3x5_3/config.h -@@ -42,6 +42,7 @@ - #define POINTING_DEVICE_CS_PIN GP21 - #undef CIRQUE_PINNACLE_DIAMETER_MM - #define CIRQUE_PINNACLE_DIAMETER_MM 40 -+#define CIRQUE_PINNACLE_TAP_ENABLE 1 - - /* Reset. */ - #define RP2040_BOOTLOADER_DOUBLE_TAP_RESET --- -2.43.0 - diff --git a/users/flokli/keyboards/dilemma/keymap.c b/users/flokli/keyboards/dilemma/keymap.c deleted file mode 100644 index 1d77c9770..000000000 --- a/users/flokli/keyboards/dilemma/keymap.c +++ /dev/null @@ -1,172 +0,0 @@ -/** - * Copyright 2022 Charly Delay (@0xcharly) - * Copyright 2023 casuanoob (@casuanoob) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include QMK_KEYBOARD_H - -enum dilemma_keymap_layers { - LAYER_BASE = 0, - LAYER_FUNCTION, - LAYER_NAVIGATION, - LAYER_MEDIA, - LAYER_POINTER, - LAYER_NUMERAL, - LAYER_SYMBOLS, -}; - -// Automatically enable sniping-mode on the pointer layer. -// #define DILEMMA_AUTO_SNIPING_ON_LAYER LAYER_POINTER - -#define ESC_MED LT(LAYER_MEDIA, KC_ESC) -#define SPC_NAV LT(LAYER_NAVIGATION, KC_SPC) -#define TAB_POI LT(LAYER_POINTER, KC_TAB) -#define ENT_SYM LT(LAYER_SYMBOLS, KC_ENT) -#define BSP_NUM LT(LAYER_NUMERAL, KC_BSPC) -#define DEL_FUN LT(LAYER_FUNCTION, KC_DEL) -#define PT_Z LT(LAYER_POINTER, KC_Z) -#define PT_SLSH LT(LAYER_POINTER, KC_SLSH) - -#ifndef POINTING_DEVICE_ENABLE -# define DRGSCRL KC_NO -# define DPI_MOD KC_NO -# define S_D_MOD KC_NO -# define SNIPING KC_NO -#endif // !POINTING_DEVICE_ENABLE - -// clang-format off -/** \brief QWERTY layout (3 rows, 10 columns). */ -const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { - [LAYER_BASE] = LAYOUT_split_3x5_3( - KC_Q, KC_W, KC_F, KC_P, KC_B, KC_J, KC_L, KC_U, KC_Y, KC_QUOT, - LGUI_T(KC_A), LALT_T(KC_R), LCTL_T(KC_S), LSFT_T(KC_T), KC_G, KC_M, LSFT_T(KC_N), LCTL_T(KC_E), LALT_T(KC_I), LGUI_T(KC_O), - PT_Z, RALT_T(KC_X), KC_C, KC_D, KC_V, KC_K, KC_H, KC_COMM, RALT_T(KC_DOT), PT_SLSH, - ESC_MED, SPC_NAV, TAB_POI, ENT_SYM, BSP_NUM, DEL_FUN - ), - -/* - * Layers used on the Dilemma. - * - * These layers started off heavily inspired by the Miryoku layout, but trimmed - * down and tailored for a stock experience that is meant to be fundation for - * further personalization. - * - * See https://github.com/manna-harbour/miryoku for the original layout. - */ - -/** - * \brief Function layer. - * - * Secondary right-hand layer has function keys mirroring the numerals on the - * primary layer with extras on the pinkie column, plus system keys on the inner - * column. App is on the tertiary thumb key and other thumb keys are duplicated - * from the base layer to enable auto-repeat. - */ - [LAYER_FUNCTION] = LAYOUT_split_3x5_3( - XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_PSCR, KC_F7, KC_F8, KC_F9, KC_F12, - KC_LGUI, KC_LALT, KC_LCTL, KC_LSFT, XXXXXXX, KC_SCRL, KC_F4, KC_F5, KC_F6, KC_F11, - XXXXXXX, KC_RALT, XXXXXXX, XXXXXXX, XXXXXXX, KC_PAUS, KC_F1, KC_F2, KC_F3, KC_F10, - XXXXXXX, _______, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX - ), - -/** - * \brief Navigation layer. - * - * Primary right-hand layer (left home thumb) is navigation and editing. Cursor - * keys are on the home position, line and page movement below, clipboard above, - * caps lock and insert on the inner column. Thumb keys are duplicated from the - * base layer to avoid having to layer change mid edit and to enable auto-repeat. - */ - [LAYER_NAVIGATION] = LAYOUT_split_3x5_3( - XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, - KC_LGUI, KC_LALT, KC_LCTL, KC_LSFT, XXXXXXX, KC_CAPS, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, - XXXXXXX, KC_RALT, XXXXXXX, XXXXXXX, XXXXXXX, KC_INS, KC_HOME, KC_PGDN, KC_PGUP, KC_END, - XXXXXXX, XXXXXXX, _______, KC_ENT, KC_BSPC, KC_DEL - ), - -/** - * \brief Media layer. - * - * Tertiary left- and right-hand layer is media and RGB control. This layer is - * symmetrical to accomodate the left- and right-hand trackball. - */ - [LAYER_MEDIA] = LAYOUT_split_3x5_3( - XXXXXXX,RGB_RMOD, RGB_TOG, RGB_MOD, XXXXXXX, XXXXXXX,RGB_RMOD, RGB_TOG, RGB_MOD, XXXXXXX, - KC_MPRV, KC_VOLD, KC_MUTE, KC_VOLU, KC_MNXT, KC_MPRV, KC_VOLD, KC_MUTE, KC_VOLU, KC_MNXT, - XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, - _______, KC_MPLY, KC_MSTP, KC_MSTP, KC_MPLY, KC_MUTE - ), - -/** \brief Mouse emulation and pointer functions. */ - [LAYER_POINTER] = LAYOUT_split_3x5_3( - QK_BOOT, EE_CLR, XXXXXXX, DPI_MOD, S_D_MOD, S_D_MOD, DPI_MOD, XXXXXXX, EE_CLR, QK_BOOT, - KC_LGUI, KC_LALT, KC_LCTL, KC_LSFT, XXXXXXX, XXXXXXX, KC_LSFT, KC_LCTL, KC_LALT, KC_LGUI, - _______, DRGSCRL, SNIPING, KC_BTN3, XXXXXXX, XXXXXXX, KC_BTN3, SNIPING, DRGSCRL, _______, - KC_BTN3, KC_BTN2, KC_BTN1, KC_BTN1, KC_BTN2, KC_BTN3 - ), - -/** - * \brief Numeral layout. - * - * Primary left-hand layer (right home thumb) is numerals and symbols. Numerals - * are in the standard numpad locations with symbols in the remaining positions. - * `KC_DOT` is duplicated from the base layer. - */ - [LAYER_NUMERAL] = LAYOUT_split_3x5_3( - KC_LBRC, KC_7, KC_8, KC_9, KC_RBRC, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, - KC_SCLN, KC_4, KC_5, KC_6, KC_EQL, XXXXXXX, KC_LSFT, KC_LCTL, KC_LALT, KC_LGUI, - KC_DOT, KC_1, KC_2, KC_3, KC_BSLS, XXXXXXX, XXXXXXX, XXXXXXX, KC_RALT, XXXXXXX, - KC_DOT, KC_0, KC_MINS, XXXXXXX, _______, XXXXXXX - ), - -/** - * \brief Symbols layer. - * - * Secondary left-hand layer has shifted symbols in the same locations to reduce - * chording when using mods with shifted symbols. `KC_LPRN` is duplicated next to - * `KC_RPRN`. - */ - [LAYER_SYMBOLS] = LAYOUT_split_3x5_3( - KC_LCBR, KC_AMPR, KC_ASTR, KC_LPRN, KC_RCBR, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, - KC_COLN, KC_DLR, KC_PERC, KC_CIRC, KC_PLUS, XXXXXXX, KC_LSFT, KC_LCTL, KC_LALT, KC_LGUI, - KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_PIPE, XXXXXXX, XXXXXXX, XXXXXXX, KC_RALT, XXXXXXX, - KC_LPRN, KC_GRV, KC_UNDS, _______, XXXXXXX, XXXXXXX - ), -}; -// clang-format on - -#ifdef POINTING_DEVICE_ENABLE -# ifdef DILEMMA_AUTO_SNIPING_ON_LAYER -layer_state_t layer_state_set_user(layer_state_t state) { - dilemma_set_pointer_sniping_enabled(layer_state_cmp(state, DILEMMA_AUTO_SNIPING_ON_LAYER)); - return state; -} -# endif // DILEMMA_AUTO_SNIPING_ON_LAYER -#endif // POINTING_DEVICE_ENABLE - -#ifdef ENCODER_MAP_ENABLE -// clang-format off -const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = { - [LAYER_BASE] = {ENCODER_CCW_CW(KC_WH_D, KC_WH_U), ENCODER_CCW_CW(KC_VOLD, KC_VOLU)}, - [LAYER_FUNCTION] = {ENCODER_CCW_CW(KC_DOWN, KC_UP), ENCODER_CCW_CW(KC_LEFT, KC_RGHT)}, - [LAYER_NAVIGATION] = {ENCODER_CCW_CW(KC_PGDN, KC_PGUP), ENCODER_CCW_CW(KC_VOLU, KC_VOLD)}, - [LAYER_MEDIA] = {ENCODER_CCW_CW(KC_PGDN, KC_PGUP), ENCODER_CCW_CW(KC_VOLU, KC_VOLD)}, - [LAYER_POINTER] = {ENCODER_CCW_CW(RGB_HUD, RGB_HUI), ENCODER_CCW_CW(RGB_SAD, RGB_SAI)}, - [LAYER_NUMERAL] = {ENCODER_CCW_CW(RGB_VAD, RGB_VAI), ENCODER_CCW_CW(RGB_SPD, RGB_SPI)}, - [LAYER_SYMBOLS] = {ENCODER_CCW_CW(RGB_RMOD, RGB_MOD), ENCODER_CCW_CW(KC_LEFT, KC_RGHT)}, -}; -// clang-format on -#endif // ENCODER_MAP_ENABLE diff --git a/users/flokli/keyboards/dilemma/rules.mk b/users/flokli/keyboards/dilemma/rules.mk deleted file mode 100644 index 24d368038..000000000 --- a/users/flokli/keyboards/dilemma/rules.mk +++ /dev/null @@ -1,3 +0,0 @@ -ENCODER_MAP_ENABLE = yes -MAXTOUCH_DEBUG = no -OPT_DEFS += -DMK_KINETIC_SPEED=1 diff --git a/users/flokli/keyboards/west.yml b/users/flokli/keyboards/west.yml deleted file mode 100644 index 5596455f0..000000000 --- a/users/flokli/keyboards/west.yml +++ /dev/null @@ -1,34 +0,0 @@ -manifest: - remotes: - - name: zmkfirmware - url-base: https://github.com/zmkfirmware - projects: - - name: zephyr - remote: zmkfirmware - revision: f8e4d15791602c67405c0fd2651167a895939565 # v3.5.0+zmk-fixes - import: - name-blocklist: - - ci-tools - - hal_altera - - hal_cypress - - hal_infineon - - hal_microchip - - hal_nxp - - hal_openisa - - hal_silabs - - hal_xtensa - - hal_st - - hal_ti - - loramac-node - - mcuboot - - mcumgr - - net-tools - - openthread - - edtt - - trusted-firmware-m - - name: zmk - remote: zmkfirmware - revision: refs/pull/2477/head # mouse move and scroll support PR - import: app/west.yml - self: - path: config diff --git a/users/flokli/nixos/.envrc b/users/flokli/nixos/.envrc deleted file mode 100644 index 5c14eb6e9..000000000 --- a/users/flokli/nixos/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -source_up - -PATH_add $(nix-build ../../.. -A users.flokli.nixos.deps --no-out-link)/bin diff --git a/users/flokli/nixos/default.nix b/users/flokli/nixos/default.nix index b507659d9..5ca6bbce1 100644 --- a/users/flokli/nixos/default.nix +++ b/users/flokli/nixos/default.nix @@ -1,8 +1,6 @@ { depot, pkgs, lib, ... }: let - systemFor = sys: (depot.ops.nixos.nixosFor sys).system; - # assumes `name` is configured appropriately in your .ssh/config deployScript = name: sys: pkgs.writeShellScriptBin "deploy-${name}" '' set -eo pipefail diff --git a/users/flokli/nixos/profiles/archeology.nix b/users/flokli/nixos/profiles/archeology.nix index c87d6bcf3..995885646 100644 --- a/users/flokli/nixos/profiles/archeology.nix +++ b/users/flokli/nixos/profiles/archeology.nix @@ -1,11 +1,8 @@ # Set of unconditional config options applicable to all archeology machines. -{ depot, pkgs, ... }: +{ pkgs, ... }: { - # Use the TVL binary cache - tvl.cache.enable = true; - # Start clickhose as a system service. services.clickhouse.enable = true; diff --git a/users/flokli/presentations/2023-09-09-nixcon-tvix/.gitignore b/users/flokli/presentations/2023-09-09-nixcon-tvix/.gitignore deleted file mode 100644 index 397b4a762..000000000 --- a/users/flokli/presentations/2023-09-09-nixcon-tvix/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.log diff --git a/users/flokli/presentations/2023-09-09-nixcon-tvix/architecture.dot b/users/flokli/presentations/2023-09-09-nixcon-tvix/architecture.dot deleted file mode 100644 index a6ea0460e..000000000 --- a/users/flokli/presentations/2023-09-09-nixcon-tvix/architecture.dot +++ /dev/null @@ -1,5 +0,0 @@ -digraph { - Builder - Store - Evaluator -} diff --git a/users/flokli/presentations/2023-09-09-nixcon-tvix/cppnix-example-lexer.cpp b/users/flokli/presentations/2023-09-09-nixcon-tvix/cppnix-example-lexer.cpp deleted file mode 100644 index 7c52bce8b..000000000 --- a/users/flokli/presentations/2023-09-09-nixcon-tvix/cppnix-example-lexer.cpp +++ /dev/null @@ -1,13 +0,0 @@ -attrpath - : attrpath '.' attr { - $$ = $1; $1->push_back(AttrName(data->symbols.create($3))); - } - | attrpath '.' string_attr - { $$ = $1; - ExprString * str = dynamic_cast($3); - if (str) { - $$->push_back(AttrName(data->symbols.create(str->s))); - delete str; - } else - $$->push_back(AttrName($3)); - } diff --git a/users/flokli/presentations/2023-09-09-nixcon-tvix/crate-deps.dot b/users/flokli/presentations/2023-09-09-nixcon-tvix/crate-deps.dot deleted file mode 100644 index 66ead74b1..000000000 --- a/users/flokli/presentations/2023-09-09-nixcon-tvix/crate-deps.dot +++ /dev/null @@ -1,19 +0,0 @@ -digraph { - bgcolor="transparent" - node [fillcolor="lightgrey",style="filled"] - - tvix_cli - tvix_eval - nix_compat - tvix_serde - tvix_store - - tvix_cli -> tvix_store - tvix_cli -> nix_compat - tvix_cli -> tvix_eval - - tvix_store -> nix_compat - tvix_eval -> nix_compat - - tvix_serde -> tvix_eval -} diff --git a/users/flokli/presentations/2023-09-09-nixcon-tvix/default.nix b/users/flokli/presentations/2023-09-09-nixcon-tvix/default.nix deleted file mode 100644 index 6dc9c7d04..000000000 --- a/users/flokli/presentations/2023-09-09-nixcon-tvix/default.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (pkgs) - fontconfig qrencode runCommand stdenv; - mkQr = url: runCommand "qrcode.png" { } '' - ${qrencode}/bin/qrencode -o $out -t SVG -s 5 \ - --background=fafafa \ - --foreground=000000 \ - ${url} - ''; -in -stdenv.mkDerivation { - name = "2023-nixcon-tvix"; - src = ./.; - - FONTCONFIG_FILE = pkgs.makeFontsConf { - fontDirectories = with pkgs; [ jetbrains-mono fira fira-code fira-mono lato ]; - }; - - nativeBuildInputs = [ pkgs.reveal-md pkgs.graphviz ]; - - buildPhase = '' - cp ${depot.tvix.logo}/logo.png tvix-logo.png - dot -Tsvg crate-deps.dot > crate-deps.svg - cp ${mkQr "https://flokli.de"} qrcode-flokli.svg - cp ${mkQr "https://tvix.dev"} qrcode-tvix.svg - - mkdir -p $out - reveal-md --static $out presentation.md - cp tvixbolt.webm $out - - CHROME_CONFIG_HOME=/build/.config reveal-md presentation.md --print $out/slides.pdf --puppeteer-chromium-executable="${pkgs.chromium}/bin/chromium" - # Above command doesn't fail on error, ensure file has been created - [[ -f "$out/slides.pdf" ]] || exit 1 - ''; - - # reveal-md presentation.md --print started timing out possibly due to - # chromium: 133.0.6943.141 -> 134.0.6998.35 - meta.ci.skip = true; -} diff --git a/users/flokli/presentations/2023-09-09-nixcon-tvix/presentation.md b/users/flokli/presentations/2023-09-09-nixcon-tvix/presentation.md deleted file mode 100644 index b37554e18..000000000 --- a/users/flokli/presentations/2023-09-09-nixcon-tvix/presentation.md +++ /dev/null @@ -1,294 +0,0 @@ ---- -author: -- Florian Klink -date: 2023-09-09 -title: "Tvix: Status update" -theme: moon -revealOptions: - transition: 'fade' ---- - -# Tvix: Status update - -![Tvix Logo](tvix-logo.png) - -2023-09-09 - -Florian Klink - ---- - -## Whoami - -- flokli -- nixpkgs contributor since 2018, maintaining systemd, nsncd and some - more stuff -- Freelance Nix/DevOps consultant -- I spend too much time on computers :-) - ---- - -## What is Tvix? - -- A new implementation of Nix -- modular -- written in Rust -- developed in the [TVL](https://tvl.fyi) monorepo -- subtree exported to [github:tvlfyi/tvix](https://github.com/tvlfyi/tvix) - ---- - -## Structure - -- strong separation between **Evaluator**, **Store** and **Builder** -- Defined interfaces between different components (Protobuf/gRPC) - - Allows adding to/combining with your own components -- A lot of helper code for some of the Nix internals in the `nix-compat` crate - -Note: Derivation types, serializers. NAR writers, nixbase32 enc/dec, Nix Hash function, stringparsing etc. - ----- - -![crate-deps.svg](crate-deps.svg) - ---- - -## Evaluator: Design - -- - Nix code is parsed via [rnix](https://github.com/nix-community/rnix-parser) -- - AST traversal, generate bytecode (with some transformations) -- - Bytecode is executed by an abstract machine with a Nix-specific instruction set - ----- - -## Evaluator: Design - -- - Builtins are separate from the "evaluator core" - - - inject your own builtins - - - this includes `builtins.derivation`! -- - IO is nicely abstracted away - - - We can run a Nixlang subset without IO in wasm (see [tvixbolt](https://bolt.tvix.dev/)), - or parse Nix into a config struct with `tvix-serde` - ----- - - -Tvixbolt Demo - ----- - -### Evaluator: Current Work - -- - Current goal: **evaluate nixpkgs the same way as Nix does** -- - Checked by comparing the calculated output paths, which checks correctness of all \"parent\" output paths too. -- - Required implementing a lot of Nix internals in `nix-compat`, and `tvix-store` (A-Term, hash modulo, NAR writer/hasher) - -Note: Getting output hashing correct, and exposing this in a re-usable fashion took quite some iterations to get right. - ----- - -### Evaluator: Current Work (cont.) -- - 🎉 Already correct for (and continously checked by CI on every commit): - - - `stdenv`, `hello` - - - `pkgsCross.aarch64-multiplatform.stdenv`, `pkgsCross.aarch64-multiplatform.hello` -- - Some work left for more complicated expressions - - - infinite recursion [when inheriting from a `builtins.tryEval` multiple times](https://b.tvl.fyi/281) - - - small details around file imports -- - Not too much performance finetuning until we're correct first. - ----- - -### Evaluator: Demo - -[![asciicast](https://asciinema.org/a/MH4tuVPLsKewJSGJUYEyIKUpj.svg)](https://asciinema.org/a/MH4tuVPLsKewJSGJUYEyIKUpj) - ---- - -## Store: Design - -- - Uses a very different underlying data model: - - - Nix stores on a per- `StorePath` granularity - - - tvix-store uses a Merkle DAG of directories, similar to git trees, but with [BLAKE3](https://github.com/BLAKE3-team/BLAKE3) digests as pointers. - - - Compat layer in front to still render/calculate NAR on demand where needed - - - Substitution, caching, ... possible to describe via composition/layering - ----- - -![tvix-store graph](tvix-store-graph.svg) - ----- - -### Store: Advantages - -- - Less downloading of data that didn't change -- - Less duplicate data on disk/storage -- - Inherently content-addressed, so P2P substitution possible -- - Allows doing verified blob streaming ([BAO](https://github.com/oconnor663/bao), [bao-tree](https://github.com/n0-computer/bao-tree)) -- - Protocol has some \"smarter\" methods to avoid roundtrips, but could all be statically pre-rendered -- - Very little data that needs to be fetched from a trusted party (or be signed) - -Note: Our way of addressing blobs by their raw blake3 digest is natively compatible with iroh, the IPFS Re-implementation in Rust - ----- - -### Store: Status - -- - Whole Merkle-based store implementation (and Nix NAR compat layer) is there - - - exercised by the output path CI tests, and a test suite. - - - three backends (Sled, in-memory, gRPC client) - - - more backends and more test suites planned. -- - FUSE filesystem to expose the store (to Tvix Builders, \"appliances\") - -Note: backends: RocksDB, sqlite, s3. fuse: lazy fetching of build input files | think about a minimal initrd to bring up network and mount the store, then run any closure. - ----- - -### Store: Demo - -[![asciicast](https://asciinema.org/a/YFB9yycHdx0OUH9N0WdAkIYua.svg)](https://asciinema.org/a/YFB9yycHdx0OUH9N0WdAkIYua) - ----- - -### Store: Status (cont.) -- - More work on store composition needed (necessary for substition and caching) -- - More work on more granular blob substititon needed. -- - More work on bridges with Nix needed - - - Get Nix to talk to a tvix-store - - - Expose existing binary caches to tvix-store - ---- - -### Builder: Design - -- - Build requests/Build protocol is less Nix-specific - - - allows reusing builders for other usages (non-sandboxed builds, other build systems, playing with other addressing mechanisms) -- - Distinction between a **specific build attempt** and the **general build recipe** - - - allows keeping metadata about failed builds - - - stats (memory/cpu consumption) - - - comparing different produced binary outputs (r11y) - ----- - -### Builder: Design - -- - Invididual builds can be run in your desired container/virt engine/scheduler, as long as it speaks the same Build API -- - Build API composition/proxying, similar to Store composition -- - allows "unattended building" (evaluate nixpkgs locally and send all build requests to a remote builder) -- - allows tailing logs from currently/already running builds - ----- - -### Builder: Status - -- - Dummy Builder implementation in `go-nix` (using OCI) -- - Some scribble notes on the Build Protocol -- - Glue code to trigger builds from inside `builtins.derivation` needs to be written -- - Builder implementation (using `systemd-nspwan` or some container engine needs to be written. -- - Web interface to visualize store contents and build graphs/builds/logs - ---- - -## Contributing - -- - Join the IRC channel (`#tvl` on `hackint`), bridged to Matrix and XMPP -- - Check our issue tracker -- - Try to use it and tell us how you broke it! -- - Add various Nix bits to `nix-compat` - -Note: or if you like what you seeing and want to sponsor parts, that's also cool :-) - ---- - -# Thanks to... - -- - all TVL contributors (some drive-by, some long-term contributors) -- - countless Nix community members for their input on the architecture and rubberducking -- - NLNET and others to sponsor parts of this - ----- - -# Questions? - - - -
    - -
    -Florian Klink / flokli.de
    - -
    - -
    -Tvix / tvix.dev
    - -
    - -
    diff --git a/users/flokli/presentations/2023-09-09-nixcon-tvix/tvix-store-graph.svg b/users/flokli/presentations/2023-09-09-nixcon-tvix/tvix-store-graph.svg deleted file mode 100644 index 56338b587..000000000 --- a/users/flokli/presentations/2023-09-09-nixcon-tvix/tvix-store-graph.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - 0x01 0x02 0x030x04 0x05BlobsDirectoriesdirectories: []files: - name: .keep digest: <empty-blob-digest> size: 0 executable: falsesymlinks: []directories: - name: keep digest: <directory-with-keep-digest> size: 1 executable: falsefiles: - name: .keep digest: <empty-blob-digest> size: 0 executable: falsesymlinks: - name: aa target: /nix/store/somewhereelsedirectories: []files: []symlinks: []directories: - name: a digest: <directory-a-digest> size: 0files: []symlinks: []DIRECTORY_WITH_KEEPDIRECTORY_COMPLICATEDDIRECTORY_ADIRECTORY_BBLOB_ABLOB_BBLOB_EMPTYPathInfonode: symlink: name: 00000000000000000000000000000000-test target: /fooreferences: []narinfo: …node: directory: name: 11111111111111111111111111111111-test digest: <directory-complicated-digest> size: 4references: []narinfo: …node: directory: name: 22222222222222222222222222222222-test digest: <directory-with-keep-digest> size: 1references: []narinfo: …node: file: name: 33333333333333333333333333333333-test digest: <blob-a-digest> size: 3 executable: falsereferences: []narinfo: … \ No newline at end of file diff --git a/users/flokli/presentations/2023-09-09-nixcon-tvix/tvixbolt.webm b/users/flokli/presentations/2023-09-09-nixcon-tvix/tvixbolt.webm deleted file mode 100644 index 69bd20f19..000000000 Binary files a/users/flokli/presentations/2023-09-09-nixcon-tvix/tvixbolt.webm and /dev/null differ diff --git a/users/flokli/presentations/2023-09-13-asg-tvix-store/default.nix b/users/flokli/presentations/2023-09-13-asg-tvix-store/default.nix deleted file mode 100644 index e1709a067..000000000 --- a/users/flokli/presentations/2023-09-13-asg-tvix-store/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (pkgs) - fontconfig qrencode runCommand stdenv; - mkQr = url: runCommand "qrcode.png" { } '' - ${qrencode}/bin/qrencode -o $out -t SVG -s 5 \ - --background=fafafa \ - --foreground=000000 \ - ${url} - ''; -in -stdenv.mkDerivation { - name = "2023-asg-tvix-store"; - src = ./.; - - FONTCONFIG_FILE = pkgs.makeFontsConf { - fontDirectories = with pkgs; [ jetbrains-mono fira fira-code fira-mono lato ]; - }; - - nativeBuildInputs = [ pkgs.reveal-md pkgs.graphviz ]; - - buildPhase = '' - cp ${depot.tvix.logo}/logo.png tvix-logo.png - cp ${mkQr "https://flokli.de"} qrcode-flokli.svg - cp ${mkQr "https://tvix.dev"} qrcode-tvix.svg - - mkdir -p $out - cp tvix-store-graph-blob-directory.svg $out/ - reveal-md --static $out presentation.md - - CHROME_CONFIG_HOME=/build/.config reveal-md presentation.md --print $out/slides.pdf --puppeteer-chromium-executable="${pkgs.chromium}/bin/chromium" - # Above command doesn't fail on error, ensure file has been created - [[ -f "$out/slides.pdf" ]] || exit 1 - ''; -} diff --git a/users/flokli/presentations/2023-09-13-asg-tvix-store/presentation.md b/users/flokli/presentations/2023-09-13-asg-tvix-store/presentation.md deleted file mode 100644 index 978934f9a..000000000 --- a/users/flokli/presentations/2023-09-13-asg-tvix-store/presentation.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -author: -- Florian Klink -date: 2023-09-09 -title: "tvix-store: A content-addressed file system and sync protocol" -theme: moon -revealOptions: - transition: 'fade' ---- - -## tvix-store -### A content-addressed file system and sync protocol - -2023-09-13 - -Florian Klink / flokli - ---- - -## Whoami - -- - flokli -- - Nix/NixOS contributor - - maintain systemd, nss and more low-level stuff there -- - Freelance Nix/DevOps consultant - -Note: more Kubernetes/DevOps exposure with work - ---- - -## What is tvix-store? -- - A new implementation of a content-addressed "storage system" - - - part of the Tvix Project, a (WIP) reimplementation of Nix and auxillary components in Rust - - - Storage model: think about git trees and its Merkle DAG… - - - … but with nicer wire format (`.proto`) and hash function (blake3) - ---- - -## Storage model -- - Once you know the root: everything else is content-addressed - - - No timestamps, no uid/gid, no xattrs, only one way to represent the same tree -- - Automatic dedup of identical subtrees in different file system trees -- - Automatic dedup of identical blobs (and you can do more chunking underneath too) - ---- - -## Storage model (cont.) -- - Granular seekable access into blobs -- - verified streaming thanks to BLAKE3 and Bao, faulty data is detected early on -- - Everything below can be retrieved from anyone without having to trust (P2P substitution, CDNs, …) - ---- - -## Usecases -- - File system tree delivery -- - Container image delivery -- - Backing store for VCS -- - Granular access into large datasets - ---- - -## Status -- - In-memory backend, a local K/V backend (Sled) -- - FUSE filesystem -- - A gRPC API to transfer things, bindings for golang and rust -- - some object storage backends in development (GCS, NATS) -- - FUTUREWORK: more storage backends / store composition / in-kernel module? - -Notes: of course you can use your own network protocol too, like HTTP CAS or iroh....plug different stores together to represent caches, blobfs - ---- - -## Contributing - -- - Join the IRC channel (`#tvl` on `hackint`), bridged to Matrix and XMPP -- - Check our issue tracker -- - Try to use it and tell us how you broke it! - -Note: if this sounds useful to you, reach out! - ---- - -# Thanks! - - - -
    - -
    -Florian Klink / flokli.de
    - -
    - -
    -Tvix / tvix.dev
    - -
    - -
    - ---- - -## Structure - -[tvix-store graph](tvix-store-graph-blob-directory.svg) diff --git a/users/flokli/presentations/2023-09-13-asg-tvix-store/tvix-store-graph-blob-directory.svg b/users/flokli/presentations/2023-09-13-asg-tvix-store/tvix-store-graph-blob-directory.svg deleted file mode 100644 index 2c87350d5..000000000 --- a/users/flokli/presentations/2023-09-13-asg-tvix-store/tvix-store-graph-blob-directory.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - 0x01 0x02 0x030x04 0x05BlobsDirectoriesdirectories: []files: - name: .keep digest: <empty-blob-digest> size: 0 executable: falsesymlinks: []directories: - name: keep digest: <directory-with-keep-digest> size: 1 executable: falsefiles: - name: .keep digest: <empty-blob-digest> size: 0 executable: falsesymlinks: - name: aa target: /nix/store/somewhereelsedirectories: []files: []symlinks: []directories: - name: a digest: <directory-a-digest> size: 0files: []symlinks: []DIRECTORY_WITH_KEEPDIRECTORY_COMPLICATEDDIRECTORY_ADIRECTORY_BBLOB_ABLOB_BBLOB_EMPTY \ No newline at end of file diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/.gitignore b/users/flokli/presentations/2024-10-25-nixcon-tvix/.gitignore deleted file mode 100644 index 397b4a762..000000000 --- a/users/flokli/presentations/2024-10-25-nixcon-tvix/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.log diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/default.nix b/users/flokli/presentations/2024-10-25-nixcon-tvix/default.nix deleted file mode 100644 index f41f023d9..000000000 --- a/users/flokli/presentations/2024-10-25-nixcon-tvix/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (pkgs) - fontconfig qrencode runCommand stdenv; - mkQr = url: runCommand "qrcode.png" { } '' - ${qrencode}/bin/qrencode -o $out -t SVG -s 5 \ - --background=fafafa \ - --foreground=000000 \ - ${url} - ''; -in -stdenv.mkDerivation { - name = "2024-nixcon-tvix"; - src = ./.; - - FONTCONFIG_FILE = pkgs.makeFontsConf { - fontDirectories = with pkgs; [ jetbrains-mono fira fira-code fira-mono lato ]; - }; - - nativeBuildInputs = [ pkgs.reveal-md pkgs.graphviz ]; - - buildPhase = '' - cp ${depot.tvix.logo}/logo.png tvix-logo.png - cp ${mkQr "https://flokli.de"} qrcode-flokli.svg - cp ${mkQr "https://tvix.dev"} qrcode-tvix.svg - - mkdir -p $out - reveal-md --static $out presentation.md - - CHROME_CONFIG_HOME=/build/.config reveal-md presentation.md --print $out/slides.pdf --puppeteer-chromium-executable="${pkgs.chromium}/bin/chromium" - # Above command doesn't fail on error, ensure file has been created - [[ -f "$out/slides.pdf" ]] || exit 1 - ''; - - # reveal-md presentation.md --print started timing out possibly due to - # chromium: 133.0.6943.141 -> 134.0.6998.35 - meta.ci.skip = true; -} diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/nar-bridge.png b/users/flokli/presentations/2024-10-25-nixcon-tvix/nar-bridge.png deleted file mode 100644 index 1cf449a99..000000000 Binary files a/users/flokli/presentations/2024-10-25-nixcon-tvix/nar-bridge.png and /dev/null differ diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/nix-compat.png b/users/flokli/presentations/2024-10-25-nixcon-tvix/nix-compat.png deleted file mode 100644 index 958ce1bf8..000000000 Binary files a/users/flokli/presentations/2024-10-25-nixcon-tvix/nix-compat.png and /dev/null differ diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/presentation.md b/users/flokli/presentations/2024-10-25-nixcon-tvix/presentation.md deleted file mode 100644 index 342774415..000000000 --- a/users/flokli/presentations/2024-10-25-nixcon-tvix/presentation.md +++ /dev/null @@ -1,261 +0,0 @@ ---- -author: -- Florian Klink -date: 2024-10-25 -title: "Tvix: Status update" -theme: solarized -revealOptions: - transition: 'fade' ---- - -# Tvix: Status update - -![Tvix Logo](tvix-logo.png) - -2024-10-25 - -Florian Klink (flokli) - ---- - -## Whoami - -- flokli -- nixpkgs contributor since 2018, maintaining systemd, nsncd and more -- Freelance Nix/DevOps consultant - ---- - -## What is Tvix? - ---- - -![tvix solves this](./tvix_solves_this.jpg) - - ---- - -## What is Tvix? - -- A Rust re-implementation of the components of the Nix package manager -- Uses different underlying approaches while retaining Nix compatibility "on the surface" -- modular architecture, allowing to recombine aspects to solve your usecase -- No "end-user CLI" for now, focus on getting the foundational architecture right and 100% correctness with Nix - ---- - -## Topics -- Component overview -- Recent developments -- Next steps - -Note: Component overview, to understand a bit better how it's different / updates since the last talk / outlook on roadmap - ---- - -## Structure - - - - **tvix-castore**, the granular data storage/syncing engine. - - - **tvix-store**, the "Nix store implementation" on top of tvix-castore - - - **nix-compat**, a library providing access to data formats, protocols and concepts - - - **tvix-eval**, a bytecode interpreter evaluator and core Nix *language* concepts and builtins - - - **tvix-build**, a generic builder interface - - - **tvix-glue**, combines tvix-eval with tvix-[ca]store and tvix-build - - -Note: one big cargo workspace / go into detail later! / nix-compat: concepts like output path calculation, doesn't depend on tvix crates -tvix-eval: language concepts being Scopes, Thunks, Nix values, "core builtins" - ----- - -![tvix-castore](./tvix-castore.png) - - -Note: Nix does do content addressing on a store path level, we're on a per-file/chunk in file. That model allows granular syncing and reuse of parts, which will speedup substitution/copying. Because everything is ca, it'll also allow decentralization and local p2p substitution. Think about everyone in the same room serving chunks. verified streaming. - ----- - -![tvix-store](./tvix-store.png) - - -Note: track all metadata about store paths (think about the sqlite db), and link to castore instead of storing NAR. NarCalculation: this computation, is super nice to cache, as this info -never needs to expire, and is reconstructable in a pure CA manner. - ----- - -![tvix-store](./nix-compat.png) - - -Note: kept as a somewhat separate library, Tvix "first consumer". But use from your code, it doesn't depend on Tvix bits. Regularly factoring out Nix concepts into this library - ----- - -![tvix-eval](./tvix-eval.png) - - -Note: only includes basic builtins, like string manipulation, math, …. Other crates can bring their own builtins - ----- - -![tvix-build](./tvix-build.png) - - -Note: Not aware of Nix, store paths etc. just flexible enough to express everything in there. Use it for your own build system! - ----- - -![tvix-glue](./tvix-glue.png) - - -Note: connects the evaluator to store and builders - ----- - -![nar-bridge](./nar-bridge.png) - - -Note: Example on how to use this: Nix HTTP binary cache lens into tvix-[ca]store, allows Nix to download from and push into. It renders NARs on-the-fly - ---- - -## Updates -Rough overview. Check blog posts and `git log` for details! - ----- - -## Updates (#1) - - - - Fixes on error catchability and context behaviour - - - More compact Nix Value types (memory-wise) - - - `tvix-cli` REPL global scope manipulation (assign variables and use them in next command) - - - `firefox.outPath` and `pkgsCross.aarch64-multiplatform.firefox.outPath` correct and added to CI 🎉 - -Notes: catchability/context to align behaviour with nix / … / assign variables and use them in the next REPL command - ----- - -## Updates (#2) - - - - OpenTelemetry integration, trace propagation throughout the entire stack - - - more backends in tvix-[ca]store (`object_store`/`local fs`/`redb`/`bigtable`/…) - - - nar-bridge RIIR, was deployed as a fetch-through cache for cache.nixos.org at Bornhack - - - store composition/combinators - - - wiring up of builds (without reference propagation yet, but reference scanning) - -Notes: o11y already proven super helpful for debugging where time is spent / first version of composition / builds waiting on reference propagation - ----- - -## Other Updates - - - - A lot of the tooling for `cache.nixos.org` usage / closure analysis making use of and contributing to `nix-compat` (`@edef`) 🎉 - - - "Replit using `tvix-[ca]store` and reporting 10x storage reduction" (`@cbrewster`) 🎉 - - - "Devenv is switching to Tvix" (Talk on Saturday 12:55, `@domenkozar`) 🎉 - ---- - -## Next steps (in no specific order): - - - - Test suite classification system, to decouple test cases from test runner and share with other Nix impls - - - (Continuous) Docs deployment, website restructuring - - - Interactions with the evaluator (LSP, DAP) - - - Persistent deployment of nar-bridge, as fetch-through cache for `cache.nixos.org` - - - Blob / Chunking protocol improvements (use local chunks where possible, allow readahead) - -Note: Allows filtering, reusing test cases in Nixcpp and Lix. - Mention some behavorial changes found. - Mention fetchTree - Make it easier for new contributors to get started - LSP / Debug adapter protocol / tvix-eval jobs - / … / is gonna improve performance for IO into store paths - ----- - -## Next steps (in no specific order) (cont.): - - - - "Build/Fetch realization goal engine" (tradeoff network bandwidth and CPU time) - - - More per-store metrics and instance names - - - More backends (p2p discovery, ipfs, …) - -Note: needed for builds / to get better insights into cache hit ratios etc. - ---- - -## Contributing - -- - Join the IRC channel (`#tvix-dev` on `hackint`), bridged to Matrix and XMPP -- - Check our issue tracker (b.tvl.fyi), as well as `tvix/docs/src/TODO.md` (but ask!) -- - Try to use it and tell us how you broke it! -- - Sponsoring - -Note: make sure to ask in the channel to ensure noone is already working on this - ---- - -# Thanks to... - -- - all Tvix contributors -- - Nix community members for their input on the architecture -- - Sponsors - -Note: some drive-by, some sticking around longer / NLNET / Clan - ----- - -# Questions? - - - -
    - -
    -Florian Klink / flokli.de
    - -
    - -
    -Tvix / tvix.dev
    - -
    - -
    diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-build.png b/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-build.png deleted file mode 100644 index 5d11e73f7..000000000 Binary files a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-build.png and /dev/null differ diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-castore.png b/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-castore.png deleted file mode 100644 index c1f42e111..000000000 Binary files a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-castore.png and /dev/null differ diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-eval.png b/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-eval.png deleted file mode 100644 index e7c034e67..000000000 Binary files a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-eval.png and /dev/null differ diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-glue.png b/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-glue.png deleted file mode 100644 index 00427aa14..000000000 Binary files a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-glue.png and /dev/null differ diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-store.png b/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-store.png deleted file mode 100644 index c35723afc..000000000 Binary files a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix-store.png and /dev/null differ diff --git a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix_solves_this.jpg b/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix_solves_this.jpg deleted file mode 100644 index d5494b1ec..000000000 Binary files a/users/flokli/presentations/2024-10-25-nixcon-tvix/tvix_solves_this.jpg and /dev/null differ diff --git a/users/fogti/.gitignore b/users/fogti/.gitignore deleted file mode 100644 index b8553ace5..000000000 --- a/users/fogti/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.#* -target/ diff --git a/users/fogti/OWNERS b/users/fogti/OWNERS deleted file mode 100644 index fb396265c..000000000 --- a/users/fogti/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -fogti diff --git a/users/fogti/dbwospof.md b/users/fogti/dbwospof.md deleted file mode 100644 index f1d68cde0..000000000 --- a/users/fogti/dbwospof.md +++ /dev/null @@ -1,112 +0,0 @@ -# distributed build without single points of failure - -## problem statement -> If we want to distribute a build across several build nodes, and want to avoid -> a "single point of failure", what needs to be considered? - -## motivation - -* distribute the build across several build nodes, because some packages take - extremely long to build - (e.g. `firefox`, `thunderbird`, `qtwebengine`, `webkitgtk`, ...) -* avoid a centralised setup like e.g. with Hydra, because we want to keep using - an on-demand workflow as usual with Nix - (e.g. `nixos-rebuild` on each host when necessary). - -## list of abbreviations - -
    -
    CA
    content-addressed
    -
    drv
    derivation
    -
    FOD
    fixed-output derivation
    -
    IHA
    input-hash-addressed
    -
    inhash
    input hash
    -
    outhash
    output hash
    -
    - -## build graph - -The build graph can't be easily distributed. It is instead left on the coordinator, -and the build nodes just get individual build jobs, which just consist of -derivations (and some information about how to get the inputs from some central -or distributed store (e.g. Ceph), this may be transmitted "out of band"). - -## inhash-exclusive - -It is necessary that each derivation build is exclusive in the sense that -the same derivation is never build multiple times simultaneously, because -this otherwise either wastes compute resources (obviously) and, in the case -of non-deterministic builds, increases complexity -(the store needs to decide which result to prefer, and the build nodes with -"losing" build results need to pull the "winning" build results from the store, -replacing the local version). Although this might be unnecessary in case -of IHA drvs, enforcing it always reduces the amount of possible suprising -results when mixing CA drvs and IHA drvs. - -## what can be meaningfully distributed - -The following is strongly opinionated, but I consider the following -(based upon the original build graph implementation from yzix 12.2021): -* We can't push the entire build graph to each build node, because they would - overlap 100%, and thus create extreme contention on the inhash-exclusive lock -* We could try to split the build graph into multiple parts with independent - inputs (partitioning), but this can be really complex, and I'm not sure - if it is worth it... This also basically excludes the yzix node types - [ `Eval`, `AssertEqual` ] (should be done by the evaluator). - Implementing this option however would make an abort of a build graph - (the simple variant does not kill running tasks, - just stop new tasks from being scheduled) really hard, and complex to get right. -* It does not make sense to distribute "node tasks" across build nodes which - almost exclusively interact with the store, and are not CPU-bound, but I/O bound. - This applies to most, if not all, useful FODs. It applies to the yzix node types - [ `Dump`, `UnDump`, `Fetch`, `Require` ] (should be performed by evaluator+store). -* TODO: figure out how to do forced rebuilds (e.g. also prefer a node which is not - the build node of the previous realisation of that task) - -## coarse per-derivation workflow - -``` - derivation - | | - | | - key build - | | - | | - V V - inhash outhash - | (either CA or IHA) - \ / - \ / - \ / - realisation -``` - -## build results - -Just for completeness, two build results are currently considered: - -* success: the build succeeded, and the result is uploaded to the central store -* failure: the build failed (e.g. build process terminated via error exit code or was killed) -* another case might be "partial": the build succeeded, but uploading to the - central store failed (the result is only available on the build node that built it). - This case is interesting, because we don't need to rerun the build, just the upload step - needs to be fixed/done semi-manually (e.g. maybe the central store ran out of storage, - or the network was unavailable) - -## build task queue - -It is naïve to think that something like a queue via `rabbitmq` (`AMQP`) or `MQTT` -suffices, because some requirements are missing: - -1. some way to push build results to the clients, and these should be associated - to the build inputs (a hacky way might use multiple queues for that, e.g. - a `tasks` input queue and a `done` output queue). -2. some way to lock "inhashes" (see section inhash-exclusive). - -The second point is somewhat easy to realise using `etcd`, and using the `watch` -mechanism it can be used to simulate a queue, and the inhash-addressing of -queued derivations can be seamlessly integrated. - -TODO: maybe we want to adjust the priorities of tasks in the queue, but Nix currently -doesn't seem to do this, so consider this only when it starts to make sense as a -performance or lag optimization. diff --git a/users/fogti/store-ref-scanner/.gitignore b/users/fogti/store-ref-scanner/.gitignore deleted file mode 100644 index 5a44eef09..000000000 --- a/users/fogti/store-ref-scanner/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/Cargo.lock diff --git a/users/fogti/store-ref-scanner/Cargo.toml b/users/fogti/store-ref-scanner/Cargo.toml deleted file mode 100644 index 624cfc0c6..000000000 --- a/users/fogti/store-ref-scanner/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "store-ref-scanner" -version = "0.1.0" -description = "scanner/extractor of Nix-like store paths from byte arrays/streams" -license = "MIT OR Apache-2.0" -categories = ["no-std", "parsing"] -edition = "2021" -homepage = "https://code.tvl.fyi/tree/users/fogti/store-ref-scanner" -include = ["/src"] - -[dependencies] diff --git a/users/fogti/store-ref-scanner/default.nix b/users/fogti/store-ref-scanner/default.nix deleted file mode 100644 index 38f3fd64e..000000000 --- a/users/fogti/store-ref-scanner/default.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - sourceFilter = name: type: - let - baseName = builtins.baseNameOf (builtins.toString name); - in - (baseName == "Cargo.toml") - || (type == "directory" && baseName == "src") - || (lib.hasSuffix ".rs" baseName) - ; -in - -pkgs.buildRustCrate rec { - pname = "store-ref-scanner"; - crateName = "store-ref-scanner"; - version = "0.1.0"; - edition = "2021"; - src = lib.cleanSourceWith { filter = sourceFilter; src = ./.; }; - - passthru.tests = pkgs.buildRustCrate { - pname = "store-ref-scanner-tests"; - inherit crateName src version edition; - buildTests = true; - postInstall = '' - set -ex - export RUST_BACKTRACE=1 - # recreate a file hierarchy as when running tests with cargo - # the source for test data - # build outputs - testRoot=target/debug - mkdir -p $testRoot - chmod +w -R . - # test harness executables are suffixed with a hash, - # like cargo does this allows to prevent name collision - # with the main executables of the crate - hash=$(basename $out) - ls -lasR $out - for file in $out/tests/*; do - f=$testRoot/$(basename $file)-$hash - cp $file $f - $f 2>&1 | tee -a $out/tests.log - done - rm -rf $out/tests - set +ex - ''; - }; - -} diff --git a/users/fogti/store-ref-scanner/fuzz/.gitignore b/users/fogti/store-ref-scanner/fuzz/.gitignore deleted file mode 100644 index b400c2782..000000000 --- a/users/fogti/store-ref-scanner/fuzz/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -corpus -artifacts diff --git a/users/fogti/store-ref-scanner/fuzz/Cargo.lock b/users/fogti/store-ref-scanner/fuzz/Cargo.lock deleted file mode 100644 index 7395dec05..000000000 --- a/users/fogti/store-ref-scanner/fuzz/Cargo.lock +++ /dev/null @@ -1,44 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "arbitrary" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "510c76ecefdceada737ea728f4f9a84bd2e1ef29f1ba555e560940fe279954de" - -[[package]] -name = "cc" -version = "1.0.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" - -[[package]] -name = "libfuzzer-sys" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a9a84a6e8b55dfefb04235e55edb2b9a2a18488fcae777a6bdaa6f06f1deb3" -dependencies = [ - "arbitrary", - "cc", - "once_cell", -] - -[[package]] -name = "once_cell" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" - -[[package]] -name = "store-ref-scanner" -version = "0.1.0" - -[[package]] -name = "store-ref-scanner-fuzz" -version = "0.0.0" -dependencies = [ - "libfuzzer-sys", - "store-ref-scanner", -] diff --git a/users/fogti/store-ref-scanner/fuzz/Cargo.toml b/users/fogti/store-ref-scanner/fuzz/Cargo.toml deleted file mode 100644 index 1832be003..000000000 --- a/users/fogti/store-ref-scanner/fuzz/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -name = "store-ref-scanner-fuzz" -version = "0.0.0" -authors = ["Automatically generated"] -publish = false -edition = "2018" - -[package.metadata] -cargo-fuzz = true - -[dependencies] -libfuzzer-sys = "0.4" - -[dependencies.store-ref-scanner] -path = ".." - -# Prevent this from interfering with workspaces -[workspace] -members = ["."] - -[[bin]] -name = "hbm-roundtrip" -path = "fuzz_targets/hbm-roundtrip.rs" -test = false -doc = false - -[[bin]] -name = "nocrash" -path = "fuzz_targets/nocrash.rs" -test = false -doc = false - -[profile.release] -incremental = false -overflow-checks = true -panic = "abort" diff --git a/users/fogti/store-ref-scanner/fuzz/fuzz_targets/hbm-roundtrip.rs b/users/fogti/store-ref-scanner/fuzz/fuzz_targets/hbm-roundtrip.rs deleted file mode 100644 index 9e21a7738..000000000 --- a/users/fogti/store-ref-scanner/fuzz/fuzz_targets/hbm-roundtrip.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![no_main] -use libfuzzer_sys::fuzz_target; - -fuzz_target!(|data: [u8; 16]| { - use store_ref_scanner::HalfBytesMask; - let a = HalfBytesMask(data); - let b = a.into_expanded(); - let c = HalfBytesMask::from_expanded(b); - assert_eq!(a, c); -}); diff --git a/users/fogti/store-ref-scanner/fuzz/fuzz_targets/nocrash.rs b/users/fogti/store-ref-scanner/fuzz/fuzz_targets/nocrash.rs deleted file mode 100644 index 48100a628..000000000 --- a/users/fogti/store-ref-scanner/fuzz/fuzz_targets/nocrash.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![no_main] -use libfuzzer_sys::fuzz_target; - -fuzz_target!(|data: &[u8]| { - use store_ref_scanner::{StoreRefScanner, StoreSpec}; - - StoreRefScanner::new(&data[..], &StoreSpec::DFL_NIX2).count(); - StoreRefScanner::new(&data[..], &StoreSpec::DFL_YZIX1).count(); -}); diff --git a/users/fogti/store-ref-scanner/src/hbm.rs b/users/fogti/store-ref-scanner/src/hbm.rs deleted file mode 100644 index 2520efd83..000000000 --- a/users/fogti/store-ref-scanner/src/hbm.rs +++ /dev/null @@ -1,167 +0,0 @@ -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -pub struct HalfBytesMask(pub [u8; 16]); - -#[allow(clippy::as_conversions, clippy::zero_prefixed_literal)] -impl HalfBytesMask { - pub const B32_REVSHA256: HalfBytesMask = - HalfBytesMask([0, 0, 0, 0, 0, 0, 255, 3, 0, 0, 0, 0, 222, 127, 207, 7]); - - pub const B64_BLAKE2B256: HalfBytesMask = HalfBytesMask([ - 0, 0, 0, 0, 0, 8, 255, 3, 254, 255, 255, 135, 254, 255, 255, 7, - ]); - - pub const DFL_REST: HalfBytesMask = HalfBytesMask([ - 0, 0, 0, 0, 0, 104, 255, 163, 254, 255, 255, 135, 254, 255, 255, 7, - ]); - - #[inline] - pub const fn from_expanded(x: [bool; 128]) -> Self { - let mut ret = [0u8; 16]; - let mut idx = 0; - while idx < 16 { - let fin = idx * 8; - let mut idx2 = 0; - while idx2 < 8 { - if x[fin + idx2] { - ret[idx] += (1 << idx2) as u8; - } - idx2 += 1; - } - idx += 1; - } - Self(ret) - } - - /// create a mask by allowing all characters via the mask which are included in the given string - pub fn from_bytes(s: &[u8]) -> Self { - s.iter().fold(Self([0u8; 16]), |mut ret, &i| { - ret.set(i, true); - ret - }) - } - - pub const fn into_expanded(self) -> [bool; 128] { - let Self(ihbm) = self; - let mut ret = [false; 128]; - let mut idx = 0; - while idx < 16 { - let fin = idx * 8; - let curi = ihbm[idx]; - let mut idx2 = 0; - while idx2 < 8 { - ret[fin + idx2] = (curi >> idx2) & 0b1 != 0; - idx2 += 1; - } - idx += 1; - } - ret - } - - pub fn contains(&self, byte: u8) -> bool { - if byte >= 0x80 { - false - } else { - (self.0[usize::from(byte / 8)] >> u32::from(byte % 8)) & 0b1 != 0 - } - } - - pub fn set(&mut self, byte: u8, allow: bool) { - if byte >= 0x80 { - if cfg!(debug_assertions) { - panic!( - "tried to manipulate invalid byte {:?} in HalfBytesMask", - byte - ); - } else { - return; - } - } - let block = &mut self.0[usize::from(byte / 8)]; - let bitpat = (1 << u32::from(byte % 8)) as u8; - if allow { - *block |= bitpat; - } else { - *block &= !bitpat; - } - } - - #[cfg(test)] - fn count_ones(&self) -> u8 { - self.0 - .iter() - .map(|i| i.count_ones()) - .sum::() - .try_into() - .unwrap() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn maskbase() { - assert_eq!(HalfBytesMask::B32_REVSHA256.count_ones(), 32); - assert_eq!(HalfBytesMask::B64_BLAKE2B256.count_ones(), 64); - } - - #[test] - fn non_ascii() { - for i in 0x80..=0xff { - assert!(!HalfBytesMask::DFL_REST.contains(i)); - } - } - - #[test] - fn dflmask() { - assert_eq!( - HalfBytesMask::from_expanded( - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ] - .map(|i| i != 0) - ), - Default::default(), - ); - - assert_eq!( - HalfBytesMask::from_expanded( - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - ] - .map(|i| i != 0) - ), - HalfBytesMask::B32_REVSHA256, - ); - - assert_eq!( - HalfBytesMask::from_expanded( - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, - ] - .map(|i| i != 0) - ), - HalfBytesMask::B64_BLAKE2B256, - ); - - assert_eq!( - HalfBytesMask::from_bytes( - b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-._?=" - ), - HalfBytesMask::DFL_REST, - ); - } -} diff --git a/users/fogti/store-ref-scanner/src/lib.rs b/users/fogti/store-ref-scanner/src/lib.rs deleted file mode 100644 index 0f86a769f..000000000 --- a/users/fogti/store-ref-scanner/src/lib.rs +++ /dev/null @@ -1,215 +0,0 @@ -#![no_std] -#![forbid(clippy::cast_ptr_alignment, trivial_casts, unconditional_recursion)] -#![deny(clippy::as_conversions)] - -mod hbm; -pub use hbm::HalfBytesMask; - -mod spec; -pub use spec::*; - -/// limit maximal length of store basename -const BASENAME_MAXLEN: usize = 255; - -/// this is a trait which implements the interface of possible inputs -/// (usually byte slices) -pub trait ScannerInput: AsRef<[u8]> + Sized { - /// Splits the input into two at the given index. - /// Afterwards self contains elements [at, len), and the returned input part contains elements [0, at). - fn split_to(&mut self, at: usize) -> Self; - fn finish(&mut self); -} - -impl ScannerInput for &[u8] { - fn split_to(&mut self, at: usize) -> Self { - let (a, b) = self.split_at(at); - *self = b; - a - } - - fn finish(&mut self) { - *self = &[]; - } -} - -impl ScannerInput for &mut [u8] { - fn split_to(&mut self, at: usize) -> Self { - // Lifetime dance taken from `impl Write for &mut [u8]`. - // Taken from crate `std`. - let (a, b) = core::mem::take(self).split_at_mut(at); - *self = b; - a - } - - fn finish(&mut self) { - *self = &mut []; - } -} - -/// this is the primary structure of this crate -/// -/// it represents a scanner which scans binary slices for store references, -/// and implements an iterator interfaces which returns these as byte slices. -pub struct StoreRefScanner<'x, Input: 'x> { - input: Input, - spec: &'x StoreSpec<'x>, -} - -impl<'x, Input> StoreRefScanner<'x, Input> -where - Input: ScannerInput + 'x, -{ - pub fn new(input: Input, spec: &'x StoreSpec<'x>) -> Self { - for i in [&spec.valid_hashbytes, &spec.valid_restbytes] { - for j in [b'\0', b' ', b'\t', b'\n', b'/', b'\\'] { - assert!(!i.contains(j)); - } - } - Self { input, spec } - } -} - -impl<'x, Input: 'x> Iterator for StoreRefScanner<'x, Input> -where - Input: ScannerInput + 'x, -{ - type Item = Input; - - fn next(&mut self) -> Option { - let hbl: usize = self.spec.hashbytes_len.into(); - 'outer: while !self.input.as_ref().is_empty() { - if !self.spec.path_to_store.is_empty() { - let p2sas = self.spec.path_to_store; - while !self.input.as_ref().starts_with(p2sas.as_bytes()) { - if self.input.as_ref().is_empty() { - break 'outer; - } - self.input.split_to(1); - } - self.input.split_to(p2sas.len()); - if self.input.as_ref().is_empty() { - break 'outer; - } - } - let hsep = matches!(self.input.as_ref().iter().next(), Some(b'/') | Some(b'\\')); - self.input.split_to(1); - if hsep && self.spec.check_rest(self.input.as_ref()) { - // we have found a valid hash - // rest contains the store basename and all following components - // now let's search for the end - // and then cut off possible following components after the basename - let rlen = self - .input - .as_ref() - .iter() - .enumerate() - .take(BASENAME_MAXLEN) - .skip(hbl) - .find(|&(_, &i)| !self.spec.valid_restbytes.contains(i)) - .map(|(eosp, _)| eosp) - .unwrap_or_else(|| core::cmp::min(BASENAME_MAXLEN, self.input.as_ref().len())); - return Some(self.input.split_to(rlen)); - } - } - self.input.finish(); - None - } -} - -#[cfg(test)] -mod tests { - use super::*; - extern crate alloc; - use alloc::{vec, vec::Vec}; - - #[test] - fn simple_nix2() { - let drv: &[u8] = br#" - Derive([("out","","r:sha256","")],[("/nix/store/2ax7bvjdfkzim69q957i0jlg0nvmapg0-util-linux-2.37.2.drv",["dev"]),("/nix/store/6b55ssmh8pzqsc4q4kw1yl3kqvr4fvqj-bash-5.1-p12.drv",["out"]),("/nix/store/fp2vx24kczlzv84avds28wyzsmrn8kyv-source.drv",["out"]),("/nix/store/s6c2lm5hpsvdwnxq9y1g3ngncghjzc3k-stdenv-linux.drv",["out"]),("/nix/store/xlnzpf4mzghi8vl0krabrgcbnqk5qjf3-pkg-config-wrapper-0.29.2.drv",["out"])],["/nix/store/03sl46khd8gmjpsad7223m32ma965vy9-fix-static.patch","/nix/store/2q3z7587yhlz0i2xvfvvap42zk5carlv-bcache-udev-modern.patch","/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],"x86_64-linux","/0g15yibzzi3rmw29gqlbms05x9dbghbvh61v1qggydvmzh3bginw/bin/bash",["-e","/nix/store/9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh"],[("buildInputs","/0sdk1r4l43yw4g6lmqdhd92vhdfhlwz3m76jxzvzsqsv63czw2km"),("builder","/0g15yibzzi3rmw29gqlbms05x9dbghbvh61v1qggydvmzh3bginw/bin/bash"),("configureFlags",""),("depsBuildBuild",""),("depsBuildBuildPropagated",""),("depsBuildTarget",""),("depsBuildTargetPropagated",""),("depsHostHost",""),("depsHostHostPropagated",""),("depsTargetTarget",""),("depsTargetTargetPropagated",""),("doCheck",""),("doInstallCheck",""),("makeFlags","PREFIX=/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9 UDEVLIBDIR=/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9/lib/udev/"),("name","bcache-tools-1.0.7"),("nativeBuildInputs","/1kw0rwgdyq9q69wmmsa5d2kap6p52b0yldbzi4w17bhcq5g5cp2f"),("out","/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"),("outputHashAlgo","sha256"),("outputHashMode","recursive"),("outputs","out"),("patches","/nix/store/2q3z7587yhlz0i2xvfvvap42zk5carlv-bcache-udev-modern.patch /nix/store/03sl46khd8gmjpsad7223m32ma965vy9-fix-static.patch"),("pname","bcache-tools"),("preBuild","sed -e \"s|/bin/sh|/0g15yibzzi3rmw29gqlbms05x9dbghbvh61v1qggydvmzh3bginw/bin/sh|\" -i *.rules\n"),("preInstall","mkdir -p \"$out/sbin\" \"$out/lib/udev/rules.d\" \"$out/share/man/man8\"\n"),("prePatch","sed -e \"/INSTALL.*initramfs\\/hook/d\" \\\n -e \"/INSTALL.*initcpio\\/install/d\" \\\n -e \"/INSTALL.*dracut\\/module-setup.sh/d\" \\\n -e \"s/pkg-config/$PKG_CONFIG/\" \\\n -i Makefile\n"),("propagatedBuildInputs",""),("propagatedNativeBuildInputs",""),("src","/nix/store/6izcafvfcbz19chi7hl20834g0fa043n-source"),("stdenv","/01ncyv8bxibj0imgfvmxgqy648n697bachil6aw6i46g1jk0bbds"),("strictDeps",""),("system","x86_64-linux"),("version","1.0.7")]) - "#; - // we convert everything into strings because it is way easier to compare elements in error messages - let refs: Vec<&str> = StoreRefScanner::new(drv, &StoreSpec::DFL_NIX2) - .map(|i| core::str::from_utf8(i).unwrap()) - .collect(); - let refs_expect: Vec<&[u8]> = vec![ - b"2ax7bvjdfkzim69q957i0jlg0nvmapg0-util-linux-2.37.2.drv", - b"6b55ssmh8pzqsc4q4kw1yl3kqvr4fvqj-bash-5.1-p12.drv", - b"fp2vx24kczlzv84avds28wyzsmrn8kyv-source.drv", - b"s6c2lm5hpsvdwnxq9y1g3ngncghjzc3k-stdenv-linux.drv", - b"xlnzpf4mzghi8vl0krabrgcbnqk5qjf3-pkg-config-wrapper-0.29.2.drv", - b"03sl46khd8gmjpsad7223m32ma965vy9-fix-static.patch", - b"2q3z7587yhlz0i2xvfvvap42zk5carlv-bcache-udev-modern.patch", - b"9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh", - b"9krlzvny65gdc8s7kpb6lkx8cd02c25b-default-builder.sh", - b"2q3z7587yhlz0i2xvfvvap42zk5carlv-bcache-udev-modern.patch", - b"03sl46khd8gmjpsad7223m32ma965vy9-fix-static.patch", - b"6izcafvfcbz19chi7hl20834g0fa043n-source", - ]; - let refs_expect: Vec<&str> = refs_expect - .into_iter() - .map(|i| core::str::from_utf8(i).unwrap()) - .collect(); - assert_eq!(refs, refs_expect); - } - - #[test] - fn simple_yzix1() { - // I haven't yet produced any yzix derivation which included /yzixs absolute paths... - let fake: &[u8] = br#" - /yzixs/4Zx1PBoft1YyAuKdhjAY1seZFHloxQ+8voHQRkRMuys: ASCII text - /yzixs/dNE3yogD4JHKHzNa2t3jQMZddT8wjqlMDB0naDIFo0A: ASCII text - /yzixs/FMluSVOHLc4bxX7F4lBCXafNljBnDn+rAM5HzG7k8LI: unified diff output, ASCII text - /yzixs/g2G3GRL87hGEdw9cq2BZWqDQP_HeHSPRLbJ9P9KH+HI: unified diff output, ASCII text - /yzixs/H08Av1ZAONwFdzVLpFQm0Sc0dvyk0sbnk82waoBig7I: ASCII text - /yzixs/IndARQp+gaGDLS3K+PeyXdaRqAcCyS3EIbRXkkYjC94: unified diff output, ASCII text - /yzixs/IrLPnbkEolTAuWRxkXpuvVs6Imb1iB6wUJcI+fxWwkU: POSIX shell script, ASCII text executable - /yzixs/JsS_H3n3TSh2R6fiIzgOPZdjSmRkV71vGxstJJKPmr4: unified diff output, ASCII text - /yzixs/LZ6pQh1x8DRxZ2IYzetBRS4LuE__IXFjpOfQPxHVwpw: unified diff output, ASCII text - /yzixs/mEi2RPep9daRs0JUvwt1JsDfgYSph5sH_+_ihwn8IGQ: ASCII text - /yzixs/nd4DyljinP3auDMHL_LrpsRJkWQpSHQK2jqtyyzWcBA: POSIX shell script, ASCII text executable - /yzixs/nzpaknF0_ONSHtd0i_e1E3pkLF1QPeJQhAB7x9Ogo_M: unified diff output, ASCII text - /yzixs/UZ3uzVUUMC1gKGLw6tg_aLFwoFrJedXB3xbhEgQOaiY: unified diff output, ASCII text - /yzixs/VKyXxKTXsDGxYJ24YgbvCc1bZkA5twp3TC+Gbi4Kwd8: unified diff output, ASCII text - /yzixs/VPJMl8O1xkc1LsJznpoQrCrQO0Iy+ODCPsgoUBLiRZc: unified diff output, ASCII text - /yzixs/W6r1ow001ASHRj+gtRfyj9Fb_gCO_pBztX8WhYXVdIc: unified diff output, ASCII text - /yzixs/xvwEcXIob_rQynUEtQiQbwaDXEobTVKEGaBMir9oH9k: unified diff output, ASCII text - /yzixs/ZPvQbRJrtyeSITvW3FUZvw99hhNOO3CFqGgmWgScxcg: ASCII text - "#; - let refs: Vec<&str> = StoreRefScanner::new(fake, &StoreSpec::DFL_YZIX1) - .map(|i| core::str::from_utf8(i).unwrap()) - .collect(); - let refs_expect: Vec<&[u8]> = vec![ - b"4Zx1PBoft1YyAuKdhjAY1seZFHloxQ+8voHQRkRMuys", - b"dNE3yogD4JHKHzNa2t3jQMZddT8wjqlMDB0naDIFo0A", - b"FMluSVOHLc4bxX7F4lBCXafNljBnDn+rAM5HzG7k8LI", - b"g2G3GRL87hGEdw9cq2BZWqDQP_HeHSPRLbJ9P9KH+HI", - b"H08Av1ZAONwFdzVLpFQm0Sc0dvyk0sbnk82waoBig7I", - b"IndARQp+gaGDLS3K+PeyXdaRqAcCyS3EIbRXkkYjC94", - b"IrLPnbkEolTAuWRxkXpuvVs6Imb1iB6wUJcI+fxWwkU", - b"JsS_H3n3TSh2R6fiIzgOPZdjSmRkV71vGxstJJKPmr4", - b"LZ6pQh1x8DRxZ2IYzetBRS4LuE__IXFjpOfQPxHVwpw", - b"mEi2RPep9daRs0JUvwt1JsDfgYSph5sH_+_ihwn8IGQ", - b"nd4DyljinP3auDMHL_LrpsRJkWQpSHQK2jqtyyzWcBA", - b"nzpaknF0_ONSHtd0i_e1E3pkLF1QPeJQhAB7x9Ogo_M", - b"UZ3uzVUUMC1gKGLw6tg_aLFwoFrJedXB3xbhEgQOaiY", - b"VKyXxKTXsDGxYJ24YgbvCc1bZkA5twp3TC+Gbi4Kwd8", - b"VPJMl8O1xkc1LsJznpoQrCrQO0Iy+ODCPsgoUBLiRZc", - b"W6r1ow001ASHRj+gtRfyj9Fb_gCO_pBztX8WhYXVdIc", - b"xvwEcXIob_rQynUEtQiQbwaDXEobTVKEGaBMir9oH9k", - b"ZPvQbRJrtyeSITvW3FUZvw99hhNOO3CFqGgmWgScxcg", - ]; - let refs_expect: Vec<&str> = refs_expect - .into_iter() - .map(|i| core::str::from_utf8(i).unwrap()) - .collect(); - assert_eq!(refs, refs_expect); - } - - #[test] - fn just_store() { - for i in [&StoreSpec::DFL_NIX2, &StoreSpec::DFL_YZIX1] { - let refs: Vec<&[u8]> = StoreRefScanner::new(i.path_to_store.as_bytes(), i).collect(); - assert!(refs.is_empty()); - } - } -} diff --git a/users/fogti/store-ref-scanner/src/spec.rs b/users/fogti/store-ref-scanner/src/spec.rs deleted file mode 100644 index 79da0842c..000000000 --- a/users/fogti/store-ref-scanner/src/spec.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::hbm::HalfBytesMask; - -pub struct StoreSpec<'path> { - /// path to store without trailing slash - pub path_to_store: &'path str, - - /// compressed map of allowed ASCII characters in hash part - pub valid_hashbytes: HalfBytesMask, - - /// compressed map of allowed ASCII characters in part after hash - pub valid_restbytes: HalfBytesMask, - - /// exact length of hash part of store paths - pub hashbytes_len: u8, -} - -impl StoreSpec<'_> { - pub(crate) fn check_rest(&self, rest: &[u8]) -> bool { - let hbl = self.hashbytes_len.into(); - rest.iter() - .take(hbl) - .take_while(|&&i| self.valid_hashbytes.contains(i)) - .count() - == hbl - } - - pub const DFL_NIX2: StoreSpec<'static> = StoreSpec { - path_to_store: "/nix/store", - valid_hashbytes: HalfBytesMask::B32_REVSHA256, - valid_restbytes: HalfBytesMask::DFL_REST, - hashbytes_len: 32, - }; - - pub const DFL_YZIX1: StoreSpec<'static> = StoreSpec { - path_to_store: "/yzixs", - valid_hashbytes: HalfBytesMask::B64_BLAKE2B256, - valid_restbytes: HalfBytesMask::DFL_REST, - hashbytes_len: 43, - }; -} diff --git a/users/j4m3s/OWNERS b/users/j4m3s/OWNERS deleted file mode 100644 index 9d95afbea..000000000 --- a/users/j4m3s/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -j4m3s diff --git a/users/j4m3s/keys.nix b/users/j4m3s/keys.nix deleted file mode 100644 index e5aaa3073..000000000 --- a/users/j4m3s/keys.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ ... }: - -{ - all = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH77KDNivaadAX0byGQgmel9hA7VcmFnL+IKYHgBVNVp tvl" - ]; -} diff --git a/users/kranzes/OWNERS b/users/kranzes/OWNERS deleted file mode 100644 index 7c5803bf4..000000000 --- a/users/kranzes/OWNERS +++ /dev/null @@ -1 +0,0 @@ -kranzes diff --git a/users/kranzes/wasm-hello-world/Cargo.lock b/users/kranzes/wasm-hello-world/Cargo.lock deleted file mode 100644 index 0f4b43856..000000000 --- a/users/kranzes/wasm-hello-world/Cargo.lock +++ /dev/null @@ -1,133 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "proc-macro2" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustversion" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" - -[[package]] -name = "syn" -version = "2.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm_hello_world" -version = "0.1.0" -dependencies = [ - "wasm-bindgen", -] diff --git a/users/kranzes/wasm-hello-world/Cargo.nix b/users/kranzes/wasm-hello-world/Cargo.nix deleted file mode 100644 index 75dcf7f5d..000000000 --- a/users/kranzes/wasm-hello-world/Cargo.nix +++ /dev/null @@ -1,1103 +0,0 @@ -# This file was @generated by crate2nix 0.14.1 with the command: -# "generate" "--all-features" -# See https://github.com/kolloch/crate2nix for more info. - -{ nixpkgs ? -, pkgs ? import nixpkgs { config = { }; } -, lib ? pkgs.lib -, stdenv ? pkgs.stdenv -, buildRustCrateForPkgs ? pkgs: pkgs.buildRustCrate - # This is used as the `crateOverrides` argument for `buildRustCrate`. -, defaultCrateOverrides ? pkgs.defaultCrateOverrides - # The features to enable for the root_crate or the workspace_members. -, rootFeatures ? [ "default" ] - # If true, throw errors instead of issueing deprecation warnings. -, strictDeprecation ? false - # Elements to add to the `-C target-feature=` argument passed to `rustc` - # (separated by `,`, prefixed with `+`). - # Used for conditional compilation based on CPU feature detection. -, targetFeatures ? [ ] - # Whether to perform release builds: longer compile times, faster binaries. -, release ? true - # Additional crate2nix configuration if it exists. -, crateConfig ? if builtins.pathExists ./crate-config.nix - then pkgs.callPackage ./crate-config.nix { } - else { } -}: - -rec { - # - # "public" attributes that we attempt to keep stable with new versions of crate2nix. - # - - rootCrate = rec { - packageId = "wasm_hello_world"; - - # Use this attribute to refer to the derivation building your root crate package. - # You can override the features with rootCrate.build.override { features = [ "default" "feature1" ... ]; }. - build = internal.buildRustCrateWithFeatures { - inherit packageId; - }; - - # Debug support which might change between releases. - # File a bug if you depend on any for non-debug work! - debug = internal.debugCrate { inherit packageId; }; - }; - # Refer your crate build derivation by name here. - # You can override the features with - # workspaceMembers."${crateName}".build.override { features = [ "default" "feature1" ... ]; }. - workspaceMembers = { - "wasm_hello_world" = rec { - packageId = "wasm_hello_world"; - build = internal.buildRustCrateWithFeatures { - packageId = "wasm_hello_world"; - }; - - # Debug support which might change between releases. - # File a bug if you depend on any for non-debug work! - debug = internal.debugCrate { inherit packageId; }; - }; - }; - - # A derivation that joins the outputs of all workspace members together. - allWorkspaceMembers = pkgs.symlinkJoin { - name = "all-workspace-members"; - paths = - let members = builtins.attrValues workspaceMembers; - in builtins.map (m: m.build) members; - }; - - # - # "internal" ("private") attributes that may change in every new version of crate2nix. - # - - internal = rec { - # Build and dependency information for crates. - # Many of the fields are passed one-to-one to buildRustCrate. - # - # Noteworthy: - # * `dependencies`/`buildDependencies`: similar to the corresponding fields for buildRustCrate. - # but with additional information which is used during dependency/feature resolution. - # * `resolvedDependencies`: the selected default features reported by cargo - only included for debugging. - # * `devDependencies` as of now not used by `buildRustCrate` but used to - # inject test dependencies into the build - - crates = { - "bumpalo" = rec { - crateName = "bumpalo"; - version = "3.16.0"; - edition = "2021"; - sha256 = "0b015qb4knwanbdlp1x48pkb4pm57b8gidbhhhxr900q2wb6fabr"; - authors = [ - "Nick Fitzgerald " - ]; - features = { - "allocator-api2" = [ "dep:allocator-api2" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "cfg-if" = rec { - crateName = "cfg-if"; - version = "1.0.0"; - edition = "2018"; - sha256 = "1za0vb97n4brpzpv8lsbnzmq5r8f2b0cpqqr0sy8h5bn751xxwds"; - libName = "cfg_if"; - authors = [ - "Alex Crichton " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - }; - "log" = rec { - crateName = "log"; - version = "0.4.21"; - edition = "2021"; - sha256 = "074hldq1q8rlzq2s2qa8f25hj4s3gpw71w64vdwzjd01a4g8rvch"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "kv_serde" = [ "kv_std" "value-bag/serde" "serde" ]; - "kv_std" = [ "std" "kv" "value-bag/error" ]; - "kv_sval" = [ "kv" "value-bag/sval" "sval" "sval_ref" ]; - "kv_unstable" = [ "kv" "value-bag" ]; - "kv_unstable_serde" = [ "kv_serde" "kv_unstable_std" ]; - "kv_unstable_std" = [ "kv_std" "kv_unstable" ]; - "kv_unstable_sval" = [ "kv_sval" "kv_unstable" ]; - "serde" = [ "dep:serde" ]; - "sval" = [ "dep:sval" ]; - "sval_ref" = [ "dep:sval_ref" ]; - "value-bag" = [ "dep:value-bag" ]; - }; - }; - "once_cell" = rec { - crateName = "once_cell"; - version = "1.19.0"; - edition = "2021"; - sha256 = "14kvw7px5z96dk4dwdm1r9cqhhy2cyj1l5n5b29mynbb8yr15nrz"; - authors = [ - "Aleksey Kladov " - ]; - features = { - "alloc" = [ "race" ]; - "atomic-polyfill" = [ "critical-section" ]; - "critical-section" = [ "dep:critical-section" "portable-atomic" ]; - "default" = [ "std" ]; - "parking_lot" = [ "dep:parking_lot_core" ]; - "portable-atomic" = [ "dep:portable-atomic" ]; - "std" = [ "alloc" ]; - }; - }; - "proc-macro2" = rec { - crateName = "proc-macro2"; - version = "1.0.85"; - edition = "2021"; - sha256 = "08zwg5l5f3czp62g4cvzgjwnk176lsrwq6kdi4x0arm9bbhlq912"; - libName = "proc_macro2"; - authors = [ - "David Tolnay " - "Alex Crichton " - ]; - dependencies = [ - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - features = { - "default" = [ "proc-macro" ]; - }; - resolvedDefaultFeatures = [ "default" "proc-macro" ]; - }; - "quote" = rec { - crateName = "quote"; - version = "1.0.36"; - edition = "2018"; - sha256 = "19xcmh445bg6simirnnd4fvkmp6v2qiwxh5f6rw4a70h76pnm9qg"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "proc-macro" ]; - "proc-macro" = [ "proc-macro2/proc-macro" ]; - }; - resolvedDefaultFeatures = [ "default" "proc-macro" ]; - }; - "rustversion" = rec { - crateName = "rustversion"; - version = "1.0.19"; - edition = "2018"; - sha256 = "1m39qd65jcd1xgqzdm3017ppimiggh2446xngwp1ngr8hjbmpi7p"; - procMacro = true; - build = "build/build.rs"; - authors = [ - "David Tolnay " - ]; - - }; - "syn" = rec { - crateName = "syn"; - version = "2.0.66"; - edition = "2021"; - sha256 = "1xfgrprsbz8j31kabvfinb4fyhajlk2q7lxa18fb006yl90kyby4"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - } - { - name = "quote"; - packageId = "quote"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - features = { - "default" = [ "derive" "parsing" "printing" "clone-impls" "proc-macro" ]; - "printing" = [ "dep:quote" ]; - "proc-macro" = [ "proc-macro2/proc-macro" "quote?/proc-macro" ]; - "test" = [ "syn-test-suite/all-features" ]; - }; - resolvedDefaultFeatures = [ "clone-impls" "default" "derive" "full" "parsing" "printing" "proc-macro" "visit" "visit-mut" ]; - }; - "unicode-ident" = rec { - crateName = "unicode-ident"; - version = "1.0.12"; - edition = "2018"; - sha256 = "0jzf1znfpb2gx8nr8mvmyqs1crnv79l57nxnbiszc7xf7ynbjm1k"; - libName = "unicode_ident"; - authors = [ - "David Tolnay " - ]; - - }; - "wasm-bindgen" = rec { - crateName = "wasm-bindgen"; - version = "0.2.100"; - edition = "2021"; - sha256 = "1x8ymcm6yi3i1rwj78myl1agqv2m86i648myy3lc97s9swlqkp0y"; - libName = "wasm_bindgen"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if"; - } - { - name = "once_cell"; - packageId = "once_cell"; - usesDefaultFeatures = false; - } - { - name = "rustversion"; - packageId = "rustversion"; - optional = true; - } - { - name = "wasm-bindgen-macro"; - packageId = "wasm-bindgen-macro"; - } - ]; - devDependencies = [ - { - name = "once_cell"; - packageId = "once_cell"; - } - ]; - features = { - "default" = [ "std" "msrv" ]; - "enable-interning" = [ "std" ]; - "msrv" = [ "rustversion" ]; - "rustversion" = [ "dep:rustversion" ]; - "serde" = [ "dep:serde" ]; - "serde-serialize" = [ "serde" "serde_json" "std" ]; - "serde_json" = [ "dep:serde_json" ]; - "strict-macro" = [ "wasm-bindgen-macro/strict-macro" ]; - "xxx_debug_only_print_generated_code" = [ "wasm-bindgen-macro/xxx_debug_only_print_generated_code" ]; - }; - resolvedDefaultFeatures = [ "default" "msrv" "rustversion" "std" ]; - }; - "wasm-bindgen-backend" = rec { - crateName = "wasm-bindgen-backend"; - version = "0.2.100"; - edition = "2021"; - sha256 = "1ihbf1hq3y81c4md9lyh6lcwbx6a5j0fw4fygd423g62lm8hc2ig"; - libName = "wasm_bindgen_backend"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "bumpalo"; - packageId = "bumpalo"; - } - { - name = "log"; - packageId = "log"; - } - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - features = [ "full" ]; - } - { - name = "wasm-bindgen-shared"; - packageId = "wasm-bindgen-shared"; - } - ]; - features = { - "extra-traits" = [ "syn/extra-traits" ]; - }; - }; - "wasm-bindgen-macro" = rec { - crateName = "wasm-bindgen-macro"; - version = "0.2.100"; - edition = "2021"; - sha256 = "01xls2dvzh38yj17jgrbiib1d3nyad7k2yw9s0mpklwys333zrkz"; - procMacro = true; - libName = "wasm_bindgen_macro"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "quote"; - packageId = "quote"; - } - { - name = "wasm-bindgen-macro-support"; - packageId = "wasm-bindgen-macro-support"; - } - ]; - features = { - "strict-macro" = [ "wasm-bindgen-macro-support/strict-macro" ]; - }; - }; - "wasm-bindgen-macro-support" = rec { - crateName = "wasm-bindgen-macro-support"; - version = "0.2.100"; - edition = "2021"; - sha256 = "1plm8dh20jg2id0320pbmrlsv6cazfv6b6907z19ys4z1jj7xs4a"; - libName = "wasm_bindgen_macro_support"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - features = [ "visit" "visit-mut" "full" ]; - } - { - name = "wasm-bindgen-backend"; - packageId = "wasm-bindgen-backend"; - } - { - name = "wasm-bindgen-shared"; - packageId = "wasm-bindgen-shared"; - } - ]; - features = { - "extra-traits" = [ "syn/extra-traits" ]; - }; - }; - "wasm-bindgen-shared" = rec { - crateName = "wasm-bindgen-shared"; - version = "0.2.100"; - edition = "2021"; - links = "wasm_bindgen"; - sha256 = "0gffxvqgbh9r9xl36gprkfnh3w9gl8wgia6xrin7v11sjcxxf18s"; - libName = "wasm_bindgen_shared"; - authors = [ - "The wasm-bindgen Developers" - ]; - dependencies = [ - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - - }; - "wasm_hello_world" = rec { - crateName = "wasm_hello_world"; - version = "0.1.0"; - edition = "2021"; - src = lib.cleanSourceWith { filter = sourceFilter; src = ./.; }; - type = [ "cdylib" ]; - dependencies = [ - { - name = "wasm-bindgen"; - packageId = "wasm-bindgen"; - } - ]; - - }; - }; - - # - # crate2nix/default.nix (excerpt start) - # - - /* Target (platform) data for conditional dependencies. - This corresponds roughly to what buildRustCrate is setting. - */ - makeDefaultTarget = platform: { - unix = platform.isUnix; - windows = platform.isWindows; - fuchsia = true; - test = false; - - inherit (platform.rust.platform) - arch - os - vendor; - family = platform.rust.platform.target-family; - env = "gnu"; - endian = - if platform.parsed.cpu.significantByte.name == "littleEndian" - then "little" else "big"; - pointer_width = toString platform.parsed.cpu.bits; - debug_assertions = false; - }; - - /* Filters common temp files and build files. */ - # TODO(pkolloch): Substitute with gitignore filter - sourceFilter = name: type: - let - baseName = builtins.baseNameOf (builtins.toString name); - in - ! ( - # Filter out git - baseName == ".gitignore" - || (type == "directory" && baseName == ".git") - - # Filter out build results - || ( - type == "directory" && ( - baseName == "target" - || baseName == "_site" - || baseName == ".sass-cache" - || baseName == ".jekyll-metadata" - || baseName == "build-artifacts" - ) - ) - - # Filter out nix-build result symlinks - || ( - type == "symlink" && lib.hasPrefix "result" baseName - ) - - # Filter out IDE config - || ( - type == "directory" && ( - baseName == ".idea" || baseName == ".vscode" - ) - ) || lib.hasSuffix ".iml" baseName - - # Filter out nix build files - || baseName == "Cargo.nix" - - # Filter out editor backup / swap files. - || lib.hasSuffix "~" baseName - || builtins.match "^\\.sw[a-z]$$" baseName != null - || builtins.match "^\\..*\\.sw[a-z]$$" baseName != null - || lib.hasSuffix ".tmp" baseName - || lib.hasSuffix ".bak" baseName - || baseName == "tests.nix" - ); - - /* Returns a crate which depends on successful test execution - of crate given as the second argument. - - testCrateFlags: list of flags to pass to the test exectuable - testInputs: list of packages that should be available during test execution - */ - crateWithTest = { crate, testCrate, testCrateFlags, testInputs, testPreRun, testPostRun }: - assert builtins.typeOf testCrateFlags == "list"; - assert builtins.typeOf testInputs == "list"; - assert builtins.typeOf testPreRun == "string"; - assert builtins.typeOf testPostRun == "string"; - let - # override the `crate` so that it will build and execute tests instead of - # building the actual lib and bin targets We just have to pass `--test` - # to rustc and it will do the right thing. We execute the tests and copy - # their log and the test executables to $out for later inspection. - test = - let - drv = testCrate.override - ( - _: { - buildTests = true; - release = false; - } - ); - # If the user hasn't set any pre/post commands, we don't want to - # insert empty lines. This means that any existing users of crate2nix - # don't get a spurious rebuild unless they set these explicitly. - testCommand = pkgs.lib.concatStringsSep "\n" - (pkgs.lib.filter (s: s != "") [ - testPreRun - "$f $testCrateFlags 2>&1 | tee -a $out" - testPostRun - ]); - in - pkgs.stdenvNoCC.mkDerivation { - name = "run-tests-${testCrate.name}"; - - inherit (crate) src; - - inherit testCrateFlags; - - buildInputs = testInputs; - - buildPhase = '' - set -e - export RUST_BACKTRACE=1 - - # build outputs - testRoot=target/debug - mkdir -p $testRoot - - # executables of the crate - # we copy to prevent std::env::current_exe() to resolve to a store location - for i in ${crate}/bin/*; do - cp "$i" "$testRoot" - done - chmod +w -R . - - # test harness executables are suffixed with a hash, like cargo does - # this allows to prevent name collision with the main - # executables of the crate - hash=$(basename $out) - for file in ${drv}/tests/*; do - f=$testRoot/$(basename $file)-$hash - cp $file $f - ${testCommand} - done - ''; - }; - in - pkgs.runCommand "${crate.name}-linked" - { - inherit (crate) outputs crateName; - passthru = (crate.passthru or { }) // { - inherit test; - }; - } - (lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) '' - echo tested by ${test} - '' + '' - ${lib.concatMapStringsSep "\n" (output: "ln -s ${crate.${output}} ${"$"}${output}") crate.outputs} - ''); - - /* A restricted overridable version of builtRustCratesWithFeatures. */ - buildRustCrateWithFeatures = - { packageId - , features ? rootFeatures - , crateOverrides ? defaultCrateOverrides - , buildRustCrateForPkgsFunc ? null - , runTests ? false - , testCrateFlags ? [ ] - , testInputs ? [ ] - # Any command to run immediatelly before a test is executed. - , testPreRun ? "" - # Any command run immediatelly after a test is executed. - , testPostRun ? "" - }: - lib.makeOverridable - ( - { features - , crateOverrides - , runTests - , testCrateFlags - , testInputs - , testPreRun - , testPostRun - }: - let - buildRustCrateForPkgsFuncOverriden = - if buildRustCrateForPkgsFunc != null - then buildRustCrateForPkgsFunc - else - ( - if crateOverrides == pkgs.defaultCrateOverrides - then buildRustCrateForPkgs - else - pkgs: (buildRustCrateForPkgs pkgs).override { - defaultCrateOverrides = crateOverrides; - } - ); - builtRustCrates = builtRustCratesWithFeatures { - inherit packageId features; - buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden; - runTests = false; - }; - builtTestRustCrates = builtRustCratesWithFeatures { - inherit packageId features; - buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden; - runTests = true; - }; - drv = builtRustCrates.crates.${packageId}; - testDrv = builtTestRustCrates.crates.${packageId}; - derivation = - if runTests then - crateWithTest - { - crate = drv; - testCrate = testDrv; - inherit testCrateFlags testInputs testPreRun testPostRun; - } - else drv; - in - derivation - ) - { inherit features crateOverrides runTests testCrateFlags testInputs testPreRun testPostRun; }; - - /* Returns an attr set with packageId mapped to the result of buildRustCrateForPkgsFunc - for the corresponding crate. - */ - builtRustCratesWithFeatures = - { packageId - , features - , crateConfigs ? crates - , buildRustCrateForPkgsFunc - , runTests - , makeTarget ? makeDefaultTarget - } @ args: - assert (builtins.isAttrs crateConfigs); - assert (builtins.isString packageId); - assert (builtins.isList features); - assert (builtins.isAttrs (makeTarget stdenv.hostPlatform)); - assert (builtins.isBool runTests); - let - rootPackageId = packageId; - mergedFeatures = mergePackageFeatures - ( - args // { - inherit rootPackageId; - target = makeTarget stdenv.hostPlatform // { test = runTests; }; - } - ); - # Memoize built packages so that reappearing packages are only built once. - builtByPackageIdByPkgs = mkBuiltByPackageIdByPkgs pkgs; - mkBuiltByPackageIdByPkgs = pkgs: - let - self = { - crates = lib.mapAttrs (packageId: value: buildByPackageIdForPkgsImpl self pkgs packageId) crateConfigs; - target = makeTarget stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; - }; - in - self; - buildByPackageIdForPkgsImpl = self: pkgs: packageId: - let - features = mergedFeatures."${packageId}" or [ ]; - crateConfig' = crateConfigs."${packageId}"; - crateConfig = - builtins.removeAttrs crateConfig' [ "resolvedDefaultFeatures" "devDependencies" ]; - devDependencies = - lib.optionals - (runTests && packageId == rootPackageId) - (crateConfig'.devDependencies or [ ]); - dependencies = - dependencyDerivations { - inherit features; - inherit (self) target; - buildByPackageId = depPackageId: - # proc_macro crates must be compiled for the build architecture - if crateConfigs.${depPackageId}.procMacro or false - then self.build.crates.${depPackageId} - else self.crates.${depPackageId}; - dependencies = - (crateConfig.dependencies or [ ]) - ++ devDependencies; - }; - buildDependencies = - dependencyDerivations { - inherit features; - inherit (self.build) target; - buildByPackageId = depPackageId: - self.build.crates.${depPackageId}; - dependencies = crateConfig.buildDependencies or [ ]; - }; - dependenciesWithRenames = - let - buildDeps = filterEnabledDependencies { - inherit features; - inherit (self) target; - dependencies = crateConfig.dependencies or [ ] ++ devDependencies; - }; - hostDeps = filterEnabledDependencies { - inherit features; - inherit (self.build) target; - dependencies = crateConfig.buildDependencies or [ ]; - }; - in - lib.filter (d: d ? "rename") (hostDeps ++ buildDeps); - # Crate renames have the form: - # - # { - # crate_name = [ - # { version = "1.2.3"; rename = "crate_name01"; } - # ]; - # # ... - # } - crateRenames = - let - grouped = - lib.groupBy - (dependency: dependency.name) - dependenciesWithRenames; - versionAndRename = dep: - let - package = crateConfigs."${dep.packageId}"; - in - { inherit (dep) rename; inherit (package) version; }; - in - lib.mapAttrs (name: builtins.map versionAndRename) grouped; - in - buildRustCrateForPkgsFunc pkgs - ( - crateConfig // { - src = crateConfig.src or ( - pkgs.fetchurl rec { - name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; - # https://www.pietroalbini.org/blog/downloading-crates-io/ - # Not rate-limited, CDN URL. - url = "https://static.crates.io/crates/${crateConfig.crateName}/${crateConfig.crateName}-${crateConfig.version}.crate"; - sha256 = - assert (lib.assertMsg (crateConfig ? sha256) "Missing sha256 for ${name}"); - crateConfig.sha256; - } - ); - extraRustcOpts = lib.lists.optional (targetFeatures != [ ]) "-C target-feature=${lib.concatMapStringsSep "," (x: "+${x}") targetFeatures}"; - inherit features dependencies buildDependencies crateRenames release; - } - ); - in - builtByPackageIdByPkgs; - - /* Returns the actual derivations for the given dependencies. */ - dependencyDerivations = - { buildByPackageId - , features - , dependencies - , target - }: - assert (builtins.isList features); - assert (builtins.isList dependencies); - assert (builtins.isAttrs target); - let - enabledDependencies = filterEnabledDependencies { - inherit dependencies features target; - }; - depDerivation = dependency: buildByPackageId dependency.packageId; - in - map depDerivation enabledDependencies; - - /* Returns a sanitized version of val with all values substituted that cannot - be serialized as JSON. - */ - sanitizeForJson = val: - if builtins.isAttrs val - then lib.mapAttrs (n: sanitizeForJson) val - else if builtins.isList val - then builtins.map sanitizeForJson val - else if builtins.isFunction val - then "function" - else val; - - /* Returns various tools to debug a crate. */ - debugCrate = { packageId, target ? makeDefaultTarget stdenv.hostPlatform }: - assert (builtins.isString packageId); - let - debug = rec { - # The built tree as passed to buildRustCrate. - buildTree = buildRustCrateWithFeatures { - buildRustCrateForPkgsFunc = _: lib.id; - inherit packageId; - }; - sanitizedBuildTree = sanitizeForJson buildTree; - dependencyTree = sanitizeForJson - ( - buildRustCrateWithFeatures { - buildRustCrateForPkgsFunc = _: crate: { - "01_crateName" = crate.crateName or false; - "02_features" = crate.features or [ ]; - "03_dependencies" = crate.dependencies or [ ]; - }; - inherit packageId; - } - ); - mergedPackageFeatures = mergePackageFeatures { - features = rootFeatures; - inherit packageId target; - }; - diffedDefaultPackageFeatures = diffDefaultPackageFeatures { - inherit packageId target; - }; - }; - in - { internal = debug; }; - - /* Returns differences between cargo default features and crate2nix default - features. - - This is useful for verifying the feature resolution in crate2nix. - */ - diffDefaultPackageFeatures = - { crateConfigs ? crates - , packageId - , target - }: - assert (builtins.isAttrs crateConfigs); - let - prefixValues = prefix: lib.mapAttrs (n: v: { "${prefix}" = v; }); - mergedFeatures = - prefixValues - "crate2nix" - (mergePackageFeatures { inherit crateConfigs packageId target; features = [ "default" ]; }); - configs = prefixValues "cargo" crateConfigs; - combined = lib.foldAttrs (a: b: a // b) { } [ mergedFeatures configs ]; - onlyInCargo = - builtins.attrNames - (lib.filterAttrs (n: v: !(v ? "crate2nix") && (v ? "cargo")) combined); - onlyInCrate2Nix = - builtins.attrNames - (lib.filterAttrs (n: v: (v ? "crate2nix") && !(v ? "cargo")) combined); - differentFeatures = lib.filterAttrs - ( - n: v: - (v ? "crate2nix") - && (v ? "cargo") - && (v.crate2nix.features or [ ]) != (v."cargo".resolved_default_features or [ ]) - ) - combined; - in - builtins.toJSON { - inherit onlyInCargo onlyInCrate2Nix differentFeatures; - }; - - /* Returns an attrset mapping packageId to the list of enabled features. - - If multiple paths to a dependency enable different features, the - corresponding feature sets are merged. Features in rust are additive. - */ - mergePackageFeatures = - { crateConfigs ? crates - , packageId - , rootPackageId ? packageId - , features ? rootFeatures - , dependencyPath ? [ crates.${packageId}.crateName ] - , featuresByPackageId ? { } - , target - # Adds devDependencies to the crate with rootPackageId. - , runTests ? false - , ... - } @ args: - assert (builtins.isAttrs crateConfigs); - assert (builtins.isString packageId); - assert (builtins.isString rootPackageId); - assert (builtins.isList features); - assert (builtins.isList dependencyPath); - assert (builtins.isAttrs featuresByPackageId); - assert (builtins.isAttrs target); - assert (builtins.isBool runTests); - let - crateConfig = crateConfigs."${packageId}" or (builtins.throw "Package not found: ${packageId}"); - expandedFeatures = expandFeatures (crateConfig.features or { }) features; - enabledFeatures = enableFeatures (crateConfig.dependencies or [ ]) expandedFeatures; - depWithResolvedFeatures = dependency: - let - inherit (dependency) packageId; - features = dependencyFeatures enabledFeatures dependency; - in - { inherit packageId features; }; - resolveDependencies = cache: path: dependencies: - assert (builtins.isAttrs cache); - assert (builtins.isList dependencies); - let - enabledDependencies = filterEnabledDependencies { - inherit dependencies target; - features = enabledFeatures; - }; - directDependencies = map depWithResolvedFeatures enabledDependencies; - foldOverCache = op: lib.foldl op cache directDependencies; - in - foldOverCache - ( - cache: { packageId, features }: - let - cacheFeatures = cache.${packageId} or [ ]; - combinedFeatures = sortedUnique (cacheFeatures ++ features); - in - if cache ? ${packageId} && cache.${packageId} == combinedFeatures - then cache - else - mergePackageFeatures { - features = combinedFeatures; - featuresByPackageId = cache; - inherit crateConfigs packageId target runTests rootPackageId; - } - ); - cacheWithSelf = - let - cacheFeatures = featuresByPackageId.${packageId} or [ ]; - combinedFeatures = sortedUnique (cacheFeatures ++ enabledFeatures); - in - featuresByPackageId // { - "${packageId}" = combinedFeatures; - }; - cacheWithDependencies = - resolveDependencies cacheWithSelf "dep" - ( - crateConfig.dependencies or [ ] - ++ lib.optionals - (runTests && packageId == rootPackageId) - (crateConfig.devDependencies or [ ]) - ); - cacheWithAll = - resolveDependencies - cacheWithDependencies "build" - (crateConfig.buildDependencies or [ ]); - in - cacheWithAll; - - /* Returns the enabled dependencies given the enabled features. */ - filterEnabledDependencies = { dependencies, features, target }: - assert (builtins.isList dependencies); - assert (builtins.isList features); - assert (builtins.isAttrs target); - - lib.filter - ( - dep: - let - targetFunc = dep.target or (features: true); - in - targetFunc { inherit features target; } - && ( - !(dep.optional or false) - || builtins.any (doesFeatureEnableDependency dep) features - ) - ) - dependencies; - - /* Returns whether the given feature should enable the given dependency. */ - doesFeatureEnableDependency = dependency: feature: - let - name = dependency.rename or dependency.name; - prefix = "${name}/"; - len = builtins.stringLength prefix; - startsWithPrefix = builtins.substring 0 len feature == prefix; - in - feature == name || feature == "dep:" + name || startsWithPrefix; - - /* Returns the expanded features for the given inputFeatures by applying the - rules in featureMap. - - featureMap is an attribute set which maps feature names to lists of further - feature names to enable in case this feature is selected. - */ - expandFeatures = featureMap: inputFeatures: - assert (builtins.isAttrs featureMap); - assert (builtins.isList inputFeatures); - let - expandFeaturesNoCycle = oldSeen: inputFeatures: - if inputFeatures != [ ] - then - let - # The feature we're currently expanding. - feature = builtins.head inputFeatures; - # All the features we've seen/expanded so far, including the one - # we're currently processing. - seen = oldSeen // { ${feature} = 1; }; - # Expand the feature but be careful to not re-introduce a feature - # that we've already seen: this can easily cause a cycle, see issue - # #209. - enables = builtins.filter (f: !(seen ? "${f}")) (featureMap."${feature}" or [ ]); - in - [ feature ] ++ (expandFeaturesNoCycle seen (builtins.tail inputFeatures ++ enables)) - # No more features left, nothing to expand to. - else [ ]; - outFeatures = expandFeaturesNoCycle { } inputFeatures; - in - sortedUnique outFeatures; - - /* This function adds optional dependencies as features if they are enabled - indirectly by dependency features. This function mimics Cargo's behavior - described in a note at: - https://doc.rust-lang.org/nightly/cargo/reference/features.html#dependency-features - */ - enableFeatures = dependencies: features: - assert (builtins.isList features); - assert (builtins.isList dependencies); - let - additionalFeatures = lib.concatMap - ( - dependency: - assert (builtins.isAttrs dependency); - let - enabled = builtins.any (doesFeatureEnableDependency dependency) features; - in - if (dependency.optional or false) && enabled - then [ (dependency.rename or dependency.name) ] - else [ ] - ) - dependencies; - in - sortedUnique (features ++ additionalFeatures); - - /* - Returns the actual features for the given dependency. - - features: The features of the crate that refers this dependency. - */ - dependencyFeatures = features: dependency: - assert (builtins.isList features); - assert (builtins.isAttrs dependency); - let - defaultOrNil = - if dependency.usesDefaultFeatures or true - then [ "default" ] - else [ ]; - explicitFeatures = dependency.features or [ ]; - additionalDependencyFeatures = - let - name = dependency.rename or dependency.name; - stripPrefixMatch = prefix: s: - if lib.hasPrefix prefix s - then lib.removePrefix prefix s - else null; - extractFeature = feature: lib.findFirst - (f: f != null) - null - (map (prefix: stripPrefixMatch prefix feature) [ - (name + "/") - (name + "?/") - ]); - dependencyFeatures = lib.filter (f: f != null) (map extractFeature features); - in - dependencyFeatures; - in - defaultOrNil ++ explicitFeatures ++ additionalDependencyFeatures; - - /* Sorts and removes duplicates from a list of strings. */ - sortedUnique = features: - assert (builtins.isList features); - assert (builtins.all builtins.isString features); - let - outFeaturesSet = lib.foldl (set: feature: set // { "${feature}" = 1; }) { } features; - outFeaturesUnique = builtins.attrNames outFeaturesSet; - in - builtins.sort (a: b: a < b) outFeaturesUnique; - - deprecationWarning = message: value: - if strictDeprecation - then builtins.throw "strictDeprecation enabled, aborting: ${message}" - else builtins.trace message value; - - # - # crate2nix/default.nix (excerpt end) - # - }; -} - diff --git a/users/kranzes/wasm-hello-world/Cargo.toml b/users/kranzes/wasm-hello-world/Cargo.toml deleted file mode 100644 index 2ad369d20..000000000 --- a/users/kranzes/wasm-hello-world/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "wasm_hello_world" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -wasm-bindgen = "0.2.100" diff --git a/users/kranzes/wasm-hello-world/default.nix b/users/kranzes/wasm-hello-world/default.nix deleted file mode 100644 index 0970f955d..000000000 --- a/users/kranzes/wasm-hello-world/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ pkgs, lib, ... }: - -(pkgs.pkgsCross.wasm32-unknown-none.callPackage ./Cargo.nix { }).rootCrate.build.overrideAttrs (oldAttrs: { - installPhase = '' - ${lib.getExe pkgs.wasm-bindgen-cli} \ - --target web \ - --out-dir $out \ - --out-name ${oldAttrs.crateName} \ - --no-typescript \ - target/lib/${oldAttrs.crateName}-${oldAttrs.metadata}.wasm - - mv src/*.html $out - ''; -}) - diff --git a/users/kranzes/wasm-hello-world/src/index.html b/users/kranzes/wasm-hello-world/src/index.html deleted file mode 100644 index d6366c8ee..000000000 --- a/users/kranzes/wasm-hello-world/src/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - diff --git a/users/kranzes/wasm-hello-world/src/lib.rs b/users/kranzes/wasm-hello-world/src/lib.rs deleted file mode 100644 index c18421482..000000000 --- a/users/kranzes/wasm-hello-world/src/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -use wasm_bindgen::prelude::*; - -#[wasm_bindgen] -extern "C" { - fn alert(s: &str); -} - -#[wasm_bindgen] -pub fn hello_world() { - alert("Hello World!"); -} diff --git a/users/lukegb/OWNERS b/users/lukegb/OWNERS deleted file mode 100644 index 4ff54b467..000000000 --- a/users/lukegb/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -lukegb diff --git a/users/lukegb/hgext/gerrithook.py b/users/lukegb/hgext/gerrithook.py deleted file mode 100644 index ef02126ba..000000000 --- a/users/lukegb/hgext/gerrithook.py +++ /dev/null @@ -1,63 +0,0 @@ -"""Bizarre hacks to make Gerrit better.""" - -import collections -import re -import random -import mercurial - -_ = mercurial.i18n._ - -cmdtable = {} -command = mercurial.registrar.command(cmdtable) - -testedwith = '5.3.1' - -_changeid_regex = re.compile(b'^Change-Id: (I.*)$', re.M) - -def random_hash(): - """Returns a random SHA1-like hex string.""" - return b"%040x" % random.getrandbits(160) - -def reposetup(ui, repo): - - class GerritRepo(repo.__class__): - def commitctx(self, ctx, *args, **kwargs): - match = _changeid_regex.search(ctx._text) - if not match: - ctx._text = ctx._text.rstrip(b'\n') - ctx._text += b'\n\nChange-Id: I' + random_hash() - return super().commitctx(ctx, *args, **kwargs) - - repo.__class__ = GerritRepo - - -@command(b'gerrit-obsolete', [], _(b'[options]')) -def gerritobsolete(ui, repo, **opts): - """Mark draft commits as obsolete by public commits based on Gerrit Change-Id tag.""" - if repo.obsstore.readonly: - ui.error(b'obsstore is readonly') - return - changesets = collections.defaultdict(set) - drafts = set() - for draft in repo.set('draft() - obsolete()'): - match = _changeid_regex.search(draft.description()) - if not match: - continue - changesets[match.groups()[0]].add(draft) - drafts.add(draft) - if not drafts: - return - publicparent = next(repo.set( - b'ancestor((public() and bookmark("canon")), %s)' % ( - b', '.join(x.hex() for x in drafts)))) - megare = b're:(?ms)^Change-Id: (%s)$' % (b'|'.join(changesets.keys()),) - markers = [] - for public in repo.set('(%s..(public() and canon)) and desc(%s)', publicparent, megare): - match = _changeid_regex.search(public.description()) - if not match: - continue - drafts = changesets[match.groups()[0]] - if not drafts: - continue - markers.append((tuple(drafts), (public,))) - mercurial.obsolete.createmarkers(repo, markers, operation=b'gerrit-obsolete') diff --git a/users/lukegb/keys.nix b/users/lukegb/keys.nix deleted file mode 100644 index 4745df550..000000000 --- a/users/lukegb/keys.nix +++ /dev/null @@ -1,11 +0,0 @@ -# My SSH public keys -{ ... }: - -rec { - termius = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINytpHct7PLdLNp6MoaOPP7ccBPUQKymVNMqix//Wt1f"; - porcorosso-nixos = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILid+1rq3k3k7Kbaw8X63vrPrQdanH55TucQwp3ZWfo+"; - clouvider-lon01-nix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINQU7Y+Ha5m0ebwUjA55xXT/xbWZAWx1fVNFufle+vQj"; - lukegb-build = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICESF0H+OCxY/CfyG9VjM6iJe+VbYc4NmGjRrwPCHaD9"; - lukegb-ca = "cert-authority,principals=\"lukegb\" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEqNOwlR7Qa8cbGpDfSCOweDPbAGQOZIcoRgh6s/J8DR"; - all = [ termius porcorosso-nixos clouvider-lon01-nix lukegb-build lukegb-ca ]; -} diff --git a/users/padraic-o-mhuiris/OWNERS b/users/padraic-o-mhuiris/OWNERS deleted file mode 100644 index ee6715b16..000000000 --- a/users/padraic-o-mhuiris/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -padraic-o-mhuiris diff --git a/users/picnoir/tvix-daemon/.gitignore b/users/picnoir/tvix-daemon/.gitignore deleted file mode 100644 index ea8c4bf7f..000000000 --- a/users/picnoir/tvix-daemon/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/users/picnoir/tvix-daemon/Cargo.lock b/users/picnoir/tvix-daemon/Cargo.lock deleted file mode 100644 index a9ea07acc..000000000 --- a/users/picnoir/tvix-daemon/Cargo.lock +++ /dev/null @@ -1,1599 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "anstream" -version = "0.6.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" - -[[package]] -name = "anstyle-parse" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-trait" -version = "0.1.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "axum" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper 1.0.1", - "tokio", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper 1.0.1", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" -dependencies = [ - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "bytes" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" - -[[package]] -name = "cc" -version = "1.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e804ac3194a48bb129643eb1d62fcc20d18c6b8c181704489353d13120bcd1" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.5.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" - -[[package]] -name = "colorchoice" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "cpufeatures" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" -dependencies = [ - "libc", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "data-encoding" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "document-features" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" -dependencies = [ - "litrs", -] - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "serde", - "sha2", - "subtle", - "zeroize", -] - -[[package]] -name = "enum-primitive-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba7795da175654fe16979af73f81f26a8ea27638d8d9823d317016888a63dc4c" -dependencies = [ - "num-traits", - "quote", - "syn", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "hashbrown" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" -dependencies = [ - "bytes", - "futures-util", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", -] - -[[package]] -name = "hyper-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" -dependencies = [ - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "pin-project-lite", - "tokio", - "tower-service", -] - -[[package]] -name = "indexmap" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" - -[[package]] -name = "libmimalloc-sys" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "litrs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mimalloc" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633" -dependencies = [ - "libmimalloc-sys", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" -dependencies = [ - "hermit-abi", - "libc", - "wasi", - "windows-sys", -] - -[[package]] -name = "nix" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" -dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", -] - -[[package]] -name = "nix-compat" -version = "0.1.0" -dependencies = [ - "bitflags 2.6.0", - "bstr", - "bytes", - "data-encoding", - "ed25519", - "ed25519-dalek", - "enum-primitive-derive", - "futures", - "glob", - "mimalloc", - "nix-compat-derive", - "nom", - "num-traits", - "num_enum", - "pin-project-lite", - "serde", - "serde_json", - "serde_repr", - "sha2", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "nix-compat-derive" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "nom" -version = "8.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" -dependencies = [ - "memchr", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "1.0.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "regex-automata" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "serde" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "rand_core", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "sync_wrapper" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" - -[[package]] -name = "thiserror" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tokio" -version = "1.40.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-listener" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96367e127b4cf47b92592a5154a563435fe28fe3fccf25917d4a34ee59c87303" -dependencies = [ - "axum", - "document-features", - "futures-core", - "futures-util", - "nix", - "pin-project", - "socket2", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-stream" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-test" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2468baabc3311435b55dd935f702f42cd1b8abb7e754fb7dfb16bd36aa88f9f7" -dependencies = [ - "async-stream", - "bytes", - "futures-core", - "tokio", - "tokio-stream", -] - -[[package]] -name = "tokio-util" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" - -[[package]] -name = "toml_edit" -version = "0.22.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper 0.1.2", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "tvix-daemon" -version = "0.1.0" -dependencies = [ - "clap", - "nix-compat", - "tokio", - "tokio-listener", - "tokio-test", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" -dependencies = [ - "memchr", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/users/picnoir/tvix-daemon/Cargo.nix b/users/picnoir/tvix-daemon/Cargo.nix deleted file mode 100644 index 7f6d40854..000000000 --- a/users/picnoir/tvix-daemon/Cargo.nix +++ /dev/null @@ -1,5732 +0,0 @@ -# This file was @generated by crate2nix 0.14.1 with the command: -# "generate" "--all-features" -# See https://github.com/kolloch/crate2nix for more info. - -{ nixpkgs ? -, pkgs ? import nixpkgs { config = { }; } -, lib ? pkgs.lib -, stdenv ? pkgs.stdenv -, buildRustCrateForPkgs ? pkgs: pkgs.buildRustCrate - # This is used as the `crateOverrides` argument for `buildRustCrate`. -, defaultCrateOverrides ? pkgs.defaultCrateOverrides - # The features to enable for the root_crate or the workspace_members. -, rootFeatures ? [ "default" ] - # If true, throw errors instead of issueing deprecation warnings. -, strictDeprecation ? false - # Elements to add to the `-C target-feature=` argument passed to `rustc` - # (separated by `,`, prefixed with `+`). - # Used for conditional compilation based on CPU feature detection. -, targetFeatures ? [ ] - # Whether to perform release builds: longer compile times, faster binaries. -, release ? true - # Additional crate2nix configuration if it exists. -, crateConfig ? if builtins.pathExists ./crate-config.nix - then pkgs.callPackage ./crate-config.nix { } - else { } -}: - -rec { - # - # "public" attributes that we attempt to keep stable with new versions of crate2nix. - # - - rootCrate = rec { - packageId = "tvix-daemon"; - - # Use this attribute to refer to the derivation building your root crate package. - # You can override the features with rootCrate.build.override { features = [ "default" "feature1" ... ]; }. - build = internal.buildRustCrateWithFeatures { - inherit packageId; - }; - - # Debug support which might change between releases. - # File a bug if you depend on any for non-debug work! - debug = internal.debugCrate { inherit packageId; }; - }; - # Refer your crate build derivation by name here. - # You can override the features with - # workspaceMembers."${crateName}".build.override { features = [ "default" "feature1" ... ]; }. - workspaceMembers = { - "tvix-daemon" = rec { - packageId = "tvix-daemon"; - build = internal.buildRustCrateWithFeatures { - packageId = "tvix-daemon"; - }; - - # Debug support which might change between releases. - # File a bug if you depend on any for non-debug work! - debug = internal.debugCrate { inherit packageId; }; - }; - }; - - # A derivation that joins the outputs of all workspace members together. - allWorkspaceMembers = pkgs.symlinkJoin { - name = "all-workspace-members"; - paths = - let members = builtins.attrValues workspaceMembers; - in builtins.map (m: m.build) members; - }; - - # - # "internal" ("private") attributes that may change in every new version of crate2nix. - # - - internal = rec { - # Build and dependency information for crates. - # Many of the fields are passed one-to-one to buildRustCrate. - # - # Noteworthy: - # * `dependencies`/`buildDependencies`: similar to the corresponding fields for buildRustCrate. - # but with additional information which is used during dependency/feature resolution. - # * `resolvedDependencies`: the selected default features reported by cargo - only included for debugging. - # * `devDependencies` as of now not used by `buildRustCrate` but used to - # inject test dependencies into the build - - crates = { - "addr2line" = rec { - crateName = "addr2line"; - version = "0.24.2"; - edition = "2018"; - crateBin = [ ]; - sha256 = "1hd1i57zxgz08j6h5qrhsnm2fi0bcqvsh389fw400xm3arz2ggnz"; - dependencies = [ - { - name = "gimli"; - packageId = "gimli"; - usesDefaultFeatures = false; - features = [ "read" ]; - } - ]; - features = { - "all" = [ "bin" ]; - "alloc" = [ "dep:alloc" ]; - "bin" = [ "loader" "rustc-demangle" "cpp_demangle" "fallible-iterator" "smallvec" "dep:clap" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "cpp_demangle" = [ "dep:cpp_demangle" ]; - "default" = [ "rustc-demangle" "cpp_demangle" "loader" "fallible-iterator" "smallvec" ]; - "fallible-iterator" = [ "dep:fallible-iterator" ]; - "loader" = [ "std" "dep:object" "dep:memmap2" "dep:typed-arena" ]; - "rustc-demangle" = [ "dep:rustc-demangle" ]; - "rustc-dep-of-std" = [ "core" "alloc" "compiler_builtins" "gimli/rustc-dep-of-std" ]; - "smallvec" = [ "dep:smallvec" ]; - "std" = [ "gimli/std" ]; - }; - }; - "adler2" = rec { - crateName = "adler2"; - version = "2.0.0"; - edition = "2021"; - sha256 = "09r6drylvgy8vv8k20lnbvwq8gp09h7smfn6h1rxsy15pgh629si"; - authors = [ - "Jonas Schievink " - "oyvindln " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - }; - "anstream" = rec { - crateName = "anstream"; - version = "0.6.15"; - edition = "2021"; - sha256 = "09nm4qj34kiwgzczdvj14x7hgsb235g4sqsay3xsz7zqn4d5rqb4"; - dependencies = [ - { - name = "anstyle"; - packageId = "anstyle"; - } - { - name = "anstyle-parse"; - packageId = "anstyle-parse"; - } - { - name = "anstyle-query"; - packageId = "anstyle-query"; - optional = true; - } - { - name = "anstyle-wincon"; - packageId = "anstyle-wincon"; - optional = true; - target = { target, features }: (target."windows" or false); - } - { - name = "colorchoice"; - packageId = "colorchoice"; - } - { - name = "is_terminal_polyfill"; - packageId = "is_terminal_polyfill"; - } - { - name = "utf8parse"; - packageId = "utf8parse"; - } - ]; - features = { - "auto" = [ "dep:anstyle-query" ]; - "default" = [ "auto" "wincon" ]; - "wincon" = [ "dep:anstyle-wincon" ]; - }; - resolvedDefaultFeatures = [ "auto" "default" "wincon" ]; - }; - "anstyle" = rec { - crateName = "anstyle"; - version = "1.0.8"; - edition = "2021"; - sha256 = "1cfmkza63xpn1kkz844mgjwm9miaiz4jkyczmwxzivcsypk1vv0v"; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "anstyle-parse" = rec { - crateName = "anstyle-parse"; - version = "0.2.5"; - edition = "2021"; - sha256 = "1jy12rvgbldflnb2x7mcww9dcffw1mx22nyv6p3n7d62h0gdwizb"; - libName = "anstyle_parse"; - dependencies = [ - { - name = "utf8parse"; - packageId = "utf8parse"; - optional = true; - } - ]; - features = { - "core" = [ "dep:arrayvec" ]; - "default" = [ "utf8" ]; - "utf8" = [ "dep:utf8parse" ]; - }; - resolvedDefaultFeatures = [ "default" "utf8" ]; - }; - "anstyle-query" = rec { - crateName = "anstyle-query"; - version = "1.1.1"; - edition = "2021"; - sha256 = "0aj22iy4pzk6mz745sfrm1ym14r0y892jhcrbs8nkj7nqx9gqdkd"; - libName = "anstyle_query"; - dependencies = [ - { - name = "windows-sys"; - packageId = "windows-sys"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_System_Console" "Win32_Foundation" ]; - } - ]; - - }; - "anstyle-wincon" = rec { - crateName = "anstyle-wincon"; - version = "3.0.4"; - edition = "2021"; - sha256 = "1y2pkvsrdxbcwircahb4wimans2pzmwwxad7ikdhj5lpdqdlxxsv"; - libName = "anstyle_wincon"; - dependencies = [ - { - name = "anstyle"; - packageId = "anstyle"; - } - { - name = "windows-sys"; - packageId = "windows-sys"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_System_Console" "Win32_Foundation" ]; - } - ]; - - }; - "async-stream" = rec { - crateName = "async-stream"; - version = "0.3.6"; - edition = "2021"; - sha256 = "0xl4zqncrdmw2g6241wgr11dxdg4h7byy6bz3l6si03qyfk72nhb"; - libName = "async_stream"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "async-stream-impl"; - packageId = "async-stream-impl"; - } - { - name = "futures-core"; - packageId = "futures-core"; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - ]; - - }; - "async-stream-impl" = rec { - crateName = "async-stream-impl"; - version = "0.3.6"; - edition = "2021"; - sha256 = "0kaplfb5axsvf1gfs2gk6c4zx6zcsns0yf3ssk7iwni7bphlvhn7"; - procMacro = true; - libName = "async_stream_impl"; - authors = [ - "Carl Lerche " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - features = [ "full" "visit-mut" ]; - } - ]; - - }; - "async-trait" = rec { - crateName = "async-trait"; - version = "0.1.83"; - edition = "2021"; - sha256 = "1p8q8gm4fv2fdka8hwy2w3f8df7p5inixqi7rlmbnky3wmysw73j"; - procMacro = true; - libName = "async_trait"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - usesDefaultFeatures = false; - features = [ "full" "parsing" "printing" "proc-macro" "visit-mut" ]; - } - ]; - - }; - "autocfg" = rec { - crateName = "autocfg"; - version = "1.4.0"; - edition = "2015"; - sha256 = "09lz3by90d2hphbq56znag9v87gfpd9gb8nr82hll8z6x2nhprdc"; - authors = [ - "Josh Stone " - ]; - - }; - "axum" = rec { - crateName = "axum"; - version = "0.7.7"; - edition = "2021"; - sha256 = "1bkhgnj7rk1aih1c1ylqkmn72mjbgi8lql1paim35j3s613kjkjh"; - dependencies = [ - { - name = "async-trait"; - packageId = "async-trait"; - } - { - name = "axum-core"; - packageId = "axum-core"; - } - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures-util"; - packageId = "futures-util"; - usesDefaultFeatures = false; - features = [ "alloc" ]; - } - { - name = "http"; - packageId = "http"; - } - { - name = "http-body"; - packageId = "http-body"; - } - { - name = "http-body-util"; - packageId = "http-body-util"; - } - { - name = "hyper"; - packageId = "hyper"; - optional = true; - } - { - name = "hyper-util"; - packageId = "hyper-util"; - optional = true; - features = [ "tokio" "server" "service" ]; - } - { - name = "itoa"; - packageId = "itoa"; - } - { - name = "matchit"; - packageId = "matchit"; - } - { - name = "memchr"; - packageId = "memchr"; - } - { - name = "mime"; - packageId = "mime"; - } - { - name = "percent-encoding"; - packageId = "percent-encoding"; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "rustversion"; - packageId = "rustversion"; - } - { - name = "serde"; - packageId = "serde"; - } - { - name = "serde_json"; - packageId = "serde_json"; - optional = true; - features = [ "raw_value" ]; - } - { - name = "serde_path_to_error"; - packageId = "serde_path_to_error"; - optional = true; - } - { - name = "serde_urlencoded"; - packageId = "serde_urlencoded"; - optional = true; - } - { - name = "sync_wrapper"; - packageId = "sync_wrapper 1.0.1"; - } - { - name = "tokio"; - packageId = "tokio"; - rename = "tokio"; - optional = true; - features = [ "time" ]; - } - { - name = "tower"; - packageId = "tower"; - usesDefaultFeatures = false; - features = [ "util" ]; - } - { - name = "tower-layer"; - packageId = "tower-layer"; - } - { - name = "tower-service"; - packageId = "tower-service"; - } - { - name = "tracing"; - packageId = "tracing"; - optional = true; - usesDefaultFeatures = false; - } - ]; - devDependencies = [ - { - name = "serde"; - packageId = "serde"; - features = [ "derive" ]; - } - { - name = "serde_json"; - packageId = "serde_json"; - } - { - name = "tokio"; - packageId = "tokio"; - rename = "tokio"; - features = [ "macros" "rt" "rt-multi-thread" "net" "test-util" ]; - } - { - name = "tower"; - packageId = "tower"; - rename = "tower"; - features = [ "util" "timeout" "limit" "load-shed" "steer" "filter" ]; - } - { - name = "tracing"; - packageId = "tracing"; - } - ]; - features = { - "__private_docs" = [ "tower/full" "dep:tower-http" ]; - "default" = [ "form" "http1" "json" "matched-path" "original-uri" "query" "tokio" "tower-log" "tracing" ]; - "form" = [ "dep:serde_urlencoded" ]; - "http1" = [ "dep:hyper" "hyper?/http1" "hyper-util?/http1" ]; - "http2" = [ "dep:hyper" "hyper?/http2" "hyper-util?/http2" ]; - "json" = [ "dep:serde_json" "dep:serde_path_to_error" ]; - "macros" = [ "dep:axum-macros" ]; - "multipart" = [ "dep:multer" ]; - "query" = [ "dep:serde_urlencoded" ]; - "tokio" = [ "dep:hyper-util" "dep:tokio" "tokio/net" "tokio/rt" "tower/make" "tokio/macros" ]; - "tower-log" = [ "tower/log" ]; - "tracing" = [ "dep:tracing" "axum-core/tracing" ]; - "ws" = [ "dep:hyper" "tokio" "dep:tokio-tungstenite" "dep:sha1" "dep:base64" ]; - }; - resolvedDefaultFeatures = [ "default" "form" "http1" "json" "matched-path" "original-uri" "query" "tokio" "tower-log" "tracing" ]; - }; - "axum-core" = rec { - crateName = "axum-core"; - version = "0.4.5"; - edition = "2021"; - sha256 = "16b1496c4gm387q20hkv5ic3k5bd6xmnvk50kwsy6ymr8rhvvwh9"; - libName = "axum_core"; - dependencies = [ - { - name = "async-trait"; - packageId = "async-trait"; - } - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures-util"; - packageId = "futures-util"; - usesDefaultFeatures = false; - features = [ "alloc" ]; - } - { - name = "http"; - packageId = "http"; - } - { - name = "http-body"; - packageId = "http-body"; - } - { - name = "http-body-util"; - packageId = "http-body-util"; - } - { - name = "mime"; - packageId = "mime"; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "rustversion"; - packageId = "rustversion"; - } - { - name = "sync_wrapper"; - packageId = "sync_wrapper 1.0.1"; - } - { - name = "tower-layer"; - packageId = "tower-layer"; - } - { - name = "tower-service"; - packageId = "tower-service"; - } - { - name = "tracing"; - packageId = "tracing"; - optional = true; - usesDefaultFeatures = false; - } - ]; - devDependencies = [ - { - name = "futures-util"; - packageId = "futures-util"; - usesDefaultFeatures = false; - features = [ "alloc" ]; - } - ]; - features = { - "__private_docs" = [ "dep:tower-http" ]; - "tracing" = [ "dep:tracing" ]; - }; - resolvedDefaultFeatures = [ "tracing" ]; - }; - "backtrace" = rec { - crateName = "backtrace"; - version = "0.3.74"; - edition = "2021"; - sha256 = "06pfif7nwx66qf2zaanc2fcq7m64i91ki9imw9xd3bnz5hrwp0ld"; - authors = [ - "The Rust Project Developers" - ]; - dependencies = [ - { - name = "addr2line"; - packageId = "addr2line"; - usesDefaultFeatures = false; - target = { target, features }: (!((target."windows" or false) && ("msvc" == target."env" or null) && (!("uwp" == target."vendor" or null)))); - } - { - name = "cfg-if"; - packageId = "cfg-if"; - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (!((target."windows" or false) && ("msvc" == target."env" or null) && (!("uwp" == target."vendor" or null)))); - } - { - name = "miniz_oxide"; - packageId = "miniz_oxide"; - usesDefaultFeatures = false; - target = { target, features }: (!((target."windows" or false) && ("msvc" == target."env" or null) && (!("uwp" == target."vendor" or null)))); - } - { - name = "object"; - packageId = "object"; - usesDefaultFeatures = false; - target = { target, features }: (!((target."windows" or false) && ("msvc" == target."env" or null) && (!("uwp" == target."vendor" or null)))); - features = [ "read_core" "elf" "macho" "pe" "xcoff" "unaligned" "archive" ]; - } - { - name = "rustc-demangle"; - packageId = "rustc-demangle"; - } - { - name = "windows-targets"; - packageId = "windows-targets"; - target = { target, features }: (target."windows" or false); - } - ]; - features = { - "cpp_demangle" = [ "dep:cpp_demangle" ]; - "default" = [ "std" ]; - "serde" = [ "dep:serde" ]; - "serialize-serde" = [ "serde" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "base64ct" = rec { - crateName = "base64ct"; - version = "1.6.0"; - edition = "2021"; - sha256 = "0nvdba4jb8aikv60az40x2w1y96sjdq8z3yp09rwzmkhiwv1lg4c"; - authors = [ - "RustCrypto Developers" - ]; - features = { - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" ]; - }; - "bitflags 1.3.2" = rec { - crateName = "bitflags"; - version = "1.3.2"; - edition = "2018"; - sha256 = "12ki6w8gn1ldq7yz9y680llwk5gmrhrzszaa17g1sbrw2r2qvwxy"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "bitflags 2.6.0" = rec { - crateName = "bitflags"; - version = "2.6.0"; - edition = "2021"; - sha256 = "1pkidwzn3hnxlsl8zizh0bncgbjnw7c41cx7bby26ncbzmiznj5h"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "arbitrary" = [ "dep:arbitrary" ]; - "bytemuck" = [ "dep:bytemuck" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - "serde" = [ "dep:serde" ]; - }; - }; - "block-buffer" = rec { - crateName = "block-buffer"; - version = "0.10.4"; - edition = "2018"; - sha256 = "0w9sa2ypmrsqqvc20nhwr75wbb5cjr4kkyhpjm1z1lv2kdicfy1h"; - libName = "block_buffer"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "generic-array"; - packageId = "generic-array"; - } - ]; - - }; - "bstr" = rec { - crateName = "bstr"; - version = "1.10.0"; - edition = "2021"; - sha256 = "036wwrchd5gq3q4k6w1j2bfl2bk2ff8c0dsa9y7w7aw7nf7knwj0"; - authors = [ - "Andrew Gallant " - ]; - dependencies = [ - { - name = "memchr"; - packageId = "memchr"; - usesDefaultFeatures = false; - } - { - name = "regex-automata"; - packageId = "regex-automata"; - optional = true; - usesDefaultFeatures = false; - features = [ "dfa-search" ]; - } - { - name = "serde"; - packageId = "serde"; - optional = true; - usesDefaultFeatures = false; - } - ]; - features = { - "alloc" = [ "memchr/alloc" "serde?/alloc" ]; - "default" = [ "std" "unicode" ]; - "serde" = [ "dep:serde" ]; - "std" = [ "alloc" "memchr/std" "serde?/std" ]; - "unicode" = [ "dep:regex-automata" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "serde" "std" "unicode" ]; - }; - "bytes" = rec { - crateName = "bytes"; - version = "1.7.2"; - edition = "2018"; - sha256 = "1wzs7l57iwqmrszdpr2mmqf1b1hgvpxafc30imxhnry0zfl9m3a2"; - authors = [ - "Carl Lerche " - "Sean McArthur " - ]; - features = { - "default" = [ "std" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "cc" = rec { - crateName = "cc"; - version = "1.1.29"; - edition = "2018"; - sha256 = "1ldw40qx2lwk9021f64cdf6d286c5zbb2gk456qqp94l66n09s2q"; - authors = [ - "Alex Crichton " - ]; - dependencies = [ - { - name = "shlex"; - packageId = "shlex"; - } - ]; - features = { - "parallel" = [ "dep:libc" "dep:jobserver" ]; - }; - }; - "cfg-if" = rec { - crateName = "cfg-if"; - version = "1.0.0"; - edition = "2018"; - sha256 = "1za0vb97n4brpzpv8lsbnzmq5r8f2b0cpqqr0sy8h5bn751xxwds"; - libName = "cfg_if"; - authors = [ - "Alex Crichton " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - }; - "clap" = rec { - crateName = "clap"; - version = "4.5.20"; - edition = "2021"; - crateBin = [ ]; - sha256 = "1s37v23gcxkjy4800qgnkxkpliz68vslpr5sgn1xar56hmnkfzxr"; - dependencies = [ - { - name = "clap_builder"; - packageId = "clap_builder"; - usesDefaultFeatures = false; - } - { - name = "clap_derive"; - packageId = "clap_derive"; - optional = true; - } - ]; - features = { - "cargo" = [ "clap_builder/cargo" ]; - "color" = [ "clap_builder/color" ]; - "debug" = [ "clap_builder/debug" "clap_derive?/debug" ]; - "default" = [ "std" "color" "help" "usage" "error-context" "suggestions" ]; - "deprecated" = [ "clap_builder/deprecated" "clap_derive?/deprecated" ]; - "derive" = [ "dep:clap_derive" ]; - "env" = [ "clap_builder/env" ]; - "error-context" = [ "clap_builder/error-context" ]; - "help" = [ "clap_builder/help" ]; - "std" = [ "clap_builder/std" ]; - "string" = [ "clap_builder/string" ]; - "suggestions" = [ "clap_builder/suggestions" ]; - "unicode" = [ "clap_builder/unicode" ]; - "unstable-doc" = [ "clap_builder/unstable-doc" "derive" ]; - "unstable-ext" = [ "clap_builder/unstable-ext" ]; - "unstable-styles" = [ "clap_builder/unstable-styles" ]; - "unstable-v5" = [ "clap_builder/unstable-v5" "clap_derive?/unstable-v5" "deprecated" ]; - "usage" = [ "clap_builder/usage" ]; - "wrap_help" = [ "clap_builder/wrap_help" ]; - }; - resolvedDefaultFeatures = [ "color" "default" "derive" "env" "error-context" "help" "std" "suggestions" "usage" ]; - }; - "clap_builder" = rec { - crateName = "clap_builder"; - version = "4.5.20"; - edition = "2021"; - sha256 = "0m6w10l2f65h3ch0d53lql6p26xxrh20ffipra9ysjsfsjmq1g0r"; - dependencies = [ - { - name = "anstream"; - packageId = "anstream"; - optional = true; - } - { - name = "anstyle"; - packageId = "anstyle"; - } - { - name = "clap_lex"; - packageId = "clap_lex"; - } - { - name = "strsim"; - packageId = "strsim"; - optional = true; - } - ]; - features = { - "color" = [ "dep:anstream" ]; - "debug" = [ "dep:backtrace" ]; - "default" = [ "std" "color" "help" "usage" "error-context" "suggestions" ]; - "std" = [ "anstyle/std" ]; - "suggestions" = [ "dep:strsim" "error-context" ]; - "unicode" = [ "dep:unicode-width" "dep:unicase" ]; - "unstable-doc" = [ "cargo" "wrap_help" "env" "unicode" "string" "unstable-ext" ]; - "unstable-styles" = [ "color" ]; - "unstable-v5" = [ "deprecated" ]; - "wrap_help" = [ "help" "dep:terminal_size" ]; - }; - resolvedDefaultFeatures = [ "color" "env" "error-context" "help" "std" "suggestions" "usage" ]; - }; - "clap_derive" = rec { - crateName = "clap_derive"; - version = "4.5.18"; - edition = "2021"; - sha256 = "1ardb26bvcpg72q9myr7yir3a8c83gx7vxk1cccabsd9n73s1ija"; - procMacro = true; - dependencies = [ - { - name = "heck"; - packageId = "heck"; - } - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - features = [ "full" ]; - } - ]; - features = { - "raw-deprecated" = [ "deprecated" ]; - "unstable-v5" = [ "deprecated" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "clap_lex" = rec { - crateName = "clap_lex"; - version = "0.7.2"; - edition = "2021"; - sha256 = "15zcrc2fa6ycdzaihxghf48180bnvzsivhf0fmah24bnnaf76qhl"; - - }; - "colorchoice" = rec { - crateName = "colorchoice"; - version = "1.0.2"; - edition = "2021"; - sha256 = "1h18ph538y8yjmbpaf8li98l0ifms2xmh3rax9666c5qfjfi3zfk"; - - }; - "const-oid" = rec { - crateName = "const-oid"; - version = "0.9.6"; - edition = "2021"; - sha256 = "1y0jnqaq7p2wvspnx7qj76m7hjcqpz73qzvr9l2p9n2s51vr6if2"; - libName = "const_oid"; - authors = [ - "RustCrypto Developers" - ]; - features = { - "arbitrary" = [ "dep:arbitrary" ]; - }; - }; - "cpufeatures" = rec { - crateName = "cpufeatures"; - version = "0.2.14"; - edition = "2018"; - sha256 = "1q3qd9qkw94vs7n5i0y3zz2cqgzcxvdgyb54ryngwmjhfbgrg1k0"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "aarch64-linux-android"); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (("aarch64" == target."arch" or null) && ("linux" == target."os" or null)); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (("aarch64" == target."arch" or null) && ("apple" == target."vendor" or null)); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (("loongarch64" == target."arch" or null) && ("linux" == target."os" or null)); - } - ]; - - }; - "crypto-common" = rec { - crateName = "crypto-common"; - version = "0.1.6"; - edition = "2018"; - sha256 = "1cvby95a6xg7kxdz5ln3rl9xh66nz66w46mm3g56ri1z5x815yqv"; - libName = "crypto_common"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "generic-array"; - packageId = "generic-array"; - features = [ "more_lengths" ]; - } - { - name = "typenum"; - packageId = "typenum"; - } - ]; - features = { - "getrandom" = [ "rand_core/getrandom" ]; - "rand_core" = [ "dep:rand_core" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "curve25519-dalek" = rec { - crateName = "curve25519-dalek"; - version = "4.1.3"; - edition = "2021"; - sha256 = "1gmjb9dsknrr8lypmhkyjd67p1arb8mbfamlwxm7vph38my8pywp"; - libName = "curve25519_dalek"; - authors = [ - "Isis Lovecruft " - "Henry de Valence " - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if"; - } - { - name = "cpufeatures"; - packageId = "cpufeatures"; - target = { target, features }: ("x86_64" == target."arch" or null); - } - { - name = "curve25519-dalek-derive"; - packageId = "curve25519-dalek-derive"; - target = { target, features }: ((!("fiat" == target."curve25519_dalek_backend" or null)) && (!("serial" == target."curve25519_dalek_backend" or null)) && ("x86_64" == target."arch" or null)); - } - { - name = "digest"; - packageId = "digest"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "fiat-crypto"; - packageId = "fiat-crypto"; - usesDefaultFeatures = false; - target = { target, features }: ("fiat" == target."curve25519_dalek_backend" or null); - } - { - name = "subtle"; - packageId = "subtle"; - usesDefaultFeatures = false; - } - { - name = "zeroize"; - packageId = "zeroize"; - optional = true; - usesDefaultFeatures = false; - } - ]; - buildDependencies = [ - { - name = "rustc_version"; - packageId = "rustc_version"; - } - ]; - features = { - "alloc" = [ "zeroize?/alloc" ]; - "default" = [ "alloc" "precomputed-tables" "zeroize" ]; - "digest" = [ "dep:digest" ]; - "ff" = [ "dep:ff" ]; - "group" = [ "dep:group" "rand_core" ]; - "group-bits" = [ "group" "ff/bits" ]; - "rand_core" = [ "dep:rand_core" ]; - "serde" = [ "dep:serde" ]; - "zeroize" = [ "dep:zeroize" ]; - }; - resolvedDefaultFeatures = [ "alloc" "digest" "precomputed-tables" "zeroize" ]; - }; - "curve25519-dalek-derive" = rec { - crateName = "curve25519-dalek-derive"; - version = "0.1.1"; - edition = "2021"; - sha256 = "1cry71xxrr0mcy5my3fb502cwfxy6822k4pm19cwrilrg7hq4s7l"; - procMacro = true; - libName = "curve25519_dalek_derive"; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - features = [ "full" ]; - } - ]; - - }; - "data-encoding" = rec { - crateName = "data-encoding"; - version = "2.6.0"; - edition = "2018"; - sha256 = "1qnn68n4vragxaxlkqcb1r28d3hhj43wch67lm4rpxlw89wnjmp8"; - libName = "data_encoding"; - authors = [ - "Julien Cretin " - ]; - features = { - "default" = [ "std" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "der" = rec { - crateName = "der"; - version = "0.7.9"; - edition = "2021"; - sha256 = "1h4vzjfa1lczxdf8avfj9qlwh1qianqlxdy1g5rn762qnvkzhnzm"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "const-oid"; - packageId = "const-oid"; - optional = true; - } - { - name = "zeroize"; - packageId = "zeroize"; - optional = true; - usesDefaultFeatures = false; - } - ]; - features = { - "alloc" = [ "zeroize?/alloc" ]; - "arbitrary" = [ "dep:arbitrary" "const-oid?/arbitrary" "std" ]; - "bytes" = [ "dep:bytes" "alloc" ]; - "derive" = [ "dep:der_derive" ]; - "flagset" = [ "dep:flagset" ]; - "oid" = [ "dep:const-oid" ]; - "pem" = [ "dep:pem-rfc7468" "alloc" "zeroize" ]; - "std" = [ "alloc" ]; - "time" = [ "dep:time" ]; - "zeroize" = [ "dep:zeroize" ]; - }; - resolvedDefaultFeatures = [ "alloc" "oid" "std" "zeroize" ]; - }; - "digest" = rec { - crateName = "digest"; - version = "0.10.7"; - edition = "2018"; - sha256 = "14p2n6ih29x81akj097lvz7wi9b6b9hvls0lwrv7b6xwyy0s5ncy"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "block-buffer"; - packageId = "block-buffer"; - optional = true; - } - { - name = "crypto-common"; - packageId = "crypto-common"; - } - ]; - features = { - "blobby" = [ "dep:blobby" ]; - "block-buffer" = [ "dep:block-buffer" ]; - "const-oid" = [ "dep:const-oid" ]; - "core-api" = [ "block-buffer" ]; - "default" = [ "core-api" ]; - "dev" = [ "blobby" ]; - "mac" = [ "subtle" ]; - "oid" = [ "const-oid" ]; - "rand_core" = [ "crypto-common/rand_core" ]; - "std" = [ "alloc" "crypto-common/std" ]; - "subtle" = [ "dep:subtle" ]; - }; - resolvedDefaultFeatures = [ "alloc" "block-buffer" "core-api" "default" "std" ]; - }; - "document-features" = rec { - crateName = "document-features"; - version = "0.2.10"; - edition = "2018"; - sha256 = "182h528pjyv4ppil2pd2nir46qrb393x5kvm4y51yhnjmgm6jsfb"; - procMacro = true; - libName = "document_features"; - libPath = "lib.rs"; - authors = [ - "Slint Developers " - ]; - dependencies = [ - { - name = "litrs"; - packageId = "litrs"; - usesDefaultFeatures = false; - } - ]; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "ed25519" = rec { - crateName = "ed25519"; - version = "2.2.3"; - edition = "2021"; - sha256 = "0lydzdf26zbn82g7xfczcac9d7mzm3qgx934ijjrd5hjpjx32m8i"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "pkcs8"; - packageId = "pkcs8"; - optional = true; - } - { - name = "signature"; - packageId = "signature"; - usesDefaultFeatures = false; - } - ]; - features = { - "alloc" = [ "pkcs8?/alloc" ]; - "default" = [ "std" ]; - "pem" = [ "alloc" "pkcs8/pem" ]; - "pkcs8" = [ "dep:pkcs8" ]; - "serde" = [ "dep:serde" ]; - "serde_bytes" = [ "serde" "dep:serde_bytes" ]; - "std" = [ "pkcs8?/std" "signature/std" ]; - "zeroize" = [ "dep:zeroize" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "ed25519-dalek" = rec { - crateName = "ed25519-dalek"; - version = "2.1.1"; - edition = "2021"; - sha256 = "0w88cafwglg9hjizldbmlza0ns3hls81zk1bcih3m5m3h67algaa"; - libName = "ed25519_dalek"; - authors = [ - "isis lovecruft " - "Tony Arcieri " - "Michael Rosenberg " - ]; - dependencies = [ - { - name = "curve25519-dalek"; - packageId = "curve25519-dalek"; - usesDefaultFeatures = false; - features = [ "digest" ]; - } - { - name = "ed25519"; - packageId = "ed25519"; - usesDefaultFeatures = false; - } - { - name = "serde"; - packageId = "serde"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "sha2"; - packageId = "sha2"; - usesDefaultFeatures = false; - } - { - name = "subtle"; - packageId = "subtle"; - usesDefaultFeatures = false; - } - { - name = "zeroize"; - packageId = "zeroize"; - optional = true; - usesDefaultFeatures = false; - } - ]; - devDependencies = [ - { - name = "curve25519-dalek"; - packageId = "curve25519-dalek"; - usesDefaultFeatures = false; - features = [ "digest" "rand_core" ]; - } - { - name = "serde"; - packageId = "serde"; - features = [ "derive" ]; - } - ]; - features = { - "alloc" = [ "curve25519-dalek/alloc" "ed25519/alloc" "serde?/alloc" "zeroize/alloc" ]; - "asm" = [ "sha2/asm" ]; - "batch" = [ "alloc" "merlin" "rand_core" ]; - "default" = [ "fast" "std" "zeroize" ]; - "digest" = [ "signature/digest" ]; - "fast" = [ "curve25519-dalek/precomputed-tables" ]; - "legacy_compatibility" = [ "curve25519-dalek/legacy_compatibility" ]; - "merlin" = [ "dep:merlin" ]; - "pem" = [ "alloc" "ed25519/pem" "pkcs8" ]; - "pkcs8" = [ "ed25519/pkcs8" ]; - "rand_core" = [ "dep:rand_core" ]; - "serde" = [ "dep:serde" "ed25519/serde" ]; - "signature" = [ "dep:signature" ]; - "std" = [ "alloc" "ed25519/std" "serde?/std" "sha2/std" ]; - "zeroize" = [ "dep:zeroize" "curve25519-dalek/zeroize" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "fast" "std" "zeroize" ]; - }; - "enum-primitive-derive" = rec { - crateName = "enum-primitive-derive"; - version = "0.3.0"; - edition = "2018"; - sha256 = "0k6wcf58h5kh64yq5nfq71va53kaya0kzxwsjwbgwm2n2zd9axxs"; - procMacro = true; - libName = "enum_primitive_derive"; - authors = [ - "Doug Goldstein " - ]; - dependencies = [ - { - name = "num-traits"; - packageId = "num-traits"; - usesDefaultFeatures = false; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - } - ]; - - }; - "equivalent" = rec { - crateName = "equivalent"; - version = "1.0.1"; - edition = "2015"; - sha256 = "1malmx5f4lkfvqasz319lq6gb3ddg19yzf9s8cykfsgzdmyq0hsl"; - - }; - "fiat-crypto" = rec { - crateName = "fiat-crypto"; - version = "0.2.9"; - edition = "2018"; - sha256 = "07c1vknddv3ak7w89n85ik0g34nzzpms6yb845vrjnv9m4csbpi8"; - libName = "fiat_crypto"; - authors = [ - "Fiat Crypto library authors " - ]; - features = { - "default" = [ "std" ]; - }; - }; - "fnv" = rec { - crateName = "fnv"; - version = "1.0.7"; - edition = "2015"; - sha256 = "1hc2mcqha06aibcaza94vbi81j6pr9a1bbxrxjfhc91zin8yr7iz"; - libPath = "lib.rs"; - authors = [ - "Alex Crichton " - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "form_urlencoded" = rec { - crateName = "form_urlencoded"; - version = "1.2.1"; - edition = "2018"; - sha256 = "0milh8x7nl4f450s3ddhg57a3flcv6yq8hlkyk6fyr3mcb128dp1"; - authors = [ - "The rust-url developers" - ]; - dependencies = [ - { - name = "percent-encoding"; - packageId = "percent-encoding"; - usesDefaultFeatures = false; - } - ]; - features = { - "alloc" = [ "percent-encoding/alloc" ]; - "default" = [ "std" ]; - "std" = [ "alloc" "percent-encoding/std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "futures" = rec { - crateName = "futures"; - version = "0.3.31"; - edition = "2018"; - sha256 = "0xh8ddbkm9jy8kc5gbvjp9a4b6rqqxvc8471yb2qaz5wm2qhgg35"; - dependencies = [ - { - name = "futures-channel"; - packageId = "futures-channel"; - usesDefaultFeatures = false; - features = [ "sink" ]; - } - { - name = "futures-core"; - packageId = "futures-core"; - usesDefaultFeatures = false; - } - { - name = "futures-executor"; - packageId = "futures-executor"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "futures-io"; - packageId = "futures-io"; - usesDefaultFeatures = false; - } - { - name = "futures-sink"; - packageId = "futures-sink"; - usesDefaultFeatures = false; - } - { - name = "futures-task"; - packageId = "futures-task"; - usesDefaultFeatures = false; - } - { - name = "futures-util"; - packageId = "futures-util"; - usesDefaultFeatures = false; - features = [ "sink" ]; - } - ]; - features = { - "alloc" = [ "futures-core/alloc" "futures-task/alloc" "futures-sink/alloc" "futures-channel/alloc" "futures-util/alloc" ]; - "async-await" = [ "futures-util/async-await" "futures-util/async-await-macro" ]; - "bilock" = [ "futures-util/bilock" ]; - "compat" = [ "std" "futures-util/compat" ]; - "default" = [ "std" "async-await" "executor" ]; - "executor" = [ "std" "futures-executor/std" ]; - "futures-executor" = [ "dep:futures-executor" ]; - "io-compat" = [ "compat" "futures-util/io-compat" ]; - "std" = [ "alloc" "futures-core/std" "futures-task/std" "futures-io/std" "futures-sink/std" "futures-util/std" "futures-util/io" "futures-util/channel" ]; - "thread-pool" = [ "executor" "futures-executor/thread-pool" ]; - "unstable" = [ "futures-core/unstable" "futures-task/unstable" "futures-channel/unstable" "futures-io/unstable" "futures-util/unstable" ]; - "write-all-vectored" = [ "futures-util/write-all-vectored" ]; - }; - resolvedDefaultFeatures = [ "alloc" "async-await" "default" "executor" "futures-executor" "std" ]; - }; - "futures-channel" = rec { - crateName = "futures-channel"; - version = "0.3.31"; - edition = "2018"; - sha256 = "040vpqpqlbk099razq8lyn74m0f161zd0rp36hciqrwcg2zibzrd"; - libName = "futures_channel"; - dependencies = [ - { - name = "futures-core"; - packageId = "futures-core"; - usesDefaultFeatures = false; - } - { - name = "futures-sink"; - packageId = "futures-sink"; - optional = true; - usesDefaultFeatures = false; - } - ]; - features = { - "alloc" = [ "futures-core/alloc" ]; - "default" = [ "std" ]; - "futures-sink" = [ "dep:futures-sink" ]; - "sink" = [ "futures-sink" ]; - "std" = [ "alloc" "futures-core/std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "futures-sink" "sink" "std" ]; - }; - "futures-core" = rec { - crateName = "futures-core"; - version = "0.3.31"; - edition = "2018"; - sha256 = "0gk6yrxgi5ihfanm2y431jadrll00n5ifhnpx090c2f2q1cr1wh5"; - libName = "futures_core"; - features = { - "default" = [ "std" ]; - "portable-atomic" = [ "dep:portable-atomic" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "futures-executor" = rec { - crateName = "futures-executor"; - version = "0.3.31"; - edition = "2018"; - sha256 = "17vcci6mdfzx4gbk0wx64chr2f13wwwpvyf3xd5fb1gmjzcx2a0y"; - libName = "futures_executor"; - dependencies = [ - { - name = "futures-core"; - packageId = "futures-core"; - usesDefaultFeatures = false; - } - { - name = "futures-task"; - packageId = "futures-task"; - usesDefaultFeatures = false; - } - { - name = "futures-util"; - packageId = "futures-util"; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "std" ]; - "num_cpus" = [ "dep:num_cpus" ]; - "std" = [ "futures-core/std" "futures-task/std" "futures-util/std" ]; - "thread-pool" = [ "std" "num_cpus" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "futures-io" = rec { - crateName = "futures-io"; - version = "0.3.31"; - edition = "2018"; - sha256 = "1ikmw1yfbgvsychmsihdkwa8a1knank2d9a8dk01mbjar9w1np4y"; - libName = "futures_io"; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "futures-macro" = rec { - crateName = "futures-macro"; - version = "0.3.31"; - edition = "2018"; - sha256 = "0l1n7kqzwwmgiznn0ywdc5i24z72zvh9q1dwps54mimppi7f6bhn"; - procMacro = true; - libName = "futures_macro"; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - features = [ "full" ]; - } - ]; - - }; - "futures-sink" = rec { - crateName = "futures-sink"; - version = "0.3.31"; - edition = "2018"; - sha256 = "1xyly6naq6aqm52d5rh236snm08kw8zadydwqz8bip70s6vzlxg5"; - libName = "futures_sink"; - features = { - "default" = [ "std" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "futures-task" = rec { - crateName = "futures-task"; - version = "0.3.31"; - edition = "2018"; - sha256 = "124rv4n90f5xwfsm9qw6y99755y021cmi5dhzh253s920z77s3zr"; - libName = "futures_task"; - features = { - "default" = [ "std" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "std" ]; - }; - "futures-util" = rec { - crateName = "futures-util"; - version = "0.3.31"; - edition = "2018"; - sha256 = "10aa1ar8bgkgbr4wzxlidkqkcxf77gffyj8j7768h831pcaq784z"; - libName = "futures_util"; - dependencies = [ - { - name = "futures-channel"; - packageId = "futures-channel"; - optional = true; - usesDefaultFeatures = false; - features = [ "std" ]; - } - { - name = "futures-core"; - packageId = "futures-core"; - usesDefaultFeatures = false; - } - { - name = "futures-io"; - packageId = "futures-io"; - optional = true; - usesDefaultFeatures = false; - features = [ "std" ]; - } - { - name = "futures-macro"; - packageId = "futures-macro"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "futures-sink"; - packageId = "futures-sink"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "futures-task"; - packageId = "futures-task"; - usesDefaultFeatures = false; - } - { - name = "memchr"; - packageId = "memchr"; - optional = true; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "pin-utils"; - packageId = "pin-utils"; - } - { - name = "slab"; - packageId = "slab"; - optional = true; - } - ]; - features = { - "alloc" = [ "futures-core/alloc" "futures-task/alloc" ]; - "async-await-macro" = [ "async-await" "futures-macro" ]; - "channel" = [ "std" "futures-channel" ]; - "compat" = [ "std" "futures_01" ]; - "default" = [ "std" "async-await" "async-await-macro" ]; - "futures-channel" = [ "dep:futures-channel" ]; - "futures-io" = [ "dep:futures-io" ]; - "futures-macro" = [ "dep:futures-macro" ]; - "futures-sink" = [ "dep:futures-sink" ]; - "futures_01" = [ "dep:futures_01" ]; - "io" = [ "std" "futures-io" "memchr" ]; - "io-compat" = [ "io" "compat" "tokio-io" ]; - "memchr" = [ "dep:memchr" ]; - "portable-atomic" = [ "futures-core/portable-atomic" ]; - "sink" = [ "futures-sink" ]; - "slab" = [ "dep:slab" ]; - "std" = [ "alloc" "futures-core/std" "futures-task/std" "slab" ]; - "tokio-io" = [ "dep:tokio-io" ]; - "unstable" = [ "futures-core/unstable" "futures-task/unstable" ]; - "write-all-vectored" = [ "io" ]; - }; - resolvedDefaultFeatures = [ "alloc" "async-await" "async-await-macro" "channel" "default" "futures-channel" "futures-io" "futures-macro" "futures-sink" "io" "memchr" "sink" "slab" "std" ]; - }; - "generic-array" = rec { - crateName = "generic-array"; - version = "0.14.7"; - edition = "2015"; - sha256 = "16lyyrzrljfq424c3n8kfwkqihlimmsg5nhshbbp48np3yjrqr45"; - libName = "generic_array"; - authors = [ - "Bartłomiej Kamiński " - "Aaron Trent " - ]; - dependencies = [ - { - name = "typenum"; - packageId = "typenum"; - } - ]; - buildDependencies = [ - { - name = "version_check"; - packageId = "version_check"; - } - ]; - features = { - "serde" = [ "dep:serde" ]; - "zeroize" = [ "dep:zeroize" ]; - }; - resolvedDefaultFeatures = [ "more_lengths" ]; - }; - "getrandom" = rec { - crateName = "getrandom"; - version = "0.2.15"; - edition = "2018"; - sha256 = "1mzlnrb3dgyd1fb84gvw10pyr8wdqdl4ry4sr64i1s8an66pqmn4"; - authors = [ - "The Rand Project Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if"; - } - { - name = "libc"; - packageId = "libc"; - usesDefaultFeatures = false; - target = { target, features }: (target."unix" or false); - } - { - name = "wasi"; - packageId = "wasi"; - usesDefaultFeatures = false; - target = { target, features }: ("wasi" == target."os" or null); - } - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "js" = [ "wasm-bindgen" "js-sys" ]; - "js-sys" = [ "dep:js-sys" ]; - "rustc-dep-of-std" = [ "compiler_builtins" "core" "libc/rustc-dep-of-std" "wasi/rustc-dep-of-std" ]; - "wasm-bindgen" = [ "dep:wasm-bindgen" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "gimli" = rec { - crateName = "gimli"; - version = "0.31.1"; - edition = "2018"; - sha256 = "0gvqc0ramx8szv76jhfd4dms0zyamvlg4whhiz11j34hh3dqxqh7"; - features = { - "default" = [ "read-all" "write" ]; - "endian-reader" = [ "read" "dep:stable_deref_trait" ]; - "fallible-iterator" = [ "dep:fallible-iterator" ]; - "read" = [ "read-core" ]; - "read-all" = [ "read" "std" "fallible-iterator" "endian-reader" ]; - "rustc-dep-of-std" = [ "dep:core" "dep:alloc" "dep:compiler_builtins" ]; - "std" = [ "fallible-iterator?/std" "stable_deref_trait?/std" ]; - "write" = [ "dep:indexmap" ]; - }; - resolvedDefaultFeatures = [ "read" "read-core" ]; - }; - "glob" = rec { - crateName = "glob"; - version = "0.3.1"; - edition = "2015"; - sha256 = "16zca52nglanv23q5qrwd5jinw3d3as5ylya6y1pbx47vkxvrynj"; - authors = [ - "The Rust Project Developers" - ]; - - }; - "hashbrown" = rec { - crateName = "hashbrown"; - version = "0.15.1"; - edition = "2021"; - sha256 = "1czsvasi3azv2079fcvbhvpisa16w6fi1mfk8zm2c5wbyqdgr6rs"; - authors = [ - "Amanieu d'Antras " - ]; - features = { - "alloc" = [ "dep:alloc" ]; - "allocator-api2" = [ "dep:allocator-api2" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "default-hasher" "inline-more" "allocator-api2" "equivalent" "raw-entry" ]; - "default-hasher" = [ "dep:foldhash" ]; - "equivalent" = [ "dep:equivalent" ]; - "nightly" = [ "allocator-api2?/nightly" "bumpalo/allocator_api" ]; - "rayon" = [ "dep:rayon" ]; - "rustc-dep-of-std" = [ "nightly" "core" "compiler_builtins" "alloc" "rustc-internal-api" "raw-entry" ]; - "serde" = [ "dep:serde" ]; - }; - }; - "heck" = rec { - crateName = "heck"; - version = "0.5.0"; - edition = "2021"; - sha256 = "1sjmpsdl8czyh9ywl3qcsfsq9a307dg4ni2vnlwgnzzqhc4y0113"; - - }; - "hermit-abi" = rec { - crateName = "hermit-abi"; - version = "0.3.9"; - edition = "2021"; - sha256 = "092hxjbjnq5fmz66grd9plxd0sh6ssg5fhgwwwqbrzgzkjwdycfj"; - libName = "hermit_abi"; - authors = [ - "Stefan Lankes" - ]; - features = { - "alloc" = [ "dep:alloc" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "alloc" "compiler_builtins/rustc-dep-of-std" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "http" = rec { - crateName = "http"; - version = "1.1.0"; - edition = "2018"; - sha256 = "0n426lmcxas6h75c2cp25m933pswlrfjz10v91vc62vib2sdvf91"; - authors = [ - "Alex Crichton " - "Carl Lerche " - "Sean McArthur " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "fnv"; - packageId = "fnv"; - } - { - name = "itoa"; - packageId = "itoa"; - } - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "http-body" = rec { - crateName = "http-body"; - version = "1.0.1"; - edition = "2018"; - sha256 = "111ir5k2b9ihz5nr9cz7cwm7fnydca7dx4hc7vr16scfzghxrzhy"; - libName = "http_body"; - authors = [ - "Carl Lerche " - "Lucio Franco " - "Sean McArthur " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "http"; - packageId = "http"; - } - ]; - - }; - "http-body-util" = rec { - crateName = "http-body-util"; - version = "0.1.2"; - edition = "2018"; - sha256 = "0kslwazg4400qnc2azkrgqqci0fppv12waicnsy5d8hncvbjjd3r"; - libName = "http_body_util"; - authors = [ - "Carl Lerche " - "Lucio Franco " - "Sean McArthur " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures-util"; - packageId = "futures-util"; - usesDefaultFeatures = false; - } - { - name = "http"; - packageId = "http"; - } - { - name = "http-body"; - packageId = "http-body"; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - ]; - - }; - "httparse" = rec { - crateName = "httparse"; - version = "1.9.5"; - edition = "2018"; - sha256 = "0ip9v8m9lvgvq1lznl31wvn0ch1v254na7lhid9p29yx9rbx6wbx"; - authors = [ - "Sean McArthur " - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "httpdate" = rec { - crateName = "httpdate"; - version = "1.0.3"; - edition = "2021"; - sha256 = "1aa9rd2sac0zhjqh24c9xvir96g188zldkx0hr6dnnlx5904cfyz"; - authors = [ - "Pyfisch " - ]; - - }; - "hyper" = rec { - crateName = "hyper"; - version = "1.4.1"; - edition = "2021"; - sha256 = "01ds8i3q6hw5kw56mavy544m11gkr87zi999siigdl3n1qpd5psh"; - authors = [ - "Sean McArthur " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures-channel"; - packageId = "futures-channel"; - optional = true; - } - { - name = "futures-util"; - packageId = "futures-util"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "http"; - packageId = "http"; - } - { - name = "http-body"; - packageId = "http-body"; - } - { - name = "httparse"; - packageId = "httparse"; - optional = true; - } - { - name = "httpdate"; - packageId = "httpdate"; - optional = true; - } - { - name = "itoa"; - packageId = "itoa"; - optional = true; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - optional = true; - } - { - name = "smallvec"; - packageId = "smallvec"; - optional = true; - features = [ "const_generics" "const_new" ]; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "sync" ]; - } - ]; - devDependencies = [ - { - name = "futures-channel"; - packageId = "futures-channel"; - features = [ "sink" ]; - } - { - name = "futures-util"; - packageId = "futures-util"; - usesDefaultFeatures = false; - features = [ "alloc" "sink" ]; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "fs" "macros" "net" "io-std" "io-util" "rt" "rt-multi-thread" "sync" "time" "test-util" ]; - } - ]; - features = { - "client" = [ "dep:want" "dep:pin-project-lite" "dep:smallvec" ]; - "ffi" = [ "dep:libc" "dep:http-body-util" "futures-util?/alloc" ]; - "full" = [ "client" "http1" "http2" "server" ]; - "http1" = [ "dep:futures-channel" "dep:futures-util" "dep:httparse" "dep:itoa" ]; - "http2" = [ "dep:futures-channel" "dep:futures-util" "dep:h2" ]; - "server" = [ "dep:httpdate" "dep:pin-project-lite" "dep:smallvec" ]; - "tracing" = [ "dep:tracing" ]; - }; - resolvedDefaultFeatures = [ "default" "http1" "server" ]; - }; - "hyper-util" = rec { - crateName = "hyper-util"; - version = "0.1.9"; - edition = "2021"; - sha256 = "12yhradh0bpwa9jjyyq6shrrcx9fxbdkrq06xj7ccfhqkyq6waa1"; - libName = "hyper_util"; - authors = [ - "Sean McArthur " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures-util"; - packageId = "futures-util"; - usesDefaultFeatures = false; - } - { - name = "http"; - packageId = "http"; - } - { - name = "http-body"; - packageId = "http-body"; - } - { - name = "hyper"; - packageId = "hyper"; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "tokio"; - packageId = "tokio"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "tower-service"; - packageId = "tower-service"; - optional = true; - } - ]; - devDependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "hyper"; - packageId = "hyper"; - features = [ "full" ]; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "macros" "test-util" "signal" ]; - } - ]; - features = { - "client" = [ "hyper/client" "dep:tracing" "dep:futures-channel" "dep:tower-service" ]; - "client-legacy" = [ "client" "dep:socket2" "tokio/sync" ]; - "full" = [ "client" "client-legacy" "server" "server-auto" "server-graceful" "service" "http1" "http2" "tokio" ]; - "http1" = [ "hyper/http1" ]; - "http2" = [ "hyper/http2" ]; - "server" = [ "hyper/server" ]; - "server-auto" = [ "server" "http1" "http2" ]; - "server-graceful" = [ "server" "tokio/sync" "futures-util/alloc" ]; - "service" = [ "dep:tower-service" ]; - "tokio" = [ "dep:tokio" "tokio/net" "tokio/rt" "tokio/time" ]; - }; - resolvedDefaultFeatures = [ "default" "http1" "server" "service" "tokio" ]; - }; - "indexmap" = rec { - crateName = "indexmap"; - version = "2.6.0"; - edition = "2021"; - sha256 = "1nmrwn8lbs19gkvhxaawffzbvrpyrb5y3drcrr645x957kz0fybh"; - dependencies = [ - { - name = "equivalent"; - packageId = "equivalent"; - usesDefaultFeatures = false; - } - { - name = "hashbrown"; - packageId = "hashbrown"; - usesDefaultFeatures = false; - } - ]; - features = { - "arbitrary" = [ "dep:arbitrary" ]; - "borsh" = [ "dep:borsh" ]; - "default" = [ "std" ]; - "quickcheck" = [ "dep:quickcheck" ]; - "rayon" = [ "dep:rayon" ]; - "rustc-rayon" = [ "dep:rustc-rayon" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "is_terminal_polyfill" = rec { - crateName = "is_terminal_polyfill"; - version = "1.70.1"; - edition = "2021"; - sha256 = "1kwfgglh91z33kl0w5i338mfpa3zs0hidq5j4ny4rmjwrikchhvr"; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "itoa" = rec { - crateName = "itoa"; - version = "1.0.11"; - edition = "2018"; - sha256 = "0nv9cqjwzr3q58qz84dcz63ggc54yhf1yqar1m858m1kfd4g3wa9"; - authors = [ - "David Tolnay " - ]; - features = { - "no-panic" = [ "dep:no-panic" ]; - }; - }; - "lazy_static" = rec { - crateName = "lazy_static"; - version = "1.5.0"; - edition = "2015"; - sha256 = "1zk6dqqni0193xg6iijh7i3i44sryglwgvx20spdvwk3r6sbrlmv"; - authors = [ - "Marvin Löbel " - ]; - features = { - "spin" = [ "dep:spin" ]; - "spin_no_std" = [ "spin" ]; - }; - }; - "libc" = rec { - crateName = "libc"; - version = "0.2.159"; - edition = "2015"; - sha256 = "1i9xpia0hn1y8dws7all8rqng6h3lc8ymlgslnljcvm376jrf7an"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "default" = [ "std" ]; - "rustc-dep-of-std" = [ "align" "rustc-std-workspace-core" ]; - "rustc-std-workspace-core" = [ "dep:rustc-std-workspace-core" ]; - "use_std" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "extra_traits" "std" ]; - }; - "libmimalloc-sys" = rec { - crateName = "libmimalloc-sys"; - version = "0.1.39"; - edition = "2018"; - links = "mimalloc"; - sha256 = "0i3b0dzz7cp0ik7ys66q92r16va78gwlbrnxhj5fnkdxsc8niai3"; - libName = "libmimalloc_sys"; - authors = [ - "Octavian Oncescu " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - } - ]; - buildDependencies = [ - { - name = "cc"; - packageId = "cc"; - } - ]; - features = { - "cty" = [ "dep:cty" ]; - "extended" = [ "cty" ]; - }; - }; - "litrs" = rec { - crateName = "litrs"; - version = "0.4.1"; - edition = "2018"; - sha256 = "19cssch9gc0x2snd9089nvwzz79zx6nzsi3icffpx25p4hck1kml"; - authors = [ - "Lukas Kalbertodt " - ]; - features = { - "check_suffix" = [ "unicode-xid" ]; - "default" = [ "proc-macro2" ]; - "proc-macro2" = [ "dep:proc-macro2" ]; - "unicode-xid" = [ "dep:unicode-xid" ]; - }; - }; - "lock_api" = rec { - crateName = "lock_api"; - version = "0.4.12"; - edition = "2021"; - sha256 = "05qvxa6g27yyva25a5ghsg85apdxkvr77yhkyhapj6r8vnf8pbq7"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "scopeguard"; - packageId = "scopeguard"; - usesDefaultFeatures = false; - } - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { - "default" = [ "atomic_usize" ]; - "owning_ref" = [ "dep:owning_ref" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "atomic_usize" "default" ]; - }; - "log" = rec { - crateName = "log"; - version = "0.4.22"; - edition = "2021"; - sha256 = "093vs0wkm1rgyykk7fjbqp2lwizbixac1w52gv109p5r4jh0p9x7"; - authors = [ - "The Rust Project Developers" - ]; - features = { - "kv_serde" = [ "kv_std" "value-bag/serde" "serde" ]; - "kv_std" = [ "std" "kv" "value-bag/error" ]; - "kv_sval" = [ "kv" "value-bag/sval" "sval" "sval_ref" ]; - "kv_unstable" = [ "kv" "value-bag" ]; - "kv_unstable_serde" = [ "kv_serde" "kv_unstable_std" ]; - "kv_unstable_std" = [ "kv_std" "kv_unstable" ]; - "kv_unstable_sval" = [ "kv_sval" "kv_unstable" ]; - "serde" = [ "dep:serde" ]; - "sval" = [ "dep:sval" ]; - "sval_ref" = [ "dep:sval_ref" ]; - "value-bag" = [ "dep:value-bag" ]; - }; - resolvedDefaultFeatures = [ "std" ]; - }; - "matchit" = rec { - crateName = "matchit"; - version = "0.7.3"; - edition = "2021"; - sha256 = "156bgdmmlv4crib31qhgg49nsjk88dxkdqp80ha2pk2rk6n6ax0f"; - authors = [ - "Ibraheem Ahmed " - ]; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "memchr" = rec { - crateName = "memchr"; - version = "2.7.4"; - edition = "2021"; - sha256 = "18z32bhxrax0fnjikv475z7ii718hq457qwmaryixfxsl2qrmjkq"; - authors = [ - "Andrew Gallant " - "bluss" - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" ]; - "logging" = [ "dep:log" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - "std" = [ "alloc" ]; - "use_std" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "mimalloc" = rec { - crateName = "mimalloc"; - version = "0.1.43"; - edition = "2018"; - sha256 = "0csnyrxc16i592gm5ffham07jyj2w98qsh9jyy1rv59lmr8474b8"; - authors = [ - "Octavian Oncescu " - "Vincent Rouillé " - "Thom Chiovoloni " - ]; - dependencies = [ - { - name = "libmimalloc-sys"; - packageId = "libmimalloc-sys"; - usesDefaultFeatures = false; - } - ]; - features = { - "debug" = [ "libmimalloc-sys/debug" ]; - "debug_in_debug" = [ "libmimalloc-sys/debug_in_debug" ]; - "extended" = [ "libmimalloc-sys/extended" ]; - "local_dynamic_tls" = [ "libmimalloc-sys/local_dynamic_tls" ]; - "no_thp" = [ "libmimalloc-sys/no_thp" ]; - "override" = [ "libmimalloc-sys/override" ]; - "secure" = [ "libmimalloc-sys/secure" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "mime" = rec { - crateName = "mime"; - version = "0.3.17"; - edition = "2015"; - sha256 = "16hkibgvb9klh0w0jk5crr5xv90l3wlf77ggymzjmvl1818vnxv8"; - authors = [ - "Sean McArthur " - ]; - - }; - "miniz_oxide" = rec { - crateName = "miniz_oxide"; - version = "0.8.0"; - edition = "2021"; - sha256 = "1wadxkg6a6z4lr7kskapj5d8pxlx7cp1ifw4daqnkzqjxych5n72"; - authors = [ - "Frommi " - "oyvindln " - ]; - dependencies = [ - { - name = "adler2"; - packageId = "adler2"; - usesDefaultFeatures = false; - } - ]; - features = { - "alloc" = [ "dep:alloc" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "with-alloc" ]; - "rustc-dep-of-std" = [ "core" "alloc" "compiler_builtins" "adler2/rustc-dep-of-std" ]; - "simd" = [ "simd-adler32" ]; - "simd-adler32" = [ "dep:simd-adler32" ]; - }; - }; - "mio" = rec { - crateName = "mio"; - version = "1.0.2"; - edition = "2021"; - sha256 = "1v1cnnn44awxbcfm4zlavwgkvbyg7gp5zzjm8mqf1apkrwflvq40"; - authors = [ - "Carl Lerche " - "Thomas de Zeeuw " - "Tokio Contributors " - ]; - dependencies = [ - { - name = "hermit-abi"; - packageId = "hermit-abi"; - rename = "libc"; - target = { target, features }: ("hermit" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: ("wasi" == target."os" or null); - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "wasi"; - packageId = "wasi"; - target = { target, features }: ("wasi" == target."os" or null); - } - { - name = "windows-sys"; - packageId = "windows-sys"; - target = { target, features }: (target."windows" or false); - features = [ "Wdk_Foundation" "Wdk_Storage_FileSystem" "Wdk_System_IO" "Win32_Foundation" "Win32_Networking_WinSock" "Win32_Storage_FileSystem" "Win32_System_IO" "Win32_System_WindowsProgramming" ]; - } - ]; - features = { - "default" = [ "log" ]; - "log" = [ "dep:log" ]; - "os-ext" = [ "os-poll" "windows-sys/Win32_System_Pipes" "windows-sys/Win32_Security" ]; - }; - resolvedDefaultFeatures = [ "net" "os-ext" "os-poll" ]; - }; - "nix" = rec { - crateName = "nix"; - version = "0.26.4"; - edition = "2018"; - sha256 = "06xgl4ybb8pvjrbmc3xggbgk3kbs1j0c4c0nzdfrmpbgrkrym2sr"; - authors = [ - "The nix-rust Project Developers" - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 1.3.2"; - } - { - name = "cfg-if"; - packageId = "cfg-if"; - } - { - name = "libc"; - packageId = "libc"; - features = [ "extra_traits" ]; - } - ]; - features = { - "aio" = [ "pin-utils" ]; - "default" = [ "acct" "aio" "dir" "env" "event" "feature" "fs" "hostname" "inotify" "ioctl" "kmod" "mman" "mount" "mqueue" "net" "personality" "poll" "process" "pthread" "ptrace" "quota" "reboot" "resource" "sched" "signal" "socket" "term" "time" "ucontext" "uio" "user" "zerocopy" ]; - "dir" = [ "fs" ]; - "memoffset" = [ "dep:memoffset" ]; - "mount" = [ "uio" ]; - "mqueue" = [ "fs" ]; - "net" = [ "socket" ]; - "pin-utils" = [ "dep:pin-utils" ]; - "ptrace" = [ "process" ]; - "sched" = [ "process" ]; - "signal" = [ "process" ]; - "socket" = [ "memoffset" ]; - "ucontext" = [ "signal" ]; - "user" = [ "feature" ]; - "zerocopy" = [ "fs" "uio" ]; - }; - resolvedDefaultFeatures = [ "feature" "fs" "user" ]; - }; - "nix-compat" = rec { - crateName = "nix-compat"; - version = "0.1.0"; - edition = "2021"; - crateBin = [ ]; - src = lib.cleanSourceWith { filter = sourceFilter; src = ../../../tvix/nix-compat; }; - libName = "nix_compat"; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 2.6.0"; - } - { - name = "bstr"; - packageId = "bstr"; - features = [ "alloc" "unicode" "serde" ]; - } - { - name = "bytes"; - packageId = "bytes"; - optional = true; - } - { - name = "data-encoding"; - packageId = "data-encoding"; - } - { - name = "ed25519"; - packageId = "ed25519"; - } - { - name = "ed25519-dalek"; - packageId = "ed25519-dalek"; - } - { - name = "enum-primitive-derive"; - packageId = "enum-primitive-derive"; - } - { - name = "futures"; - packageId = "futures"; - optional = true; - } - { - name = "glob"; - packageId = "glob"; - } - { - name = "mimalloc"; - packageId = "mimalloc"; - } - { - name = "nix-compat-derive"; - packageId = "nix-compat-derive"; - optional = true; - } - { - name = "nom"; - packageId = "nom"; - } - { - name = "num-traits"; - packageId = "num-traits"; - } - { - name = "num_enum"; - packageId = "num_enum"; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - optional = true; - } - { - name = "serde"; - packageId = "serde"; - features = [ "derive" ]; - } - { - name = "serde_json"; - packageId = "serde_json"; - } - { - name = "serde_repr"; - packageId = "serde_repr"; - } - { - name = "sha2"; - packageId = "sha2"; - } - { - name = "thiserror"; - packageId = "thiserror"; - } - { - name = "tokio"; - packageId = "tokio"; - optional = true; - features = [ "io-util" "macros" "sync" ]; - } - { - name = "tracing"; - packageId = "tracing"; - } - ]; - devDependencies = [ - { - name = "futures"; - packageId = "futures"; - } - { - name = "mimalloc"; - packageId = "mimalloc"; - } - ]; - features = { - "async" = [ "tokio" ]; - "bytes" = [ "dep:bytes" ]; - "daemon" = [ "tokio" "nix-compat-derive" "futures" ]; - "default" = [ "async" "daemon" "wire" "nix-compat-derive" ]; - "futures" = [ "dep:futures" ]; - "nix-compat-derive" = [ "dep:nix-compat-derive" ]; - "pin-project-lite" = [ "dep:pin-project-lite" ]; - "tokio" = [ "dep:tokio" ]; - "wire" = [ "tokio" "pin-project-lite" "bytes" ]; - }; - resolvedDefaultFeatures = [ "async" "bytes" "daemon" "default" "futures" "nix-compat-derive" "pin-project-lite" "tokio" "wire" ]; - }; - "nix-compat-derive" = rec { - crateName = "nix-compat-derive"; - version = "0.1.0"; - edition = "2021"; - src = lib.cleanSourceWith { filter = sourceFilter; src = ../../../tvix/nix-compat-derive; }; - procMacro = true; - libName = "nix_compat_derive"; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - features = [ "proc-macro" ]; - } - { - name = "quote"; - packageId = "quote"; - features = [ "proc-macro" ]; - } - { - name = "syn"; - packageId = "syn"; - features = [ "full" "extra-traits" ]; - } - ]; - - }; - "nom" = rec { - crateName = "nom"; - version = "8.0.0"; - edition = "2021"; - sha256 = "01cl5xng9d0gxf26h39m0l8lprgpa00fcc75ps1yzgbib1vn35yz"; - authors = [ - "contact@geoffroycouprie.com" - ]; - dependencies = [ - { - name = "memchr"; - packageId = "memchr"; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "std" ]; - "std" = [ "alloc" "memchr/std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "nu-ansi-term" = rec { - crateName = "nu-ansi-term"; - version = "0.46.0"; - edition = "2018"; - sha256 = "115sywxh53p190lyw97alm14nc004qj5jm5lvdj608z84rbida3p"; - libName = "nu_ansi_term"; - authors = [ - "ogham@bsago.me" - "Ryan Scheel (Havvy) " - "Josh Triplett " - "The Nushell Project Developers" - ]; - dependencies = [ - { - name = "overload"; - packageId = "overload"; - } - { - name = "winapi"; - packageId = "winapi"; - target = { target, features }: ("windows" == target."os" or null); - features = [ "consoleapi" "errhandlingapi" "fileapi" "handleapi" "processenv" ]; - } - ]; - features = { - "derive_serde_style" = [ "serde" ]; - "serde" = [ "dep:serde" ]; - }; - }; - "num-traits" = rec { - crateName = "num-traits"; - version = "0.2.19"; - edition = "2021"; - sha256 = "0h984rhdkkqd4ny9cif7y2azl3xdfb7768hb9irhpsch4q3gq787"; - libName = "num_traits"; - authors = [ - "The Rust Project Developers" - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { - "default" = [ "std" ]; - "libm" = [ "dep:libm" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "num_enum" = rec { - crateName = "num_enum"; - version = "0.7.3"; - edition = "2021"; - sha256 = "0yai0vafhy85mvhknzfqd7lm04hzaln7i5c599rhy8mj831kyqaf"; - authors = [ - "Daniel Wagner-Hall " - "Daniel Henry-Mantilla " - "Vincent Esche " - ]; - dependencies = [ - { - name = "num_enum_derive"; - packageId = "num_enum_derive"; - usesDefaultFeatures = false; - } - ]; - features = { - "complex-expressions" = [ "num_enum_derive/complex-expressions" ]; - "default" = [ "std" ]; - "std" = [ "num_enum_derive/std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "num_enum_derive" = rec { - crateName = "num_enum_derive"; - version = "0.7.3"; - edition = "2021"; - sha256 = "0mksna1jj87ydh146gn6jcqkvvs920c3dgh0p4f3xk184kpl865g"; - procMacro = true; - authors = [ - "Daniel Wagner-Hall " - "Daniel Henry-Mantilla " - "Vincent Esche " - ]; - dependencies = [ - { - name = "proc-macro-crate"; - packageId = "proc-macro-crate"; - optional = true; - } - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - features = [ "parsing" ]; - } - ]; - devDependencies = [ - { - name = "syn"; - packageId = "syn"; - features = [ "extra-traits" "parsing" ]; - } - ]; - features = { - "complex-expressions" = [ "syn/full" ]; - "default" = [ "std" ]; - "proc-macro-crate" = [ "dep:proc-macro-crate" ]; - "std" = [ "proc-macro-crate" ]; - }; - resolvedDefaultFeatures = [ "proc-macro-crate" "std" ]; - }; - "object" = rec { - crateName = "object"; - version = "0.36.5"; - edition = "2018"; - sha256 = "0gk8lhbs229c68lapq6w6qmnm4jkj48hrcw5ilfyswy514nhmpxf"; - dependencies = [ - { - name = "memchr"; - packageId = "memchr"; - usesDefaultFeatures = false; - } - ]; - features = { - "all" = [ "read" "write" "build" "std" "compression" "wasm" ]; - "alloc" = [ "dep:alloc" ]; - "build" = [ "build_core" "write_std" "elf" ]; - "build_core" = [ "read_core" "write_core" ]; - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "compression" = [ "dep:flate2" "dep:ruzstd" "std" ]; - "core" = [ "dep:core" ]; - "default" = [ "read" "compression" ]; - "doc" = [ "read_core" "write_std" "build_core" "std" "compression" "archive" "coff" "elf" "macho" "pe" "wasm" "xcoff" ]; - "pe" = [ "coff" ]; - "read" = [ "read_core" "archive" "coff" "elf" "macho" "pe" "xcoff" "unaligned" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" "alloc" "memchr/rustc-dep-of-std" ]; - "std" = [ "memchr/std" ]; - "unstable-all" = [ "all" "unstable" ]; - "wasm" = [ "dep:wasmparser" ]; - "write" = [ "write_std" "coff" "elf" "macho" "pe" "xcoff" ]; - "write_core" = [ "dep:crc32fast" "dep:indexmap" "dep:hashbrown" ]; - "write_std" = [ "write_core" "std" "indexmap?/std" "crc32fast?/std" ]; - }; - resolvedDefaultFeatures = [ "archive" "coff" "elf" "macho" "pe" "read_core" "unaligned" "xcoff" ]; - }; - "once_cell" = rec { - crateName = "once_cell"; - version = "1.20.2"; - edition = "2021"; - sha256 = "0xb7rw1aqr7pa4z3b00y7786gyf8awx2gca3md73afy76dzgwq8j"; - authors = [ - "Aleksey Kladov " - ]; - features = { - "alloc" = [ "race" ]; - "atomic-polyfill" = [ "critical-section" ]; - "critical-section" = [ "dep:critical-section" "portable-atomic" ]; - "default" = [ "std" ]; - "parking_lot" = [ "dep:parking_lot_core" ]; - "portable-atomic" = [ "dep:portable-atomic" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "race" "std" ]; - }; - "overload" = rec { - crateName = "overload"; - version = "0.1.1"; - edition = "2018"; - sha256 = "0fdgbaqwknillagy1xq7xfgv60qdbk010diwl7s1p0qx7hb16n5i"; - authors = [ - "Daniel Salvadori " - ]; - - }; - "parking_lot" = rec { - crateName = "parking_lot"; - version = "0.12.3"; - edition = "2021"; - sha256 = "09ws9g6245iiq8z975h8ycf818a66q3c6zv4b5h8skpm7hc1igzi"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "lock_api"; - packageId = "lock_api"; - } - { - name = "parking_lot_core"; - packageId = "parking_lot_core"; - } - ]; - features = { - "arc_lock" = [ "lock_api/arc_lock" ]; - "deadlock_detection" = [ "parking_lot_core/deadlock_detection" ]; - "nightly" = [ "parking_lot_core/nightly" "lock_api/nightly" ]; - "owning_ref" = [ "lock_api/owning_ref" ]; - "serde" = [ "lock_api/serde" ]; - }; - resolvedDefaultFeatures = [ "default" ]; - }; - "parking_lot_core" = rec { - crateName = "parking_lot_core"; - version = "0.9.10"; - edition = "2021"; - sha256 = "1y3cf9ld9ijf7i4igwzffcn0xl16dxyn4c5bwgjck1dkgabiyh0y"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if"; - } - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "redox_syscall"; - packageId = "redox_syscall"; - target = { target, features }: ("redox" == target."os" or null); - } - { - name = "smallvec"; - packageId = "smallvec"; - } - { - name = "windows-targets"; - packageId = "windows-targets"; - target = { target, features }: (target."windows" or false); - } - ]; - features = { - "backtrace" = [ "dep:backtrace" ]; - "deadlock_detection" = [ "petgraph" "thread-id" "backtrace" ]; - "petgraph" = [ "dep:petgraph" ]; - "thread-id" = [ "dep:thread-id" ]; - }; - }; - "percent-encoding" = rec { - crateName = "percent-encoding"; - version = "2.3.1"; - edition = "2018"; - sha256 = "0gi8wgx0dcy8rnv1kywdv98lwcx67hz0a0zwpib5v2i08r88y573"; - libName = "percent_encoding"; - authors = [ - "The rust-url developers" - ]; - features = { - "default" = [ "std" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "pin-project" = rec { - crateName = "pin-project"; - version = "1.1.6"; - edition = "2021"; - sha256 = "1v4924b870bss0x5ahww9a164d4dbny90vzkmljfbqfxc6hj7wds"; - libName = "pin_project"; - dependencies = [ - { - name = "pin-project-internal"; - packageId = "pin-project-internal"; - } - ]; - - }; - "pin-project-internal" = rec { - crateName = "pin-project-internal"; - version = "1.1.6"; - edition = "2021"; - sha256 = "1y2pjavbcq40njylbnw3929i8nnrcdzrhgalzgqk57ya2n2jsl54"; - procMacro = true; - libName = "pin_project_internal"; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - usesDefaultFeatures = false; - features = [ "parsing" "printing" "clone-impls" "proc-macro" "full" "visit-mut" ]; - } - ]; - - }; - "pin-project-lite" = rec { - crateName = "pin-project-lite"; - version = "0.2.14"; - edition = "2018"; - sha256 = "00nx3f04agwjlsmd3mc5rx5haibj2v8q9b52b0kwn63wcv4nz9mx"; - libName = "pin_project_lite"; - - }; - "pin-utils" = rec { - crateName = "pin-utils"; - version = "0.1.0"; - edition = "2018"; - sha256 = "117ir7vslsl2z1a7qzhws4pd01cg2d3338c47swjyvqv2n60v1wb"; - libName = "pin_utils"; - authors = [ - "Josef Brandl " - ]; - - }; - "pkcs8" = rec { - crateName = "pkcs8"; - version = "0.10.2"; - edition = "2021"; - sha256 = "1dx7w21gvn07azszgqd3ryjhyphsrjrmq5mmz1fbxkj5g0vv4l7r"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "der"; - packageId = "der"; - features = [ "oid" ]; - } - { - name = "spki"; - packageId = "spki"; - } - ]; - features = { - "3des" = [ "encryption" "pkcs5/3des" ]; - "alloc" = [ "der/alloc" "der/zeroize" "spki/alloc" ]; - "des-insecure" = [ "encryption" "pkcs5/des-insecure" ]; - "encryption" = [ "alloc" "pkcs5/alloc" "pkcs5/pbes2" "rand_core" ]; - "getrandom" = [ "rand_core/getrandom" ]; - "pem" = [ "alloc" "der/pem" "spki/pem" ]; - "pkcs5" = [ "dep:pkcs5" ]; - "rand_core" = [ "dep:rand_core" ]; - "sha1-insecure" = [ "encryption" "pkcs5/sha1-insecure" ]; - "std" = [ "alloc" "der/std" "spki/std" ]; - "subtle" = [ "dep:subtle" ]; - }; - resolvedDefaultFeatures = [ "alloc" "std" ]; - }; - "proc-macro-crate" = rec { - crateName = "proc-macro-crate"; - version = "3.2.0"; - edition = "2021"; - sha256 = "0yzsqnavb3lmrcsmbrdjfrky9vcbl46v59xi9avn0796rb3likwf"; - libName = "proc_macro_crate"; - authors = [ - "Bastian Köcher " - ]; - dependencies = [ - { - name = "toml_edit"; - packageId = "toml_edit"; - } - ]; - - }; - "proc-macro2" = rec { - crateName = "proc-macro2"; - version = "1.0.87"; - edition = "2021"; - sha256 = "16mifsq1nqzk81qm82aszib44jsd23gpqic5z4kbmzpnvjhdmr5k"; - libName = "proc_macro2"; - authors = [ - "David Tolnay " - "Alex Crichton " - ]; - dependencies = [ - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - features = { - "default" = [ "proc-macro" ]; - }; - resolvedDefaultFeatures = [ "default" "proc-macro" ]; - }; - "quote" = rec { - crateName = "quote"; - version = "1.0.37"; - edition = "2018"; - sha256 = "1brklraw2g34bxy9y4q1nbrccn7bv36ylihv12c9vlcii55x7fdm"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - } - ]; - features = { - "default" = [ "proc-macro" ]; - "proc-macro" = [ "proc-macro2/proc-macro" ]; - }; - resolvedDefaultFeatures = [ "default" "proc-macro" ]; - }; - "rand_core" = rec { - crateName = "rand_core"; - version = "0.6.4"; - edition = "2018"; - sha256 = "0b4j2v4cb5krak1pv6kakv4sz6xcwbrmy2zckc32hsigbrwy82zc"; - authors = [ - "The Rand Project Developers" - "The Rust Project Developers" - ]; - dependencies = [ - { - name = "getrandom"; - packageId = "getrandom"; - optional = true; - } - ]; - features = { - "getrandom" = [ "dep:getrandom" ]; - "serde" = [ "dep:serde" ]; - "serde1" = [ "serde" ]; - "std" = [ "alloc" "getrandom" "getrandom/std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "getrandom" "std" ]; - }; - "redox_syscall" = rec { - crateName = "redox_syscall"; - version = "0.5.7"; - edition = "2021"; - sha256 = "07vpgfr6a04k0x19zqr1xdlqm6fncik3zydbdi3f5g3l5k7zwvcv"; - libName = "syscall"; - authors = [ - "Jeremy Soller " - ]; - dependencies = [ - { - name = "bitflags"; - packageId = "bitflags 2.6.0"; - } - ]; - features = { - "core" = [ "dep:core" ]; - "default" = [ "userspace" ]; - "rustc-dep-of-std" = [ "core" "bitflags/rustc-dep-of-std" ]; - }; - resolvedDefaultFeatures = [ "default" "userspace" ]; - }; - "regex-automata" = rec { - crateName = "regex-automata"; - version = "0.4.8"; - edition = "2021"; - sha256 = "18wd530ndrmygi6xnz3sp345qi0hy2kdbsa89182nwbl6br5i1rn"; - libName = "regex_automata"; - authors = [ - "The Rust Project Developers" - "Andrew Gallant " - ]; - features = { - "default" = [ "std" "syntax" "perf" "unicode" "meta" "nfa" "dfa" "hybrid" ]; - "dfa" = [ "dfa-build" "dfa-search" "dfa-onepass" ]; - "dfa-build" = [ "nfa-thompson" "dfa-search" ]; - "dfa-onepass" = [ "nfa-thompson" ]; - "hybrid" = [ "alloc" "nfa-thompson" ]; - "internal-instrument" = [ "internal-instrument-pikevm" ]; - "internal-instrument-pikevm" = [ "logging" "std" ]; - "logging" = [ "dep:log" "aho-corasick?/logging" "memchr?/logging" ]; - "meta" = [ "syntax" "nfa-pikevm" ]; - "nfa" = [ "nfa-thompson" "nfa-pikevm" "nfa-backtrack" ]; - "nfa-backtrack" = [ "nfa-thompson" ]; - "nfa-pikevm" = [ "nfa-thompson" ]; - "nfa-thompson" = [ "alloc" ]; - "perf" = [ "perf-inline" "perf-literal" ]; - "perf-literal" = [ "perf-literal-substring" "perf-literal-multisubstring" ]; - "perf-literal-multisubstring" = [ "std" "dep:aho-corasick" ]; - "perf-literal-substring" = [ "aho-corasick?/perf-literal" "dep:memchr" ]; - "std" = [ "regex-syntax?/std" "memchr?/std" "aho-corasick?/std" "alloc" ]; - "syntax" = [ "dep:regex-syntax" "alloc" ]; - "unicode" = [ "unicode-age" "unicode-bool" "unicode-case" "unicode-gencat" "unicode-perl" "unicode-script" "unicode-segment" "unicode-word-boundary" "regex-syntax?/unicode" ]; - "unicode-age" = [ "regex-syntax?/unicode-age" ]; - "unicode-bool" = [ "regex-syntax?/unicode-bool" ]; - "unicode-case" = [ "regex-syntax?/unicode-case" ]; - "unicode-gencat" = [ "regex-syntax?/unicode-gencat" ]; - "unicode-perl" = [ "regex-syntax?/unicode-perl" ]; - "unicode-script" = [ "regex-syntax?/unicode-script" ]; - "unicode-segment" = [ "regex-syntax?/unicode-segment" ]; - }; - resolvedDefaultFeatures = [ "dfa-search" ]; - }; - "rustc-demangle" = rec { - crateName = "rustc-demangle"; - version = "0.1.24"; - edition = "2015"; - sha256 = "07zysaafgrkzy2rjgwqdj2a8qdpsm6zv6f5pgpk9x0lm40z9b6vi"; - libName = "rustc_demangle"; - authors = [ - "Alex Crichton " - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "rustc-dep-of-std" = [ "core" "compiler_builtins" ]; - }; - }; - "rustc_version" = rec { - crateName = "rustc_version"; - version = "0.4.1"; - edition = "2018"; - sha256 = "14lvdsmr5si5qbqzrajgb6vfn69k0sfygrvfvr2mps26xwi3mjyg"; - dependencies = [ - { - name = "semver"; - packageId = "semver"; - } - ]; - - }; - "rustversion" = rec { - crateName = "rustversion"; - version = "1.0.17"; - edition = "2018"; - sha256 = "1mm3fckyvb0l2209in1n2k05sws5d9mpkszbnwhq3pkq8apjhpcm"; - procMacro = true; - build = "build/build.rs"; - authors = [ - "David Tolnay " - ]; - - }; - "ryu" = rec { - crateName = "ryu"; - version = "1.0.18"; - edition = "2018"; - sha256 = "17xx2s8j1lln7iackzd9p0sv546vjq71i779gphjq923vjh5pjzk"; - authors = [ - "David Tolnay " - ]; - features = { - "no-panic" = [ "dep:no-panic" ]; - }; - }; - "scopeguard" = rec { - crateName = "scopeguard"; - version = "1.2.0"; - edition = "2015"; - sha256 = "0jcz9sd47zlsgcnm1hdw0664krxwb5gczlif4qngj2aif8vky54l"; - authors = [ - "bluss" - ]; - features = { - "default" = [ "use_std" ]; - }; - }; - "semver" = rec { - crateName = "semver"; - version = "1.0.23"; - edition = "2018"; - sha256 = "12wqpxfflclbq4dv8sa6gchdh92ahhwn4ci1ls22wlby3h57wsb1"; - authors = [ - "David Tolnay " - ]; - features = { - "default" = [ "std" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "serde" = rec { - crateName = "serde"; - version = "1.0.210"; - edition = "2018"; - sha256 = "0flc0z8wgax1k4j5bf2zyq48bgzyv425jkd5w0i6wbh7f8j5kqy8"; - authors = [ - "Erick Tryzelaar " - "David Tolnay " - ]; - dependencies = [ - { - name = "serde_derive"; - packageId = "serde_derive"; - optional = true; - } - { - name = "serde_derive"; - packageId = "serde_derive"; - target = { target, features }: false; - } - ]; - devDependencies = [ - { - name = "serde_derive"; - packageId = "serde_derive"; - } - ]; - features = { - "default" = [ "std" ]; - "derive" = [ "serde_derive" ]; - "serde_derive" = [ "dep:serde_derive" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "derive" "serde_derive" "std" ]; - }; - "serde_derive" = rec { - crateName = "serde_derive"; - version = "1.0.210"; - edition = "2015"; - sha256 = "07yzy4wafk79ps0hmbqmsqh5xjna4pm4q57wc847bb8gl3nh4f94"; - procMacro = true; - authors = [ - "Erick Tryzelaar " - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - features = [ "proc-macro" ]; - } - { - name = "quote"; - packageId = "quote"; - usesDefaultFeatures = false; - features = [ "proc-macro" ]; - } - { - name = "syn"; - packageId = "syn"; - usesDefaultFeatures = false; - features = [ "clone-impls" "derive" "parsing" "printing" "proc-macro" ]; - } - ]; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "serde_json" = rec { - crateName = "serde_json"; - version = "1.0.128"; - edition = "2021"; - sha256 = "1n43nia50ybpcfmh3gcw4lcc627qsg9nyakzwgkk9pm10xklbxbg"; - authors = [ - "Erick Tryzelaar " - "David Tolnay " - ]; - dependencies = [ - { - name = "itoa"; - packageId = "itoa"; - } - { - name = "memchr"; - packageId = "memchr"; - usesDefaultFeatures = false; - } - { - name = "ryu"; - packageId = "ryu"; - } - { - name = "serde"; - packageId = "serde"; - usesDefaultFeatures = false; - } - ]; - devDependencies = [ - { - name = "serde"; - packageId = "serde"; - features = [ "derive" ]; - } - ]; - features = { - "alloc" = [ "serde/alloc" ]; - "default" = [ "std" ]; - "indexmap" = [ "dep:indexmap" ]; - "preserve_order" = [ "indexmap" "std" ]; - "std" = [ "memchr/std" "serde/std" ]; - }; - resolvedDefaultFeatures = [ "default" "raw_value" "std" ]; - }; - "serde_path_to_error" = rec { - crateName = "serde_path_to_error"; - version = "0.1.16"; - edition = "2021"; - sha256 = "19hlz2359l37ifirskpcds7sxg0gzpqvfilibs7whdys0128i6dg"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "itoa"; - packageId = "itoa"; - } - { - name = "serde"; - packageId = "serde"; - } - ]; - - }; - "serde_repr" = rec { - crateName = "serde_repr"; - version = "0.1.19"; - edition = "2021"; - sha256 = "1sb4cplc33z86pzlx38234xr141wr3cmviqgssiadisgl8dlar3c"; - procMacro = true; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - } - ]; - - }; - "serde_urlencoded" = rec { - crateName = "serde_urlencoded"; - version = "0.7.1"; - edition = "2018"; - sha256 = "1zgklbdaysj3230xivihs30qi5vkhigg323a9m62k8jwf4a1qjfk"; - authors = [ - "Anthony Ramine " - ]; - dependencies = [ - { - name = "form_urlencoded"; - packageId = "form_urlencoded"; - } - { - name = "itoa"; - packageId = "itoa"; - } - { - name = "ryu"; - packageId = "ryu"; - } - { - name = "serde"; - packageId = "serde"; - } - ]; - - }; - "sha2" = rec { - crateName = "sha2"; - version = "0.10.8"; - edition = "2018"; - sha256 = "1j1x78zk9il95w9iv46dh9wm73r6xrgj32y6lzzw7bxws9dbfgbr"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if"; - } - { - name = "cpufeatures"; - packageId = "cpufeatures"; - target = { target, features }: (("aarch64" == target."arch" or null) || ("x86_64" == target."arch" or null) || ("x86" == target."arch" or null)); - } - { - name = "digest"; - packageId = "digest"; - } - ]; - devDependencies = [ - { - name = "digest"; - packageId = "digest"; - features = [ "dev" ]; - } - ]; - features = { - "asm" = [ "sha2-asm" ]; - "asm-aarch64" = [ "asm" ]; - "default" = [ "std" ]; - "oid" = [ "digest/oid" ]; - "sha2-asm" = [ "dep:sha2-asm" ]; - "std" = [ "digest/std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "sharded-slab" = rec { - crateName = "sharded-slab"; - version = "0.1.7"; - edition = "2018"; - sha256 = "1xipjr4nqsgw34k7a2cgj9zaasl2ds6jwn89886kww93d32a637l"; - libName = "sharded_slab"; - authors = [ - "Eliza Weisman " - ]; - dependencies = [ - { - name = "lazy_static"; - packageId = "lazy_static"; - } - ]; - features = { - "loom" = [ "dep:loom" ]; - }; - }; - "shlex" = rec { - crateName = "shlex"; - version = "1.3.0"; - edition = "2015"; - sha256 = "0r1y6bv26c1scpxvhg2cabimrmwgbp4p3wy6syj9n0c4s3q2znhg"; - authors = [ - "comex " - "Fenhl " - "Adrian Taylor " - "Alex Touchet " - "Daniel Parks " - "Garrett Berg " - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "signal-hook-registry" = rec { - crateName = "signal-hook-registry"; - version = "1.4.2"; - edition = "2015"; - sha256 = "1cb5akgq8ajnd5spyn587srvs4n26ryq0p78nswffwhv46sf1sd9"; - libName = "signal_hook_registry"; - authors = [ - "Michal 'vorner' Vaner " - "Masaki Hara " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - } - ]; - - }; - "signature" = rec { - crateName = "signature"; - version = "2.2.0"; - edition = "2021"; - sha256 = "1pi9hd5vqfr3q3k49k37z06p7gs5si0in32qia4mmr1dancr6m3p"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "rand_core"; - packageId = "rand_core"; - optional = true; - usesDefaultFeatures = false; - } - ]; - features = { - "derive" = [ "dep:derive" ]; - "digest" = [ "dep:digest" ]; - "rand_core" = [ "dep:rand_core" ]; - "std" = [ "alloc" "rand_core?/std" ]; - }; - resolvedDefaultFeatures = [ "alloc" "std" ]; - }; - "slab" = rec { - crateName = "slab"; - version = "0.4.9"; - edition = "2018"; - sha256 = "0rxvsgir0qw5lkycrqgb1cxsvxzjv9bmx73bk5y42svnzfba94lg"; - authors = [ - "Carl Lerche " - ]; - buildDependencies = [ - { - name = "autocfg"; - packageId = "autocfg"; - } - ]; - features = { - "default" = [ "std" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "smallvec" = rec { - crateName = "smallvec"; - version = "1.13.2"; - edition = "2018"; - sha256 = "0rsw5samawl3wsw6glrsb127rx6sh89a8wyikicw6dkdcjd1lpiw"; - authors = [ - "The Servo Project Developers" - ]; - features = { - "arbitrary" = [ "dep:arbitrary" ]; - "const_new" = [ "const_generics" ]; - "drain_keep_rest" = [ "drain_filter" ]; - "serde" = [ "dep:serde" ]; - }; - resolvedDefaultFeatures = [ "const_generics" "const_new" ]; - }; - "socket2" = rec { - crateName = "socket2"; - version = "0.5.7"; - edition = "2021"; - sha256 = "070r941wbq76xpy039an4pyiy3rfj7mp7pvibf1rcri9njq5wc6f"; - authors = [ - "Alex Crichton " - "Thomas de Zeeuw " - ]; - dependencies = [ - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "windows-sys"; - packageId = "windows-sys"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Foundation" "Win32_Networking_WinSock" "Win32_System_IO" "Win32_System_Threading" "Win32_System_WindowsProgramming" ]; - } - ]; - features = { }; - resolvedDefaultFeatures = [ "all" ]; - }; - "spki" = rec { - crateName = "spki"; - version = "0.7.3"; - edition = "2021"; - sha256 = "17fj8k5fmx4w9mp27l970clrh5qa7r5sjdvbsln987xhb34dc7nr"; - authors = [ - "RustCrypto Developers" - ]; - dependencies = [ - { - name = "base64ct"; - packageId = "base64ct"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "der"; - packageId = "der"; - features = [ "oid" ]; - } - ]; - features = { - "alloc" = [ "base64ct?/alloc" "der/alloc" ]; - "arbitrary" = [ "std" "dep:arbitrary" "der/arbitrary" ]; - "base64" = [ "dep:base64ct" ]; - "fingerprint" = [ "sha2" ]; - "pem" = [ "alloc" "der/pem" ]; - "sha2" = [ "dep:sha2" ]; - "std" = [ "der/std" "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" "std" ]; - }; - "strsim" = rec { - crateName = "strsim"; - version = "0.11.1"; - edition = "2015"; - sha256 = "0kzvqlw8hxqb7y598w1s0hxlnmi84sg5vsipp3yg5na5d1rvba3x"; - authors = [ - "Danny Guo " - "maxbachmann " - ]; - - }; - "subtle" = rec { - crateName = "subtle"; - version = "2.6.1"; - edition = "2018"; - sha256 = "14ijxaymghbl1p0wql9cib5zlwiina7kall6w7g89csprkgbvhhk"; - authors = [ - "Isis Lovecruft " - "Henry de Valence " - ]; - features = { - "default" = [ "std" "i128" ]; - }; - }; - "syn" = rec { - crateName = "syn"; - version = "2.0.87"; - edition = "2021"; - sha256 = "0bd3mfcswvn4jkrp7ich5kk58kmpph8412yxd36nsfnh8vilrai5"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - usesDefaultFeatures = false; - } - { - name = "quote"; - packageId = "quote"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "unicode-ident"; - packageId = "unicode-ident"; - } - ]; - features = { - "default" = [ "derive" "parsing" "printing" "clone-impls" "proc-macro" ]; - "printing" = [ "dep:quote" ]; - "proc-macro" = [ "proc-macro2/proc-macro" "quote?/proc-macro" ]; - "test" = [ "syn-test-suite/all-features" ]; - }; - resolvedDefaultFeatures = [ "clone-impls" "default" "derive" "extra-traits" "full" "parsing" "printing" "proc-macro" "visit-mut" ]; - }; - "sync_wrapper 0.1.2" = rec { - crateName = "sync_wrapper"; - version = "0.1.2"; - edition = "2018"; - sha256 = "0q01lyj0gr9a93n10nxsn8lwbzq97jqd6b768x17c8f7v7gccir0"; - authors = [ - "Actyx AG " - ]; - features = { - "futures" = [ "futures-core" ]; - "futures-core" = [ "dep:futures-core" ]; - }; - }; - "sync_wrapper 1.0.1" = rec { - crateName = "sync_wrapper"; - version = "1.0.1"; - edition = "2018"; - sha256 = "150k6lwvr4nl237ngsz8fj5j78k712m4bggrfyjsidllraz5l1m7"; - authors = [ - "Actyx AG " - ]; - features = { - "futures" = [ "futures-core" ]; - "futures-core" = [ "dep:futures-core" ]; - }; - }; - "thiserror" = rec { - crateName = "thiserror"; - version = "2.0.11"; - edition = "2021"; - sha256 = "1z0649rpa8c2smzx129bz4qvxmdihj30r2km6vfpcv9yny2g4lnl"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "thiserror-impl"; - packageId = "thiserror-impl"; - } - ]; - features = { - "default" = [ "std" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "thiserror-impl" = rec { - crateName = "thiserror-impl"; - version = "2.0.11"; - edition = "2021"; - sha256 = "1hkkn7p2y4cxbffcrprybkj0qy1rl1r6waxmxqvr764axaxc3br6"; - procMacro = true; - libName = "thiserror_impl"; - authors = [ - "David Tolnay " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - } - ]; - - }; - "thread_local" = rec { - crateName = "thread_local"; - version = "1.1.8"; - edition = "2021"; - sha256 = "173i5lyjh011gsimk21np9jn8al18rxsrkjli20a7b8ks2xgk7lb"; - authors = [ - "Amanieu d'Antras " - ]; - dependencies = [ - { - name = "cfg-if"; - packageId = "cfg-if"; - } - { - name = "once_cell"; - packageId = "once_cell"; - } - ]; - features = { }; - }; - "tokio" = rec { - crateName = "tokio"; - version = "1.40.0"; - edition = "2021"; - sha256 = "166rllhfkyqp0fs7sxn6crv74iizi4wzd3cvxkcpmlk52qip1c72"; - authors = [ - "Tokio Contributors " - ]; - dependencies = [ - { - name = "backtrace"; - packageId = "backtrace"; - target = { target, features }: (target."tokio_taskdump" or false); - } - { - name = "bytes"; - packageId = "bytes"; - optional = true; - } - { - name = "libc"; - packageId = "libc"; - optional = true; - target = { target, features }: (target."unix" or false); - } - { - name = "mio"; - packageId = "mio"; - optional = true; - usesDefaultFeatures = false; - } - { - name = "parking_lot"; - packageId = "parking_lot"; - optional = true; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "signal-hook-registry"; - packageId = "signal-hook-registry"; - optional = true; - target = { target, features }: (target."unix" or false); - } - { - name = "socket2"; - packageId = "socket2"; - optional = true; - target = { target, features }: (!(builtins.elem "wasm" target."family")); - features = [ "all" ]; - } - { - name = "tokio-macros"; - packageId = "tokio-macros"; - optional = true; - } - { - name = "windows-sys"; - packageId = "windows-sys"; - optional = true; - target = { target, features }: (target."windows" or false); - } - ]; - devDependencies = [ - { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); - } - { - name = "socket2"; - packageId = "socket2"; - target = { target, features }: (!(builtins.elem "wasm" target."family")); - } - { - name = "windows-sys"; - packageId = "windows-sys"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Foundation" "Win32_Security_Authorization" ]; - } - ]; - features = { - "bytes" = [ "dep:bytes" ]; - "full" = [ "fs" "io-util" "io-std" "macros" "net" "parking_lot" "process" "rt" "rt-multi-thread" "signal" "sync" "time" ]; - "io-util" = [ "bytes" ]; - "libc" = [ "dep:libc" ]; - "macros" = [ "tokio-macros" ]; - "mio" = [ "dep:mio" ]; - "net" = [ "libc" "mio/os-poll" "mio/os-ext" "mio/net" "socket2" "windows-sys/Win32_Foundation" "windows-sys/Win32_Security" "windows-sys/Win32_Storage_FileSystem" "windows-sys/Win32_System_Pipes" "windows-sys/Win32_System_SystemServices" ]; - "parking_lot" = [ "dep:parking_lot" ]; - "process" = [ "bytes" "libc" "mio/os-poll" "mio/os-ext" "mio/net" "signal-hook-registry" "windows-sys/Win32_Foundation" "windows-sys/Win32_System_Threading" "windows-sys/Win32_System_WindowsProgramming" ]; - "rt-multi-thread" = [ "rt" ]; - "signal" = [ "libc" "mio/os-poll" "mio/net" "mio/os-ext" "signal-hook-registry" "windows-sys/Win32_Foundation" "windows-sys/Win32_System_Console" ]; - "signal-hook-registry" = [ "dep:signal-hook-registry" ]; - "socket2" = [ "dep:socket2" ]; - "test-util" = [ "rt" "sync" "time" ]; - "tokio-macros" = [ "dep:tokio-macros" ]; - "tracing" = [ "dep:tracing" ]; - "windows-sys" = [ "dep:windows-sys" ]; - }; - resolvedDefaultFeatures = [ "bytes" "default" "fs" "full" "io-std" "io-util" "libc" "macros" "mio" "net" "parking_lot" "process" "rt" "rt-multi-thread" "signal" "signal-hook-registry" "socket2" "sync" "test-util" "time" "tokio-macros" "windows-sys" ]; - }; - "tokio-listener" = rec { - crateName = "tokio-listener"; - version = "0.3.2"; - edition = "2021"; - sha256 = "00vkr1cywd2agn8jbkzwwf7y4ps3cfjm8l9ab697px2cgc97wdln"; - libName = "tokio_listener"; - dependencies = [ - { - name = "axum"; - packageId = "axum"; - rename = "axum07"; - } - { - name = "document-features"; - packageId = "document-features"; - } - { - name = "futures-core"; - packageId = "futures-core"; - } - { - name = "futures-util"; - packageId = "futures-util"; - optional = true; - } - { - name = "nix"; - packageId = "nix"; - optional = true; - usesDefaultFeatures = false; - target = { target, features }: (target."unix" or false); - features = [ "user" "fs" ]; - } - { - name = "pin-project"; - packageId = "pin-project"; - } - { - name = "socket2"; - packageId = "socket2"; - optional = true; - features = [ "all" ]; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "net" "io-std" "time" "sync" ]; - } - { - name = "tokio-util"; - packageId = "tokio-util"; - optional = true; - features = [ "net" "codec" ]; - } - { - name = "tracing"; - packageId = "tracing"; - } - ]; - devDependencies = [ - { - name = "tokio"; - packageId = "tokio"; - features = [ "macros" "rt" "io-util" ]; - } - ]; - features = { - "axum07" = [ "dep:hyper1" "dep:hyper-util" "dep:futures-util" "dep:tower-service" "dep:tower" ]; - "clap" = [ "dep:clap" ]; - "default" = [ "user_facing_default" "tokio-util" ]; - "hyper014" = [ "dep:hyper014" ]; - "inetd" = [ "dep:futures-util" ]; - "nix" = [ "dep:nix" ]; - "serde" = [ "dep:serde" "serde_with" ]; - "serde_with" = [ "dep:serde_with" ]; - "socket2" = [ "dep:socket2" ]; - "socket_options" = [ "socket2" ]; - "tokio-util" = [ "dep:tokio-util" ]; - "tonic010" = [ "dep:tonic_010" ]; - "tonic011" = [ "dep:tonic" ]; - "unix_path_tools" = [ "nix" ]; - "user_facing_default" = [ "inetd" "unix" "unix_path_tools" "sd_listen" "socket_options" ]; - }; - resolvedDefaultFeatures = [ "default" "inetd" "nix" "sd_listen" "socket2" "socket_options" "tokio-util" "unix" "unix_path_tools" "user_facing_default" ]; - }; - "tokio-macros" = rec { - crateName = "tokio-macros"; - version = "2.4.0"; - edition = "2021"; - sha256 = "0lnpg14h1v3fh2jvnc8cz7cjf0m7z1xgkwfpcyy632g829imjgb9"; - procMacro = true; - libName = "tokio_macros"; - authors = [ - "Tokio Contributors " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - features = [ "full" ]; - } - ]; - - }; - "tokio-stream" = rec { - crateName = "tokio-stream"; - version = "0.1.16"; - edition = "2021"; - sha256 = "1wc65gprcsyzqlr0k091glswy96kph90i32gffi4ksyh03hnqkjg"; - libName = "tokio_stream"; - authors = [ - "Tokio Contributors " - ]; - dependencies = [ - { - name = "futures-core"; - packageId = "futures-core"; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "sync" ]; - } - ]; - devDependencies = [ - { - name = "tokio"; - packageId = "tokio"; - features = [ "full" "test-util" ]; - } - ]; - features = { - "default" = [ "time" ]; - "fs" = [ "tokio/fs" ]; - "full" = [ "time" "net" "io-util" "fs" "sync" "signal" ]; - "io-util" = [ "tokio/io-util" ]; - "net" = [ "tokio/net" ]; - "signal" = [ "tokio/signal" ]; - "sync" = [ "tokio/sync" "tokio-util" ]; - "time" = [ "tokio/time" ]; - "tokio-util" = [ "dep:tokio-util" ]; - }; - resolvedDefaultFeatures = [ "default" "time" ]; - }; - "tokio-test" = rec { - crateName = "tokio-test"; - version = "0.4.4"; - edition = "2021"; - sha256 = "1xzri2m3dg8nzdyznm77nymvil9cyh1gfdfrbnska51iqfmvls14"; - libName = "tokio_test"; - authors = [ - "Tokio Contributors " - ]; - dependencies = [ - { - name = "async-stream"; - packageId = "async-stream"; - } - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures-core"; - packageId = "futures-core"; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "rt" "sync" "time" "test-util" ]; - } - { - name = "tokio-stream"; - packageId = "tokio-stream"; - } - ]; - devDependencies = [ - { - name = "tokio"; - packageId = "tokio"; - features = [ "full" ]; - } - ]; - - }; - "tokio-util" = rec { - crateName = "tokio-util"; - version = "0.7.12"; - edition = "2021"; - sha256 = "0spc0g4irbnf2flgag22gfii87avqzibwfm0si0d1g0k9ijw7rv1"; - libName = "tokio_util"; - authors = [ - "Tokio Contributors " - ]; - dependencies = [ - { - name = "bytes"; - packageId = "bytes"; - } - { - name = "futures-core"; - packageId = "futures-core"; - } - { - name = "futures-sink"; - packageId = "futures-sink"; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "sync" ]; - } - ]; - devDependencies = [ - { - name = "tokio"; - packageId = "tokio"; - features = [ "full" ]; - } - ]; - features = { - "__docs_rs" = [ "futures-util" ]; - "compat" = [ "futures-io" ]; - "full" = [ "codec" "compat" "io-util" "time" "net" "rt" ]; - "futures-io" = [ "dep:futures-io" ]; - "futures-util" = [ "dep:futures-util" ]; - "hashbrown" = [ "dep:hashbrown" ]; - "io-util" = [ "io" "tokio/rt" "tokio/io-util" ]; - "net" = [ "tokio/net" ]; - "rt" = [ "tokio/rt" "tokio/sync" "futures-util" "hashbrown" ]; - "slab" = [ "dep:slab" ]; - "time" = [ "tokio/time" "slab" ]; - "tracing" = [ "dep:tracing" ]; - }; - resolvedDefaultFeatures = [ "codec" "default" "net" ]; - }; - "toml_datetime" = rec { - crateName = "toml_datetime"; - version = "0.6.8"; - edition = "2021"; - sha256 = "0hgv7v9g35d7y9r2afic58jvlwnf73vgd1mz2k8gihlgrf73bmqd"; - authors = [ - "Alex Crichton " - ]; - features = { - "serde" = [ "dep:serde" ]; - }; - }; - "toml_edit" = rec { - crateName = "toml_edit"; - version = "0.22.22"; - edition = "2021"; - sha256 = "1xf7sxfzmnc45f75x302qrn5aph52vc8w226v59yhrm211i8vr2a"; - authors = [ - "Andronik Ordian " - "Ed Page " - ]; - dependencies = [ - { - name = "indexmap"; - packageId = "indexmap"; - features = [ "std" ]; - } - { - name = "toml_datetime"; - packageId = "toml_datetime"; - } - { - name = "winnow"; - packageId = "winnow"; - optional = true; - } - ]; - features = { - "default" = [ "parse" "display" ]; - "parse" = [ "dep:winnow" ]; - "perf" = [ "dep:kstring" ]; - "serde" = [ "dep:serde" "toml_datetime/serde" "dep:serde_spanned" ]; - }; - resolvedDefaultFeatures = [ "default" "display" "parse" ]; - }; - "tower" = rec { - crateName = "tower"; - version = "0.5.1"; - edition = "2018"; - sha256 = "0kvbp97bhb4sk24vhihcz74ngn0i4ygxqikmxndgng3w926r6wr8"; - authors = [ - "Tower Maintainers " - ]; - dependencies = [ - { - name = "futures-core"; - packageId = "futures-core"; - optional = true; - } - { - name = "futures-util"; - packageId = "futures-util"; - optional = true; - usesDefaultFeatures = false; - features = [ "alloc" ]; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - optional = true; - } - { - name = "sync_wrapper"; - packageId = "sync_wrapper 0.1.2"; - optional = true; - } - { - name = "tokio"; - packageId = "tokio"; - optional = true; - features = [ "sync" ]; - } - { - name = "tower-layer"; - packageId = "tower-layer"; - } - { - name = "tower-service"; - packageId = "tower-service"; - } - { - name = "tracing"; - packageId = "tracing"; - optional = true; - usesDefaultFeatures = false; - features = [ "std" ]; - } - ]; - devDependencies = [ - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "macros" "sync" "test-util" "rt-multi-thread" ]; - } - { - name = "tracing"; - packageId = "tracing"; - usesDefaultFeatures = false; - features = [ "std" ]; - } - ]; - features = { - "__common" = [ "futures-core" "pin-project-lite" ]; - "balance" = [ "discover" "load" "ready-cache" "make" "slab" "util" ]; - "buffer" = [ "__common" "tokio/sync" "tokio/rt" "tokio-util" "tracing" ]; - "discover" = [ "__common" ]; - "filter" = [ "__common" "futures-util" ]; - "full" = [ "balance" "buffer" "discover" "filter" "hedge" "limit" "load" "load-shed" "make" "ready-cache" "reconnect" "retry" "spawn-ready" "steer" "timeout" "util" ]; - "futures-core" = [ "dep:futures-core" ]; - "futures-util" = [ "dep:futures-util" ]; - "hdrhistogram" = [ "dep:hdrhistogram" ]; - "hedge" = [ "util" "filter" "futures-util" "hdrhistogram" "tokio/time" "tracing" ]; - "indexmap" = [ "dep:indexmap" ]; - "limit" = [ "__common" "tokio/time" "tokio/sync" "tokio-util" "tracing" ]; - "load" = [ "__common" "tokio/time" "tracing" ]; - "load-shed" = [ "__common" ]; - "log" = [ "tracing/log" ]; - "make" = [ "futures-util" "pin-project-lite" "tokio/io-std" ]; - "pin-project-lite" = [ "dep:pin-project-lite" ]; - "ready-cache" = [ "futures-core" "futures-util" "indexmap" "tokio/sync" "tracing" "pin-project-lite" ]; - "reconnect" = [ "make" "tokio/io-std" "tracing" ]; - "retry" = [ "__common" "tokio/time" "util" ]; - "slab" = [ "dep:slab" ]; - "spawn-ready" = [ "__common" "futures-util" "tokio/sync" "tokio/rt" "util" "tracing" ]; - "sync_wrapper" = [ "dep:sync_wrapper" ]; - "timeout" = [ "pin-project-lite" "tokio/time" ]; - "tokio" = [ "dep:tokio" ]; - "tokio-stream" = [ "dep:tokio-stream" ]; - "tokio-util" = [ "dep:tokio-util" ]; - "tracing" = [ "dep:tracing" ]; - "util" = [ "__common" "futures-util" "pin-project-lite" "sync_wrapper" ]; - }; - resolvedDefaultFeatures = [ "__common" "futures-core" "futures-util" "log" "make" "pin-project-lite" "sync_wrapper" "tokio" "tracing" "util" ]; - }; - "tower-layer" = rec { - crateName = "tower-layer"; - version = "0.3.3"; - edition = "2018"; - sha256 = "03kq92fdzxin51w8iqix06dcfgydyvx7yr6izjq0p626v9n2l70j"; - libName = "tower_layer"; - authors = [ - "Tower Maintainers " - ]; - - }; - "tower-service" = rec { - crateName = "tower-service"; - version = "0.3.3"; - edition = "2018"; - sha256 = "1hzfkvkci33ra94xjx64vv3pp0sq346w06fpkcdwjcid7zhvdycd"; - libName = "tower_service"; - authors = [ - "Tower Maintainers " - ]; - - }; - "tracing" = rec { - crateName = "tracing"; - version = "0.1.40"; - edition = "2018"; - sha256 = "1vv48dac9zgj9650pg2b4d0j3w6f3x9gbggf43scq5hrlysklln3"; - authors = [ - "Eliza Weisman " - "Tokio Contributors " - ]; - dependencies = [ - { - name = "log"; - packageId = "log"; - optional = true; - } - { - name = "pin-project-lite"; - packageId = "pin-project-lite"; - } - { - name = "tracing-attributes"; - packageId = "tracing-attributes"; - optional = true; - } - { - name = "tracing-core"; - packageId = "tracing-core"; - usesDefaultFeatures = false; - } - ]; - devDependencies = [ - { - name = "log"; - packageId = "log"; - } - ]; - features = { - "attributes" = [ "tracing-attributes" ]; - "default" = [ "std" "attributes" ]; - "log" = [ "dep:log" ]; - "log-always" = [ "log" ]; - "std" = [ "tracing-core/std" ]; - "tracing-attributes" = [ "dep:tracing-attributes" ]; - "valuable" = [ "tracing-core/valuable" ]; - }; - resolvedDefaultFeatures = [ "attributes" "default" "log" "std" "tracing-attributes" ]; - }; - "tracing-attributes" = rec { - crateName = "tracing-attributes"; - version = "0.1.27"; - edition = "2018"; - sha256 = "1rvb5dn9z6d0xdj14r403z0af0bbaqhg02hq4jc97g5wds6lqw1l"; - procMacro = true; - libName = "tracing_attributes"; - authors = [ - "Tokio Contributors " - "Eliza Weisman " - "David Barsky " - ]; - dependencies = [ - { - name = "proc-macro2"; - packageId = "proc-macro2"; - } - { - name = "quote"; - packageId = "quote"; - } - { - name = "syn"; - packageId = "syn"; - usesDefaultFeatures = false; - features = [ "full" "parsing" "printing" "visit-mut" "clone-impls" "extra-traits" "proc-macro" ]; - } - ]; - features = { }; - }; - "tracing-core" = rec { - crateName = "tracing-core"; - version = "0.1.32"; - edition = "2018"; - sha256 = "0m5aglin3cdwxpvbg6kz0r9r0k31j48n0kcfwsp6l49z26k3svf0"; - libName = "tracing_core"; - authors = [ - "Tokio Contributors " - ]; - dependencies = [ - { - name = "once_cell"; - packageId = "once_cell"; - optional = true; - } - { - name = "valuable"; - packageId = "valuable"; - optional = true; - usesDefaultFeatures = false; - target = { target, features }: (target."tracing_unstable" or false); - } - ]; - features = { - "default" = [ "std" "valuable/std" ]; - "once_cell" = [ "dep:once_cell" ]; - "std" = [ "once_cell" ]; - "valuable" = [ "dep:valuable" ]; - }; - resolvedDefaultFeatures = [ "default" "once_cell" "std" "valuable" ]; - }; - "tracing-log" = rec { - crateName = "tracing-log"; - version = "0.2.0"; - edition = "2018"; - sha256 = "1hs77z026k730ij1a9dhahzrl0s073gfa2hm5p0fbl0b80gmz1gf"; - libName = "tracing_log"; - authors = [ - "Tokio Contributors " - ]; - dependencies = [ - { - name = "log"; - packageId = "log"; - } - { - name = "once_cell"; - packageId = "once_cell"; - } - { - name = "tracing-core"; - packageId = "tracing-core"; - } - ]; - features = { - "ahash" = [ "dep:ahash" ]; - "default" = [ "log-tracer" "std" ]; - "interest-cache" = [ "lru" "ahash" ]; - "lru" = [ "dep:lru" ]; - "std" = [ "log/std" ]; - }; - resolvedDefaultFeatures = [ "log-tracer" "std" ]; - }; - "tracing-subscriber" = rec { - crateName = "tracing-subscriber"; - version = "0.3.18"; - edition = "2018"; - sha256 = "12vs1bwk4kig1l2qqjbbn2nm5amwiqmkcmnznylzmnfvjy6083xd"; - libName = "tracing_subscriber"; - authors = [ - "Eliza Weisman " - "David Barsky " - "Tokio Contributors " - ]; - dependencies = [ - { - name = "nu-ansi-term"; - packageId = "nu-ansi-term"; - optional = true; - } - { - name = "sharded-slab"; - packageId = "sharded-slab"; - optional = true; - } - { - name = "smallvec"; - packageId = "smallvec"; - optional = true; - } - { - name = "thread_local"; - packageId = "thread_local"; - optional = true; - } - { - name = "tracing-core"; - packageId = "tracing-core"; - usesDefaultFeatures = false; - } - { - name = "tracing-log"; - packageId = "tracing-log"; - optional = true; - usesDefaultFeatures = false; - features = [ "log-tracer" "std" ]; - } - ]; - devDependencies = [ - { - name = "tracing-log"; - packageId = "tracing-log"; - } - ]; - features = { - "ansi" = [ "fmt" "nu-ansi-term" ]; - "chrono" = [ "dep:chrono" ]; - "default" = [ "smallvec" "fmt" "ansi" "tracing-log" "std" ]; - "env-filter" = [ "matchers" "regex" "once_cell" "tracing" "std" "thread_local" ]; - "fmt" = [ "registry" "std" ]; - "json" = [ "tracing-serde" "serde" "serde_json" ]; - "local-time" = [ "time/local-offset" ]; - "matchers" = [ "dep:matchers" ]; - "nu-ansi-term" = [ "dep:nu-ansi-term" ]; - "once_cell" = [ "dep:once_cell" ]; - "parking_lot" = [ "dep:parking_lot" ]; - "regex" = [ "dep:regex" ]; - "registry" = [ "sharded-slab" "thread_local" "std" ]; - "serde" = [ "dep:serde" ]; - "serde_json" = [ "dep:serde_json" ]; - "sharded-slab" = [ "dep:sharded-slab" ]; - "smallvec" = [ "dep:smallvec" ]; - "std" = [ "alloc" "tracing-core/std" ]; - "thread_local" = [ "dep:thread_local" ]; - "time" = [ "dep:time" ]; - "tracing" = [ "dep:tracing" ]; - "tracing-log" = [ "dep:tracing-log" ]; - "tracing-serde" = [ "dep:tracing-serde" ]; - "valuable" = [ "tracing-core/valuable" "valuable_crate" "valuable-serde" "tracing-serde/valuable" ]; - "valuable-serde" = [ "dep:valuable-serde" ]; - "valuable_crate" = [ "dep:valuable_crate" ]; - }; - resolvedDefaultFeatures = [ "alloc" "ansi" "default" "fmt" "nu-ansi-term" "registry" "sharded-slab" "smallvec" "std" "thread_local" "tracing-log" ]; - }; - "tvix-daemon" = rec { - crateName = "tvix-daemon"; - version = "0.1.0"; - edition = "2021"; - crateBin = [ - { - name = "tvix-daemon"; - path = "src/main.rs"; - requiredFeatures = [ ]; - } - ]; - src = lib.cleanSourceWith { filter = sourceFilter; src = ./.; }; - dependencies = [ - { - name = "clap"; - packageId = "clap"; - features = [ "derive" "env" ]; - } - { - name = "nix-compat"; - packageId = "nix-compat"; - features = [ "wire" ]; - } - { - name = "tokio"; - packageId = "tokio"; - features = [ "full" ]; - } - { - name = "tokio-listener"; - packageId = "tokio-listener"; - } - { - name = "tracing"; - packageId = "tracing"; - } - { - name = "tracing-subscriber"; - packageId = "tracing-subscriber"; - } - ]; - devDependencies = [ - { - name = "tokio-test"; - packageId = "tokio-test"; - } - ]; - - }; - "typenum" = rec { - crateName = "typenum"; - version = "1.17.0"; - edition = "2018"; - sha256 = "09dqxv69m9lj9zvv6xw5vxaqx15ps0vxyy5myg33i0kbqvq0pzs2"; - build = "build/main.rs"; - authors = [ - "Paho Lurie-Gregg " - "Andre Bogus " - ]; - features = { - "scale-info" = [ "dep:scale-info" ]; - "scale_info" = [ "scale-info/derive" ]; - }; - }; - "unicode-ident" = rec { - crateName = "unicode-ident"; - version = "1.0.13"; - edition = "2018"; - sha256 = "1zm1xylzsdfvm2a5ib9li3g5pp7qnkv4amhspydvgbmd9k6mc6z9"; - libName = "unicode_ident"; - authors = [ - "David Tolnay " - ]; - - }; - "utf8parse" = rec { - crateName = "utf8parse"; - version = "0.2.2"; - edition = "2018"; - sha256 = "088807qwjq46azicqwbhlmzwrbkz7l4hpw43sdkdyyk524vdxaq6"; - authors = [ - "Joe Wilm " - "Christian Duerr " - ]; - features = { }; - resolvedDefaultFeatures = [ "default" ]; - }; - "valuable" = rec { - crateName = "valuable"; - version = "0.1.0"; - edition = "2018"; - sha256 = "0v9gp3nkjbl30z0fd56d8mx7w1csk86wwjhfjhr400wh9mfpw2w3"; - features = { - "default" = [ "std" ]; - "derive" = [ "valuable-derive" ]; - "std" = [ "alloc" ]; - "valuable-derive" = [ "dep:valuable-derive" ]; - }; - resolvedDefaultFeatures = [ "alloc" "std" ]; - }; - "version_check" = rec { - crateName = "version_check"; - version = "0.9.5"; - edition = "2015"; - sha256 = "0nhhi4i5x89gm911azqbn7avs9mdacw2i3vcz3cnmz3mv4rqz4hb"; - authors = [ - "Sergio Benitez " - ]; - - }; - "wasi" = rec { - crateName = "wasi"; - version = "0.11.0+wasi-snapshot-preview1"; - edition = "2018"; - sha256 = "08z4hxwkpdpalxjps1ai9y7ihin26y9f476i53dv98v45gkqg3cw"; - authors = [ - "The Cranelift Project Developers" - ]; - features = { - "compiler_builtins" = [ "dep:compiler_builtins" ]; - "core" = [ "dep:core" ]; - "default" = [ "std" ]; - "rustc-dep-of-std" = [ "compiler_builtins" "core" "rustc-std-workspace-alloc" ]; - "rustc-std-workspace-alloc" = [ "dep:rustc-std-workspace-alloc" ]; - }; - resolvedDefaultFeatures = [ "default" "std" ]; - }; - "winapi" = rec { - crateName = "winapi"; - version = "0.3.9"; - edition = "2015"; - sha256 = "06gl025x418lchw1wxj64ycr7gha83m44cjr5sarhynd9xkrm0sw"; - authors = [ - "Peter Atashian " - ]; - dependencies = [ - { - name = "winapi-i686-pc-windows-gnu"; - packageId = "winapi-i686-pc-windows-gnu"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "i686-pc-windows-gnu"); - } - { - name = "winapi-x86_64-pc-windows-gnu"; - packageId = "winapi-x86_64-pc-windows-gnu"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "x86_64-pc-windows-gnu"); - } - ]; - features = { - "debug" = [ "impl-debug" ]; - }; - resolvedDefaultFeatures = [ "consoleapi" "errhandlingapi" "fileapi" "handleapi" "processenv" ]; - }; - "winapi-i686-pc-windows-gnu" = rec { - crateName = "winapi-i686-pc-windows-gnu"; - version = "0.4.0"; - edition = "2015"; - sha256 = "1dmpa6mvcvzz16zg6d5vrfy4bxgg541wxrcip7cnshi06v38ffxc"; - libName = "winapi_i686_pc_windows_gnu"; - authors = [ - "Peter Atashian " - ]; - - }; - "winapi-x86_64-pc-windows-gnu" = rec { - crateName = "winapi-x86_64-pc-windows-gnu"; - version = "0.4.0"; - edition = "2015"; - sha256 = "0gqq64czqb64kskjryj8isp62m2sgvx25yyj3kpc2myh85w24bki"; - libName = "winapi_x86_64_pc_windows_gnu"; - authors = [ - "Peter Atashian " - ]; - - }; - "windows-sys" = rec { - crateName = "windows-sys"; - version = "0.52.0"; - edition = "2021"; - sha256 = "0gd3v4ji88490zgb6b5mq5zgbvwv7zx1ibn8v3x83rwcdbryaar8"; - libName = "windows_sys"; - authors = [ - "Microsoft" - ]; - dependencies = [ - { - name = "windows-targets"; - packageId = "windows-targets"; - } - ]; - features = { - "Wdk_Foundation" = [ "Wdk" ]; - "Wdk_Graphics" = [ "Wdk" ]; - "Wdk_Graphics_Direct3D" = [ "Wdk_Graphics" ]; - "Wdk_Storage" = [ "Wdk" ]; - "Wdk_Storage_FileSystem" = [ "Wdk_Storage" ]; - "Wdk_Storage_FileSystem_Minifilters" = [ "Wdk_Storage_FileSystem" ]; - "Wdk_System" = [ "Wdk" ]; - "Wdk_System_IO" = [ "Wdk_System" ]; - "Wdk_System_OfflineRegistry" = [ "Wdk_System" ]; - "Wdk_System_Registry" = [ "Wdk_System" ]; - "Wdk_System_SystemInformation" = [ "Wdk_System" ]; - "Wdk_System_SystemServices" = [ "Wdk_System" ]; - "Wdk_System_Threading" = [ "Wdk_System" ]; - "Win32_Data" = [ "Win32" ]; - "Win32_Data_HtmlHelp" = [ "Win32_Data" ]; - "Win32_Data_RightsManagement" = [ "Win32_Data" ]; - "Win32_Devices" = [ "Win32" ]; - "Win32_Devices_AllJoyn" = [ "Win32_Devices" ]; - "Win32_Devices_BiometricFramework" = [ "Win32_Devices" ]; - "Win32_Devices_Bluetooth" = [ "Win32_Devices" ]; - "Win32_Devices_Communication" = [ "Win32_Devices" ]; - "Win32_Devices_DeviceAndDriverInstallation" = [ "Win32_Devices" ]; - "Win32_Devices_DeviceQuery" = [ "Win32_Devices" ]; - "Win32_Devices_Display" = [ "Win32_Devices" ]; - "Win32_Devices_Enumeration" = [ "Win32_Devices" ]; - "Win32_Devices_Enumeration_Pnp" = [ "Win32_Devices_Enumeration" ]; - "Win32_Devices_Fax" = [ "Win32_Devices" ]; - "Win32_Devices_HumanInterfaceDevice" = [ "Win32_Devices" ]; - "Win32_Devices_PortableDevices" = [ "Win32_Devices" ]; - "Win32_Devices_Properties" = [ "Win32_Devices" ]; - "Win32_Devices_Pwm" = [ "Win32_Devices" ]; - "Win32_Devices_Sensors" = [ "Win32_Devices" ]; - "Win32_Devices_SerialCommunication" = [ "Win32_Devices" ]; - "Win32_Devices_Tapi" = [ "Win32_Devices" ]; - "Win32_Devices_Usb" = [ "Win32_Devices" ]; - "Win32_Devices_WebServicesOnDevices" = [ "Win32_Devices" ]; - "Win32_Foundation" = [ "Win32" ]; - "Win32_Gaming" = [ "Win32" ]; - "Win32_Globalization" = [ "Win32" ]; - "Win32_Graphics" = [ "Win32" ]; - "Win32_Graphics_Dwm" = [ "Win32_Graphics" ]; - "Win32_Graphics_Gdi" = [ "Win32_Graphics" ]; - "Win32_Graphics_GdiPlus" = [ "Win32_Graphics" ]; - "Win32_Graphics_Hlsl" = [ "Win32_Graphics" ]; - "Win32_Graphics_OpenGL" = [ "Win32_Graphics" ]; - "Win32_Graphics_Printing" = [ "Win32_Graphics" ]; - "Win32_Graphics_Printing_PrintTicket" = [ "Win32_Graphics_Printing" ]; - "Win32_Management" = [ "Win32" ]; - "Win32_Management_MobileDeviceManagementRegistration" = [ "Win32_Management" ]; - "Win32_Media" = [ "Win32" ]; - "Win32_Media_Audio" = [ "Win32_Media" ]; - "Win32_Media_DxMediaObjects" = [ "Win32_Media" ]; - "Win32_Media_KernelStreaming" = [ "Win32_Media" ]; - "Win32_Media_Multimedia" = [ "Win32_Media" ]; - "Win32_Media_Streaming" = [ "Win32_Media" ]; - "Win32_Media_WindowsMediaFormat" = [ "Win32_Media" ]; - "Win32_NetworkManagement" = [ "Win32" ]; - "Win32_NetworkManagement_Dhcp" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Dns" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_InternetConnectionWizard" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_IpHelper" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Multicast" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Ndis" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetBios" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetManagement" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetShell" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_NetworkDiagnosticsFramework" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_P2P" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_QoS" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Rras" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_Snmp" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WNet" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WebDav" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WiFi" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsConnectionManager" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsFilteringPlatform" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsFirewall" = [ "Win32_NetworkManagement" ]; - "Win32_NetworkManagement_WindowsNetworkVirtualization" = [ "Win32_NetworkManagement" ]; - "Win32_Networking" = [ "Win32" ]; - "Win32_Networking_ActiveDirectory" = [ "Win32_Networking" ]; - "Win32_Networking_Clustering" = [ "Win32_Networking" ]; - "Win32_Networking_HttpServer" = [ "Win32_Networking" ]; - "Win32_Networking_Ldap" = [ "Win32_Networking" ]; - "Win32_Networking_WebSocket" = [ "Win32_Networking" ]; - "Win32_Networking_WinHttp" = [ "Win32_Networking" ]; - "Win32_Networking_WinInet" = [ "Win32_Networking" ]; - "Win32_Networking_WinSock" = [ "Win32_Networking" ]; - "Win32_Networking_WindowsWebServices" = [ "Win32_Networking" ]; - "Win32_Security" = [ "Win32" ]; - "Win32_Security_AppLocker" = [ "Win32_Security" ]; - "Win32_Security_Authentication" = [ "Win32_Security" ]; - "Win32_Security_Authentication_Identity" = [ "Win32_Security_Authentication" ]; - "Win32_Security_Authorization" = [ "Win32_Security" ]; - "Win32_Security_Credentials" = [ "Win32_Security" ]; - "Win32_Security_Cryptography" = [ "Win32_Security" ]; - "Win32_Security_Cryptography_Catalog" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_Certificates" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_Sip" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_Cryptography_UI" = [ "Win32_Security_Cryptography" ]; - "Win32_Security_DiagnosticDataQuery" = [ "Win32_Security" ]; - "Win32_Security_DirectoryServices" = [ "Win32_Security" ]; - "Win32_Security_EnterpriseData" = [ "Win32_Security" ]; - "Win32_Security_ExtensibleAuthenticationProtocol" = [ "Win32_Security" ]; - "Win32_Security_Isolation" = [ "Win32_Security" ]; - "Win32_Security_LicenseProtection" = [ "Win32_Security" ]; - "Win32_Security_NetworkAccessProtection" = [ "Win32_Security" ]; - "Win32_Security_WinTrust" = [ "Win32_Security" ]; - "Win32_Security_WinWlx" = [ "Win32_Security" ]; - "Win32_Storage" = [ "Win32" ]; - "Win32_Storage_Cabinets" = [ "Win32_Storage" ]; - "Win32_Storage_CloudFilters" = [ "Win32_Storage" ]; - "Win32_Storage_Compression" = [ "Win32_Storage" ]; - "Win32_Storage_DistributedFileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_FileHistory" = [ "Win32_Storage" ]; - "Win32_Storage_FileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_Imapi" = [ "Win32_Storage" ]; - "Win32_Storage_IndexServer" = [ "Win32_Storage" ]; - "Win32_Storage_InstallableFileSystems" = [ "Win32_Storage" ]; - "Win32_Storage_IscsiDisc" = [ "Win32_Storage" ]; - "Win32_Storage_Jet" = [ "Win32_Storage" ]; - "Win32_Storage_Nvme" = [ "Win32_Storage" ]; - "Win32_Storage_OfflineFiles" = [ "Win32_Storage" ]; - "Win32_Storage_OperationRecorder" = [ "Win32_Storage" ]; - "Win32_Storage_Packaging" = [ "Win32_Storage" ]; - "Win32_Storage_Packaging_Appx" = [ "Win32_Storage_Packaging" ]; - "Win32_Storage_ProjectedFileSystem" = [ "Win32_Storage" ]; - "Win32_Storage_StructuredStorage" = [ "Win32_Storage" ]; - "Win32_Storage_Vhd" = [ "Win32_Storage" ]; - "Win32_Storage_Xps" = [ "Win32_Storage" ]; - "Win32_System" = [ "Win32" ]; - "Win32_System_AddressBook" = [ "Win32_System" ]; - "Win32_System_Antimalware" = [ "Win32_System" ]; - "Win32_System_ApplicationInstallationAndServicing" = [ "Win32_System" ]; - "Win32_System_ApplicationVerifier" = [ "Win32_System" ]; - "Win32_System_ClrHosting" = [ "Win32_System" ]; - "Win32_System_Com" = [ "Win32_System" ]; - "Win32_System_Com_Marshal" = [ "Win32_System_Com" ]; - "Win32_System_Com_StructuredStorage" = [ "Win32_System_Com" ]; - "Win32_System_Com_Urlmon" = [ "Win32_System_Com" ]; - "Win32_System_ComponentServices" = [ "Win32_System" ]; - "Win32_System_Console" = [ "Win32_System" ]; - "Win32_System_CorrelationVector" = [ "Win32_System" ]; - "Win32_System_DataExchange" = [ "Win32_System" ]; - "Win32_System_DeploymentServices" = [ "Win32_System" ]; - "Win32_System_DeveloperLicensing" = [ "Win32_System" ]; - "Win32_System_Diagnostics" = [ "Win32_System" ]; - "Win32_System_Diagnostics_Ceip" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_Debug" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_Debug_Extensions" = [ "Win32_System_Diagnostics_Debug" ]; - "Win32_System_Diagnostics_Etw" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_ProcessSnapshotting" = [ "Win32_System_Diagnostics" ]; - "Win32_System_Diagnostics_ToolHelp" = [ "Win32_System_Diagnostics" ]; - "Win32_System_DistributedTransactionCoordinator" = [ "Win32_System" ]; - "Win32_System_Environment" = [ "Win32_System" ]; - "Win32_System_ErrorReporting" = [ "Win32_System" ]; - "Win32_System_EventCollector" = [ "Win32_System" ]; - "Win32_System_EventLog" = [ "Win32_System" ]; - "Win32_System_EventNotificationService" = [ "Win32_System" ]; - "Win32_System_GroupPolicy" = [ "Win32_System" ]; - "Win32_System_HostCompute" = [ "Win32_System" ]; - "Win32_System_HostComputeNetwork" = [ "Win32_System" ]; - "Win32_System_HostComputeSystem" = [ "Win32_System" ]; - "Win32_System_Hypervisor" = [ "Win32_System" ]; - "Win32_System_IO" = [ "Win32_System" ]; - "Win32_System_Iis" = [ "Win32_System" ]; - "Win32_System_Ioctl" = [ "Win32_System" ]; - "Win32_System_JobObjects" = [ "Win32_System" ]; - "Win32_System_Js" = [ "Win32_System" ]; - "Win32_System_Kernel" = [ "Win32_System" ]; - "Win32_System_LibraryLoader" = [ "Win32_System" ]; - "Win32_System_Mailslots" = [ "Win32_System" ]; - "Win32_System_Mapi" = [ "Win32_System" ]; - "Win32_System_Memory" = [ "Win32_System" ]; - "Win32_System_Memory_NonVolatile" = [ "Win32_System_Memory" ]; - "Win32_System_MessageQueuing" = [ "Win32_System" ]; - "Win32_System_MixedReality" = [ "Win32_System" ]; - "Win32_System_Ole" = [ "Win32_System" ]; - "Win32_System_PasswordManagement" = [ "Win32_System" ]; - "Win32_System_Performance" = [ "Win32_System" ]; - "Win32_System_Performance_HardwareCounterProfiling" = [ "Win32_System_Performance" ]; - "Win32_System_Pipes" = [ "Win32_System" ]; - "Win32_System_Power" = [ "Win32_System" ]; - "Win32_System_ProcessStatus" = [ "Win32_System" ]; - "Win32_System_Recovery" = [ "Win32_System" ]; - "Win32_System_Registry" = [ "Win32_System" ]; - "Win32_System_RemoteDesktop" = [ "Win32_System" ]; - "Win32_System_RemoteManagement" = [ "Win32_System" ]; - "Win32_System_RestartManager" = [ "Win32_System" ]; - "Win32_System_Restore" = [ "Win32_System" ]; - "Win32_System_Rpc" = [ "Win32_System" ]; - "Win32_System_Search" = [ "Win32_System" ]; - "Win32_System_Search_Common" = [ "Win32_System_Search" ]; - "Win32_System_SecurityCenter" = [ "Win32_System" ]; - "Win32_System_Services" = [ "Win32_System" ]; - "Win32_System_SetupAndMigration" = [ "Win32_System" ]; - "Win32_System_Shutdown" = [ "Win32_System" ]; - "Win32_System_StationsAndDesktops" = [ "Win32_System" ]; - "Win32_System_SubsystemForLinux" = [ "Win32_System" ]; - "Win32_System_SystemInformation" = [ "Win32_System" ]; - "Win32_System_SystemServices" = [ "Win32_System" ]; - "Win32_System_Threading" = [ "Win32_System" ]; - "Win32_System_Time" = [ "Win32_System" ]; - "Win32_System_TpmBaseServices" = [ "Win32_System" ]; - "Win32_System_UserAccessLogging" = [ "Win32_System" ]; - "Win32_System_Variant" = [ "Win32_System" ]; - "Win32_System_VirtualDosMachines" = [ "Win32_System" ]; - "Win32_System_WindowsProgramming" = [ "Win32_System" ]; - "Win32_System_Wmi" = [ "Win32_System" ]; - "Win32_UI" = [ "Win32" ]; - "Win32_UI_Accessibility" = [ "Win32_UI" ]; - "Win32_UI_ColorSystem" = [ "Win32_UI" ]; - "Win32_UI_Controls" = [ "Win32_UI" ]; - "Win32_UI_Controls_Dialogs" = [ "Win32_UI_Controls" ]; - "Win32_UI_HiDpi" = [ "Win32_UI" ]; - "Win32_UI_Input" = [ "Win32_UI" ]; - "Win32_UI_Input_Ime" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_KeyboardAndMouse" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_Pointer" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_Touch" = [ "Win32_UI_Input" ]; - "Win32_UI_Input_XboxController" = [ "Win32_UI_Input" ]; - "Win32_UI_InteractionContext" = [ "Win32_UI" ]; - "Win32_UI_Magnification" = [ "Win32_UI" ]; - "Win32_UI_Shell" = [ "Win32_UI" ]; - "Win32_UI_Shell_PropertiesSystem" = [ "Win32_UI_Shell" ]; - "Win32_UI_TabletPC" = [ "Win32_UI" ]; - "Win32_UI_TextServices" = [ "Win32_UI" ]; - "Win32_UI_WindowsAndMessaging" = [ "Win32_UI" ]; - "Win32_Web" = [ "Win32" ]; - "Win32_Web_InternetExplorer" = [ "Win32_Web" ]; - }; - resolvedDefaultFeatures = [ "Wdk" "Wdk_Foundation" "Wdk_Storage" "Wdk_Storage_FileSystem" "Wdk_System" "Wdk_System_IO" "Win32" "Win32_Foundation" "Win32_Networking" "Win32_Networking_WinSock" "Win32_Security" "Win32_Storage" "Win32_Storage_FileSystem" "Win32_System" "Win32_System_Console" "Win32_System_IO" "Win32_System_Pipes" "Win32_System_SystemServices" "Win32_System_Threading" "Win32_System_WindowsProgramming" "default" ]; - }; - "windows-targets" = rec { - crateName = "windows-targets"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0wwrx625nwlfp7k93r2rra568gad1mwd888h1jwnl0vfg5r4ywlv"; - libName = "windows_targets"; - authors = [ - "Microsoft" - ]; - dependencies = [ - { - name = "windows_aarch64_gnullvm"; - packageId = "windows_aarch64_gnullvm"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "aarch64-pc-windows-gnullvm"); - } - { - name = "windows_aarch64_msvc"; - packageId = "windows_aarch64_msvc"; - target = { target, features }: (("aarch64" == target."arch" or null) && ("msvc" == target."env" or null) && (!(target."windows_raw_dylib" or false))); - } - { - name = "windows_i686_gnu"; - packageId = "windows_i686_gnu"; - target = { target, features }: (("x86" == target."arch" or null) && ("gnu" == target."env" or null) && (!("llvm" == target."abi" or null)) && (!(target."windows_raw_dylib" or false))); - } - { - name = "windows_i686_gnullvm"; - packageId = "windows_i686_gnullvm"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "i686-pc-windows-gnullvm"); - } - { - name = "windows_i686_msvc"; - packageId = "windows_i686_msvc"; - target = { target, features }: (("x86" == target."arch" or null) && ("msvc" == target."env" or null) && (!(target."windows_raw_dylib" or false))); - } - { - name = "windows_x86_64_gnu"; - packageId = "windows_x86_64_gnu"; - target = { target, features }: (("x86_64" == target."arch" or null) && ("gnu" == target."env" or null) && (!("llvm" == target."abi" or null)) && (!(target."windows_raw_dylib" or false))); - } - { - name = "windows_x86_64_gnullvm"; - packageId = "windows_x86_64_gnullvm"; - target = { target, features }: (stdenv.hostPlatform.rust.rustcTarget == "x86_64-pc-windows-gnullvm"); - } - { - name = "windows_x86_64_msvc"; - packageId = "windows_x86_64_msvc"; - target = { target, features }: ((("x86_64" == target."arch" or null) || ("arm64ec" == target."arch" or null)) && ("msvc" == target."env" or null) && (!(target."windows_raw_dylib" or false))); - } - ]; - - }; - "windows_aarch64_gnullvm" = rec { - crateName = "windows_aarch64_gnullvm"; - version = "0.52.6"; - edition = "2021"; - sha256 = "1lrcq38cr2arvmz19v32qaggvj8bh1640mdm9c2fr877h0hn591j"; - authors = [ - "Microsoft" - ]; - - }; - "windows_aarch64_msvc" = rec { - crateName = "windows_aarch64_msvc"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0sfl0nysnz32yyfh773hpi49b1q700ah6y7sacmjbqjjn5xjmv09"; - authors = [ - "Microsoft" - ]; - - }; - "windows_i686_gnu" = rec { - crateName = "windows_i686_gnu"; - version = "0.52.6"; - edition = "2021"; - sha256 = "02zspglbykh1jh9pi7gn8g1f97jh1rrccni9ivmrfbl0mgamm6wf"; - authors = [ - "Microsoft" - ]; - - }; - "windows_i686_gnullvm" = rec { - crateName = "windows_i686_gnullvm"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0rpdx1537mw6slcpqa0rm3qixmsb79nbhqy5fsm3q2q9ik9m5vhf"; - authors = [ - "Microsoft" - ]; - - }; - "windows_i686_msvc" = rec { - crateName = "windows_i686_msvc"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0rkcqmp4zzmfvrrrx01260q3xkpzi6fzi2x2pgdcdry50ny4h294"; - authors = [ - "Microsoft" - ]; - - }; - "windows_x86_64_gnu" = rec { - crateName = "windows_x86_64_gnu"; - version = "0.52.6"; - edition = "2021"; - sha256 = "0y0sifqcb56a56mvn7xjgs8g43p33mfqkd8wj1yhrgxzma05qyhl"; - authors = [ - "Microsoft" - ]; - - }; - "windows_x86_64_gnullvm" = rec { - crateName = "windows_x86_64_gnullvm"; - version = "0.52.6"; - edition = "2021"; - sha256 = "03gda7zjx1qh8k9nnlgb7m3w3s1xkysg55hkd1wjch8pqhyv5m94"; - authors = [ - "Microsoft" - ]; - - }; - "windows_x86_64_msvc" = rec { - crateName = "windows_x86_64_msvc"; - version = "0.52.6"; - edition = "2021"; - sha256 = "1v7rb5cibyzx8vak29pdrk8nx9hycsjs4w0jgms08qk49jl6v7sq"; - authors = [ - "Microsoft" - ]; - - }; - "winnow" = rec { - crateName = "winnow"; - version = "0.6.20"; - edition = "2021"; - sha256 = "16y4i8z9vh8hazjxg5mvmq0c5i35wlk8rxi5gkq6cn5vlb0zxh9n"; - dependencies = [ - { - name = "memchr"; - packageId = "memchr"; - optional = true; - usesDefaultFeatures = false; - } - ]; - features = { - "debug" = [ "std" "dep:anstream" "dep:anstyle" "dep:is-terminal" "dep:terminal_size" ]; - "default" = [ "std" ]; - "simd" = [ "dep:memchr" ]; - "std" = [ "alloc" "memchr?/std" ]; - "unstable-doc" = [ "alloc" "std" "simd" "unstable-recover" ]; - }; - resolvedDefaultFeatures = [ "alloc" "default" "std" ]; - }; - "zeroize" = rec { - crateName = "zeroize"; - version = "1.8.1"; - edition = "2021"; - sha256 = "1pjdrmjwmszpxfd7r860jx54cyk94qk59x13sc307cvr5256glyf"; - authors = [ - "The RustCrypto Project Developers" - ]; - features = { - "default" = [ "alloc" ]; - "derive" = [ "zeroize_derive" ]; - "serde" = [ "dep:serde" ]; - "std" = [ "alloc" ]; - "zeroize_derive" = [ "dep:zeroize_derive" ]; - }; - resolvedDefaultFeatures = [ "alloc" ]; - }; - }; - - # - # crate2nix/default.nix (excerpt start) - # - - /* Target (platform) data for conditional dependencies. - This corresponds roughly to what buildRustCrate is setting. - */ - makeDefaultTarget = platform: { - unix = platform.isUnix; - windows = platform.isWindows; - fuchsia = true; - test = false; - - inherit (platform.rust.platform) - arch - os - vendor; - family = platform.rust.platform.target-family; - env = "gnu"; - endian = - if platform.parsed.cpu.significantByte.name == "littleEndian" - then "little" else "big"; - pointer_width = toString platform.parsed.cpu.bits; - debug_assertions = false; - }; - - /* Filters common temp files and build files. */ - # TODO(pkolloch): Substitute with gitignore filter - sourceFilter = name: type: - let - baseName = builtins.baseNameOf (builtins.toString name); - in - ! ( - # Filter out git - baseName == ".gitignore" - || (type == "directory" && baseName == ".git") - - # Filter out build results - || ( - type == "directory" && ( - baseName == "target" - || baseName == "_site" - || baseName == ".sass-cache" - || baseName == ".jekyll-metadata" - || baseName == "build-artifacts" - ) - ) - - # Filter out nix-build result symlinks - || ( - type == "symlink" && lib.hasPrefix "result" baseName - ) - - # Filter out IDE config - || ( - type == "directory" && ( - baseName == ".idea" || baseName == ".vscode" - ) - ) || lib.hasSuffix ".iml" baseName - - # Filter out nix build files - || baseName == "Cargo.nix" - - # Filter out editor backup / swap files. - || lib.hasSuffix "~" baseName - || builtins.match "^\\.sw[a-z]$$" baseName != null - || builtins.match "^\\..*\\.sw[a-z]$$" baseName != null - || lib.hasSuffix ".tmp" baseName - || lib.hasSuffix ".bak" baseName - || baseName == "tests.nix" - ); - - /* Returns a crate which depends on successful test execution - of crate given as the second argument. - - testCrateFlags: list of flags to pass to the test exectuable - testInputs: list of packages that should be available during test execution - */ - crateWithTest = { crate, testCrate, testCrateFlags, testInputs, testPreRun, testPostRun }: - assert builtins.typeOf testCrateFlags == "list"; - assert builtins.typeOf testInputs == "list"; - assert builtins.typeOf testPreRun == "string"; - assert builtins.typeOf testPostRun == "string"; - let - # override the `crate` so that it will build and execute tests instead of - # building the actual lib and bin targets We just have to pass `--test` - # to rustc and it will do the right thing. We execute the tests and copy - # their log and the test executables to $out for later inspection. - test = - let - drv = testCrate.override - ( - _: { - buildTests = true; - release = false; - } - ); - # If the user hasn't set any pre/post commands, we don't want to - # insert empty lines. This means that any existing users of crate2nix - # don't get a spurious rebuild unless they set these explicitly. - testCommand = pkgs.lib.concatStringsSep "\n" - (pkgs.lib.filter (s: s != "") [ - testPreRun - "$f $testCrateFlags 2>&1 | tee -a $out" - testPostRun - ]); - in - pkgs.stdenvNoCC.mkDerivation { - name = "run-tests-${testCrate.name}"; - - inherit (crate) src; - - inherit testCrateFlags; - - buildInputs = testInputs; - - buildPhase = '' - set -e - export RUST_BACKTRACE=1 - - # build outputs - testRoot=target/debug - mkdir -p $testRoot - - # executables of the crate - # we copy to prevent std::env::current_exe() to resolve to a store location - for i in ${crate}/bin/*; do - cp "$i" "$testRoot" - done - chmod +w -R . - - # test harness executables are suffixed with a hash, like cargo does - # this allows to prevent name collision with the main - # executables of the crate - hash=$(basename $out) - for file in ${drv}/tests/*; do - f=$testRoot/$(basename $file)-$hash - cp $file $f - ${testCommand} - done - ''; - }; - in - pkgs.runCommand "${crate.name}-linked" - { - inherit (crate) outputs crateName; - passthru = (crate.passthru or { }) // { - inherit test; - }; - } - (lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) '' - echo tested by ${test} - '' + '' - ${lib.concatMapStringsSep "\n" (output: "ln -s ${crate.${output}} ${"$"}${output}") crate.outputs} - ''); - - /* A restricted overridable version of builtRustCratesWithFeatures. */ - buildRustCrateWithFeatures = - { packageId - , features ? rootFeatures - , crateOverrides ? defaultCrateOverrides - , buildRustCrateForPkgsFunc ? null - , runTests ? false - , testCrateFlags ? [ ] - , testInputs ? [ ] - # Any command to run immediatelly before a test is executed. - , testPreRun ? "" - # Any command run immediatelly after a test is executed. - , testPostRun ? "" - }: - lib.makeOverridable - ( - { features - , crateOverrides - , runTests - , testCrateFlags - , testInputs - , testPreRun - , testPostRun - }: - let - buildRustCrateForPkgsFuncOverriden = - if buildRustCrateForPkgsFunc != null - then buildRustCrateForPkgsFunc - else - ( - if crateOverrides == pkgs.defaultCrateOverrides - then buildRustCrateForPkgs - else - pkgs: (buildRustCrateForPkgs pkgs).override { - defaultCrateOverrides = crateOverrides; - } - ); - builtRustCrates = builtRustCratesWithFeatures { - inherit packageId features; - buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden; - runTests = false; - }; - builtTestRustCrates = builtRustCratesWithFeatures { - inherit packageId features; - buildRustCrateForPkgsFunc = buildRustCrateForPkgsFuncOverriden; - runTests = true; - }; - drv = builtRustCrates.crates.${packageId}; - testDrv = builtTestRustCrates.crates.${packageId}; - derivation = - if runTests then - crateWithTest - { - crate = drv; - testCrate = testDrv; - inherit testCrateFlags testInputs testPreRun testPostRun; - } - else drv; - in - derivation - ) - { inherit features crateOverrides runTests testCrateFlags testInputs testPreRun testPostRun; }; - - /* Returns an attr set with packageId mapped to the result of buildRustCrateForPkgsFunc - for the corresponding crate. - */ - builtRustCratesWithFeatures = - { packageId - , features - , crateConfigs ? crates - , buildRustCrateForPkgsFunc - , runTests - , makeTarget ? makeDefaultTarget - } @ args: - assert (builtins.isAttrs crateConfigs); - assert (builtins.isString packageId); - assert (builtins.isList features); - assert (builtins.isAttrs (makeTarget stdenv.hostPlatform)); - assert (builtins.isBool runTests); - let - rootPackageId = packageId; - mergedFeatures = mergePackageFeatures - ( - args // { - inherit rootPackageId; - target = makeTarget stdenv.hostPlatform // { test = runTests; }; - } - ); - # Memoize built packages so that reappearing packages are only built once. - builtByPackageIdByPkgs = mkBuiltByPackageIdByPkgs pkgs; - mkBuiltByPackageIdByPkgs = pkgs: - let - self = { - crates = lib.mapAttrs (packageId: value: buildByPackageIdForPkgsImpl self pkgs packageId) crateConfigs; - target = makeTarget stdenv.hostPlatform; - build = mkBuiltByPackageIdByPkgs pkgs.buildPackages; - }; - in - self; - buildByPackageIdForPkgsImpl = self: pkgs: packageId: - let - features = mergedFeatures."${packageId}" or [ ]; - crateConfig' = crateConfigs."${packageId}"; - crateConfig = - builtins.removeAttrs crateConfig' [ "resolvedDefaultFeatures" "devDependencies" ]; - devDependencies = - lib.optionals - (runTests && packageId == rootPackageId) - (crateConfig'.devDependencies or [ ]); - dependencies = - dependencyDerivations { - inherit features; - inherit (self) target; - buildByPackageId = depPackageId: - # proc_macro crates must be compiled for the build architecture - if crateConfigs.${depPackageId}.procMacro or false - then self.build.crates.${depPackageId} - else self.crates.${depPackageId}; - dependencies = - (crateConfig.dependencies or [ ]) - ++ devDependencies; - }; - buildDependencies = - dependencyDerivations { - inherit features; - inherit (self.build) target; - buildByPackageId = depPackageId: - self.build.crates.${depPackageId}; - dependencies = crateConfig.buildDependencies or [ ]; - }; - dependenciesWithRenames = - let - buildDeps = filterEnabledDependencies { - inherit features; - inherit (self) target; - dependencies = crateConfig.dependencies or [ ] ++ devDependencies; - }; - hostDeps = filterEnabledDependencies { - inherit features; - inherit (self.build) target; - dependencies = crateConfig.buildDependencies or [ ]; - }; - in - lib.filter (d: d ? "rename") (hostDeps ++ buildDeps); - # Crate renames have the form: - # - # { - # crate_name = [ - # { version = "1.2.3"; rename = "crate_name01"; } - # ]; - # # ... - # } - crateRenames = - let - grouped = - lib.groupBy - (dependency: dependency.name) - dependenciesWithRenames; - versionAndRename = dep: - let - package = crateConfigs."${dep.packageId}"; - in - { inherit (dep) rename; inherit (package) version; }; - in - lib.mapAttrs (name: builtins.map versionAndRename) grouped; - in - buildRustCrateForPkgsFunc pkgs - ( - crateConfig // { - src = crateConfig.src or ( - pkgs.fetchurl rec { - name = "${crateConfig.crateName}-${crateConfig.version}.tar.gz"; - # https://www.pietroalbini.org/blog/downloading-crates-io/ - # Not rate-limited, CDN URL. - url = "https://static.crates.io/crates/${crateConfig.crateName}/${crateConfig.crateName}-${crateConfig.version}.crate"; - sha256 = - assert (lib.assertMsg (crateConfig ? sha256) "Missing sha256 for ${name}"); - crateConfig.sha256; - } - ); - extraRustcOpts = lib.lists.optional (targetFeatures != [ ]) "-C target-feature=${lib.concatMapStringsSep "," (x: "+${x}") targetFeatures}"; - inherit features dependencies buildDependencies crateRenames release; - } - ); - in - builtByPackageIdByPkgs; - - /* Returns the actual derivations for the given dependencies. */ - dependencyDerivations = - { buildByPackageId - , features - , dependencies - , target - }: - assert (builtins.isList features); - assert (builtins.isList dependencies); - assert (builtins.isAttrs target); - let - enabledDependencies = filterEnabledDependencies { - inherit dependencies features target; - }; - depDerivation = dependency: buildByPackageId dependency.packageId; - in - map depDerivation enabledDependencies; - - /* Returns a sanitized version of val with all values substituted that cannot - be serialized as JSON. - */ - sanitizeForJson = val: - if builtins.isAttrs val - then lib.mapAttrs (n: sanitizeForJson) val - else if builtins.isList val - then builtins.map sanitizeForJson val - else if builtins.isFunction val - then "function" - else val; - - /* Returns various tools to debug a crate. */ - debugCrate = { packageId, target ? makeDefaultTarget stdenv.hostPlatform }: - assert (builtins.isString packageId); - let - debug = rec { - # The built tree as passed to buildRustCrate. - buildTree = buildRustCrateWithFeatures { - buildRustCrateForPkgsFunc = _: lib.id; - inherit packageId; - }; - sanitizedBuildTree = sanitizeForJson buildTree; - dependencyTree = sanitizeForJson - ( - buildRustCrateWithFeatures { - buildRustCrateForPkgsFunc = _: crate: { - "01_crateName" = crate.crateName or false; - "02_features" = crate.features or [ ]; - "03_dependencies" = crate.dependencies or [ ]; - }; - inherit packageId; - } - ); - mergedPackageFeatures = mergePackageFeatures { - features = rootFeatures; - inherit packageId target; - }; - diffedDefaultPackageFeatures = diffDefaultPackageFeatures { - inherit packageId target; - }; - }; - in - { internal = debug; }; - - /* Returns differences between cargo default features and crate2nix default - features. - - This is useful for verifying the feature resolution in crate2nix. - */ - diffDefaultPackageFeatures = - { crateConfigs ? crates - , packageId - , target - }: - assert (builtins.isAttrs crateConfigs); - let - prefixValues = prefix: lib.mapAttrs (n: v: { "${prefix}" = v; }); - mergedFeatures = - prefixValues - "crate2nix" - (mergePackageFeatures { inherit crateConfigs packageId target; features = [ "default" ]; }); - configs = prefixValues "cargo" crateConfigs; - combined = lib.foldAttrs (a: b: a // b) { } [ mergedFeatures configs ]; - onlyInCargo = - builtins.attrNames - (lib.filterAttrs (n: v: !(v ? "crate2nix") && (v ? "cargo")) combined); - onlyInCrate2Nix = - builtins.attrNames - (lib.filterAttrs (n: v: (v ? "crate2nix") && !(v ? "cargo")) combined); - differentFeatures = lib.filterAttrs - ( - n: v: - (v ? "crate2nix") - && (v ? "cargo") - && (v.crate2nix.features or [ ]) != (v."cargo".resolved_default_features or [ ]) - ) - combined; - in - builtins.toJSON { - inherit onlyInCargo onlyInCrate2Nix differentFeatures; - }; - - /* Returns an attrset mapping packageId to the list of enabled features. - - If multiple paths to a dependency enable different features, the - corresponding feature sets are merged. Features in rust are additive. - */ - mergePackageFeatures = - { crateConfigs ? crates - , packageId - , rootPackageId ? packageId - , features ? rootFeatures - , dependencyPath ? [ crates.${packageId}.crateName ] - , featuresByPackageId ? { } - , target - # Adds devDependencies to the crate with rootPackageId. - , runTests ? false - , ... - } @ args: - assert (builtins.isAttrs crateConfigs); - assert (builtins.isString packageId); - assert (builtins.isString rootPackageId); - assert (builtins.isList features); - assert (builtins.isList dependencyPath); - assert (builtins.isAttrs featuresByPackageId); - assert (builtins.isAttrs target); - assert (builtins.isBool runTests); - let - crateConfig = crateConfigs."${packageId}" or (builtins.throw "Package not found: ${packageId}"); - expandedFeatures = expandFeatures (crateConfig.features or { }) features; - enabledFeatures = enableFeatures (crateConfig.dependencies or [ ]) expandedFeatures; - depWithResolvedFeatures = dependency: - let - inherit (dependency) packageId; - features = dependencyFeatures enabledFeatures dependency; - in - { inherit packageId features; }; - resolveDependencies = cache: path: dependencies: - assert (builtins.isAttrs cache); - assert (builtins.isList dependencies); - let - enabledDependencies = filterEnabledDependencies { - inherit dependencies target; - features = enabledFeatures; - }; - directDependencies = map depWithResolvedFeatures enabledDependencies; - foldOverCache = op: lib.foldl op cache directDependencies; - in - foldOverCache - ( - cache: { packageId, features }: - let - cacheFeatures = cache.${packageId} or [ ]; - combinedFeatures = sortedUnique (cacheFeatures ++ features); - in - if cache ? ${packageId} && cache.${packageId} == combinedFeatures - then cache - else - mergePackageFeatures { - features = combinedFeatures; - featuresByPackageId = cache; - inherit crateConfigs packageId target runTests rootPackageId; - } - ); - cacheWithSelf = - let - cacheFeatures = featuresByPackageId.${packageId} or [ ]; - combinedFeatures = sortedUnique (cacheFeatures ++ enabledFeatures); - in - featuresByPackageId // { - "${packageId}" = combinedFeatures; - }; - cacheWithDependencies = - resolveDependencies cacheWithSelf "dep" - ( - crateConfig.dependencies or [ ] - ++ lib.optionals - (runTests && packageId == rootPackageId) - (crateConfig.devDependencies or [ ]) - ); - cacheWithAll = - resolveDependencies - cacheWithDependencies "build" - (crateConfig.buildDependencies or [ ]); - in - cacheWithAll; - - /* Returns the enabled dependencies given the enabled features. */ - filterEnabledDependencies = { dependencies, features, target }: - assert (builtins.isList dependencies); - assert (builtins.isList features); - assert (builtins.isAttrs target); - - lib.filter - ( - dep: - let - targetFunc = dep.target or (features: true); - in - targetFunc { inherit features target; } - && ( - !(dep.optional or false) - || builtins.any (doesFeatureEnableDependency dep) features - ) - ) - dependencies; - - /* Returns whether the given feature should enable the given dependency. */ - doesFeatureEnableDependency = dependency: feature: - let - name = dependency.rename or dependency.name; - prefix = "${name}/"; - len = builtins.stringLength prefix; - startsWithPrefix = builtins.substring 0 len feature == prefix; - in - feature == name || feature == "dep:" + name || startsWithPrefix; - - /* Returns the expanded features for the given inputFeatures by applying the - rules in featureMap. - - featureMap is an attribute set which maps feature names to lists of further - feature names to enable in case this feature is selected. - */ - expandFeatures = featureMap: inputFeatures: - assert (builtins.isAttrs featureMap); - assert (builtins.isList inputFeatures); - let - expandFeaturesNoCycle = oldSeen: inputFeatures: - if inputFeatures != [ ] - then - let - # The feature we're currently expanding. - feature = builtins.head inputFeatures; - # All the features we've seen/expanded so far, including the one - # we're currently processing. - seen = oldSeen // { ${feature} = 1; }; - # Expand the feature but be careful to not re-introduce a feature - # that we've already seen: this can easily cause a cycle, see issue - # #209. - enables = builtins.filter (f: !(seen ? "${f}")) (featureMap."${feature}" or [ ]); - in - [ feature ] ++ (expandFeaturesNoCycle seen (builtins.tail inputFeatures ++ enables)) - # No more features left, nothing to expand to. - else [ ]; - outFeatures = expandFeaturesNoCycle { } inputFeatures; - in - sortedUnique outFeatures; - - /* This function adds optional dependencies as features if they are enabled - indirectly by dependency features. This function mimics Cargo's behavior - described in a note at: - https://doc.rust-lang.org/nightly/cargo/reference/features.html#dependency-features - */ - enableFeatures = dependencies: features: - assert (builtins.isList features); - assert (builtins.isList dependencies); - let - additionalFeatures = lib.concatMap - ( - dependency: - assert (builtins.isAttrs dependency); - let - enabled = builtins.any (doesFeatureEnableDependency dependency) features; - in - if (dependency.optional or false) && enabled - then [ (dependency.rename or dependency.name) ] - else [ ] - ) - dependencies; - in - sortedUnique (features ++ additionalFeatures); - - /* - Returns the actual features for the given dependency. - - features: The features of the crate that refers this dependency. - */ - dependencyFeatures = features: dependency: - assert (builtins.isList features); - assert (builtins.isAttrs dependency); - let - defaultOrNil = - if dependency.usesDefaultFeatures or true - then [ "default" ] - else [ ]; - explicitFeatures = dependency.features or [ ]; - additionalDependencyFeatures = - let - name = dependency.rename or dependency.name; - stripPrefixMatch = prefix: s: - if lib.hasPrefix prefix s - then lib.removePrefix prefix s - else null; - extractFeature = feature: lib.findFirst - (f: f != null) - null - (map (prefix: stripPrefixMatch prefix feature) [ - (name + "/") - (name + "?/") - ]); - dependencyFeatures = lib.filter (f: f != null) (map extractFeature features); - in - dependencyFeatures; - in - defaultOrNil ++ explicitFeatures ++ additionalDependencyFeatures; - - /* Sorts and removes duplicates from a list of strings. */ - sortedUnique = features: - assert (builtins.isList features); - assert (builtins.all builtins.isString features); - let - outFeaturesSet = lib.foldl (set: feature: set // { "${feature}" = 1; }) { } features; - outFeaturesUnique = builtins.attrNames outFeaturesSet; - in - builtins.sort (a: b: a < b) outFeaturesUnique; - - deprecationWarning = message: value: - if strictDeprecation - then builtins.throw "strictDeprecation enabled, aborting: ${message}" - else builtins.trace message value; - - # - # crate2nix/default.nix (excerpt end) - # - }; -} - diff --git a/users/picnoir/tvix-daemon/Cargo.toml b/users/picnoir/tvix-daemon/Cargo.toml deleted file mode 100644 index 2aca99f20..000000000 --- a/users/picnoir/tvix-daemon/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "tvix-daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -nix-compat = { path = "../../../tvix/nix-compat", features = ["wire"] } -tokio-listener = "0.3.1" -tokio = { version = "1.36.0", features = ["full"] } -tracing-subscriber = "0.3.18" -tracing = "0.1.40" -clap = { version = "4.5.3", features = ["derive", "env"] } - -[dev-dependencies] -tokio-test = "0.4.4" diff --git a/users/picnoir/tvix-daemon/README.md b/users/picnoir/tvix-daemon/README.md deleted file mode 100644 index 1c65790a2..000000000 --- a/users/picnoir/tvix-daemon/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Tvix-daemon - -A **super** incomplete implementation of a Nix-compatible daemon. Same as the original except it's backed by Tvix-Store. - -For now, this is mostly used as a playground to implement the Nix daemon wire format in nix-compat. - -On the long run, I hope this to be useful to get some real-world usage experience of tvix-store. - -## Build - -When inside this directory: - -```sh -mg shell :shell -cargo build -``` diff --git a/users/picnoir/tvix-daemon/default.nix b/users/picnoir/tvix-daemon/default.nix deleted file mode 100644 index d970ac360..000000000 --- a/users/picnoir/tvix-daemon/default.nix +++ /dev/null @@ -1,53 +0,0 @@ -{ depot, pkgs, ... }: - -let - crate2nix = pkgs.callPackage ./Cargo.nix { - defaultCrateOverrides = { - tvix-castore = prev: { - PROTO_ROOT = depot.tvix.castore.protos.protos; - nativeBuildInputs = protobufDep prev; - }; - - tvix-store = prev: { - PROTO_ROOT = depot.tvix.store.protos.protos; - nativeBuildInputs = protobufDep prev; - }; - }; - }; - protobufDep = prev: (prev.nativeBuildInputs or [ ]) ++ [ pkgs.buildPackages.protobuf ]; -in -{ - shell = (import ./shell.nix { inherit pkgs; }); - tvix-daemon = crate2nix.rootCrate.build; - clippy = pkgs.stdenv.mkDerivation { - name = "tvix-daemon-clippy"; - # The cleaned sources. - src = depot.third_party.gitignoreSource ./.; - cargoDeps = crate2nix.allWorkspaceMembers; - - nativeBuildInputs = with pkgs; [ - cargo - clippy - pkg-config - protobuf - rustc - rustPlatform.cargoSetupHook - ]; - - buildPhase = "cargo clippy --tests --all-features --benches --examples | tee $out"; - }; - crate2nix-check = - let - crate2nix-check = depot.tvix.utils.mkCrate2nixCheck ./Cargo.nix; - in - crate2nix-check.command.overrideAttrs { - meta.ci.extraSteps = { - inherit crate2nix-check; - }; - }; - meta.ci.targets = [ - "tvix-daemon" - "shell" - "crate2nix-check" - ]; -} diff --git a/users/picnoir/tvix-daemon/shell.nix b/users/picnoir/tvix-daemon/shell.nix deleted file mode 100644 index 6ec6b961f..000000000 --- a/users/picnoir/tvix-daemon/shell.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ pkgs, ... }: -pkgs.mkShell { - name = "tvix-daemon"; - packages = [ - pkgs.cargo - pkgs.cargo-machete - pkgs.cargo-expand - pkgs.clippy - pkgs.evans - pkgs.fuse - pkgs.go - pkgs.grpcurl - pkgs.hyperfine - pkgs.nix_2_3 # b/313 - pkgs.pkg-config - pkgs.rust-analyzer - pkgs.rustc - pkgs.rustfmt - pkgs.protobuf - ]; -} diff --git a/users/picnoir/tvix-daemon/src/main.rs b/users/picnoir/tvix-daemon/src/main.rs deleted file mode 100644 index d60fcfbff..000000000 --- a/users/picnoir/tvix-daemon/src/main.rs +++ /dev/null @@ -1,118 +0,0 @@ -use clap::Parser; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio_listener::{self, SystemOptions, UserOptions}; -use tracing::{debug, error, info, instrument, Level}; - -use nix_compat::wire::ProtocolVersion; -use nix_compat::worker_protocol::{self, server_handshake_client, ClientSettings, Trust}; - -#[derive(Parser, Debug)] -struct Cli { - /// Listening unix socket path - #[arg(short, long)] - socket: Option, - /// Log verbosity level. Can be "error", "warn", "info", "debug", "trace", or a number 1-5 - #[arg(short, long, env)] - verbosity: Option, -} - -#[tokio::main] -#[instrument()] -async fn main() { - let args = Cli::parse(); - tracing_subscriber::fmt() - .compact() - .with_max_level( - args.verbosity - .unwrap_or_else(|| panic!("Can't parse log verbosity")), - ) - .try_init() - .unwrap(); - info!("Started Tvix daemon"); - let addr = args - .socket - .unwrap_or_else(|| "sd_listen_unix".to_string()) - .parse() - .expect("Invalid listening socket address"); - let system_options: SystemOptions = Default::default(); - let mut user_options: UserOptions = Default::default(); - user_options.recv_buffer_size = Some(1024); - user_options.send_buffer_size = Some(1024); - info!(user_options.send_buffer_size); - info!(user_options.recv_buffer_size); - let mut listener = tokio_listener::Listener::bind(&addr, &system_options, &user_options) - .await - .unwrap(); - info!(listener_address = ?listener, "Listening for incoming connections"); - while let Ok((conn, addr)) = listener.accept().await { - info!(addr = %addr, "Incoming connection"); - tokio::spawn(async move { worker(conn).await }); - } -} - -/// Structure used to hold the client socket connection and some -/// metadata about the connection. -#[derive(Debug)] -struct ClientConnection { - pub conn: R, - pub version: ProtocolVersion, - pub client_settings: Option, -} - -/// Worker in charge to respond a Nix client using the Nix wire -/// protocol. -#[instrument()] -async fn worker(mut conn: R) -where - R: AsyncReadExt + AsyncWriteExt + Unpin + std::fmt::Debug, -{ - match server_handshake_client(&mut conn, "2.18.2", Trust::Trusted).await { - Ok(picked_protocol_version) => { - let mut client_connection = ClientConnection { - conn, - version: picked_protocol_version, - client_settings: None, - }; - debug!("Client hanshake succeeded"); - debug!(picked_protocol_version = ?picked_protocol_version); - // TODO: implement logging. For now, we'll just send - // STDERR_LAST, which is good enough to get Nix respond to - // us. - client_connection - .conn - .write_u64_le(worker_protocol::STDERR_LAST) - .await - .unwrap(); - loop { - let op = worker_protocol::read_op(&mut client_connection.conn) - .await - .unwrap(); - match op { - worker_protocol::Operation::SetOptions => { - let settings = op_set_options(&mut client_connection).await.unwrap(); - client_connection.client_settings = Some(settings); - debug!(settings = ?client_connection.client_settings, "Received client settings"); - } - _ => { - error!(op = ?op, "Unimplemented operation"); - break; - } - } - } - } - Err(e) => error!("Client handshake failed: {}", e), - } -} - -async fn op_set_options(conn: &mut ClientConnection) -> std::io::Result -where - R: AsyncReadExt + AsyncWriteExt + Unpin + std::fmt::Debug, -{ - // TODO: This code used read_client_settings which did not implement the protocol correctly, - // returning default() for now to unblock CI. - let settings = ClientSettings::default(); - // The client expects us to send some logs when we're processing - // the settings. Sending STDERR_LAST signal we're done processing. - conn.conn.write_u64_le(worker_protocol::STDERR_LAST).await?; - Ok(settings) -} diff --git a/users/picnoir/tvix-daemon/vm-test/README.md b/users/picnoir/tvix-daemon/vm-test/README.md deleted file mode 100644 index bd7f14f7e..000000000 --- a/users/picnoir/tvix-daemon/vm-test/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Integration VM Test - -This VM test fails for now. We use it to conveniently test our implementation on a real world Nix setup. - -For now, it only adds a new path to the store. It'll likely do more in the future. diff --git a/users/picnoir/tvix-daemon/vm-test/default.nix b/users/picnoir/tvix-daemon/vm-test/default.nix deleted file mode 100644 index e70690ee0..000000000 --- a/users/picnoir/tvix-daemon/vm-test/default.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - nixosTestDrv = pkgs.nixosTest { - name = "tvix-daemon-vm-test"; - nodes.machine = { config, pkgs, ... }: { - environment.systemPackages = [ - (pkgs.writers.writeBashBin "poke-daemon" '' - NIX_REMOTE=unix:///nix/var/nix/daemon-socket/socket nix-instantiate -E '"''${/etc/nscd.conf}"' - '') - ]; - systemd.services.nix-daemon.serviceConfig.ExecStart = [ - "" - "${depot.users.picnoir.tvix-daemon.tvix-daemon}/bin/tvix-daemon" - ]; - - }; - testScript = '' - machine.wait_for_unit("multi-user.target") - machine.succeed("poke-daemon") - ''; - }; -in -nixosTestDrv // { - # The test fails for now. TOREMOVE when we reach the stage where we - # can add stuff to the store. - meta.ci.skip = true; -} diff --git a/users/qyliss/OWNERS b/users/qyliss/OWNERS deleted file mode 100644 index 68724206a..000000000 --- a/users/qyliss/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -qyliss diff --git a/users/qyliss/keys.nix b/users/qyliss/keys.nix deleted file mode 100644 index d0837a7c6..000000000 --- a/users/qyliss/keys.nix +++ /dev/null @@ -1,8 +0,0 @@ -# Public key from https://github.com/alyssais.keys -{ ... }: - -{ - all = [ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDO11Pr7jKaRZ2It1yB312SKFN8mCV7aVYdry16LNwtnA6EDgFxyshG4Zmhl9asxQ9wa1lT3tdKB6ArA+VKxXMZB0zm15jYSLKpHQxMT7T3SqtTluJQpJD9zRtWeHbW/e1mtgn3tPYTHERB4HVGKIeGk97eOR2YOdXPHOIWhOXpogDtUlyt1bmWl0gyRHbWhViLeReHYhsu0KbZlo+ntN9aN7lPVkDfa7gUARv6IeGE5hAYHPRWmQ3VJCDaQnzsTtesLPFiNmV6Pq7qtWbHVNOG9XQLXJhD/305+yDZ2y/+KuBEQCroiWF8fPY/8gutfkZ0ZLjdGbXl38j5v+yRjreh+wjcN5MYWCWM18hMdutpoMd9D7PXaZz90V2vS+mRC81t3zXKrAy3Ke+LQBmlWSWxmKWdDoOTGOHjyPuCC/q+In7Q8hetB9/b9WUXTwEaaE3lUsa7y5JHAekNmdSoN3WD10nGYVUMvRRPGAlyqZTQdvxhn+6Pyu2piwIv/TMmC1CwiHr+fLbHxXQF745sOBQNmrdfiOzqDsKleybNB6i0AdDm5UZcYRcMLuxmryxN8O8qNUdMjMGoCeFcGwAIieqM+0xkPiByKr8ky2yV2lwOaZ4jrp/3j5GsGoQlvNKIPdCA/GQFad6vuqvhlbWcbdfiNpawrppLcJBsGB2NVjGbNQ==" - ]; -} diff --git a/users/sterni/OWNERS b/users/sterni/OWNERS deleted file mode 100644 index 6434d4ca3..000000000 --- a/users/sterni/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -sterni diff --git a/users/sterni/acme/README.md b/users/sterni/acme/README.md deleted file mode 100644 index c3ccb1ea0..000000000 --- a/users/sterni/acme/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# //users/sterni/acme - -Utilities and configurations related to the [acme][] text editor -from [Plan 9][]. - -## mkbqnkeyboard.bqn - -Script to generate Plan 9 `/lib/keyboard` entries providing compose -sequences for the Unicode characters used by [BQN][]. For usage -instructions, refer to [its own documentation](./mkbqnkeyboard.md). - -[acme]: https://9p.io/sys/doc/acme/acme.pdf -[Plan 9]: https://p9f.org/about.html -[BQN]: https://mlochbaum.github.io/BQN/ diff --git a/users/sterni/acme/mkbqnkeyboard.bqn b/users/sterni/acme/mkbqnkeyboard.bqn deleted file mode 100755 index 8adc4a388..000000000 --- a/users/sterni/acme/mkbqnkeyboard.bqn +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env BQN -# SPDX-FileCopyrightText: Copyright © 2024-2025 by sterni -# SPDX-License-Identifier: MIT -# -# Generate Compose Sequences for /lib/keyboard that enable entering BQN specific -# Unicode characters using their familiar key combinations in Plan 9 programs. - -# TODO(sterni): move these helper functions somewhere reusable -LogBase ← ÷˜○•math.Log10 -Digs ← (⌊ 1⊸+)∘LogBase -DivMod ← ⌊∘÷˜⋈| -hd←"0123456789ABCDEF" -ToHex ← {hd⊏˜(16⊸DivMod⟜⊑ ∾ 1⊸↓)⍟(-⟜1 𝕨⊸⌈⟜(16⊸Digs)) 𝕩} # 𝕨 is the min amount of digits -FromHex ← {+´(16⋆⌽↕≠𝕩)×hd⊐𝕩} -IsAscii ← 127⊸≥-⟜@ - -# Parse CLI -opts ← { - flags‿args ← 2↑'-' ((≠⟜⊑)¨⊔⊢) 𝕩 - ⟨sort,help,inPlace⟩ ⇐ "shi"∊∾1⊸↓¨flags - - argCount ← 2 - {𝕤 - •Out "Usage: "∾•name∾" [-s] [-i] /path/to/inputrc /path/to/lib/keyboard - - -i Modify lib/keyboard in place. If not given, print to stdout. - -s Sort output by Unicode Codepoint." - •Exit ¬help - }⍟(help∨argCount≠≠args) @ - - inputrcPath‿keyboardPath ⇐ •wdpath⊸•file.At¨args - WriteOutput ⇐ inPlace◶⟨•out¨,keyboardPath⊸•fLines⟩ -} •args - -# Main Program - -# Read inputrc, dropping comment and empty lines. Also drop the rule for \\. -# Since Plan9 requires an explicit keypress before entering a compose sequence, -# we don't need to add a way to type \ (or any ASCII character for that matter). -# This simplifies the parser below since we don't need to unescape anything. -inputrc←1↓(("#"⊸≢⟜(1⊸↑)∧0⊸≠∘≠)¨/⊢)•FLines opts.inputrcPath -# After removing all backslashes, the ASCII character used representing the used -# key and the resulting codepoint have a consistent position in the lines. -# Remove all ASCII chars in a second step. -# map contains pairs of ⟨BQN char, key used to type it as an ASCII char⟩ -map←(¬∘IsAscii∘⊑¨/⊢)5‿1⊸⊏¨'\'(≠/⊢)¨inputrc - -# Render the first three fields of lib/keyboard: -# ⟨Codepoint (Hex), Compose Sequence, Resulting Character⟩ -newfields←{𝕊 c‿k: ⟨4 ToHex c-@,"\"∾k,c⟩}¨map -# In the file, the fields need be padded to a specific length… -fieldsz←6‿12‿0⌈⌈´˘⍉≠¨>newfields -# … and there's a fourth name field separated by a tab. -# We don't make an effort to add a per character description there (yet). -tab←@+9 -newlines←((tab∾"BQN char") ∾´fieldsz⊸(↑¨))¨ newfields - -# Due to the consistent spacing we can just compute the sort order on the -# resulting character at index 18. -Sort ← (⍋ 18⊸⊑¨)⊏⊢ - -# Deduplicate output before writing, so the script can be executed multiple -# times or after inputrc has been changed without introducing duplicates. Since -# we duplicate on entire lines, existing alternative compose sequences aren't -# removed. -opts.WriteOutput ⍷ Sort⍟opts.sort (•FLines opts.keyboardPath)∾newlines diff --git a/users/sterni/acme/mkbqnkeyboard.md b/users/sterni/acme/mkbqnkeyboard.md deleted file mode 100644 index 744004aab..000000000 --- a/users/sterni/acme/mkbqnkeyboard.md +++ /dev/null @@ -1,60 +0,0 @@ -# mkbqnkeyboard.bqn - -[mkbqnkeyboard.bqn][] is a script that updates a given Plan 9 `/lib/keyboard` -file to support the familiar [BQN keymap][] via compose sequences. Since -it uses the GNU Readline [inputrc distributed with BQN][inputrc] as a database -for the keymap, you can use a [remapped][] version of the layout. -Once applied, you'll be able to type the Unicode characters used by BQN -via Compose followed by \\ and the -mapped ASCII character. For details on the file and what button -is used for Compose, refer to -[keyboard(6)][p9f-keyboard] (see also -[plan9port's keyboard(7)][p9p-keyboard], [9front's keyboard(6)][9front-keyboard] etc.). - -TIP: [mkbqnkeyboard.bqn][] has only been tested with [plan9port][], -so the instructions below may not work with every Plan 9 variant. -If you have any any information on/trouble with getting it to work on -a proper Plan 9 (fork), feel free to [let me know][me] or -[send a patch][submitting-patches]. - -The process for updating `/lib/keyboard` with [mkbqnkeyboard.bqn][] is a follows: - -1. Prerequisites: - - - [CBQN][] (other BQN implementations are untested) - - A local checkout of [mlochbaum/BQN][], - `aecb56a323aa` is the latest tested revision. - -2. Run - - ./mkbqnkeyboard.bqn -i /path/to/mlochbaum/BQN/editors/inputrc /path/to/lib/keyboard - - If you omit `-i`, the modified `keyboard` file will be printed to stdout instead - of written to the file. If you add `-s`, the result will be sorted by (resulting) codepoint. - -3. If you're using **plan9port**, you'll need to - - 1. Apply [latin1-increase-compose-capacity.patch][] since the default compose - sequence lookup table is too small to hold all the mappings BQN adds. - 2. Recompile plan9port. - - Other Plan 9 variants may also require extra steps. - -4. The compose sequences should now work in the [acme][] and [sam][] text editors - as well as all other Plan 9 programs. - -[acme]: https://9p.io/sys/doc/acme/acme.pdf -[sam]: https://9p.io/sys/doc/sam/sam.pdf -[BQN keymap]: https://mlochbaum.github.io/BQN/keymap.html -[me]: https://grep.tvl.fyi/search/?q=%20path%3Aops%2Fusers%2Fdefault.nix%20name%20%3D%20%22sterni%22%3B&fold_case=auto®ex=false&context=true -[mkbqnkeyboard.bqn]: ./mkbqnkeyboard.bqn -[inputrc]: https://github.com/mlochbaum/BQN/blob/master/editors/inputrc -[remapped]: https://mlochbaum.github.io/BQN/editors/index.html#alternate-layouts -[p9f-keyboard]: https://p9f.org/magic/man2html/6/keyboard -[p9p-keyboard]: https://9fans.github.io/plan9port/man/man7/keyboard.html -[9front-keyboard]: http://man.9front.org/6/keyboard -[plan9port]: https://9fans.github.io/plan9port/ -[submitting-patches]: https://code.tvl.fyi/about/docs/REVIEWS.md -[mlochbaum/BQN]: https://github.com/mlochbaum/BQN -[CBQN]: https://github.com/dzaima/cbqn -[latin1-increase-compose-capacity.patch]: ./plan9port/latin1-increase-compose-capacity.patch diff --git a/users/sterni/acme/plan9port/default.nix b/users/sterni/acme/plan9port/default.nix deleted file mode 100644 index 2a26e7003..000000000 --- a/users/sterni/acme/plan9port/default.nix +++ /dev/null @@ -1,75 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - patchesFromDir = dir: - lib.filter - (lib.hasSuffix ".patch") - (lib.mapAttrsToList - (name: _: dir + "/${name}") - (builtins.readDir dir)); - - mkbqnkeyboard' = pkgs.writeShellScript "mkbqnkeyboard'" '' - exec ${pkgs.cbqn}/bin/BQN ${../mkbqnkeyboard.bqn} -si \ - "${pkgs.srcOnly pkgs.mbqn}/editors/inputrc" "$1" - ''; - - inherit (depot.users.sterni.acme) plan9port; -in - -pkgs.plan9port.overrideAttrs (old: { - patches = old.patches or [ ] ++ patchesFromDir ./.; - postPatch = old.postPatch or "" + '' - ${mkbqnkeyboard'} lib/keyboard - - cp --reflink=auto ${./../plumb}/* plumb/ - mv plumb/sterni.plumbing plumb/initial.plumbing - ''; - - passthru = old.passthru or { } // { - wrapper = - let - PLAN9 = "${plan9port}/plan9"; - globalBins = [ - "9p" - "9pfuse" - ]; - in - pkgs.runCommandNoCC "${old.pname}-wrapper-${old.version}" - { - nativeBuildInputs = [ - pkgs.buildPackages.makeWrapper - ]; - } - '' - mkdir -p "$out/bin" - - ln -s "${plan9port}/bin/9" "$out/bin/" - for cmd in ${lib.escapeShellArgs globalBins}; do - makeWrapper "${PLAN9}/bin/$cmd" "$out/bin/$cmd" \ - --set PLAN9 "${PLAN9}" - done - - ''; - }; - - postInstall = '' - echo '48.3626 10.9026 483\ - (OpenLab Augsburg)' > $out/plan9/sky/here - ''; - - doInstallCheck = true; - installCheckPhase = old.installCheckPhase or "" + '' - export NAMESPACE="$(mktemp -d)" - "$out/bin/9" plumber -f & - pid="$!" - until [[ -e "$NAMESPACE/plumb" ]]; do - sleep 0.1 - done - "$out/bin/9" 9p write plumb/rules < ${./../plumb}/sterni.plumbing - kill "$pid" - ''; - - meta = old.meta or { } // { - ci.targets = [ "wrapper" ]; - }; -}) diff --git a/users/sterni/acme/plan9port/devdraw-ignore-primary-selection.patch b/users/sterni/acme/plan9port/devdraw-ignore-primary-selection.patch deleted file mode 100644 index d50a3af3b..000000000 --- a/users/sterni/acme/plan9port/devdraw-ignore-primary-selection.patch +++ /dev/null @@ -1,83 +0,0 @@ -From b46a68c7327bf1df62d6f836cd5aa53c5b2b96b3 Mon Sep 17 00:00:00 2001 -From: sternenseemann -Date: Sat, 1 Feb 2025 19:33:30 +0100 -Subject: [PATCH] src/cmd/devdraw: ignore primary selection - -By default devdraw updates the primary selection when Snarfing (which is -a little questionable as it's supposed to hold the current selection) -and prefers the primary selection when Pasting. I use xwayland-satellite -which does not support syncing the primary selection between wayland and -X11 which prevents Pasting in plan9port altogether as soon as you've -Snarfed once (as long as the primary selection is empty, everything -works as expected, but Snarfing populates the primary selection neither -devdraw nor xwayland-satellite will ever clear the primary selection). - -This issue in xwayland-satellite is tracked at -. - -In the meantime, I'm working around this issue by just ignoring the -primary selection altogether. I suspect the preference for the primary -selection in devdraw is wrong anyways. The Snarf/Paste operations fit -how the X11 clipboard is supposed to work and is different to the -primary selection. ---- - src/cmd/devdraw/x11-screen.c | 24 +++++++----------------- - 1 file changed, 7 insertions(+), 17 deletions(-) - -diff --git a/src/cmd/devdraw/x11-screen.c b/src/cmd/devdraw/x11-screen.c -index 6b02dd7a..201ff044 100644 ---- a/src/cmd/devdraw/x11-screen.c -+++ b/src/cmd/devdraw/x11-screen.c -@@ -1287,7 +1287,6 @@ _xtoplan9mouse(Xwin *w, XEvent *e, Mouse *m) - - if(_x.putsnarf != _x.assertsnarf){ - _x.assertsnarf = _x.putsnarf; -- XSetSelectionOwner(_x.display, XA_PRIMARY, w->drawable, CurrentTime); - if(_x.clipboard != None) - XSetSelectionOwner(_x.display, _x.clipboard, w->drawable, CurrentTime); - XFlush(_x.display); -@@ -1527,7 +1526,7 @@ rpc_getsnarf(void) - { - uchar *data; - Atom clipboard; -- XWindow xw; -+ XWindow xw = None; - Xwin *w; - - qlock(&clip.lk); -@@ -1539,26 +1538,17 @@ rpc_getsnarf(void) - if(_x.putsnarf != _x.assertsnarf) - goto mine; - -- /* -- * Is there a primary selection (highlighted text in an xterm)? -- */ -- clipboard = XA_PRIMARY; -- xw = XGetSelectionOwner(_x.display, XA_PRIMARY); -- // TODO check more -- if(xw == w->drawable){ -- mine: -- data = (uchar*)strdup(clip.buf); -- goto out; -- } -- - /* - * If not, is there a clipboard selection? - */ -- if(xw == None && _x.clipboard != None){ -+ if(_x.clipboard != None){ - clipboard = _x.clipboard; - xw = XGetSelectionOwner(_x.display, _x.clipboard); -- if(xw == w->drawable) -- goto mine; -+ if(xw == w->drawable) { -+ mine: -+ data = (uchar*)strdup(clip.buf); -+ goto out; -+ } - } - - /* --- -2.47.0 - diff --git a/users/sterni/acme/plan9port/latin1-increase-compose-capacity.patch b/users/sterni/acme/plan9port/latin1-increase-compose-capacity.patch deleted file mode 100644 index 9f407080d..000000000 --- a/users/sterni/acme/plan9port/latin1-increase-compose-capacity.patch +++ /dev/null @@ -1,16 +0,0 @@ -All BQN character compose sequence use the same leading character (\). Since there -are about 80 of them, the standard lookup table size is not enough. - -diff --git a/src/cmd/devdraw/latin1.c b/src/cmd/devdraw/latin1.c -index 87c0be45..c8e79e33 100644 ---- a/src/cmd/devdraw/latin1.c -+++ b/src/cmd/devdraw/latin1.c -@@ -10,7 +10,7 @@ static struct cvlist - { - char *ld; /* must be seen before using this conversion */ - char *si; /* options for last input characters */ -- Rune so[60]; /* the corresponding Rune for each si entry */ -+ Rune so[100]; /* the corresponding Rune for each si entry */ - } latintab[] = { - #include "latin1.h" - 0, 0, { 0 } diff --git a/users/sterni/acme/plan9port/neo-modifier-fix.patch b/users/sterni/acme/plan9port/neo-modifier-fix.patch deleted file mode 100644 index f5e587d53..000000000 --- a/users/sterni/acme/plan9port/neo-modifier-fix.patch +++ /dev/null @@ -1,24 +0,0 @@ -commit 139924014d126578e5a008f1df7a55831e668287 -Author: sternenseemann -Date: Sat Mar 19 15:52:59 2022 +0100 - - cmd/devdraw: Don't use X11 standard interpretation for modifiers - - This patch is based on a similar one [1] for drawterm by Sören Tempel. - - [1]: https://github.com/nmeum/aports/blob/master/8pit/drawterm/modifier-fix.patch - -diff --git a/src/cmd/devdraw/x11-screen.c b/src/cmd/devdraw/x11-screen.c -index 0bbc25d6..511fc093 100644 ---- a/src/cmd/devdraw/x11-screen.c -+++ b/src/cmd/devdraw/x11-screen.c -@@ -408,6 +408,9 @@ runxevent(XEvent *xev) - case KeyPress: - ke = (XKeyEvent*)xev; - XLookupString(ke, NULL, 0, &k, NULL); -+ /* dont use standard interpretation for modifiers */ -+ if(IsModifierKey(k)) -+ k = XLookupKeysym(ke, 0); - c = ke->state; - switch(k) { - case XK_Alt_L: diff --git a/users/sterni/acme/plumb/.skip-tree b/users/sterni/acme/plumb/.skip-tree deleted file mode 100644 index 8b1378917..000000000 --- a/users/sterni/acme/plumb/.skip-tree +++ /dev/null @@ -1 +0,0 @@ - diff --git a/users/sterni/acme/plumb/git b/users/sterni/acme/plumb/git deleted file mode 100644 index f52b567f0..000000000 --- a/users/sterni/acme/plumb/git +++ /dev/null @@ -1,5 +0,0 @@ -# based on https://blog.silvela.org/post/2021-12-11-acme-tricks/ -type is text -data matches '[0-9a-f]*[a-f][0-9a-f]*' -data matches '([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]+)' -plumb start rc -c 'cd '$wdir'; cd `{git rev-parse --show-toplevel} && git show --pretty=fuller '$1' | plumb -i -d edit -a ''action=showdata filename=+git/'$1''' ' diff --git a/users/sterni/acme/plumb/man b/users/sterni/acme/plumb/man deleted file mode 100644 index 7845dc779..000000000 --- a/users/sterni/acme/plumb/man +++ /dev/null @@ -1,4 +0,0 @@ -# Man pages (taken from /plumb/basic), e.g. man(1) -type is text -data matches '([a-zA-Z¡-0-9_\-./]+)\(([1-8])\)' -plumb start rc -c 'man '$2' '$1' >[2=1] | nobs | plumb -i -d edit -a ''action=showdata filename=/man/'$1'('$2')''' diff --git a/users/sterni/acme/plumb/sterni.plumbing b/users/sterni/acme/plumb/sterni.plumbing deleted file mode 100644 index bea27e711..000000000 --- a/users/sterni/acme/plumb/sterni.plumbing +++ /dev/null @@ -1,12 +0,0 @@ -# TODO(sterni): are rules for :linenumber etc. needed or acme default? -# TODO(sterni): file: urls -# TODO(sterni): xdg-open for mail addresses, images, pdfs etc. - -editor = acme -include man - -depot = /home/lukas/src/depot -include tvl - -include git -include urls diff --git a/users/sterni/acme/plumb/tvl b/users/sterni/acme/plumb/tvl deleted file mode 100644 index 994b4129a..000000000 --- a/users/sterni/acme/plumb/tvl +++ /dev/null @@ -1,78 +0,0 @@ -# TODO(sterni): document TVL short links, -# for now see //tools/cheddar, //web/atward, //tools/magrathea -# and //ops/modules/monorepo-gerrit. - -# TVL short links that go to the browser, e.g. cl/8413, b/187 - -type is text -data matches 'cl/([0-9]+)' -data set https://cl.tvl.fyi/c/depot/+/$1 -plumb to web -plumb start web $data - -type is text -data matches 'b/([0-9]+)' -data set https://b.tvl.fyi/issues/$1 -plumb to web -plumb start web $data - -# TVL revision short links e.g. r/9000, r/3 - -type is text -data matches 'r/([0-9]+)' -data set refs/r/$1 -plumb start rc -c 'cd '$wdir'; cd `{git rev-parse --show-toplevel} && git show --pretty=fuller '$data' | plumb -i -d edit -a ''action=showdata filename=+git/'$data''' ' - -# TVL target short links - -# TODO(sterni): implement subtargets -# TODO(sterni): can we add an acme address to target paths somehow? - -# TODO(sterni): look at //tools/magrathea's parsing. -# TODO(sterni): only be strict at the boundary -depotpathchar = '[^:.,;!?"''`|~(){}\[\]<> ]' -depotpath = '//('$depotpathchar'+)' - -# TVL short links to files in depot, open in local editor, e.g. -# -# - //users/sterni/acme/plumb/tvl, -# - //default.nix, -# - //nix/readTree/README.md, -# - //tools/magrathea/mg.scm -# -# We impose the same restrictions for the initial path, -# but are liberal in the file name - -type is text -data matches '//('$depotchar'+/)?([^ ]*'$depotpathchar')' -arg isfile $depot/$1$2 -data set $file -plumb to edit -plumb client $editor - -# TVL short links to directories in depot, mapped to default.nix, e.g. //nix/readTree - -type is text -data matches $depotpath -arg isfile $depot/$1/default.nix -data set $file -plumb to edit -plumb client $editor - -# TVL short links to targets that aren't expressed by default.nix, e.g. //third_party/lisp/alexandria - -type is text -data matches $depotpath -arg isfile $depot/$1.nix -data set $file -plumb to edit -plumb client $editor - -# TVL short links to directories in depot (without default.nix), e.g. //ops/machines - -type is text -data matches $depotpath -arg isdir $depot/$1 -data set $dir -plumb to edit -plumb client $editor diff --git a/users/sterni/acme/plumb/urls b/users/sterni/acme/plumb/urls deleted file mode 100644 index 087743bcb..000000000 --- a/users/sterni/acme/plumb/urls +++ /dev/null @@ -1,7 +0,0 @@ -# URLs, e.g. https://tvl.fyi -# Based on /plumb/basic, but with most protocols removed -# TODO(sterni): add default case to xdg-open -type is text -data matches '(https?)://[a-zA-Z0-9_@\-]+([.:][a-zA-Z0-9_@\-]+)*/?[a-zA-Z0-9_?,%#~&/\-+=]+([:.][a-zA-Z0-9_?,%#~&/\-+=]+)*' -plumb to web -plumb start web $0 diff --git a/users/sterni/blipqn/.gitignore b/users/sterni/blipqn/.gitignore deleted file mode 100644 index cc7836862..000000000 --- a/users/sterni/blipqn/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.so -*.o diff --git a/users/sterni/blipqn/GNUmakefile b/users/sterni/blipqn/GNUmakefile deleted file mode 100644 index 273a69e8f..000000000 --- a/users/sterni/blipqn/GNUmakefile +++ /dev/null @@ -1,24 +0,0 @@ -DESTDIR ?= -PREFIX ?= /usr -LIBDIR ?= $(DESTDIR)$(PREFIX)/lib -BINDIR ?= $(DESTDIR)$(PREFIX)/bin - -CFLAGS ?= -Os -CFLAGS += -Wall -Wextra -LIBNAME = libflipdot.so - -$(LIBNAME): flipdot.o - $(CC) -shared -o $@ $^ - -.PHONY: clean fmt install -clean: - rm -f *.o - rm -f $(LIBNAME) - -fmt: - clang-format -style=google -i *.c - -install: $(LIBNAME) - install -Dm755 $(LIBNAME) -t $(LIBDIR) - install -Dm644 blipqn.bqn -t $(LIBDIR) - install -Dm755 examples.bqn $(BINDIR)/blipqn-examples diff --git a/users/sterni/blipqn/blipqn.bqn b/users/sterni/blipqn/blipqn.bqn deleted file mode 100644 index f78332fbd..000000000 --- a/users/sterni/blipqn/blipqn.bqn +++ /dev/null @@ -1,43 +0,0 @@ -WithFlipdot⇐ - -t ← { - bool ⇐ "i8" - # needs bound checking in wrapper (no c7 in CBQN) and zero byte appended - charp ⇐ "*i8:c8" - # assume size_t is at least 32bit - size ⇐ "u32" - # used for struct flipdot * - hdl ⇐ "*" -} - -ffi_flipdot_open ← "libflipdot.so" •FFI t.hdl‿"flipdot_open"‿t.charp‿"u16" -ffi_flipdot_close ← "libflipdot.so" •FFI ""‿"flipdot_close"‿t.hdl -ffi_flipdot_send ← "libflipdot.so" •FFI t.bool‿"flipdot_send"‿t.hdl‿"*u8"‿t.size - -Compact ← +´∘(⌽ × 2⊸⋆∘↕∘≠)˘∘(∘‿8⊸⥊) - -MakeFlipdot ← { - host‿port‿w‿h: - "Hostname must be ASCII" ! ∧´(@+127)≥host - "Total pixel count must be divisible by 8" ! 0=8|w×h - - hdl ← FFI_flipdot_open (host∾@)‿port - Close ⇐ {𝕤 ⋄ FFI_flipdot_close ⋈hdl} - - shape ⇐ h‿w - empty ⇐ shape⥊0 - Send ⇐ {FFI_flipdot_send hdl∾(⊢⋈≠) Compact 𝕩} -} - -# Inspired by Go's defer. Will execute 𝔽 after 𝔾 (passing 𝕨 and 𝕩 to each) -# even if an error occurs. If an error occurred, _defer_ will cause an -# assertion failure with the error message after executing 𝔾. This looses -# the original error location, though. -_defer_ ← { - # can't use •CurrentError if 𝕩 is namespace: https://github.com/dzaima/cbqn/commit/d6609df82 - # to avoid this problem, always wrap 𝕩 in a list and unwrap it before calling 𝔾 - s‿r ← (1⊸⋈∘𝔾∘⊑)⎊(0⊸⋈∘•CurrentError) ⋈𝕩 ⋄ 𝔽 𝕩 ⋄ r⊣r!s; - (𝕨⊸𝔽) _𝕣_ (𝕨⊸𝔾) 𝕩 -} - -WithFlipdot ← {{𝕩.Close @} _defer_ 𝕏 MakeFlipdot 𝕨} diff --git a/users/sterni/blipqn/default.nix b/users/sterni/blipqn/default.nix deleted file mode 100644 index d1024a3eb..000000000 --- a/users/sterni/blipqn/default.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ pkgs, lib, ... }: - -let - inherit (pkgs) llvmPackages; - drv = llvmPackages.stdenv.mkDerivation { - name = "blipqn"; - - src = lib.cleanSource ./.; - - makeFlags = [ "PREFIX=$(out)" ]; - - nativeBuildInputs = [ - llvmPackages.clang-tools - ]; - - buildInputs = [ - pkgs.cbqn - ]; - - doCheck = true; - checkInputs = [ - pkgs.netcat-openbsd - ]; - checkPhase = '' - runHook preCheck - nc -lu 2323 > raw & - BQN ./examples.bqn localhost 2323 32 10 235 - sleep .5 - kill %1 - base64 raw > received - diff -u received - <⟨ -"random"‿{𝕩.Send 𝕩.shape •rand.Range 2}, -"235"‿{𝕩.Send 1˙⌾(4‿22⊸⊑) 𝕩.empty}, -⟩ - -usage ← "Usage: "∾•name∾" HOST PORT WIDTH HEIGHT EXAMPLE"∾" - - where EXAMPLE is one of - -"∾∾{(7↑"")∾"- "∾𝕩∾@+10}¨⊏examples - -# TODO(sterni): this is an atrocious interface -opts ← { - (•Exit 1˙∘•Out)⍟(5⊸≠≠•args) usage - host‿port‿width‿height‿example ← •args - - example ⇐ - cfg ⇐ ⟨host⟩∾•ParseFloat¨ port‿width‿height -} - -action ← examples (⊏⊸(⊑∘⊐) ⊑ ⊏˜⟜1)⟜< opts.example - -opts.cfg WithFlipdot action diff --git a/users/sterni/blipqn/flipdot.c b/users/sterni/blipqn/flipdot.c deleted file mode 100644 index 8a913115a..000000000 --- a/users/sterni/blipqn/flipdot.c +++ /dev/null @@ -1,89 +0,0 @@ -#define _DEFAULT_SOURCE // see getnameinfo(3), for NI_MAX* -#define _POSIX_C_SOURCE 200112L // see getaddrinfo(3) -#include -#include -#include -#include -#include -#include -#include -#ifndef FLIPDOT_DEBUG -#define FLIPDOT_DEBUG 0 -#endif - -int resolve_addr(char *host, char *port, struct addrinfo **addrs) { - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - - hints.ai_socktype = SOCK_DGRAM; - hints.ai_family = AF_UNSPEC; - hints.ai_flags |= AI_NUMERICSERV; - - return getaddrinfo(host, port, &hints, addrs); -} - -struct flipdot { - int sockfd; - struct addrinfo *addrs; -}; - -// Assumes all pointers in struct flipdot are not NULL which should be the case -// for any struct returned by flipdot_open(). -void flipdot_close(struct flipdot *flipdot) { - if (FLIPDOT_DEBUG) fprintf(stderr, "flipdot_close() called\n"); - freeaddrinfo(flipdot->addrs); - close(flipdot->sockfd); - free(flipdot); -} - -// Returns NULL if some error occurred. Note that errno isn't necessarily set. -struct flipdot *flipdot_open(char *host, in_port_t port_number) { - char port[NI_MAXSERV]; - struct flipdot *flipdot = malloc(sizeof(struct flipdot)); - if (flipdot == NULL) goto error; - - memset(flipdot, 0, sizeof(struct flipdot)); - flipdot->sockfd = -1; - flipdot->addrs = NULL; - - if (snprintf(port, sizeof(port), "%d", port_number) < 0) goto error; - if (resolve_addr(host, port, &flipdot->addrs) != 0) goto error; - - flipdot->sockfd = socket(flipdot->addrs->ai_family, SOCK_DGRAM, IPPROTO_UDP); - if (flipdot->sockfd < 0) goto error; - - if (FLIPDOT_DEBUG) { - char resolved_ip[NI_MAXHOST], resolved_port[NI_MAXSERV]; - if (getnameinfo(flipdot->addrs->ai_addr, flipdot->addrs->ai_addrlen, - resolved_ip, sizeof(resolved_ip), resolved_port, - sizeof(resolved_port), - NI_NUMERICHOST | NI_NUMERICSERV | NI_DGRAM) == 0) - fprintf(stderr, "flipdot_open(): using %s, port %s\n", resolved_ip, - resolved_port); - } - - return flipdot; - -error: - if (flipdot != NULL) { - if (flipdot->sockfd >= 0) close(flipdot->sockfd); - if (flipdot->addrs != NULL) freeaddrinfo(flipdot->addrs); - free(flipdot); - } - - return NULL; -} - -// Send given bytes[len] to the given flipdot, returns 1 if all bytes were sent -// and no locally detectable errors occurred, 0 otherwise. -int8_t flipdot_send(struct flipdot *flipdot, uint8_t *bitmap, - size_t bitmap_len) { - ssize_t sent = sendto(flipdot->sockfd, bitmap, bitmap_len, 0, - flipdot->addrs->ai_addr, flipdot->addrs->ai_addrlen); - - if (FLIPDOT_DEBUG) { - fprintf(stderr, "flipdot_send(): sent %ld bytes\n", sent); - } - - return (sent == (ssize_t)bitmap_len); -} diff --git a/users/sterni/blërg/README.md b/users/sterni/blërg/README.md deleted file mode 100644 index 552543c71..000000000 --- a/users/sterni/blërg/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# blërg - -## dependencies - -- [CBQN][] (other [BQN][] implementations may work, but are untested) -- Marshall Lochbaum's [bqn-libs][] which blërg expects to find at the - location the `BQN_LIBS` environment variable points to. -- [execline][] -- POSIX `printf(1)` (e.g. from GNU coreutils) -- `mail-notes` backend - - //users/sterni/mn2html - - [mblaze(7)][mblaze] -- `git` backend - - [git][] - - [lowdown][] for Markdown support - - [pandoc][] for Org Mode support - -[mblaze]: https://github.com/leahneukirchen/mblaze/ -[execline]: https://skarnet.org/software/execline/ -[BQN]: https://mlochbaum.github.io/BQN/ -[CBQN]: https://github.com/dzaima/cbqn -[bqn-libs]: https://github.com/mlochbaum/bqn-libs/ -[lowdown]: https://kristaps.bsd.lv/lowdown/ -[pandoc]: https://pandoc.org/ -[git]: https://git-scm.com/ diff --git a/users/sterni/blërg/blërg.bqn b/users/sterni/blërg/blërg.bqn deleted file mode 100755 index 7c25647bd..000000000 --- a/users/sterni/blërg/blërg.bqn +++ /dev/null @@ -1,179 +0,0 @@ -#!/usr/bin/env BQN -# SPDX-FileCopyrightText: Copyright © 2024-2025 sterni -# SPDX-License-Identifier: GPL-3.0-only -# -# blërg is a reimplementation of mblog in BQN. BQN is used as a sort of bespoke -# scripting languages so we can rely on external tools for certain tasks (e.g. -# transforming HTML and parsing MIME messages). A list of dependencies is -# maintained in README.md. - -# Utilities - -MkDirP ← •file.CreateDir⍟(¬•file.Exists) - -AsciiDown ← ⊢ - ('A'-'a')⊸×⟜('A'⊸≤∧≤⟜'Z') -Slugify ← '-'⊸⊣⍟(('A'⊸≤ ∧ ≤⟜'z') ¬∘∨ "-_0123456789"⊸(⊑∊˜)⟜<)¨ AsciiDown - -DropPrefix ← {𝕩(≠/⊣)𝕨↑˜≠𝕩} -StripLeft ← (¬ ∧`∘=)/⊢ -StripRight ← ⌽ StripLeft⟜⌽ - -_join ← {(∾⟜(𝕗⊸∾))´𝕩;𝕨∾𝕗∾𝕩} - -nl ← @+10 -SplitChar ← (= (¯1˙⍟⊣)¨ +`∘=)⊔⊢ -Lines ← nl⊸SplitChar - -ReadPosInt ← {(𝕨⊸×+⊣)´ ⌽'0'-˜𝕩} # ty leah2 -ReadPosDec ← 10⊸ReadPosInt - -Chomp ← {⟨nl⟩≡¯1↑𝕩? ¯1↓𝕩; 𝕩} - -Run ← { - 𝕊 𝕩: 1 𝕊 𝕩; - doChomp 𝕊 cmd: - exit‿stdout‿stderr ← •SH cmd - exit∾Chomp⍟doChomp¨ stdout‿stderr -} - -R ← {𝕊 exit‿stdout‿stderr: stderr!0=exit ⋄ stdout}∘Run -LR ← Lines∘R - -# see execline-block(7) -Execline ← ∾ { - # Not a string nor any other list - 𝕩: 0≠•Type𝕩? ⋈•Fmt 𝕩; - # List, but not a string (i.e. block) - 𝕩: 2≠•Type⊑𝕩? ⟨""⟩∾˜∾(' '⊸∾¨ 𝕊)¨𝕩; - # String (i.e. arg) - ⋈𝕩 -}¨ - -GetEnv ← {R "importas"‿"env"‿𝕩‿"printf"‿"%s"‿"$env"} - -RelPath ← •wdpath⊸•file.At -SplitExt ← (∊⌾⌽ (∨`∘∧ + ¯2⊸×∘∧) =⟜'.')⊔⊢ - -# 3p dependencies - -j ← { - # Update README.md if dependency discovery changes - ⟨Parse⟩ ⇐ •Import (GetEnv "BQN_LIBS") •file.At "json.bqn" - - ObjGet ⇐ (⊏⊸(⊑∘⊐) ⊑ ⊏˜⟜1)⟜< - ObjGetPath ⇐ ObjGet˜´⟜⌽ - - _objGetDef ⇐ {𝕨 (⊏⊸(⊑∘⊐) ⊑ (∾⟜(⋈𝕗))∘(⊏˜⟜1)) <𝕩} -} - -# (Apple) Mail Notes Backend - -# TODO(sterni): avoid argv limit by chunking -Hdrs ← {LR "mhdr"‿"-dh"‿(':' _join 𝕨)∾𝕩} -Dates ← {ReadPosDec¨ LR "mhdr"‿"-Dh"‿"Date"∾𝕩} -headerNames ← "X-Uniform-Type-Identifier"‿"X-Universally-Unique-Identifier"‿"Subject" - -MailNotesBackend ← {𝕊 config: - mailDir ← RelPath config j.ObjGet "maildir" - Entries ⇐ {𝕊: - ms ← LR "mlist"‿mailDir - th ← ⟨≠ms,≠headerNames⟩⥊headerNames Hdrs ms - dh ← Dates ms - ah ← (("com.apple.mail-note"⊸≡⊑)˘/⊢) th∾˘dh≍˘ms - {𝕊 ·‿uuid‿title‿time‿path: - title ⇐ ⋄ time ⇐ - id ⇐ Slugify uuid - Render ⇐ {R "execline-cd"‿𝕩‿"mshow"‿"-x"‿path ⋄ R "mn2html"‿path} - }˘ ah - } -} - -# Git Backend - -converters ← ⍉>⟨ - # TODO(sterni): avoid cat - ⟨"html", ⋈"cat"⟩, - ⟨"md", "lowdown"‿"-T"‿"html"‿"--html-no-skiphtml"‿"--html-no-escapehtml"‿"--html-callout-mdn"⟩, - # TODO(sterni): use emacs - ⟨"org", "pandoc"‿"-f"‿"org"‿"-t"‿"html5"⟩, -⟩ - -# TODO(sterni): pipefail -PipelineCmd ← {Execline "pipeline"‿𝕨∾𝕩} - -GitBackend ← {𝕊 config: - repo ← RelPath config j.ObjGet "repository" - path ← ∾⟜'/' '/' StripRight config "." j._ObjGetDef "path" - - # We use zero separated fields when dealing with paths, so quoting is unnecessary - GitCmd ← {"git"‿"-c"‿"core.quotePath=false"‿"-C"‿repo∾𝕩} - rev ← R GitCmd "rev-parse"‿"HEAD" - # Use the author date of the latest commit on the file to establish the date - # of the file. The author date is easier to arbitrarily change and survives - # history rewrites. It could be interesting to ignore commits that touch - # multiple files (especially treewide ones). - PathDate ← {ReadPosDec R GitCmd "log"‿"--date=unix"‿"--pretty=tformat:%ad"‿"-1"‿rev‿"--"‿𝕩} - - Entries ⇐ {𝕤⋄ - blobs ← ∘‿2⥊@ SplitChar R GitCmd "ls-tree"‿"-zr"‿"--format=%(path)%x00%(objectname)"‿rev‿path - {𝕊 p‿b: - extlessp‿ext ← SplitExt p - id ⇐ Slugify path DropPrefix extlessp - # TODO(sterni): extract from file if possible - title ⇐ •file.Name extlessp - time ⇐ PathDate p - Render ⇐ {𝕤 - conv ← converters j.ObjGet ext - R (GitCmd "cat-file"‿"blob"‿b) PipelineCmd conv - } - }˘blobs - } -} - -backends ← ⍉>⟨"mail-notes"‿mailNotesBackend, "git"‿gitBackend⟩ - -# Rendering - -RenderPage ← { -∾" - - - -"‿𝕨‿" - -

    "‿𝕨‿"

    "‿𝕩 -} - -WriteEntry ← {outDir 𝕊 entry: - entryDir ← MkDirP outDir •file.At entry.id - (entryDir •file.At "index.html") •file.Chars entry.title RenderPage entry.Render entryDir - # TODO(sterni): urlencode - "
  • "∾entry.title∾"
  • " -} - -# Main - -configFile‿outDir ← { - # Usage: blërg - ! 2=≠•args - # TODO(sterni): expand ~/ - RelPath¨ •args -} - -config ← { - raw ← j.Parse •FChars configFile - - [bns,bcs] ← raw j.ObjGet "backends" - bcs ↩ bcs ∾˘⟜{2‿1⥊"name"‿𝕩}¨ bns - bts ← j.ObjGet⟜"type"¨ bcs - backends ⇐ bcs {𝕏 𝕨}¨ backends⊸j.ObjGet¨ bts - - title ⇐ raw j.ObjGet "title" -} - -entries ← ((⍒ •ns.Get⟜"time"¨)⊏⊢) ∾{𝕩.Entries @}¨ config.backends -"All entry IDs must be unique"!(≠=≠∘⍷) •ns.Get⟜"id"¨ entries - -MkDirP outDir -entryIndex ← outDir⊸WriteEntry¨ entries -(outDir •file.At "index.html") •file.Chars config.title RenderPage ∾"
      "∾entryIndex∾"
    " diff --git a/users/sterni/blërg/default.nix b/users/sterni/blërg/default.nix deleted file mode 100644 index 0dacf5e15..000000000 --- a/users/sterni/blërg/default.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - # update README.md when changing this - runtimeDependencies = [ - depot.users.sterni.mn2html - pkgs.mblaze - pkgs.execline # execline-cd, importas, pipeline - # coreutils # for printf (assumed to be installed) - pkgs.pandoc - pkgs.lowdown - ]; - - # … and this - buildInputs = [ - pkgs.cbqn - ]; - - BQN_LIBS = depot.third_party.bqn-libs + "/lib"; -in - -pkgs.runCommandNoCC "blerg" -{ - src = builtins.path { - name = "blerg.bqn"; - path = ./. + "/blërg.bqn"; - }; - nativeBuildInputs = [ pkgs.buildPackages.makeWrapper ]; - inherit buildInputs; - passthru.shell = pkgs.mkShell { - name = "blërg-shell"; - packages = runtimeDependencies ++ buildInputs; - inherit BQN_LIBS; - }; -} - '' - install -Dm755 "$src" "$out/bin/blërg" - patchShebangs "$out/bin/blërg" - wrapProgram "$out/bin/blërg" \ - --prefix PATH : "${lib.makeBinPath runtimeDependencies}" \ - --set BQN_LIBS "${BQN_LIBS}" - '' diff --git a/users/sterni/clhs-lookup/README.md b/users/sterni/clhs-lookup/README.md deleted file mode 100644 index 1f42ff43a..000000000 --- a/users/sterni/clhs-lookup/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# clhs-lookup - -Simple cli to lookup symbols' documentation in a local copy of the -Common Lisp HyperSpec. - -## usage - -``` -clhs-lookup [--print] symbol [symbol [...]] - - --print Print documentation paths to stdout instead of - opening them with $BROWSER (defaults to xdg-open). -``` diff --git a/users/sterni/clhs-lookup/clhs-lookup.lisp b/users/sterni/clhs-lookup/clhs-lookup.lisp deleted file mode 100644 index 0e61dd901..000000000 --- a/users/sterni/clhs-lookup/clhs-lookup.lisp +++ /dev/null @@ -1,46 +0,0 @@ -(in-package :clhs-lookup) -(declaim (optimize (safety 3))) - -(defun find-symbols-paths (syms clhs) - "Find pathnames to HyperSpec files describing the listed - symbol names (as strings). Paths are returned in the order - of the symbols given with missing entries removed." - (check-type syms list) - (check-type clhs pathname) - (let* ((data-dir (merge-pathnames "HyperSpec/Data/" clhs)) - (data (merge-pathnames "Map_Sym.txt" data-dir)) - (found (make-hash-table :test #'equal)) - (syms (mapcar #'string-upcase syms))) - (with-open-file (s data :direction :input) - (loop - with missing = syms - for symbol-line = (read-line s nil :eof) - for path-line = (read-line s nil :eof) - until (or (eq symbol-line :eof) - (eq path-line :eof) - (null missing)) - for pos = (position symbol-line missing :test #'equal) - when pos - do (progn - (delete symbol-line missing) - (setf (gethash symbol-line found) path-line))) - ; TODO(sterni): get rid of Data/../ in path - (mapcar - (lambda (x) (merge-pathnames x data-dir)) - (remove nil - (mapcar (lambda (x) (gethash x found)) syms)))))) - -(defun main () - (let* ((browser (or (uiop:getenvp "BROWSER") "xdg-open")) - (args (uiop:command-line-arguments)) - (prin (member "--print" args :test #'equal)) - (syms (remove-if (lambda (x) (eq (char x 0) #\-)) args)) - (paths (find-symbols-paths syms *clhs-path*))) - (if (null paths) - (uiop:quit 1) - (dolist (p paths) - (if prin - (format t "~A~%" p) - (uiop:launch-program - (format nil "~A ~A" browser p) - :force-shell t)))))) diff --git a/users/sterni/clhs-lookup/default.nix b/users/sterni/clhs-lookup/default.nix deleted file mode 100644 index 1cde38e8c..000000000 --- a/users/sterni/clhs-lookup/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ pkgs, depot, ... }: - -let - inherit (pkgs) fetchzip writeText; - inherit (depot.nix) buildLisp; - inherit (builtins) replaceStrings; - - clhsVersion = "7-0"; - - clhs = fetchzip { - name = "HyperSpec-${replaceStrings [ "-" ] [ "." ] clhsVersion}"; - url = "ftp://ftp.lispworks.com/pub/software_tools/reference/HyperSpec-${clhsVersion}.tar.gz"; - sha256 = "1zsi35245m5sfb862ibzy0pzlph48wvlggnqanymhgqkpa1v20ak"; - stripRoot = false; - }; - - clhs-path = writeText "clhs-path.lisp" '' - (in-package :clhs-lookup.clhs-path) - (defparameter *clhs-path* (pathname "${clhs}/")) - ''; - - clhs-lookup = buildLisp.program { - name = "clhs-lookup"; - - deps = [ - { - default = buildLisp.bundled "asdf"; - sbcl = buildLisp.bundled "uiop"; - } - ]; - - srcs = [ - ./packages.lisp - clhs-path - ./clhs-lookup.lisp - ]; - }; -in -clhs-lookup diff --git a/users/sterni/clhs-lookup/packages.lisp b/users/sterni/clhs-lookup/packages.lisp deleted file mode 100644 index d059b96ce..000000000 --- a/users/sterni/clhs-lookup/packages.lisp +++ /dev/null @@ -1,10 +0,0 @@ -(defpackage :clhs-lookup.clhs-path - (:use :cl) - (:export :*clhs-path*)) - -(defpackage clhs-lookup - (:use :cl :uiop) - (:import-from :clhs-lookup.clhs-path :*clhs-path*) - (:export :main - :find-symbols-paths)) - diff --git a/users/sterni/dot-time-man-pages/OWNERS b/users/sterni/dot-time-man-pages/OWNERS deleted file mode 100644 index b9bc074a8..000000000 --- a/users/sterni/dot-time-man-pages/OWNERS +++ /dev/null @@ -1 +0,0 @@ -edef diff --git a/users/sterni/dot-time-man-pages/default.nix b/users/sterni/dot-time-man-pages/default.nix deleted file mode 100644 index 269617420..000000000 --- a/users/sterni/dot-time-man-pages/default.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ depot, lib, ... }: - -let - # TODO(sterni): find a better place for this: is dot time //fun? - - # get the email address of a depot user from //ops/users - findEmail = user: - let - res = builtins.filter ({ username, ... }: username == user) depot.ops.users; - len = builtins.length res; - in - if len == 1 - then (builtins.head res).email - else builtins.throw "findEmail: got ${toString len} results instead of 1"; - - # dot-time(7) man page, ported from dotti.me - dot-time = rec { - name = "dot-time"; - section = 7; - content = '' - .Dd $Mdocdate$ - .Dt ${lib.toUpper name} ${toString section} - .Os - .Sh NAME - .Nm ${name} - .Nd a universal convention for conveying time - .Sh DESCRIPTION - For those of us who travel often or coordinate across many timezones, - working with local time is frequently impractical. - ISO8601, in all its wisdom, allows for time zone designators, - but still represents the hours and minutes as local time, - thus making it inconvenient for quickly comparing timestamps from - different locations. - .Pp - Dot time instead uses UTC for all date, hour, and minute indications, - and while it allows for time zone designators, they are optional - information that can be dropped without changing the indicated time. - It uses an alternate hour separator to make it easy to distinguish from - regular ISO8601. - When a time zone designator is provided, one can easily obtain - the matching local time by adding the UTC offset to the UTC time. - .Sh EXAMPLES - These timestamps all represent the same point in time. - .TS - allbox tab(|); - lb | lb | lb - l | l | l. - dot time|ISO8601|RFC3339 - 2019-06-19T22·13-04|2019-06-19T18:13-04|2019-06-19T18:13:00-04:00 - 2019-06-19T22·13+00|2019-06-19T22:13+00|2019-06-19T22:13:00Z - 2019-06-19T22·13+02|2019-06-20T00:13+02|2019-06-20T00:13:00+02:00 - .TE - .Sh SEE ALSO - .Lk https://dotti.me dotti.me - .Sh AUTHORS - .An -nosplit - .Sy dot time - has been proposed and documented by - .An edef Aq Mt ${findEmail "edef"} - and ported to - .Xr mdoc 7 - by - .An sterni Aq Mt ${findEmail "sterni"} . - ''; - }; - -in -depot.users.sterni.nix.build.manPages "dot-time" { } [ - dot-time -] diff --git a/users/sterni/emacs/default.nix b/users/sterni/emacs/default.nix deleted file mode 100644 index 61ac9da16..000000000 --- a/users/sterni/emacs/default.nix +++ /dev/null @@ -1,109 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - inherit (pkgs.stdenv.hostPlatform) is64bit; - - # Wrap chktex(1) with the flags we want because the chktex flycheck checker - # ignores tex-chktex-extra-flags and has no other way to set flags. I did - # not want to mess around with chktexrc because that seems to involve copying - # around a lot of rules (that would need to be updated?). - # - # Warning 8 is about correct dash length. This is really annoying because it'll - # light up everywhere if you use typographically correct dashes in German text. - chktexLessWarnings = pkgs.writeShellScript "chktex-less-warnings" '' - exec chktex -n8 "$@" - ''; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs-pgtk).withPackages (epkgs: [ - epkgs.bqn-mode - #epkgs.elpaPackages.ada-mode - epkgs.elpaPackages.rainbow-mode - epkgs.elpaPackages.undo-tree - epkgs.elpaPackages.which-key - epkgs.melpaPackages.adoc-mode - epkgs.melpaPackages.cmake-mode - epkgs.melpaPackages.deft - epkgs.melpaPackages.direnv - epkgs.melpaPackages.dockerfile-mode - epkgs.melpaPackages.editorconfig - epkgs.melpaPackages.elfeed - epkgs.melpaPackages.evil - epkgs.melpaPackages.evil-collection - epkgs.melpaPackages.flycheck - epkgs.melpaPackages.haskell-mode - epkgs.melpaPackages.hl-todo - epkgs.melpaPackages.jq-mode - epkgs.melpaPackages.lsp-haskell - epkgs.melpaPackages.lsp-mode - epkgs.melpaPackages.lsp-ui - epkgs.melpaPackages.magit - epkgs.melpaPackages.markdown-mode - epkgs.melpaPackages.meson-mode - epkgs.melpaPackages.nix-mode - epkgs.melpaPackages.org-clock-csv - epkgs.melpaPackages.paredit - epkgs.melpaPackages.rainbow-delimiters - epkgs.melpaPackages.sly - epkgs.melpaPackages.yaml-mode - epkgs.rust-mode - epkgs.tvlPackages.tvl - epkgs.urweb-mode - ] ++ lib.optionals is64bit [ - epkgs.melpaPackages.languagetool - ]); - - configDirectory = pkgs.symlinkJoin { - name = "emacs.d"; - paths = [ - ./. - (pkgs.writeTextFile { - name = "injected-emacs.d"; - destination = "/nix-inject.el"; - text = - # Java doesn't seem to be available for non 64bit platforms in nixpkgs - # CBQN doesn't seem to support i686 at least - lib.optionalString is64bit '' - ;; bqn-mode - (setq bqn-interpreter-path "${pkgs.cbqn}/bin/BQN") - - ;; languagetool - (setq languagetool-java-bin "${pkgs.jre}/bin/java" - languagetool-console-command "${pkgs.languagetool}/share/languagetool-commandline.jar" - languagetool-server-command "${pkgs.languagetool}/share/languagetool-server.jar") - '' + '' - - ;; use bash instead of fish from SHELL for some things, as it plays - ;; nicer with TERM=dumb, as I don't need/want vterm anyways. - ;; We want it to source /etc/profile for some extra setup that - ;; kicks in if TERM=dumb, meaning we can't use dash/sh mode. - (setq shell-file-name "${pkgs.bash}/bin/bash" - explicit-bash-args '("-l")) - - ;; chktex wrapper that disables warnings I don't want - (setq flycheck-tex-chktex-executable "${chktexLessWarnings}") - (setq tex-chktex-program "${chktexLessWarnings}") - - (provide 'nix-inject) - ''; - }) - ]; - postBuild = '' - rm "$out/default.nix" - ''; - }; -in - -# sadly we can't give an init-file via the command line -(pkgs.writeShellScriptBin "emacs" '' - exec ${emacs}/bin/emacs \ - --no-init-file \ - --directory ${configDirectory} \ - --eval "(require 'init)" \ - "$@" -'').overrideAttrs (super: { - buildCommand = '' - ${super.buildCommand} - - ln -s "${emacs}/bin/emacsclient" "$out/bin/emacsclient" - ''; -}) diff --git a/users/sterni/emacs/init.el b/users/sterni/emacs/init.el deleted file mode 100644 index 6e851f33d..000000000 --- a/users/sterni/emacs/init.el +++ /dev/null @@ -1,397 +0,0 @@ -;; set up package infrastructure - -(require 'use-package) -(package-initialize) - -;; By default, Emacs only uses the default font for ASCII and then falls back to -;; fontset-default which uses random fonts (the documentation describes this -;; accurately). Emacs would be better off if it used the fallback order defined -;; by fontconfig instead of implementing its own scheme for this… -;; In any case, I've found that after setting the default font via methods like -;; (add-to-list 'default-frame-alist …), (set-face-attribute 'default …) etc. -;; it is impossible to change the fontset this font becomes part of (for ascii). -;; Specifically, the following snippet from the Emacs manual just does not seem -;; to work (https://www.gnu.org/software/emacs/manual/html_node/emacs/Modifying-Fontsets.html): -;; -;; (set-fontset-font "fontset-startup" nil "DejaVu Sans Mono" -;; nil 'append) -;; -;; This may very well be my ignorace, but I've found that just setting the ascii -;; and unicode charsets of fontset-startup to a generic Monospace-11 (remember -;; if we use set-face-attribute to change the font height, everything breaks!) -;; works fine. -(let ((font "Monospace-11")) - (set-fontset-font "fontset-startup" 'ascii font) - (set-fontset-font "fontset-startup" 'unicode font)) - -(setq inhibit-startup-message t - display-time-24hr-format t - select-enable-clipboard t) - -;; Reload files -(global-auto-revert-mode 1) - -;; Indent -(setq-default indent-tabs-mode nil) -(setq tab-width 2 - css-indent-offset tab-width) - -;; UTF-8 -(setq locale-coding-system 'utf-8) -(set-terminal-coding-system 'utf-8) -(set-keyboard-coding-system 'utf-8) -(set-selection-coding-system 'utf-8) -(prefer-coding-system 'utf-8) - -;; Disable unnecessary GUI elements -(scroll-bar-mode 0) -(menu-bar-mode 0) -(tool-bar-mode 0) - -(add-hook 'after-make-frame-functions - (lambda (frame) (scroll-bar-mode 0))) - -;; don't center on cursor when scrolling -(setq scroll-conservatively 1) - -;; type less -(defalias 'yes-or-no-p 'y-or-n-p) - -;; Extra settings when graphical session -(when window-system - (setq frame-title-format '(buffer-file-name "%f" ("%b"))) - (mouse-wheel-mode t) - (blink-cursor-mode -1)) - -;; /tmp is a tmpfs, but we may want to recover from power loss -(custom-set-variables - `(temporary-file-directory ,(concat (getenv "HOME") "/.emacs/tmp"))) - -(setq auto-save-file-name-transforms - `((".*" ,temporary-file-directory t))) -(setq backup-directory-alist - `((".*" . ,temporary-file-directory))) -(setq undo-tree-history-directory-alist - `((".*" . ,temporary-file-directory))) -(setq backup-by-copying t) -(setq create-lockfiles nil) - -;; save history -(savehist-mode) -(setq savehist-additional-variables '(search-ring regexp-search-ring magit-cl-history)) - -;; buffers - -;; performance migitations -(global-so-long-mode) - -;; unique component should come first for better completion -(setq uniquify-buffer-name-style 'forward) - -;; completions -(ido-mode 1) -(setq ido-enable-flex-matching t) -(ido-everywhere) -(fido-mode) - -;; Display column numbers -(column-number-mode t) -(setq-default fill-column 80) -(setq display-fill-column-indicator-column t) -(add-hook 'prog-mode-hook #'display-fill-column-indicator-mode) - -;; whitespace -(setq whitespace-style '(face trailing tabs) - whitespace-line-column fill-column) -(add-hook 'prog-mode-hook #'whitespace-mode) -(setq-default indicate-empty-lines t) -(setq-default indicate-buffer-boundaries 'left) -(setq sentence-end-double-space nil) - -;; search - -;; TODO(sterni): can we use ripgrep for xref? -(defun sterni-find-regexp (regexp) - "Find all matches for REGEXP in a specified directory. -Like \\[project-find-regexp], but always ask for a directory (defaulting to -`default-directory') and never prompt for a file glob pattern." - (interactive (list (project--read-regexp))) - (require 'xref) - (let* ((dir (read-directory-name "Base directory: " - default-directory nil t)) - (files (project--files-in-directory dir nil))) - (xref-show-xrefs - (apply-partially #'project--find-regexp-in-files regexp files) - nil))) - -;;; Configure built in modes - -;; Perl -(setq perl-indent-level 2) -(setq perl-continued-statement-offset 0) -(setq perl-continued-brace-offset 0) - -;; org mode - -(setq org-clock-persist 'history) -(org-clock-persistence-insinuate) - -(let* ((org-folder (concat (getenv "HOME") "/files/sync/org")) - (org-archive-file (concat org-folder "/archive.org"))) - (setq org-archive-location (concat org-archive-file "::") - org-agenda-files (remove org-archive-file - (directory-files-recursively org-folder "\\.org$")) - org-default-notes-file (concat org-folder "/inbox.org") - initial-buffer-choice (concat org-folder "/context.org") - org-refile-targets '((org-agenda-files . (:maxlevel . 4))))) - -;; latex - -(defun latex-word-count () - "Calls texcount on the file the current buffer points to and displays the result." - (interactive) - (save-buffer) - (let* ((file (buffer-file-name)) ; needs to happen outside with-current-buffer - (word-count - (with-output-to-string - (with-current-buffer standard-output - (call-process "texcount" nil t nil "-brief" "-utf8" file))))) - (message (string-trim-right word-count)))) - -;; ediff -;; doesn't create new window for ediff controls which I always open accidentally -(setq ediff-window-setup-function 'ediff-setup-windows-plain) - -;; man -(setq Man-notify-method 'pushy) ; display man page in current window - -;; shell - -; default, but allows ';' as prompt -(setq shell-prompt-pattern "^[^#$%>;\n]*[#$%>;] *") - -;; projects (see also evil config) - -(defun project-magit () - "Run magit in the current project dir" - (interactive) - (magit (project-root (project-current t)))) - -(define-key project-prefix-map (kbd "G") 'project-magit) - -(setq project-switch-commands - '((project-find-file "Find file") - (project-find-regexp "Find regexp") - (project-dired "Dired") - (project-shell "Shell") - (project-magit "Magit"))) - -;;; Configure packages -(use-package undo-tree - :config - (global-undo-tree-mode) - (setq undo-tree-auto-save-history t)) - -(use-package magit - :after evil - :config - ; reset (buffer-local) fill-column value to emacs' default - ; gerrit doesn't like 80 column commit messages… - (add-hook 'git-commit-mode-hook (lambda () (setq fill-column 72))) - (evil-define-key 'normal 'global (kbd "gr") 'magit-status)) -(use-package tvl - :after magit - :custom tvl-depot-path (concat (getenv "HOME") "/src/depot")) - -(setq ediff-split-window-function 'split-window-horizontally) - -(use-package evil - :init - (setq evil-want-integration t) - (setq evil-want-keybinding nil) - (setq evil-shift-width 2) - (setq evil-split-window-below t) - (setq evil-split-window-right t) - (setq evil-undo-system 'undo-tree) - :config - (evil-mode 1) - (evil-set-leader 'normal ",") ;; TODO(sterni): space would be nice, but… - (evil-set-leader 'visual ",") - ;; buffer management - (evil-define-key 'normal 'global (kbd "bk") 'kill-buffer) - (evil-define-key 'normal 'global (kbd "bb") 'switch-to-buffer) - (evil-define-key 'normal 'global (kbd "bo") 'switch-to-buffer-other-window) - (evil-define-key 'normal 'global (kbd "bl") 'list-buffers) - (evil-define-key 'normal 'global (kbd "br") 'revert-buffer) - ;; window management: C-w hjkl is annoying in neo - (define-key evil-window-map (kbd "") 'evil-window-left) - (define-key evil-window-map (kbd "") 'evil-window-right) - (define-key evil-window-map (kbd "") 'evil-window-up) - (define-key evil-window-map (kbd "") 'evil-window-down) - ;; projects - (evil-define-key 'normal 'global (kbd "pf") 'project-find-file) - (evil-define-key 'normal 'global (kbd "pg") 'project-find-regexp) - (evil-define-key 'normal 'global (kbd "pd") 'project-dired) - (evil-define-key 'normal 'global (kbd "ps") 'project-shell) - (evil-define-key 'normal 'global (kbd "pR") 'project-query-replace-regexp) - (evil-define-key 'normal 'global (kbd "pK") 'project-kill-buffers) - (evil-define-key 'normal 'global (kbd "pp") 'project-switch-project) - ;; emacs - (evil-define-key 'visual 'global (kbd "ee") 'eval-region) - (evil-define-key 'normal 'global (kbd "ee") 'eval-last-sexp) - (evil-define-key 'normal 'global (kbd "ep") 'eval-print-last-sexp) - (evil-define-key 'normal 'global (kbd "eh") 'help) - (evil-define-key 'normal 'global (kbd "em") 'man) - (evil-define-key '(normal visual) 'global (kbd "eu") 'browse-url-at-point) - (evil-define-key '(normal visual) 'global (kbd "ef") 'ffap) - (evil-define-key 'normal 'global (kbd "eo") 'occur) - (evil-define-key 'normal 'global (kbd "eg") 'sterni-find-regexp) - (evil-define-key 'normal 'global (kbd "er") 'rename-visited-file) - ;; modify what is displayed - (evil-define-key 'normal 'global (kbd "dw") - (lambda () - (interactive) - (whitespace-mode 'toggle) - (display-fill-column-indicator-mode 'toggle))) - ;; org-mode - (evil-define-key 'normal 'global (kbd "oa") 'org-agenda) - (evil-define-key 'normal 'global (kbd "oc") 'org-capture) - (evil-define-key 'normal 'org-mode-map (kbd "or") 'org-refile) - (evil-define-key 'normal 'org-mode-map (kbd "oAA") 'org-archive-subtree) - (evil-define-key 'normal 'org-mode-map (kbd "oAT") 'org-toggle-archive-tag)) - -(use-package evil-collection - :after evil - :config - (evil-collection-init)) - -;; parens -(use-package rainbow-delimiters - :hook ((prog-mode . rainbow-delimiters-mode))) - -(setq show-paren-delay 0) -(show-paren-mode) - -(use-package paredit - :hook ((emacs-lisp-mode . paredit-mode) - (lisp-mode . paredit-mode) - (ielm-mode . paredit-mode) - (lisp-interaction-mode . paredit-mode))) - -(use-package which-key :config (which-key-mode t)) - -(use-package nix-mode :mode "\\.nix\\'") -(use-package nix-drv-mode :mode "\\.drv\\'") - -(use-package direnv - :config (direnv-mode)) - -(use-package editorconfig - :config (editorconfig-mode 1)) - -(use-package haskell-mode) -(use-package flycheck - :init (global-flycheck-mode) - :custom flycheck-keymap-prefix (kbd "!")) -(use-package lsp-mode - :hook ((haskell-mode . lsp-deferred)) - :commands (lsp lsp-deferred) - :custom - lsp-modeline-code-actions-segments '() ; using lsp-ui-sideline instead - :config - (evil-define-key 'normal 'global - (kbd "lwr") 'lsp-workspace-restart - (kbd "lwq") 'lsp-workspace-shutdown - (kbd "la=") 'lsp-format-buffer - (kbd "lar") 'lsp-rename - (kbd "laa") 'lsp-execute-code-action)) -(use-package lsp-ui - :after lsp-mode - :custom - lsp-ui-doc-enable t - lsp-ui-doc-border "DimGray" - lsp-ui-doc-delay 0.5 - :config - (set-face-background 'lsp-ui-doc-background "WhiteSmoke") - (set-face-foreground 'lsp-ui-sideline-code-action "SaddleBrown") - (setq lsp-ui-sideline-code-actions-prefix "🔨 " - lsp-ui-sideline-show-diagnostics nil - lsp-ui-sideline-show-code-actions t) ; is :custom, but won't take effect? - (evil-define-key 'normal lsp-ui-mode-map - ;; TODO(sterni): emulate using xref for non-lsp? - (kbd "lgr") 'lsp-ui-peek-find-references - (kbd "lgd") 'lsp-ui-peek-find-definitions - (kbd "lc") 'lsp-ui-flycheck-list)) -(use-package lsp-haskell - :after lsp-mode - :custom - lsp-haskell-formatting-provider "ormolu") - -(use-package urweb-mode) -(use-package bqn-mode - :mode "\\.bqn\\'" - :custom bqn-mode-map-prefix "C-s-") ; probably rather using C-\ -(use-package yaml-mode) -(use-package dockerfile-mode) -(use-package jq-mode - :config (add-to-list 'auto-mode-alist '("\\.jq\\'" . jq-mode))) -(use-package rust-mode) -(use-package sly - :after evil - :hook ((sly-mrepl-mode . (lambda () - (enable-paredit-mode) - (rainbow-delimiters-mode-enable)))) - :config - (evil-define-key '(normal insert) sly-mrepl-mode-map (kbd "C-r") 'isearch-backward)) - -; TODO(sterni): https://github.com/NixOS/nixpkgs/pull/173893/files -; (use-package ada-mode) - -(use-package rainbow-mode) -(use-package hl-todo - :hook ((prog-mode . hl-todo-mode)) - :config - (setq hl-todo-keyword-faces - '(("TODO" . "#FF0000") - ("FIXME" . "#FF0000") - ("HACK" . "#7f7f7f") - ("XXX" . "#aa0000")))) - -(use-package markdown-mode - :commands (markdown-mode gfm-mode) - :mode (("\\.md\\'" . markdown-mode))) -(use-package adoc-mode - :mode (("\\.adoc\\'" . adoc-mode))) -(use-package languagetool - :after evil - :custom - languagetool-java-arguments '("-Dfile.encoding=UTF-8") - languagetool-default-language "en-GB" - languagetool-mother-tongue "de-DE" - :config - (evil-define-key 'normal 'global (kbd "mll") 'languagetool-check) - (evil-define-key 'normal 'global (kbd "mlc") 'languagetool-correct-at-point) - (evil-define-key 'normal 'global (kbd "mls") 'languagetool-set-language) - (evil-define-key 'normal 'global (kbd "mlr") 'languagetool-clear-suggestions) - ;; Fill background of issues instead of just underlining to make it easier to read - (set-face-background 'languagetool-issue-default "yellow") - (set-face-background 'languagetool-issue-misspelling "red")) - -(use-package deft - :config - ;; This is based on (car deft-extensions), but unfortunately the variable is - ;; not re-bound in the hook defined by defcustom, so it is always "txt". - (setq deft-default-extension "org") - (setq deft-recursive t) - (evil-define-key 'normal 'global (kbd "mn") 'deft) - :custom - deft-directory (expand-file-name "~/files/sync/org") - deft-extensions '("org" "md" "txt" "tex")) - -(unless (server-running-p) - (server-start)) - -(require 'subscriptions) ; elfeed config -(require 'nix-inject) - -(provide 'init) diff --git a/users/sterni/emacs/subscriptions.el b/users/sterni/emacs/subscriptions.el deleted file mode 100644 index 12199e683..000000000 --- a/users/sterni/emacs/subscriptions.el +++ /dev/null @@ -1,66 +0,0 @@ -;;; elfeed -(use-package elfeed - :after evil - :config - ;; elfeed bindings for evil - (evil-define-key 'normal 'global (kbd "mf") 'elfeed) - (evil-define-key '(normal visual) elfeed-search-mode-map - (kbd "o") 'elfeed-search-browse-url - (kbd "r") 'elfeed-search-untag-all-unread - (kbd "u") 'elfeed-search-tag-all-unread - (kbd "ff") 'elfeed-search-fetch - (kbd "fc") 'elfeed-db-compact) - ;; elfeed subscriptions - (setq elfeed-feeds - (append - ;; immutable subscriptions tracked in git - '(("https://repology.org/maintainer/sternenseemann%40systemli.org/feed-for-repo/nix_unstable/atom" releases) - ("https://www.stackage.org/feed" releases) - ("https://text.causal.agency/feed.atom" blog) - ("http://xsteadfastx.org/feed/" blog) - ("https://tvl.fyi/feed.atom" blog) - ("https://hannes.robur.coop/atom" blog) - ("https://stevelosh.com/rss.xml" blog) - ("https://blog.benjojo.co.uk/rss.xml" blog) - ("https://leahneukirchen.org/blog/index.atom" blog) - ("https://leahneukirchen.org/trivium/index.atom" blog links) - ("https://firefly.nu/feeds/all.atom.xml" blog) - ("https://tazj.in/feed.atom" blog) - ("https://alyssa.is/feed.xml" blog) - ("https://eta.st/feed.xml" blog) - ("https://spectrum-os.org/git/www/atom/bibliography.html" links blog) - ("https://vulns.xyz/feed.xml" blog) - ("https://www.german-foreign-policy.com/?type=9818" news) - ("https://compilercrim.es/rss.xml" blog) - ("http://blog.nullspace.io/feed.xml" blog) - ("https://blog.kingcons.io/rss.xml" blog) - ("https://www.imperialviolet.org/iv-rss.xml" blog) - ("http://shitopenlabsays.tumblr.com/rss" openlab) - ("https://kristaps.bsd.lv/lowdown/atom.xml" releases) - ("http://0pointer.net/blog/index.atom" blog) - ("https://emacsninja.com/feed.atom" blog) - ("https://emacshorrors.com/feed.atom" blog) - ("http://therealmntmn.tumblr.com/rss" blog) - ("http://blog.duangle.com/feeds/posts/default" blog) - ("http://ccc.de/de/rss/updates.xml" news) - ("http://ffaaaffaffaffaa.tumblr.com/rss" pictures) - ("http://fotografiona.tumblr.com/rss" pictures) - ("http://guteaussicht.org/rss" pictures) - ("http://konvergenzfehler.de/feed/" blog) - ("https://markuscisler.com/feed.xml" blog) - ("http://www.whvrt.de/rss" pictures) - ("https://barnslig.eu/feed/" blog) - ("https://mgsloan.com/feed.xml" blog) - ("http://beza1e1.tuxen.de/blog_en.atom" blog) - ("https://anchor.fm/s/94bb000/podcast/rss" podcast)) - ;; http://www.wollenzin.de/feed/ ;_; - - ;; add more feeds from an untracked file in $HOME - (let ((file (concat (getenv "HOME") - "/.config/emacs-custom/mutable-subscriptions.el"))) - (when (file-exists-p file) - (read (with-temp-buffer - (insert-file-contents file) - (buffer-string)))))))) - -(provide 'subscriptions) diff --git a/users/sterni/exercises/aoc/.gitignore b/users/sterni/exercises/aoc/.gitignore deleted file mode 100644 index b9720d745..000000000 --- a/users/sterni/exercises/aoc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/*/input -/*/*/input \ No newline at end of file diff --git a/users/sterni/exercises/aoc/2021/default.nix b/users/sterni/exercises/aoc/2021/default.nix deleted file mode 100644 index d3ed563ec..000000000 --- a/users/sterni/exercises/aoc/2021/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ depot ? import ../../../../.. { } -, pkgs ? depot.third_party.nixpkgs -, ... -}: - -pkgs.mkShell { - nativeBuildInputs = [ - pkgs.cbqn - ]; -} diff --git a/users/sterni/exercises/aoc/2021/solutions.bqn b/users/sterni/exercises/aoc/2021/solutions.bqn deleted file mode 100755 index 755c94404..000000000 --- a/users/sterni/exercises/aoc/2021/solutions.bqn +++ /dev/null @@ -1,484 +0,0 @@ -#!/usr/bin/env BQN - -⟨Xor⟩ ← •Import "../lib.bqn" - -# -# Utilities -# - -⟨IsAsciiNum,ReadInt,ReadDec,SplitOn,_fix⟩ ← •Import •path∾"/../lib.bqn" - -ReadInput ← {•file.Lines ∾ •path‿"/input/day"‿(•Fmt 𝕩)} - -# -# 2021-12-01 -# - -# part 1 - -day1ExampleInput ← 199‿200‿208‿210‿200‿207‿240‿269‿260‿263 -day1Input ← ReadDec¨ReadInput 1 - -# NB: Because distance from the ground is never smaller than zero, it's -# no problem that nudge inserts a zero at the end of the right list -PositiveDeltaCount ← +´∘(⊢<«)+˝˘∘↕ - -! 7 = 1 PositiveDeltaCount day1ExampleInput - -•Out "Day 1.1: "∾•Fmt 1 PositiveDeltaCount day1Input - -# part 2 - -! 5 = 3 PositiveDeltaCount day1ExampleInput - -•Out "Day 1.2: "∾•Fmt 3 PositiveDeltaCount day1Input - -# -# 2021-12-02 -# - -# part 1 - -day2ExampleInput ← ⟨ - "forward 5", - "down 5", - "forward 8", - "up 3", - "down 8", - "forward 2", -⟩ - -day2Input ← ReadInput 2 - -ParseSubmarineCommand ← (((↕2)⊸((((-1)⊸⋆)∘(2⊸|))×(=⟜(⌊∘(÷⟜2))))∘("duf"⊸⊐)∘⊑)×ReadDec∘(IsAsciiNum/⊢)) - -SubmarineDestProduct ← {×´+´ParseSubmarineCommand¨𝕩} - -! 150 = SubmarineDestProduct day2ExampleInput - -•Out "Day 2.1: "∾•Fmt SubmarineDestProduct day2Input - -# part 2 - -SubmarineAimedDestProduct ← { - ×´+´((×´)∘(1⊸↓)≍(1⊸⊑))¨ (<0‿0‿0) (⊢∾((⊑∘⌽⊣)+(⊑⊢)))` ParseSubmarineCommand¨𝕩 -} - -! 900 = SubmarineAimedDestProduct day2ExampleInput - -•Out "Day 2.2: "∾•Fmt SubmarineAimedDestProduct day2Input - -# -# 2021-12-03 -# - -BinTable ← '0'-˜> - -day3ExampleInput ← BinTable ⟨ - "00100", - "11110", - "10110", - "10111", - "10101", - "01111", - "00111", - "11100", - "10000", - "11001", - "00010", - "01010", -⟩ - -day3Input ← BinTable ReadInput 3 - -DeBinList ← ((2⊸×)+⊣)´⌽ -_tableAggr ← {((÷⟜2)∘(/⟜⥊)´∘⌽∘≢𝔽(+˝))𝕩} -GammaRate ← < _tableAggr - -! 22 = DeBinList GammaRate day3ExampleInput -! 9 = DeBinList ¬GammaRate day3ExampleInput - -•Out "Day 3.1: "∾•Fmt (¬×○DeBinList⊢) GammaRate day3Input - -_lifeSupportRating ← { - # Need to rename the arguments, otherwise the ternary expr becomes a function - bitPos ← 𝕨 - Cmp ← 𝔽 - - crit ← Cmp _tableAggr 𝕩 - matchPos ← bitPos ⊑˘ crit ((⥊˜⟜≢)=⊢) 𝕩 - match ← matchPos/𝕩 - {1=≠match?⊏match;(bitPos+1) Cmp _lifeSupportRating match} -} - -OxygenGeneratorRating ← DeBinList 0 ≤_lifeSupportRating ⊢ -CO2ScrubberRating ← DebinList 0 >_lifeSupportRating ⊢ - -! 23 = OxygenGeneratorRating day3ExampleInput -! 10 = CO2ScrubberRating day3ExampleInput - -•Out "Day 3.2: "∾•Fmt (OxygenGeneratorRating×CO2ScrubberRating) day3Input - -# -# 2021-12-04 -# - -day4Numbers ← ReadDec¨ ',' SplitOn ⊑ReadInput 4 -day4Boards ← ReadDec¨>˘(' '⊸SplitOn¨)> (<⟨⟩) SplitOn 2↓ReadInput 4 - -BoardWins ← {C ← ∨´∘(∧´˘) ⋄ (C∨C∘⍉)𝕩} - -_CallNumber ← {(𝕗∊⥊𝕩) (∨⍟(¬∘BoardWins∘⊢))˘ 𝕨} - -BoardWinScores ← { - 𝕩 (0⊸[[{[]{<()<>>", - "[(()[<>])]({[<{<<[]>>(", - "{([(<{}[<>[]}>{[]{[(<()>", - "(((({<>}<{<{<>}{[]{[]{}", - "[[<[([]))<([[{}[[()]]]", - "[{[{({}]{}}([{[{{{}}([]", - "{<[[]]>}<{[{[{[]{()[[[]", - "[<(<(<(<{}))><([]([]()", - "<{([([[(<>()){}]>(<<{{", - "<{([{{}}[<[[[<>{}]]]>[]]", -⟩ -day10Input ← ReadInput 10 - -# part 1 - -opp ← "([{<" -clp ← ")]}>" -SwapParen ← (opp∾⌽clp)⊸((⊑⊐)⊑(⌽⊣)) - -ParenStacks ← ((<⟨⟩)⊸(((⊑∊)⟜clp⊢)◶(∾˜⟜SwapParen)‿(1⊸↓⊣)`)) -LegalParens ← ((1⊸↑)¨∘»∘ParenStacks ((∊⟜opp⊢)∨(≡⟜⋈)¨) ⊢) - -_ScoreFor_ ← {𝕗⊸(𝕘⊸⊐⊏⊣) 𝕩} - -SyntaxScore ← +´∘(0‿3‿57‿1197‿25137 _ScoreFor_ (" "∾clp))∘∾∘(1⊸↑∘(¬∘LegalParens/⊢)¨) - -! 26397 = SyntaxScore day10ExampleInput -•Out "Day 10.1: "∾•Fmt SyntaxScore day10Input - -# part 2 - -AutocompleteScore ← { - Score ← (5⊸×⊸+)˜´∘⌽∘((1+↕4) _ScoreFor_ clp) - # TODO(sterni): we compute ParenStacks twice here - ((⌊÷⟜2)∘≠⊑⊢) ∧ Score∘(⊑⌽)∘ParenStacks¨ (∧´∘LegalParens¨/⊢) 𝕩 -} - -! 288957 = AutocompleteScore day10ExampleInput -•Out "Day 10.2: "∾•Fmt AutocompleteScore day10Input - -# -# 2021-12-11 -# - -day11Input ← '0'-˜> ReadInput 11 -day11ExampleInput ← >⟨ - ⟨5,4,8,3,1,4,3,2,2,3,⟩, - ⟨2,7,4,5,8,5,4,7,1,1,⟩, - ⟨5,2,6,4,5,5,6,1,7,3,⟩, - ⟨6,1,4,1,3,3,6,1,4,6,⟩, - ⟨6,3,5,7,3,8,5,4,7,8,⟩, - ⟨4,1,6,7,5,2,4,6,4,5,⟩, - ⟨2,1,7,6,8,4,1,7,2,1,⟩, - ⟨6,8,8,2,8,8,1,1,3,4,⟩, - ⟨4,8,4,6,8,4,8,5,5,4,⟩, - ⟨5,2,8,3,7,5,1,5,2,6,⟩, -⟩ - -# part 1 - -OctopusFlash ← { - ((⥊⟜0)∘≢𝕊⊢) 𝕩; - flashing ← (¬𝕨)∧9<𝕩 - energy ← ((«˘»)+(»˘«)+(»˘»)+(«˘«)+(»˘)+(«˘)+«+») flashing - ((𝕨∨flashing)⊸𝕊)⍟(0<+´⥊flashing) energy+𝕩 -} - -OctopusStep ← ((9⊸≥)×⊢)∘OctopusFlash∘(1⊸+) -OctopusFlashCount ← {+´⥊0=>(OctopusStep⊣)`(1+𝕨)⥊<𝕩} - -! 1656 = 100 OctopusFlashCount day11ExampleInput -•Out "Day 11.1: "∾•Fmt 100 OctopusFlashCount day11Input - -# part 2 - -_iterCountUntil_ ← { - 0 𝕊 𝕩; - 𝔾◶⟨((𝕨+1)⊸𝕊)∘𝔽, 𝕨˙⟩ 𝕩 -} - -OctopusAllFlashing ← OctopusStep _iterCountUntil_ (∧´∘⥊∘(0⊸=)) - -! 195 = OctopusAllFlashing day11ExampleInput - -•Out "Day 11.2: "∾•Fmt OctopusAllFlashing day11Input - -# -# 2021-12-13 -# - -SplitFoldingInstructions ← ("fold along"⊸(⊣≡≠⊸↑)¨⊔⊢)∘(0⊸(≠⟜≠¨/⊢)) -day13ExampleInput ← SplitFoldingInstructions ⟨ - "6,10", - "0,14", - "9,10", - "0,3", - "10,4", - "4,11", - "6,0", - "6,12", - "4,1", - "0,13", - "10,12", - "3,4", - "3,0", - "8,4", - "1,10", - "2,14", - "8,10", - "9,0", - "", - "fold along y=7", - "fold along x=5", -⟩ -day13Input ← SplitFoldingInstructions ReadInput 13 - -ParseDots ← ReadDec¨∘(','⊸SplitOn)¨ -ParseFolds ← (⊑∘'y'⊸∊≍ReadDec∘(IsAsciiNum/⊢))¨ -day13ExampleDots ← ParseDots ⊑ day13ExampleInput - -# part 1 - -# 𝕨=0 => x, 𝕨=1 => y -# 𝕩 is coordinate to fold around -# 𝕗 is input dot list (see ParseDots) -_Fold ← {⍷∘((𝕩⊸(((2⊸×⊣)-⊢)⌊⊢)∘⊑≍1⊸⊑)¨⌾(⌽¨⍟𝕨)) 𝕗} - -! 17 = ≠ 1 day13ExampleDots _Fold 7 - -day13Dots ← ParseDots ⊑ day13Input -day13Folds ← ParseFolds 1 ⊑ day13Input - -•Out "Day 13.1: "∾•Fmt ≠ (day13Dots _Fold)´ ⊑day13Folds - -# part 2 - -PerformAllFolds ← {𝕩 {(𝕨 _Fold)´𝕩}˜´ ⌽𝕨} -DotMatrix ← { - ⟨width, height⟩ ← 1+⌈˝∘‿2⥊∾𝕩 - {𝕩? '█';' '}¨ height‿width⥊≠¨⊔((⊣+(width⊸×)∘⊢)´)¨ 𝕩 -} - -•Out "Day 13.2:" -•Out •Fmt DotMatrix day13Folds PerformAllFolds day13Dots - -# -# 2021-12-14 -# - -day14Polymer ← ⊑ReadInput 14 -day14Mapping ← 2↓ReadInput 14 - -lp ← (2⊸↑)¨ day14Mapping -le ← ⍷∾lp - -# returns array as long as 𝕨 detailing how many times the element -# at any given index occurs in 𝕩. -Counts ← ((≠⊣)↑(/⁼)∘⊐) - -deltaPairs ← { - addedPairs ← ((-1)⊸⊑¨day14Mapping) (⌽⌾(0⊸⊑))∘(∾¨)¨ lp - removedPairs ← ⋈¨ (2⊸↑)¨ lp - addedPairs (-○(lp⊸Counts))¨ removedPairs -} - -pairCount ← lp Counts ⥊∘(⋈˘) 2↕day14Polymer - -PairInsert ← {𝕩 +´ 𝕩רdeltaPairs} - -pairElementCount ← (le⊸Counts)¨lp - -ElementRarityDiff ← { - ((-1)⊸⊑-⊑)∧ ⌈2÷˜ +´ pairElementCount×PairInsert⍟𝕩 pairCount -} - -•Out "Day 14.1: "∾•Fmt ElementRarityDiff 10 -•Out "Day 14.2: "∾•Fmt ElementRarityDiff 40 - -# -# 2021-12-15 -# - -day15ExampleInput ← >⟨ - 1‿1‿6‿3‿7‿5‿1‿7‿4‿2 - 1‿3‿8‿1‿3‿7‿3‿6‿7‿2 - 2‿1‿3‿6‿5‿1‿1‿3‿2‿8 - 3‿6‿9‿4‿9‿3‿1‿5‿6‿9 - 7‿4‿6‿3‿4‿1‿7‿1‿1‿1 - 1‿3‿1‿9‿1‿2‿8‿1‿3‿7 - 1‿3‿5‿9‿9‿1‿2‿4‿2‿1 - 3‿1‿2‿5‿4‿2‿1‿6‿3‿9 - 1‿2‿9‿3‿1‿3‿8‿5‿2‿1 - 2‿3‿1‿1‿9‿4‿4‿5‿8‿1 -⟩ -day15Input ← '0'-˜ ((≠⋈≠∘⊑)⥊∾)ReadInput 15 - -LowestRiskLevel ← { - start ← 0˙⌾⊑ (⥊⟜∞) ≢𝕩 - ir ← (1⊑≢𝕩)⥊∞ - Step ← {𝕩 ⌊ 𝕨 + (ir⊸«⌊ir⊸»⌊∞⊸«˘⌊∞⊸»˘) 𝕩} - ⊑⌽⥊ 𝕩⊸Step _fix start -} - -! 40 = LowestRiskLevel day15ExampleInput - -•Out "Day 15.1: "∾•Fmt LowestRiskLevel day15Input - -FiveByFiveMap ← {(9⊸|)⌾(-⟜1) ∾(<𝕩)+ +⌜˜↕5} - -! 315 = LowestRiskLevel FiveByFiveMap day15ExampleInput - -•Out "Day 15.2: "∾•Fmt LowestRiskLevel FiveByFiveMap day15Input - -# -# 2021-12-20 -# - -ParsePic ← (⋈⟜0)∘('#'⊸=)∘> - -day20ExampleAlgo ← '#'="..#.#..#####.#.#.#.###.##.....###.##.#..###.####..#####..#....#..#..##..###..######.###...####..#..#####..##..#.#####...##.#.#..#.##..#.#......#.###.######.###.####...#.##.##..#..#..#####.....#.#....###..#.##......#.....#..#..#..##..#...##.######.####.####.#.#...#.......#..#.#.#...####.##.#......#..#...##.#.##..#...##.#.##..###.#......#.#.......#.#.#.####.###.##...#.....####.#..#..#.##.#....##..#.####....##...##..#...#......#.#.......#.......##..####..#...#.#.#...##..#.#..###..#####........#..####......#..#" -day20ExamplePic ← ParsePic ⟨"#..#.", "#....", "##..#", "..#..", "..###"⟩ -day20Input ← ReadInput 20 -day20Algo ← '#'=⊑day20Input -day20Pic ← ParsePic 2↓day20Input - -GrowAxis ← {(⊢ (-1)⊸⌽∘∾ (⥊⟜𝕨)∘(2˙⌾⊑)∘≢) 𝕩} -Grow ← {𝕨 GrowAxis 𝕨 GrowAxis˘ 𝕩} - -Enhance ← { - inf ← 1⊑𝕩 - npic ← ((⊑⟜𝕨)∘DebinList∘⥊)˘˘ 3‿3↕ (inf⊸Grow)⍟2 ⊑𝕩 - ninf ← 𝕨⊑˜511×inf - npic⋈ninf -} -_EnhancedPixelCount ← {+´⥊⊑ (𝕨⊸Enhance)⍟𝕗 𝕩} - -! 35 = day20ExampleAlgo 2 _EnhancedPixelCount day20ExamplePic -! 3351 = day20ExampleAlgo 50 _EnhancedPixelCount day20ExamplePic - -•Out "Day 20.1: "∾•Fmt day20Algo 2 _EnhancedPixelCount day20Pic -•Out "Day 20.2: "∾•Fmt day20algo 50 _EnhancedPixelCount day20Pic - -# -# 2021-12-25 -# - -day25Input ← ".>v" ⊐ > ReadInput 25 -day25ExampleInput ← ".>v"⊐∘‿10⥊"v...>>.vv>.vv>>.vv..>>.>v>...v>>v>>.>.v.v>v.vv.v..>.>>..v....vv..>.>v.v.v..>>v.v....v..v.>" - -MoveHerd ← {(𝕩∧𝕩≠𝕨)+𝕨× (𝕨=𝕩) (Xor⟜(1⊸⌽)∨⊢) (0=𝕩)∧(-1)⌽𝕨=𝕩} - -_fixCount ← { - 1 𝕊 𝕩; - 𝕩 ≡◶⟨(𝕨+1)⊸𝕊, 𝕨˙⟩ 𝔽 𝕩 -} - -MoveAllHerds ← (2⊸MoveHerd)∘(1⊸MoveHerd˘) - -! 58 = MoveAllHerds _fixCount day25ExampleInput -•Out "Day 25.1: "∾•Fmt MoveAllHerds _fixCount day25Input diff --git a/users/sterni/exercises/aoc/2022/.skip-subtree b/users/sterni/exercises/aoc/2022/.skip-subtree deleted file mode 100644 index 39d189449..000000000 --- a/users/sterni/exercises/aoc/2022/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -nix solutions don't use readTree and the rest is non-nix diff --git a/users/sterni/exercises/aoc/2022/01/1.bqn b/users/sterni/exercises/aoc/2022/01/1.bqn deleted file mode 100644 index 022b476aa..000000000 --- a/users/sterni/exercises/aoc/2022/01/1.bqn +++ /dev/null @@ -1,7 +0,0 @@ -lib ← •Import •path∾"/../../lib.bqn" -input ← lib.ReadDec¨¨ (<"") lib.SplitOn •FLines •path∾"/input" - -a‿·‿b ← +`3↑∨+´¨ input - -•Out "day01.1: "∾•Fmt a -•Out "day01.2: "∾•Fmt b diff --git a/users/sterni/exercises/aoc/2022/01/1.k b/users/sterni/exercises/aoc/2022/01/1.k deleted file mode 100644 index 42d64dfb6..000000000 --- a/users/sterni/exercises/aoc/2022/01/1.k +++ /dev/null @@ -1 +0,0 @@ -(+\e@3#>e:(+/.'1_)'(&0=#'i)_i:0:"input")_1 diff --git a/users/sterni/exercises/aoc/2022/02/2.bqn b/users/sterni/exercises/aoc/2022/02/2.bqn deleted file mode 100644 index 65e3c817b..000000000 --- a/users/sterni/exercises/aoc/2022/02/2.bqn +++ /dev/null @@ -1,7 +0,0 @@ -lib ← •Import •path∾"/../../lib.bqn" -i ← 3|"ABCXYZ"⊸⊐¨ ' ' ⊑¨∘lib.SplitOn¨ •FLines •path∾"/input" -S1 ← {1+𝕩+3×3|1+𝕩-𝕨} -S2 ← {𝕨 S1 3|𝕨+𝕩-1} - -•Out "day02.1: "∾•Fmt +´S1´¨i -•Out "day02.2: "∾•Fmt +´S2´¨i diff --git a/users/sterni/exercises/aoc/2022/02/2.k b/users/sterni/exercises/aoc/2022/02/2.k deleted file mode 100644 index 9b6d10058..000000000 --- a/users/sterni/exercises/aoc/2022/02/2.k +++ /dev/null @@ -1 +0,0 @@ -+/{{y+1+3*3!1+y-x}[x]'y,3!x+y-1}.'3!"ABCXYZ"?(0:"input")_'1 diff --git a/users/sterni/exercises/aoc/2022/03/3.bqn b/users/sterni/exercises/aoc/2022/03/3.bqn deleted file mode 100644 index 642fccd45..000000000 --- a/users/sterni/exercises/aoc/2022/03/3.bqn +++ /dev/null @@ -1,8 +0,0 @@ -i ← •FLines •path∾"/input" -c ← ∾(↕26)⊸+¨"aA" -P ← {1+⊑c⊐⊑𝕩} -S ← (∊/⊣) -G ← ((⊣/(↕÷˜⟜≠))⊔⊢) - -•Out "day03.1: "∾•Fmt +´(P S˝)¨2‿∘⊸⥊¨i -•Out "day03.2: "∾•Fmt +´3(P S´)¨∘G i diff --git a/users/sterni/exercises/aoc/2022/03/3.k b/users/sterni/exercises/aoc/2022/03/3.k deleted file mode 100644 index 3e31f5f32..000000000 --- a/users/sterni/exercises/aoc/2022/03/3.k +++ /dev/null @@ -1 +0,0 @@ -+/'(58*r<1)+r:-96+(,/{?y@&~^x?y}/')'((2 0N#)';0N 3#)@\:0:"input" diff --git a/users/sterni/exercises/aoc/2022/04/4.bqn b/users/sterni/exercises/aoc/2022/04/4.bqn deleted file mode 100644 index 0b8f1b450..000000000 --- a/users/sterni/exercises/aoc/2022/04/4.bqn +++ /dev/null @@ -1,11 +0,0 @@ -⟨SplitOn, ReadDec⟩ ← •Import "../../lib.bqn" - -Sections ← { - a‿b ← ReadDec¨ (<'-') SplitOn 𝕩 - ↕⌾(-⟜a) 1+b -} -i ← ∘‿2⥊Sections¨ ∾(<',') SplitOn¨ •FLines "input" -Is ← ∊´∘((⍋≠¨)⊏⊢) - -•Out "day04.1: "∾•Fmt +´(∧´Is)˘ i -•Out "day04.2: "∾•Fmt +´(∨´Is)˘ i diff --git a/users/sterni/exercises/aoc/2022/05/5.bqn b/users/sterni/exercises/aoc/2022/05/5.bqn deleted file mode 100644 index 15b0dfc80..000000000 --- a/users/sterni/exercises/aoc/2022/05/5.bqn +++ /dev/null @@ -1,18 +0,0 @@ -⟨ReadDec, SplitOn, IsAsciiNum⟩ ← •Import "../../lib.bqn" -rs‿rc ← (<"") SplitOn •FLines "../05/input" - -stacks ← { - count ← '0'-˜⊑⌽' ' (≠/⊢) ⊑⌽rs - ' ' (≠/⊢)¨<˘ (count×4) ((»∘(0⊸=)∘(4⊸|)∘↕⊣)/↑) ⍉> (-1)↓rs -} - -cmds ← {0‿1‿1-˜ ReadDec¨ ((∧´IsAsciiNum)¨/⊢) (<' ') SplitOn 𝕩}¨ rc - -_ApplyCmd ← { - s Fn _self c‿f‿t : - m‿k ← 2↑ c ((≤⟜(↕≠))⊔⊢) f⊑s - (Fn m)⊸∾⌾(t⊸⊑) k˙⌾(f⊸⊑) s -} - -•Out "day05.1: "∾⊑¨stacks ⌽_ApplyCmd˜´ ⌽ cmds -•Out "day05.2: "∾⊑¨stacks ⊢_ApplyCmd˜´ ⌽ cmds diff --git a/users/sterni/exercises/aoc/2022/06/6.bqn b/users/sterni/exercises/aoc/2022/06/6.bqn deleted file mode 100644 index 041a2e910..000000000 --- a/users/sterni/exercises/aoc/2022/06/6.bqn +++ /dev/null @@ -1,4 +0,0 @@ -i ← ⊑•FLines "input" -FirstMarker ← {𝕩+⊑/(∧´∘¬⊒)˘𝕩↕i} -•Out "day06.1: "∾•Fmt FirstMarker 4 -•Out "day06.2: "∾•Fmt FirstMarker 14 diff --git a/users/sterni/exercises/aoc/2022/06/6.k b/users/sterni/exercises/aoc/2022/06/6.k deleted file mode 100644 index 3dc0de0a3..000000000 --- a/users/sterni/exercises/aoc/2022/06/6.k +++ /dev/null @@ -1 +0,0 @@ -4 14{x+*&x=#'?'x':y}\:1:"input" diff --git a/users/sterni/exercises/aoc/2022/07/7.bqn b/users/sterni/exercises/aoc/2022/07/7.bqn deleted file mode 100644 index 2fc387f34..000000000 --- a/users/sterni/exercises/aoc/2022/07/7.bqn +++ /dev/null @@ -1,24 +0,0 @@ -lib ← •Import "../../lib.bqn" -cmds ← 1↓ '$' ((+`= ⟜(⊑¨))⊔⊢) •FLines "input" -paths ← (<⟨⟩) { - 𝕨 𝕊 "$ ls": 𝕨; - 𝕨 𝕊 "$ cd /": ⟨⟩; - 𝕨 𝕊 "$ cd ..": (-1)↓𝕨; - 𝕨 𝕊 𝕩: 𝕨∾<5↓𝕩 # "$ cd …" -}` ⊑¨cmds -ParseLs ← { - dirs‿files ← 2↑((lib.IsAsciiNum∘⊑∘⊑)¨⊔⊢) ((<' ')⊸lib.SplitOn)¨ 1↓𝕩 - (1⊑¨dirs)⋈(lib.ReadDec 0⊸⊑)¨files -} -dirlists ← ParseLs⌾(1⊸⊑)¨⥊⋈˘(("$ cd"⊸≢⟜(4⊸↑)∘⊑¨)∘(1⊸⊏)˘/⊢) (⍒≠¨paths)⊏⍉paths≍cmds -DirSize ← {⊑𝕨 (⊑∘(1⊸⊑¨∘⊣⊐⊢)⊑⊣) <𝕩} -DirName ← ∾'/'⊸∾¨ -dirsizes ← ⊑¨ ⟨⟩ { - szs 𝕊 ⟨dir, subdirs‿files⟩: - Canon ← DirName dir⊸∾⟜⋈ - sz ← +´files∾szs⊸DirSize∘Canon¨ subdirs - szs∾'0'-˜•FLines "input" -Visible ← { - _vis ← {(⌈`∘(¯1⊸»˘⌾⍉)<⊢)⌾𝕏 𝕗} - ∨´𝕩 _vis¨ ⟨⊢,⌽,⍉,⌽⍉⟩ -} - -•Out "day08.1: "∾•Fmt +´⥊Visible i - -ViewingDistances ← { - DirView ← {≠1(»⟜(∧`(⊑𝕩)⊸>)/⊢) 1↓𝕩} - _spliceDir ← {! =´≢𝕗 ⋄ 𝕏⁼(⊢↓(⊏⟜(𝕏𝕗))∘⊣)´¨ ⋈⌜˜↕≠𝕗} - ×´ DirView¨¨ 𝕩 _spliceDir¨ ⟨⊢, ⌽˘, ⍉, ⌽˘⍉⟩ -} - -•Out "day08.2: "∾•Fmt ⌈´⥊ViewingDistances i diff --git a/users/sterni/exercises/aoc/2022/09/9.bqn b/users/sterni/exercises/aoc/2022/09/9.bqn deleted file mode 100644 index fff38b591..000000000 --- a/users/sterni/exercises/aoc/2022/09/9.bqn +++ /dev/null @@ -1,17 +0,0 @@ -⟨SplitOn,ReadDec⟩ ← •Import "../../lib.bqn" -i ← ReadDec⌾(1⊸⊑)¨ (<' ')⊸SplitOn¨ •FLines "input" - -UnitDelta ← (⊢÷(|+0⊸=)) -ExpandStep ← { - 𝕊 "L"‿l: 𝕊 (-l)‿0; - 𝕊 "R"‿r: 𝕊 r‿0; - 𝕊 "U"‿u: 𝕊 0‿u; - 𝕊 "D"‿d: 𝕊 0‿(-d); - 𝕊 delta: ((⌈´|)⥊<∘UnitDelta) delta -} - -Step ← {knots 𝕊 delta: {h 𝕊 t: (UnitDelta h-t) +⍟(1<⌈´|h-t) t}` (delta⊸+)⌾⊑ knots} -Visited ← {+´0=⊒(¯1⊸⊑)¨(<𝕨⥊<0‿0) Step` ∾ExpandStep¨ 𝕩} - -•Out "day09.1: "∾•Fmt 2 Visited i -•Out "day09.2: "∾•Fmt 10 Visited i diff --git a/users/sterni/exercises/aoc/2022/10/10.bqn b/users/sterni/exercises/aoc/2022/10/10.bqn deleted file mode 100644 index 04e3d6a8e..000000000 --- a/users/sterni/exercises/aoc/2022/10/10.bqn +++ /dev/null @@ -1,25 +0,0 @@ -⟨SplitOn,ReadDec⟩ ← •Import "../../lib.bqn" -# Instead of implementing the VM described in the problem, translate the -# program to instructions with equivalent timing for a similar VM that -# only needs 1 cycle for every instruction. -is ← ∾{"noop": <"noop"; 𝕩: (<"noop")∾((↕⊣)=|)¨)×(≠¨˘)∘>∘(⊣»Turn`)) ↕len×≠items -} - -•Out "day11.1: "∾•Fmt 3 Sim 20 -•Out "day11.2: "∾•Fmt 1 Sim 10000 diff --git a/users/sterni/exercises/aoc/2022/12/12.bqn b/users/sterni/exercises/aoc/2022/12/12.bqn deleted file mode 100644 index cf42f6f89..000000000 --- a/users/sterni/exercises/aoc/2022/12/12.bqn +++ /dev/null @@ -1,16 +0,0 @@ -⟨ImportBqnLibs,_fix⟩ ← •Import "../../lib.bqn" -⟨ReplaceAll⟩ ← ImportBqnLibs "strings.bqn" -i ← >•FLines "input" - -elevation ← 'a'-˜⟨"S","E"⟩‿⟨"a","z"⟩ ReplaceAll⌾⥊ i -starts ← (⊏⟜∞‿0)¨⟨'S'=i,0=elevation⟩ -end ← 'E'=i - -Step ← { - 𝕊 steps: - Go ← {𝕏⁼((⊢∾¨↕∘≢)(≤⟜(∞⊸»˘∘+⟜1))˜𝕏elevation)⊑>((⥊⟜∞)∘≢⊸⋈)˜∞⊸»˘1+𝕏steps} - steps⌊´Go¨⟨⊢,⌽˘,⍉,⍉⌽⟩ -} -Shortest ← {⊑end/⊸⊏○⥊Step _fix 𝕩} - -•Out¨ "day12.1: "‿"day12.2: "∾¨ •Fmt∘Shortest¨ starts diff --git a/users/sterni/exercises/aoc/2022/13/13.bqn b/users/sterni/exercises/aoc/2022/13/13.bqn deleted file mode 100644 index 0242cc509..000000000 --- a/users/sterni/exercises/aoc/2022/13/13.bqn +++ /dev/null @@ -1,14 +0,0 @@ -lib ← •Import "../../lib.bqn" -str ← lib.ImportBqnLibs "strings.bqn" -i ← >⟨"[","]"⟩‿⟨"⟨","⟩"⟩⊸(•BQN str.ReplaceAll)¨¨0((⟨⟩⊸≡¨¯1˙⍟⊣¨(+`(=⟜≠)¨))⊔⊢)•FLines "input" - -Ord ← { - i1 𝕊 i2: 1‿1≡•Type¨ i1‿i2? ¯1‿1‿0⊑˜i1(=+≤)i2; - i1 𝕊 l2: 1‿0≡•Type¨ i1‿l2? l2 Ord˜ ⋈i1; - l1 𝕊 i2: 0‿1≡•Type¨ l1‿i2? l1 Ord ⋈i2; - l1 𝕊 l2: 0‿0≡•Type¨ l1‿l2? - ⊑1↑0(≠/⊢)l1 Ord¨○((l1⌈○≠l2)⊸(↑⌾(+⟜1))) l2 -} - -•Out "day13.1: "∾•Fmt +´1+/(1⊸=Ord´)˘i -•Out "day13.2: "∾•Fmt ×´1‿2++´˘¯1=⟨⟨2⟩⟩‿⟨⟨6⟩⟩Ord⌜⥊i diff --git a/users/sterni/exercises/aoc/2022/15/15.bqn b/users/sterni/exercises/aoc/2022/15/15.bqn deleted file mode 100644 index e47355856..000000000 --- a/users/sterni/exercises/aoc/2022/15/15.bqn +++ /dev/null @@ -1,18 +0,0 @@ -lib ← •Import "../../lib.bqn" - -F ← ¬∘('-'⊸=∨lib.IsAsciiNum) -i ← ⌽˘˘∘‿2‿2⥊lib.ReadDec¨>(0⊸<⟜≠¨/⊢)∘((F ¯1˙⍟⊣¨(+`F))⊔⊢)¨ •FLines "input" - -ssp ← 4000000 - -sds ← (⊏˘∾˘(+´˘(|(-˝))˘)) i - -# _fix is needed to deal with e.g. ⟨0‿15, 5‿8, 12‿23⟩ -MergeRanges ← ((⊑∾⊑∘⌽)∘∧∘∾)¨∘(+`∘((<∞‿∞)⊸»{<´1‿2⊏𝕨∾𝕩}¨⊢)⊔⊢) lib._fix - -Range ← {cky 𝕊 y‿x‿d: x+¯1‿1×d-|cky-y} -RangesY ← {<˘∧𝕩(⊣Range˘({cky 𝕊 y‿·‿d: d≥|y-cky}˘/⊢))sds} -OutRangeY ← {(1<≠)◶⟨0˙,𝕩⊸+∘(ssp⊸×⟜(+⟜1))∘(1⊸⊑)∘∾⟩ MergeRanges ssp⌊0⌈RangesY 𝕩} - -•Out "day15.1: "∾•Fmt +´-˜´¨MergeRanges RangesY 2÷˜ssp -•Out "day15.2: "∾•Fmt +´OutRangeY¨↕ssp diff --git a/users/sterni/exercises/aoc/2022/16/16.k b/users/sterni/exercises/aoc/2022/16/16.k deleted file mode 100644 index 40d5ace60..000000000 --- a/users/sterni/exercises/aoc/2022/16/16.k +++ /dev/null @@ -1,21 +0,0 @@ -/ parsing -(f;r;t):+{x[1 4],,9_x^'","}'" "\' 0:"input" -(f;t):`s$''(f;t) -r:f!{`I$x[&(x<58)&471;o[n-1;rt];rt]} - -*tf'p[29;,,`AA] diff --git a/users/sterni/exercises/aoc/2022/17/17.bqn b/users/sterni/exercises/aoc/2022/17/17.bqn deleted file mode 100644 index 21b94221a..000000000 --- a/users/sterni/exercises/aoc/2022/17/17.bqn +++ /dev/null @@ -1,51 +0,0 @@ -jets ← '>'= "<>" (∊˜/⊢) •FChars "input" -pieces ← >¨⟨1‿1‿1‿1⟩‿⟨0‿1‿0,1‿1‿1,0‿1‿0⟩‿⟨0‿0‿1,0‿0‿1,1‿1‿1⟩‿⟨⋈1,⋈1,⋈1,⋈1⟩‿⟨1‿1,1‿1⟩ -w ← 7 -initial ← 0‿w⥊0 - -# Warning: mutated global! -ji ← 0 -_try ← {(⊢ 𝕩˙⍟(≠○(+´∘⥊∘∨⟜𝕨)) 𝔽) 𝕩} -Fall ← { - pushed ← 𝕨 ((ji⊑jets)◶«‿»)˘ _try 𝕩 - ji ↩ (≠jets)|ji+1 - fallen ← 𝕨 » _try pushed - 𝕨 𝕊⍟(pushed≢fallen) fallen -} -Height ← ≠∘(∨´˘/⊢) -ThrowPiece ← { - piece ← 𝕩 (|˜⟜≠⊑⊢) pieces - chamber ← (((3+≠piece)⊸+∘⊑∘(1⊸↑)∘⌽∘(1⊸+)∘/∨´˘)↑⊢)⌾⌽𝕨 - falling ← (≠chamber)↑(»⍟2 w⊸↑)˘piece - chamber (⊣∨Fall) falling -} - -•Out "day17.1: "∾•Fmt Height initial ThrowPiece˜´ ⌽↕2022 - -# https://mlochbaum.github.io/BQN/doc/control.html#while -While ← {𝕩{𝔽⍟𝔾∘𝔽_𝕣_𝔾∘𝔽⍟𝔾𝕩}𝕨@}´ -{ - target ← 1000000000000 - ji ↩ 0 ⋄ i ← 0 ⋄ res ← @ - - chamber ← initial - cycles ← ⟨≠pieces,≠jets⟩⥊<⟨⟩ - - While {𝕤⋄res=@}‿{𝕤 - chamber ↩ chamber ThrowPiece i - i +↩ 1 - - t ← i|˜≠pieces - cycles ↩ { - new ← 𝕩∾)⊢)⌈⊢)⎉1)⌾(F a⊸⍉)𝕩}¨<𝕩} -Exterior ← (⊢-○Exposed ¯1⊸=∘(Displace lib._fix)∘(-∘Interior+⊢)) - -•Out "day18.1: "∾•Fmt Exposed cubes -•Out "day18.2: "∾•Fmt Exterior cubes diff --git a/users/sterni/exercises/aoc/2022/20/20.bqn b/users/sterni/exercises/aoc/2022/20/20.bqn deleted file mode 100644 index 8d4c905e8..000000000 --- a/users/sterni/exercises/aoc/2022/20/20.bqn +++ /dev/null @@ -1,13 +0,0 @@ -⟨ReadDec⟩ ← •Import "../../lib.bqn" -enc ← ReadDec¨ •FLines "input" - -CoordSum ← +´∘(1000‿2000‿3000⊸((⊢≠⊸|+⟜(⊑∘(/=⟜0)∘⊢))⊏⊢)) -Mix ← { - M ← {m 𝕊 i: - l ← ≠m - i {n ← (l-1)|(𝕩⊑m)+⊑/𝕩=𝕨 ⋄ (n⊸↑(∾⟜𝕩)⊸∾n⊸↓) 𝕩(≠/⊢)𝕨}˜´ ⌽↕l - } - CoordSum ((⊢M⍟𝕨↕∘≠)⊏⊢) 𝕩 -} -•Out "day20.1: "∾•Fmt 1 Mix enc -•Out "day20.2: "∾•Fmt 10 Mix 811589153×enc diff --git a/users/sterni/exercises/aoc/2022/21/21.bqn b/users/sterni/exercises/aoc/2022/21/21.bqn deleted file mode 100644 index 2f91f55d4..000000000 --- a/users/sterni/exercises/aoc/2022/21/21.bqn +++ /dev/null @@ -1,25 +0,0 @@ -⟨ImportBqnLibs, IsAsciiNum, ReadDec⟩ ← •Import "../../lib.bqn" -⟨ReplaceAll, Split⟩ ← ImportBqnLibs "strings.bqn" - -i ← ": "⊸Split¨ •FLines "input" -ReplaceInts ← { - 𝕊 𝕩: 𝕊´ 2↑(¬∘(∧´IsAsciiNum∘⊑∘⌽)¨⊔⊢) 𝕩; - # TODO: Efficient replace on tokens - is 𝕊 es: (((•Fmt⍟(0⊸≠•Type))¨⌾(1⊸⊑) <˘⍉>is)⊸ReplaceAll⌾(1⊸⊑))¨ es -} - -c ← 0 -CanEval ← (IsAsciiNum∨∊⟜"+-/* ") -Eval ← { - a‿s‿b ← " " Split 𝕩 - f ← ⊑+‿-‿×‿÷⊏˜"+-*/"⊐s - a F○ReadDec b -} -EvalExprs ← { - p‿e ← 2↑((∧´CanEval∘⊑∘⌽)¨⊔⊢) 𝕩 - ev ← (Eval⌾(⊑⌽))¨ e - c +↩1 - (⊑(⊑¨ev)∊˜<"root")◶⟨EvalExprs∘(ReplaceInts⟜p),1⊸⊑⊑⟩ ev -} - -•Show EvalExprs ReplaceInts i diff --git a/users/sterni/exercises/aoc/2022/25/25.bqn b/users/sterni/exercises/aoc/2022/25/25.bqn deleted file mode 100644 index 921099141..000000000 --- a/users/sterni/exercises/aoc/2022/25/25.bqn +++ /dev/null @@ -1,4 +0,0 @@ -c ← "=-012" -F ← +´∘(⊢×(5⊸⋆)∘⌽∘↕∘≠)∘(-⟜2)∘(c⊸⊐) -T ← {c⊏˜5|2+𝕩 {(⌊5÷˜𝕨+2) (𝕊⟜(𝕨⊸∾))⍟(0<𝕨) 𝕩} ⟨⟩} -•Out "day25.1: "∾T +´F¨ •FLines "input" diff --git a/users/sterni/exercises/aoc/2022/25/25.k b/users/sterni/exercises/aoc/2022/25/25.k deleted file mode 100644 index df956f002..000000000 --- a/users/sterni/exercises/aoc/2022/25/25.k +++ /dev/null @@ -1 +0,0 @@ -c@2+{(1_o,0)+x+-5*o:2//archive/.tar.gz" - }, - "likely-music": { - "branch": "master", - "description": "experimental application for probabilistic music composition", - "homepage": "", - "owner": "sternenseemann", - "repo": "likely-music", - "rev": "c9bef141d846c493a045385ab8146aa28fc8ef33", - "sha256": "1wqgxx8wk7lrvyn9h66gga2wf7dcq7si8wq1w5gfhjnwnsrnvs6y", - "type": "tarball", - "url": "https://github.com/sternenseemann/likely-music/archive/c9bef141d846c493a045385ab8146aa28fc8ef33.tar.gz", - "url_template": "https://github.com///archive/.tar.gz" - } -} diff --git a/users/sterni/external/sources.nix b/users/sterni/external/sources.nix deleted file mode 100644 index cdcde6da5..000000000 --- a/users/sterni/external/sources.nix +++ /dev/null @@ -1,197 +0,0 @@ -# This file has been generated by Niv. -_: -let - - # - # The fetchers. fetch_ fetches specs of type . - # - - fetch_file = pkgs: name: spec: - let - name' = sanitizeName name + "-src"; - in - if spec.builtin or true then - builtins_fetchurl { inherit (spec) url sha256; name = name'; } - else - pkgs.fetchurl { inherit (spec) url sha256; name = name'; }; - - fetch_tarball = pkgs: name: spec: - let - name' = sanitizeName name + "-src"; - in - if spec.builtin or true then - builtins_fetchTarball { name = name'; inherit (spec) url sha256; } - else - pkgs.fetchzip { name = name'; inherit (spec) url sha256; }; - - fetch_git = name: spec: - let - ref = - if spec ? ref then spec.ref else - if spec ? branch then "refs/heads/${spec.branch}" else - if spec ? tag then "refs/tags/${spec.tag}" else - abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; - submodules = if spec ? submodules then spec.submodules else false; - submoduleArg = - let - nixSupportsSubmodules = builtins.compareVersions builtins.nixVersion "2.4" >= 0; - emptyArgWithWarning = - if submodules == true - then - builtins.trace - ( - "The niv input \"${name}\" uses submodules " - + "but your nix's (${builtins.nixVersion}) builtins.fetchGit " - + "does not support them" - ) - { } - else { }; - in - if nixSupportsSubmodules - then { inherit submodules; } - else emptyArgWithWarning; - in - builtins.fetchGit - ({ url = spec.repo; inherit (spec) rev; inherit ref; } // submoduleArg); - - fetch_local = spec: spec.path; - - fetch_builtin-tarball = name: throw - ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`. - $ niv modify ${name} -a type=tarball -a builtin=true''; - - fetch_builtin-url = name: throw - ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`. - $ niv modify ${name} -a type=file -a builtin=true''; - - # - # Various helpers - # - - # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695 - sanitizeName = name: - ( - concatMapStrings (s: if builtins.isList s then "-" else s) - ( - builtins.split "[^[:alnum:]+._?=-]+" - ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name) - ) - ); - - # The set of packages used when specs are fetched using non-builtins. - mkPkgs = sources: system: - let - sourcesNixpkgs = - import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; }; - hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath; - hasThisAsNixpkgsPath = == ./.; - in - if builtins.hasAttr "nixpkgs" sources - then sourcesNixpkgs - else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then - import { } - else - abort - '' - Please specify either (through -I or NIX_PATH=nixpkgs=...) or - add a package called "nixpkgs" to your sources.json. - ''; - - # The actual fetching function. - fetch = pkgs: name: spec: - - if ! builtins.hasAttr "type" spec then - abort "ERROR: niv spec ${name} does not have a 'type' attribute" - else if spec.type == "file" then fetch_file pkgs name spec - else if spec.type == "tarball" then fetch_tarball pkgs name spec - else if spec.type == "git" then fetch_git name spec - else if spec.type == "local" then fetch_local spec - else if spec.type == "builtin-tarball" then fetch_builtin-tarball name - else if spec.type == "builtin-url" then fetch_builtin-url name - else - abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}"; - - # If the environment variable NIV_OVERRIDE_${name} is set, then use - # the path directly as opposed to the fetched source. - replace = name: drv: - let - saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; - ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; - in - if ersatz == "" then drv else - # this turns the string into an actual Nix path (for both absolute and - # relative paths) - if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; - - # Ports of functions for older nix versions - - # a Nix version of mapAttrs if the built-in doesn't exist - mapAttrs = builtins.mapAttrs or ( - f: set: with builtins; - listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set)) - ); - - # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295 - range = first: last: if first > last then [ ] else builtins.genList (n: first + n) (last - first + 1); - - # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257 - stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1)); - - # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269 - stringAsChars = f: s: concatStrings (map f (stringToCharacters s)); - concatMapStrings = f: list: concatStrings (map f list); - concatStrings = builtins.concatStringsSep ""; - - # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331 - optionalAttrs = cond: as: if cond then as else { }; - - # fetchTarball version that is compatible between all the versions of Nix - builtins_fetchTarball = { url, name ? null, sha256 }@attrs: - let - inherit (builtins) lessThan nixVersion fetchTarball; - in - if lessThan nixVersion "1.12" then - fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) - else - fetchTarball attrs; - - # fetchurl version that is compatible between all the versions of Nix - builtins_fetchurl = { url, name ? null, sha256 }@attrs: - let - inherit (builtins) lessThan nixVersion fetchurl; - in - if lessThan nixVersion "1.12" then - fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; })) - else - fetchurl attrs; - - # Create the final "sources" from the config - mkSources = config: - mapAttrs - ( - name: spec: - if builtins.hasAttr "outPath" spec - then - abort - "The values in sources.json should not have an 'outPath' attribute" - else - spec // { outPath = replace name (fetch config.pkgs name spec); } - ) - config.sources; - - # The "config" used by the fetchers - mkConfig = - { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null - , sources ? if isNull sourcesFile then { } else builtins.fromJSON (builtins.readFile sourcesFile) - , system ? builtins.currentSystem - , pkgs ? mkPkgs sources system - }: rec { - # The sources, i.e. the attribute set of spec name to spec - inherit sources; - - # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers - inherit pkgs; - }; - -in -mkSources (mkConfig { }) // { __functor = _: settings: mkSources (mkConfig settings); } diff --git a/users/sterni/git-only-push/default.nix b/users/sterni/git-only-push/default.nix deleted file mode 100644 index 9b89d24e0..000000000 --- a/users/sterni/git-only-push/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, ... }: - -pkgs.runCommandNoCC "git-only-push" -{ - nativeBuildInputs = [ pkgs.buildPackages.shellcheck ]; - buildInputs = [ pkgs.bash ]; - src = ./git-only-push.sh; -} - '' - shellcheck "$src" - install -Dm755 "$src" "$out/bin/git-only-push" - '' diff --git a/users/sterni/git-only-push/git-only-push.sh b/users/sterni/git-only-push/git-only-push.sh deleted file mode 100755 index dd49204ea..000000000 --- a/users/sterni/git-only-push/git-only-push.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: Copyright (c) 2024 by sterni -# -# WARNING: This script is not well tested and may find a way to eat your commits. -# -# git only-push lets you push a specific range or list of commits to a remote -# ref based on a given revision (defaults to refs/remotes/origin/HEAD). This can -# be useful to push a subset of commits (that are ready for review) from a local -# commit chain to a PR branch (or gerrit style review ref). -# -# This is achieved by cherry-picking the relevant commits onto the base revision -# in a temporary worktree. For this the commits need to apply independently of -# prior commits not included in the selection, of course. -# -# git only-push is to be considered experimental. Its command line interface is -# janky and may be revised. - -set -eu - -die() { - printf '%s: %s\n' "$(basename "$0")" "$2" - exit "$1" -} - -usage() { - printf '%s\n' \ - "git only-push [-n] [-f] [-x] [-b ] -r -t [--] ..." \ - >&2 -} - -base=refs/remotes/origin/HEAD -dry=false - -# TODO(sterni): non-interactive mode, e.g. clean up also on cherry-pick failure -while getopts "b:r:t:nxfh" opt; do - case $opt in - # TODO(sterni): it is probably too close to --branch? - b) - base="$OPTARG" - ;; - t) - to="$OPTARG" - ;; - r) - remote="$OPTARG" - ;; - n) - dry=true - ;; - x) - cherry_pick_x=true - ;; - f) - # TODO(sterni): support --force-with-lease - push_f=true - ;; - h|?) - usage - # TODO(sterni): add man page - # shellcheck disable=SC2016 - [ "$opt" = "h" ] && printf ' -\t-r \tRemote to push to. -\t-t \tTarget ref to push to. -\t-b \tOptional: Base revision to cherry-pick commits onto. Defaults to refs/remotes/origin/HEAD. -\t-x\t\tUse `git cherry-pick -x` for creating cherry-picks. -\t-f\-\tForce push to remote ref. -\t-n\t\tDry run. -' - [ "$opt" = "h" ] && exit 0 || exit 100 - ;; - esac -done - -shift $((OPTIND - 1)) - -if [ -z "${to:-}" ]; then - usage - die 100 "Missing -t flag" -fi - -if [ -z "${remote:-}" ]; then - usage - die 100 "Missing -r flag" -fi - -if [ "$#" -eq 0 ]; then - usage - die 100 "Missing commits" -fi - -repo="$(git rev-parse --show-toplevel)" -worktree= - -cleanup() { - test -n "$worktree" && test -e "$worktree" \ - && git -C "$repo" worktree remove "$worktree" -} -trap cleanup EXIT - -if $dry; then - printf 'Would create worktree and checkout %s\n' "$base" >&2 -else - worktree="$(mktemp -d)" - git -C "$repo" worktree add "$worktree" "$base" -fi - -for arg in "$@"; do - # Resolve ranges, get them into chronological order - revs="$(git -C "$repo" rev-list --reverse --no-walk "$arg")" - - for rev in $revs; do - if $dry; then - printf 'Would cherry pick %s\n' "$rev" >&2 - else - no_cherry_pick=false - git -C "$worktree" cherry-pick ${cherry_pick_x:+-x} "$rev" || no_cherry_pick=true - if $no_cherry_pick; then - tmp="$worktree" - # Prevent cleanup from removing the worktree - worktree="" - die 101 "Could not cherry pick $rev. Please manually fixup worktree at $tmp" - fi - fi - done -done - -if $dry; then - printf 'Would push resulting HEAD to %s on %s\n' "$to" "$remote" >&2 -else - git -C "$worktree" push ${push_f:+-f} "$remote" "HEAD:$to" -fi diff --git a/users/sterni/htmlman/README.md b/users/sterni/htmlman/README.md deleted file mode 100644 index 258233d4c..000000000 --- a/users/sterni/htmlman/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# htmlman - -static site generator for man pages intended for -rendering man page documentation viewable using -a web browser. - -## usage - -If you have a nix expression, `doc.nix`, like this: - -```nix -{ depot, ... }: - -depot.users.sterni.htmlman { - title = "foo project"; - pages = [ - { - name = "foo"; - section = 1; - } - { - name = "foo"; - section = 3; - path = ../devman/foo.3; - } - ]; - manDir = ../man; -} -``` - -You can run the following to directly deploy the resulting -documentation output to a specific target directory: - -```sh -nix-build -A deploy doc.nix && ./result target_directory -``` diff --git a/users/sterni/htmlman/default.nix b/users/sterni/htmlman/default.nix deleted file mode 100644 index 6bf21ce2d..000000000 --- a/users/sterni/htmlman/default.nix +++ /dev/null @@ -1,268 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - inherit (depot.nix) - getBins - runExecline - yants - ; - - inherit (depot.tools) - cheddar - ; - - inherit (pkgs) - mandoc - coreutils - fetchurl - writers - ; - - bins = getBins cheddar [ "cheddar" ] - // getBins mandoc [ "mandoc" ] - // getBins coreutils [ "cat" "mv" "mkdir" ] - ; - - normalizeDrv = fetchurl { - url = "https://necolas.github.io/normalize.css/8.0.1/normalize.css"; - sha256 = "04jmvybwh2ks4dlnfa70sb3a3z3ig4cv0ya9rizjvm140xq1h22q"; - }; - - execlineStdoutInto = target: line: [ - "redirfd" - "-w" - "1" - target - ] ++ line; - - # I will not write a pure nix markdown renderer - # I will not write a pure nix markdown renderer - # I will not write a pure nix markdown renderer - # I will not write a pure nix markdown renderer - # I will not write a pure nix markdown renderer - markdown = md: - let - html = runExecline.local "rendered-markdown" - { - stdin = md; - } - ([ - "importas" - "-iu" - "out" - "out" - ] ++ execlineStdoutInto "$out" [ - bins.cheddar - "--about-filter" - "description.md" - ]); - in - builtins.readFile html; - - indexTemplate = { title, description, pages ? [ ] }: '' - - - - - ${title} - - - -
    -

    ${title}

    - ${markdown description} -

    man pages

    - -
    - - - ''; - - defaultStyle = import ./defaultStyle.nix { }; - - # This deploy script automatically copies the build result into - # a TARGET directory and marks it as writeable optionally. - # It is exposed as the deploy attribute of the result of - # htmlman, so an htmlman expression can be used like this: - # nix-build -A deploy htmlman.nix && ./result target_dir - deployScript = title: drv: writers.writeDash "deploy-${title}" '' - usage() { - printf 'Usage: %s [-w] TARGET\n\n' "$0" - printf 'Deploy htmlman documentation to TARGET directory.\n\n' - printf ' -h Display this help message\n' - printf ' -w Make TARGET directory writeable\n' - } - - if test "$#" -lt 1; then - usage - exit 100 - fi - - writeable=false - - while test "$#" -gt 0; do - case "$1" in - -h) - usage - exit 0 - ;; - -w) - writeable=true - ;; - -*) - usage - exit 100 - ;; - *) - if test -z "$target"; then - target="$1" - else - echo "Too many arguments" - exit 100 - fi - ;; - esac - - shift - done - - if test -z "$target"; then - echo "Missing TARGET" - usage - exit 100 - fi - - set -ex - - mkdir -p "$target" - cp -RTL --reflink=auto "${drv}" "$target" - - if $writeable; then - chmod -R +w "$target" - fi - ''; - - htmlman = - { title - # title of the index page - , description ? "" - # description which is displayed after - # the main heading on the index page - , pages ? [ ] - # man pages of the following structure: - # { - # name : string; - # section : int; - # path : either path string; - # } - # path is optional, if it is not given, - # the man page source must be located at - # "${manDir}/${name}.${toString section}" - , manDir ? null - # directory in which man page sources are located - , style ? defaultStyle - # CSS to use as a string - , normalizeCss ? true - # whether to include normalize.css before the custom CSS - , linkXr ? "all" - # How to handle cross references in the html output: - # - # * none: don't convert cross references into hyperlinks - # * all: link all cross references as if they were - # rendered into $out by htmlman - # * inManDir: link to all man pages which have their source - # in `manDir` and use the format string defined - # in linkXrFallback for all other cross references. - , linkXrFallback ? "https://manpages.debian.org/unstable/%N.%S.en.html" - # fallback link to use if linkXr == "inManDir" and the man - # page is not in ${manDir}. Placeholders %N (name of page) - # and %S (section of page) can be used. See mandoc(1) for - # more information. - }: - - let - linkXrEnum = yants.enum "linkXr" [ "all" "inManDir" "none" ]; - - index = indexTemplate { - inherit title description pages; - }; - - resolvePath = { path ? null, name, section }: - if path != null - then path - else "${manDir}/${name}.${toString section}"; - - mandocOpts = lib.concatStringsSep "," ([ - "style=style.css" - ] ++ linkXrEnum.match linkXr { - all = [ "man=./%N.%S.html" ]; - inManDir = [ "man=./%N.%S.html;${linkXrFallback}" ]; - none = [ ]; - }); - - html = - runExecline.local "htmlman-${title}" - { - derivationArgs = { - inherit index style; - passAsFile = [ "index" "style" ]; - }; - } - ([ - "multisubstitute" - [ - "importas" - "-iu" - "out" - "out" - "importas" - "-iu" - "index" - "indexPath" - "importas" - "-iu" - "style" - "stylePath" - ] - "if" - [ bins.mkdir "-p" "$out" ] - "if" - [ bins.mv "$index" "\${out}/index.html" ] - "if" - (execlineStdoutInto "\${out}/style.css" [ - "if" - ([ - bins.cat - ] ++ lib.optional normalizeCss normalizeDrv - ++ [ - "$style" - ]) - ]) - # let mandoc check for available man pages - "execline-cd" - "${manDir}" - ] ++ lib.concatMap - ({ name, section, ... }@p: - execlineStdoutInto "\${out}/${name}.${toString section}.html" [ - "if" - [ - bins.mandoc - "-mdoc" - "-T" - "html" - "-O" - mandocOpts - (resolvePath p) - ] - ]) - pages); - in - html // { - deploy = deployScript title html; - }; -in -htmlman diff --git a/users/sterni/htmlman/defaultStyle.nix b/users/sterni/htmlman/defaultStyle.nix deleted file mode 100644 index a44b5ef06..000000000 --- a/users/sterni/htmlman/defaultStyle.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ ... }: - -'' - body { - font-size: 1em; - line-height: 1.5; - font-family: serif; - background-color: #efefef; - } - - h1, h2, h3, h4, h5, h6 { - font-family: sans-serif; - font-size: 1em; - margin: 5px 0; - } - - h1 { - margin-top: 0; - } - - a:link, a:visited { - color: #3e7eff; - } - - h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - text-decoration: none; - } - - .manual-text, .index-text { - padding: 20px; - max-width: 800px; - background-color: white; - margin: 0 auto; - } - - table.head, table.foot { - display: none; - } - - .Nd { - display: inline; - } - - /* use same as cheddar for man pages */ - pre { - padding: 16px; - background-color: #f6f8fa; - } -'' diff --git a/users/sterni/keys.nix b/users/sterni/keys.nix deleted file mode 100644 index 0a422bc0d..000000000 --- a/users/sterni/keys.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ ... }: - -{ - all = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJk+KvgvI2oJTppMASNUfMcMkA2G5ZNt+HnWDzaXKLlo lukas@wolfgang" - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIZTrefeqOlXDz7nnDWw820+29vLgn6R3o4N1G3lRWrr lukas@ludwig" - ]; -} diff --git a/users/sterni/machines/.skip-subtree b/users/sterni/machines/.skip-subtree deleted file mode 100644 index a79762853..000000000 --- a/users/sterni/machines/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -Subdirectories are manually reexposed by default.nix as the contain NixOS modules diff --git a/users/sterni/machines/default.nix b/users/sterni/machines/default.nix deleted file mode 100644 index 7bf6db85d..000000000 --- a/users/sterni/machines/default.nix +++ /dev/null @@ -1,81 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - bins = depot.nix.getBins pkgs.nq [ "nqtail" "nq" ]; - - machines = lib.mapAttrs - (name: _: - depot.ops.nixos.nixosFor (import (./. + ("/" + name))) - ) - (lib.filterAttrs (_: type: type == "directory") (builtins.readDir ./.)); - - # TODO(sterni): share code with rebuild-system - localDeployScriptFor = { system, config, ... }: - pkgs.writeShellScript "local-deploy-${system.name}" '' - set -eu - if [[ "$(hostname)" != "${config.networking.hostName}" ]]; then - echo "$0: unexpected hostname: $(hostname). Are you deploying on the right machine?" - exit 1 - fi - nix-env -p /nix/var/nix/profiles/system --set "${system}" - "${system}/bin/switch-to-configuration" switch - ''; - - # Builds the system on the remote machine - deployScriptFor = { system, ... }@machine: - pkgs.writeShellScript "remote-deploy-${system.name}" '' - set -eu - - if [ $# != 1 ]; then - printf 'usage: %s [USER@]HOST' "$0" - exit 100 - fi - - readonly TARGET_HOST="$1" - readonly DEPLOY_DRV="${ - builtins.unsafeDiscardOutputDependency ( - # Wrapper script around localDeployScriptFor that merely starts the - # local deploy script using and nq and then waits using nqtail. This means - # we can't Ctrl-C the deploy and it won't be terminated by a lost - # connection. - pkgs.writeShellScript "queue-deploy-${system.name}" '' - readonly STATE_DIR="''${XDG_STATE_HOME:-$HOME/.local/state}/sterni-deploy" - mkdir -p "$STATE_DIR" - - export NQDIR="$STATE_DIR" - - "${bins.nq}" "${localDeployScriptFor machine}" - "${bins.nqtail}" - '' - ).drvPath - }" - - nix-copy-closure -s --gzip --to "$TARGET_HOST" "$DEPLOY_DRV" - - readonly DEPLOY_OUT="$(ssh "$TARGET_HOST" "nix-store -r '$DEPLOY_DRV'")" - - ssh "$TARGET_HOST" "$DEPLOY_OUT" - ''; - -in - -depot.nix.readTree.drvTargets ( - # this somehow becomes necessarily ugly with nixpkgs-fmt - machines // { inherit deployScriptFor; } // - - lib.mapAttrs' - (name: _: { - name = "${name}System"; - value = machines.${name}.system; - }) - machines - - // - - lib.mapAttrs' - (name: _: { - name = "${name}Deploy"; - value = deployScriptFor machines.${name}; - }) - machines -) diff --git a/users/sterni/machines/ingeborg/default.nix b/users/sterni/machines/ingeborg/default.nix deleted file mode 100644 index b4516a3c6..000000000 --- a/users/sterni/machines/ingeborg/default.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ config, lib, pkgs, depot, ... }: - -{ - imports = [ - # Third party modules - "${depot.third_party.agenix.src}/modules/age.nix" - # Basic settings - ../../modules/common.nix - # These modules touch things related to booting (filesystems, initrd network…) - ./hardware.nix - ./network.nix - # (More or less) pluggable service configuration - (depot.path.origSrc + "/ops/modules/btrfs-auto-scrub.nix") - ./monitoring.nix - ./minecraft.nix - ./http/sterni.lv.nix - ./http/code.sterni.lv.nix - ./http/flipdot.openlab-augsburg.de.nix - ./tv.nix - ./quassel.nix - - # Inactive: - # ./http/likely-music.sterni.lv.nix - - # TODO(sterni): fail2ban - # TODO(sterni): automatic backups for full recovery - ]; - - config = { - system.stateVersion = "24.05"; - }; -} diff --git a/users/sterni/machines/ingeborg/hardware.nix b/users/sterni/machines/ingeborg/hardware.nix deleted file mode 100644 index d1085ebe1..000000000 --- a/users/sterni/machines/ingeborg/hardware.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ config, lib, pkgs, depot, ... }: - -{ - # Booting / Kernel - boot = { - loader.grub = { - enable = true; - devices = [ - "/dev/disk/by-id/wwn-0x5000c500a4859731" - "/dev/disk/by-id/wwn-0x5000c500a485c1b5" - ]; - }; - - initrd = { - availableKernelModules = [ - "ahci" - "btrfs" - "sd_mod" - "xhci_pci" - "e1000e" - "usbhid" - ]; - kernelModules = [ - "dm-snapshot" - ]; - }; - - swraid = { - enable = true; - mdadmConf = '' - ARRAY /dev/md/boot-raid metadata=1.2 name=nixos:boot-raid UUID=13007b9d:ab7a1129:c45ec40f:3c9f2111 - ARRAY /dev/md/encrypted-container-raid metadata=1.2 name=nixos:encrypted-container-raid UUID=38dfa683:a6d30690:32a5de6f:fb7980fe - ''; - }; - - kernelModules = [ - "kvm-intel" - ]; - }; - - # Filesystems - services.lvm.enable = true; - - boot.initrd.luks.devices."container" = { - device = "/dev/md/encrypted-container-raid"; - preLVM = true; - }; - - fileSystems = { - "/" = { - device = "/dev/mainvg/root"; - fsType = "btrfs"; - }; - - "/boot" = { - device = "/dev/disk/by-label/boot"; - fsType = "ext4"; - }; - }; - - swapDevices = [ - { device = "/dev/mainvg/swap"; } - ]; - - # CPU - hardware = { - cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - enableRedistributableFirmware = true; - }; - - nix.settings = { - max-jobs = 2; - cores = 4; - }; - - powerManagement.cpuFreqGovernor = "performance"; -} diff --git a/users/sterni/machines/ingeborg/http/code.sterni.lv.nix b/users/sterni/machines/ingeborg/http/code.sterni.lv.nix deleted file mode 100644 index 40ff85b53..000000000 --- a/users/sterni/machines/ingeborg/http/code.sterni.lv.nix +++ /dev/null @@ -1,287 +0,0 @@ -{ depot, pkgs, lib, config, ... }: - -let - virtualHost = "code.sterni.lv"; - - repoSections = [ - { - section = "active"; - repos = { - spacecookie = { - description = "gopher server (and library for Haskell)"; - upstream = "https://github.com/sternenseemann/spacecookie.git"; - }; - "mirror/depot" = { - description = "monorepo for the virus lounge"; - upstream = "https://code.tvl.fyi/depot.git"; - cgit.defbranch = "canon"; - }; - "mirror/flipdot-gschichtler" = { - description = "message queue system for OpenLab's flipdot display"; - upstream = "https://github.com/openlab-aux/flipdot-gschichtler.git"; - }; - "mirror/nixpkgs" = { - description = "Nix packages collection"; - upstream = "https://github.com/nixos/nixpkgs.git"; - cgit.enable-commit-graph = "0"; # too slow - }; - "mirror/vuizvui" = { - description = "Nix(OS) expressions used by the OpenLab and its members"; - upstream = "https://github.com/openlab-aux/vuizvui.git"; - }; - }; - } - { - section = "poc"; - repos = { - emoji-generic = { - description = "generic emoji library for Haskell"; - upstream = "https://github.com/sternenseemann/emoji-generic.git"; - }; - grav2ty = { - description = "“realistic” 2d space game"; - upstream = "https://github.com/sternenseemann/grav2ty.git"; - }; - haskell-dot-time = { - description = "UTC-centric time library for haskell with dot time support"; - cgit.defbranch = "main"; - }; - buchstabensuppe = { - description = "toy font rendering for low pixelcount, high contrast displays"; - upstream = "https://github.com/sternenseemann/buchstabensuppe.git"; - cgit.defbranch = "main"; - }; - "mirror/saneterm" = { - description = "modern line-oriented terminal emulator without support for TUIs"; - upstream = "https://git.8pit.net/saneterm.git"; - }; - }; - } - { - # TODO(sterni): resisort, klammeraffe, cl-ca, ponify, tinyrl - section = "archive"; - repos = { - gopher-proxy = { - description = "Gopher over HTTP proxy"; - upstream = "https://github.com/sternenseemann/gopher-proxy.git"; - }; - likely-music = { - description = "experimental application for probabilistic music composition"; - upstream = "https://github.com/sternenseemann/likely-music.git"; - }; - logbook = { - description = "file format for keeping a personal log"; - upstream = "https://github.com/sternenseemann/logbook.git"; - }; - sternenblog = { - description = "file based cgi blog software"; - upstream = "https://github.com/sternenseemann/sternenblog.git"; - }; - }; - } - ]; - - repoPath = name: repo: repo.path or "/srv/git/${name}.git"; - - cgitRepoEntry = name: repo: - lib.concatStringsSep "\n" ( - [ - "repo.url=${name}" - "repo.path=${repoPath name repo}" - ] - ++ lib.optional (repo ? description) "repo.desc=${repo.description}" - ++ lib.mapAttrsToList (n: v: "repo.${n}=${v}") repo.cgit or { } - ); - - cgitHead = pkgs.writeText "cgit-head.html" '' - - ''; - - cgitConfig = pkgs.writeText "cgitrc" '' - virtual-root=/ - - enable-http-clone=1 - clone-url=https://${virtualHost}/$CGIT_REPO_URL - - enable-blame=1 - enable-log-filecount=1 - enable-log-linecount=1 - enable-index-owner=0 - enable-blame=1 - enable-commit-graph=1 - - robots=noindex,nofollow - - root-title=code.sterni.lv - root-desc= - css=/cgit.css - head-include=${cgitHead} - - mimetype-file=${pkgs.mime-types}/etc/mime.types - - noplainemail=1 - - about-filter=${depot.tools.cheddar.about-filter}/bin/cheddar-about - source-filter=${depot.tools.cheddar}/bin/cheddar - readme=:README.md - readme=:readme.md - - section-sort=0 - ${ - lib.concatMapStringsSep "\n" (section: - '' - section=${section.section} - - '' - + builtins.concatStringsSep "\n\n" (lib.mapAttrsToList cgitRepoEntry section.repos) - ) repoSections - } - ''; - - /* Merge a list of attrs, but fail when the same attribute occurs twice. - - Type: [ attrs ] -> attrs - */ - mergeManyDistinctAttrs = lib.foldAttrs - ( - val: nul: - if nul == null then val else throw "Every attribute name may occur only once" - ) - null; - - flatRepos = mergeManyDistinctAttrs - (builtins.map (section: section.repos) repoSections); - - reposToMirror = lib.filterAttrs (_: repo: repo ? upstream) flatRepos; - - # User and group name used for running the mirror scripts - mirroredReposOwner = "git"; - - # Make repo name suitable for systemd unit/timer - unitName = name: "mirror-${lib.strings.sanitizeDerivationName name}"; -in - -{ - imports = [ - ./nginx.nix - ]; - - config = { - services.fcgiwrap.instances.cgit = { - process = { - user = "http"; - group = "http"; - }; - socket = { - user = "http"; - group = "http"; - }; - }; - - services.nginx.virtualHosts."${virtualHost}" = { - enableACME = true; - forceSSL = true; - root = "${pkgs.cgit-pink}/cgit/"; - extraConfig = '' - try_files $uri @cgit; - - # Note this overrides the default robots.txt cgit-pink ships - location = /robots.txt { - add_header Content-Type text/plain; - return 200 "User-agent: *\nDisallow: /\n"; - } - - location @cgit { - include ${pkgs.nginx}/conf/fastcgi_params; - fastcgi_param SCRIPT_FILENAME ${pkgs.cgit-pink}/cgit/cgit.cgi; - fastcgi_param PATH_INFO $uri; - fastcgi_param QUERY_STRING $args; - fastcgi_param HTTP_HOST $server_name; - fastcgi_param CGIT_CONFIG ${cgitConfig}; - fastcgi_pass unix:${toString config.services.fcgiwrap.instances.cgit.socket.address}; - } - ''; - }; - - users = { - users.${mirroredReposOwner} = { - group = mirroredReposOwner; - isSystemUser = true; - }; - - groups.${mirroredReposOwner} = { }; - }; - - - systemd.timers = lib.mapAttrs' - ( - name: repo: - { - name = unitName name; - value = { - description = "regularly update mirror git repository ${name}"; - wantedBy = [ "timers.target" ]; - enable = true; - timerConfig = { - # Fire every 6h and distribute the workload over next 6h randomly - OnCalendar = "*-*-* 00/6:00:00"; - RandomizedDelaySec = "6h"; - Persistent = true; - }; - }; - } - ) - reposToMirror; - - systemd.services = lib.mapAttrs' - ( - name: repo: - { - name = unitName name; - value = { - description = "mirror git repository ${name}"; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - - script = - let - path = repoPath name repo; - in - '' - set -euo pipefail - - export PATH="${lib.makeBinPath [ pkgs.coreutils pkgs.git ]}" - - if test ! -d "${path}"; then - mkdir -p "$(dirname "${path}")" - git clone --mirror "${repo.upstream}" "${path}" - exit 0 - fi - - cd "${path}" - - git fetch "${repo.upstream}" '+refs/*:refs/*' --prune - - # no auto gc here and we're not pruning for nothing… - git gc - ''; - - serviceConfig = { - Type = "oneshot"; - User = mirroredReposOwner; - Group = mirroredReposOwner; - }; - }; - } - ) - reposToMirror; - }; -} diff --git a/users/sterni/machines/ingeborg/http/flipdot.openlab-augsburg.de.nix b/users/sterni/machines/ingeborg/http/flipdot.openlab-augsburg.de.nix deleted file mode 100644 index c86956a0a..000000000 --- a/users/sterni/machines/ingeborg/http/flipdot.openlab-augsburg.de.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ depot, lib, config, ... }: - -let - inherit (depot.users.sterni.external.flipdot-gschichtler) - bahnhofshalle - warteraum - nixosModule - ; -in - -{ - imports = [ - nixosModule - ./nginx.nix - ]; - - config = { - age.secrets = lib.genAttrs [ - "warteraum-salt" - "warteraum-tokens" - ] - (name: { - file = depot.users.sterni.secrets."${name}.age"; - }); - - services.flipdot-gschichtler = { - enable = true; - virtualHost = "flipdot.openlab-augsburg.de"; - packages = { - inherit bahnhofshalle warteraum; - }; - saltFile = config.age.secretsDir + "/warteraum-salt"; - tokensFile = config.age.secretsDir + "/warteraum-tokens"; - }; - }; -} diff --git a/users/sterni/machines/ingeborg/http/likely-music.sterni.lv.nix b/users/sterni/machines/ingeborg/http/likely-music.sterni.lv.nix deleted file mode 100644 index 8da03ac5e..000000000 --- a/users/sterni/machines/ingeborg/http/likely-music.sterni.lv.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.users.sterni.external.likely-music) - nixosModule - likely-music - ; -in - -{ - imports = [ - ./nginx.nix - nixosModule - ]; - - config = { - services.likely-music = { - enable = true; - virtualHost = "likely-music.sterni.lv"; - package = likely-music; - }; - }; -} diff --git a/users/sterni/machines/ingeborg/http/nginx.nix b/users/sterni/machines/ingeborg/http/nginx.nix deleted file mode 100644 index d551b8391..000000000 --- a/users/sterni/machines/ingeborg/http/nginx.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ ... }: - -{ - config = { - users = { - users.http = { - isSystemUser = true; - group = "http"; - }; - - groups.http = { }; - }; - - services.nginx = { - enable = true; - recommendedTlsSettings = true; - recommendedGzipSettings = true; - recommendedProxySettings = true; - - user = "http"; - group = "http"; - - appendHttpConfig = '' - charset utf-8; - ''; - }; - - networking.firewall.allowedTCPPorts = [ 80 443 ]; - }; -} diff --git a/users/sterni/machines/ingeborg/http/sterni.lv.nix b/users/sterni/machines/ingeborg/http/sterni.lv.nix deleted file mode 100644 index 870a71983..000000000 --- a/users/sterni/machines/ingeborg/http/sterni.lv.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ pkgs, depot, ... }: - -let - inherit (depot.users.sterni.nix.html) - __findFile - ; -in - -{ - imports = [ - ./nginx.nix - ]; - - config = { - services.nginx.virtualHosts."sterni.lv" = { - enableACME = true; - forceSSL = true; - root = depot.users.sterni.nix.build.website "sterni.lv" { } { - "index.html" = { ... }: pkgs.writeText "index.html" ( - { } [ - ( { } [ - ( { charset = "utf-8"; } null) - ( { } "no thoughts") - ]) - (<body> { } "🦩") - ] - ); - }; - # TODO(sterni): tmp.sterni.lv - locations."/tmp/".root = toString /srv/http; - extraConfig = '' - location = /robots.txt { - add_header Content-Type text/plain; - return 200 "User-agent: *\nDisallow: /tmp\n"; - } - ''; - }; - }; -} diff --git a/users/sterni/machines/ingeborg/irccat.nix b/users/sterni/machines/ingeborg/irccat.nix deleted file mode 100644 index 0c40f15e3..000000000 --- a/users/sterni/machines/ingeborg/irccat.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ depot, config, pkgs, lib, ... }: - -{ - imports = [ - (depot.path.origSrc + "/ops/modules/irccat.nix") - ]; - - config = { - services.depot.irccat = { - enable = true; - secretsFile = builtins.toFile "empty.json" "{}"; # TODO(sterni): register - config = { - tcp.listen = ":4722"; # ircc - irc = { - server = "irc.hackint.org:6697"; - tls = true; - nick = config.networking.hostName; - realname = "irccat"; - }; - }; - }; - }; -} diff --git a/users/sterni/machines/ingeborg/minecraft.nix b/users/sterni/machines/ingeborg/minecraft.nix deleted file mode 100644 index 0ca892d4c..000000000 --- a/users/sterni/machines/ingeborg/minecraft.nix +++ /dev/null @@ -1,127 +0,0 @@ -{ pkgs, depot, config, ... }: - -let - carpet = pkgs.fetchurl { - url = "https://github.com/gnembon/fabric-carpet/releases/download/1.4.158/fabric-carpet-1.21.2-1.4.158+v241022.jar"; - sha256 = "0c76r0gz7nyn91k86flvwpbbypw5v41iib7kkvbyjb84aaafb8ap"; - }; - - carpet-extra = pkgs.fetchurl { - url = "https://github.com/gnembon/carpet-extra/releases/download/1.4.158/carpet-extra-1.21.2-1.4.158.jar"; - sha256 = "083zifzpdgl7xxd989nm1svrrqxl4fmv7wxna10cyipg6jjabjq1"; - }; - - userGroup = "minecraft"; - - makeJvmOpts = megs: [ - "-Xms${toString megs}M" - "-Xmx${toString megs}M" - ]; - - whitelist = { - spreadwasser = "242a66eb-2df2-4585-9a28-ac763ad0d0f9"; - sternenseemann = "d8e48069-1905-4886-a5da-a4ee917ee254"; - }; - - rconPasswordFile = config.age.secretsDir + "/minecraft-rcon"; - - baseProperties = { - white-list = true; - allow-flight = true; - difficulty = "hard"; - function-permission-level = 4; - snooper-enabled = false; - # TODO(sterni): replaced (?) by simulation-distance which defaults to 1 - view-distance = 12; - sync-chunk-writes = "false"; # the single biggest performance fix - max-tick-time = 6000000; # TODO(sterni): disable watchdog via carpet - enforce-secure-profile = false; - # TODO(sterni): set disable pause-when-empty-seconds? we don't have anything in spawn though. - }; -in - -{ - imports = [ - ../../modules/minecraft-fabric.nix - ../../modules/backup-minecraft-fabric.nix - ]; - - config = { - environment.systemPackages = [ - pkgs.mcrcon - pkgs.jre - ]; - - users = { - users."${userGroup}" = { - isNormalUser = true; - openssh.authorizedKeys.keys = depot.users.sterni.keys.all; - shell = "${pkgs.fish}/bin/fish"; - }; - - groups."${userGroup}" = { }; - }; - - age.secrets = { - minecraft-rcon.file = depot.users.sterni.secrets."minecraft-rcon.age"; - }; - - services.backup-minecraft-fabric-servers = { - enable = true; - repository = "/srv/backup/from-local/minecraft"; - }; - - services.minecraft-fabric-server = { - creative = { - enable = false; # not actively used - version = "1.21.3"; - mods = [ - carpet - carpet-extra - ]; - world = config.users.users.${userGroup}.home + "/worlds/creative"; - - jvmOpts = makeJvmOpts 2048; - user = userGroup; - group = userGroup; - - inherit whitelist rconPasswordFile; - ops = whitelist; - - serverProperties = baseProperties // { - server-port = 25566; - "rcon.port" = 25576; - gamemode = "creative"; - enable-command-block = true; - motd = "storage design server"; - spawn-protection = 2; - }; - }; - - carpet = { - enable = true; - version = "1.21.3"; - mods = [ - carpet - carpet-extra - ]; - world = config.users.users.${userGroup}.home + "/worlds/carpet"; - - jvmOpts = makeJvmOpts 4096; - user = userGroup; - group = userGroup; - - inherit whitelist rconPasswordFile; - ops = whitelist; - - serverProperties = baseProperties // { - server-port = 25565; - "rcon.port" = 25575; - motd = "ich tu fleissig hustlen nenn mich bob der baumeister"; - - level-seed = 7240251176989694927; # for posterity - }; - }; - }; - }; -} diff --git a/users/sterni/machines/ingeborg/monitoring.nix b/users/sterni/machines/ingeborg/monitoring.nix deleted file mode 100644 index a29838954..000000000 --- a/users/sterni/machines/ingeborg/monitoring.nix +++ /dev/null @@ -1,189 +0,0 @@ -{ pkgs, lib, config, depot, ... }: - -let - ircChannel = "#sterni.lv"; - irccatPort = - builtins.replaceStrings [ ":" ] [ "" ] - config.services.depot.irccat.config.tcp.listen; - - send-irc-msg = pkgs.writeShellScript "send-irc-msg" '' - set -euo pipefail - printf '%s %s\n' ${lib.escapeShellArg ircChannel} "$1" | \ - ${lib.getBin pkgs.netcat-openbsd}/bin/nc -N localhost ${irccatPort} - ''; - - netdataPort = 19999; -in - -{ - imports = [ - ./http/nginx.nix - ./irccat.nix - ]; - - config = { - services.depot.irccat.config.irc.channels = [ - ircChannel - ]; - - # Since we have irccat we can wire up mdadm --monitor - boot.swraid.mdadmConf = '' - PROGRAM ${ - pkgs.writeShellScript "mdmonitor-to-irc" '' - ${send-irc-msg} "mdmonitor: $1($2''${3:+, $3})" - '' - } - ''; - - # Based on nixos/modules/services/monitoring/smard.nix which has a much - # too specific smartd-notify.sh (and I'm too lazy to propose a redesign) - systemd.services.smartd = { - description = "S.M.A.R.T. Daemon"; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "notify"; - ExecStart = - let - smartdNotify = pkgs.writeShellScript "smartd-notify.sh" '' - ${send-irc-msg} "smartd: $SMARTD_FAILTYPE($SMARTD_DEVICE): $SMARTD_MESSAGE" - ''; - smartdConf = pkgs.writeText "smartd.conf" ( - # Short self test every day 03:00 - # Long self test every tuesday 05:00 - lib.concatMapStrings - (d: '' - ${d} -m <nomailer> -M exec ${smartdNotify} -a -o on -s (S/../.././03|L/../../2/05) - '') - [ "DEFAULT" "DEVICESCAN" ] - ); - in - lib.concatStringsSep " " [ - "${pkgs.smartmontools}/sbin/smartd" - "-A" - "/var/log/smartd" - "--no-fork" - "--configfile=${smartdConf}" - ]; - }; - }; - - services = { - netdata = { - enable = true; - config = { - logs = { - access = "syslog"; - error = "syslog"; - debug = "syslog"; - health = "syslog"; - collector = "syslog"; - }; - web = { - "default port" = toString netdataPort; - "bind to" = "localhost:${toString netdataPort}"; - }; - health = { - "script to execute on alarm" = pkgs.writeShellScript "simple-alarm-notify" '' - set -euo pipefail - - # This humongous list is copied over from netdata's alarm-notify.sh - roles="''${1}" # the roles that should be notified for this event - args_host="''${2}" # the host generated this event - unique_id="''${3}" # the unique id of this event - alarm_id="''${4}" # the unique id of the alarm that generated this event - event_id="''${5}" # the incremental id of the event, for this alarm id - when="''${6}" # the timestamp this event occurred - name="''${7}" # the name of the alarm, as given in netdata health.d entries - chart="''${8}" # the name of the chart (type.id) - status="''${9}" # the current status : REMOVED, UNINITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL - old_status="''${10}" # the previous status: REMOVED, UNINITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL - value="''${11}" # the current value of the alarm - old_value="''${12}" # the previous value of the alarm - src="''${13}" # the line number and file the alarm has been configured - duration="''${14}" # the duration in seconds of the previous alarm state - non_clear_duration="''${15}" # the total duration in seconds this is/was non-clear - units="''${16}" # the units of the value - info="''${17}" # a short description of the alarm - value_string="''${18}" # friendly value (with units) - # shellcheck disable=SC2034 - # variable is unused, but https://github.com/netdata/netdata/pull/5164#discussion_r255572947 - old_value_string="''${19}" # friendly old value (with units), previously named "old_value_string" - calc_expression="''${20}" # contains the expression that was evaluated to trigger the alarm - calc_param_values="''${21}" # the values of the parameters in the expression, at the time of the evaluation - total_warnings="''${22}" # Total number of alarms in WARNING state - total_critical="''${23}" # Total number of alarms in CRITICAL state - total_warn_alarms="''${24}" # List of alarms in warning state - total_crit_alarms="''${25}" # List of alarms in critical state - classification="''${26}" # The class field from .conf files - edit_command_line="''${27}" # The command to edit the alarm, with the line number - child_machine_guid="''${28}" # the machine_guid of the child - transition_id="''${29}" # the transition_id of the alert - summary="''${30}" # the summary text field of the alert - - # Verify that they haven't extended the arg list - ARG_COUNT_EXPECTED=30 - - if [[ "$#" != "$ARG_COUNT_EXPECTED" ]]; then - echo "$0: WARNING: unexpected number of arguments: $#. Did netdata add more?" >&2 - fi - - MSG="netdata: $status ''${name//_/ } ($chart): ''${summary//_/ } = $value_string" - - # Filter rules by chart name. This is necessary, since the "enabled alarms" - # filter only allows for filtering alarm types, not specific alarms - # belonging to that alarm. - case "$chart" in - # netdata prefers the automatically assigned names (dm-<n>, md<n>, - # sd<c>) over ids for alerts, so this configuration assumes that - # we have two physical disks which we kind of assert using the - # grub configuration (it is more difficult with the soft raid - # config). - # ${assert builtins.length config.boot.loader.grub.devices == 2; ""} - disk_util.sda | disk_util.sdb | disk_backlog.sda | disk_backlog.sdb) - - ;; - disk_util.* | disk_backlog.*) - echo "$0: INFO: DISCARDING message: $MSG" >&2 - exit 0 - ;; - *) - ;; - esac - - echo "$0: INFO: sending message: $MSG" >&2 - ${send-irc-msg} "$MSG" - ''; - }; - }; - }; - - # https://learn.netdata.cloud/docs/netdata-agent/configuration/running-the-netdata-agent-behind-a-reverse-proxy/nginx - nginx.virtualHosts."monitoring.sterni.lv" = { - forceSSL = true; - enableACME = true; - extraConfig = '' - auth_basic "netdata"; - auth_basic_user_file ${config.age.secretsDir}/netdata-htpasswd; - - location / { - proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Server $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_pass http://127.0.0.1:${toString netdataPort}; - proxy_http_version 1.1; - proxy_pass_request_headers on; - proxy_set_header Connection "keep-alive"; - proxy_store off; - } - ''; - }; - }; - - age.secrets.netdata-htpasswd = { - file = depot.users.sterni.secrets."netdata-htpasswd.age"; - inherit (config.services.nginx) group; - owner = config.services.nginx.user; - mode = "700"; - }; - }; -} diff --git a/users/sterni/machines/ingeborg/network.nix b/users/sterni/machines/ingeborg/network.nix deleted file mode 100644 index 2e8731389..000000000 --- a/users/sterni/machines/ingeborg/network.nix +++ /dev/null @@ -1,69 +0,0 @@ -{ config, pkgs, lib, depot, ... }: - -let - ipv6 = "2a01:4f9:2a:1bc6::/64"; - - ipv4 = "95.216.27.158"; - gatewayv4 = "95.216.27.129"; - netmaskv4 = "255.255.255.192"; -in - -{ - config = { - boot = { - kernelParams = [ - "ip=${ipv4}::${gatewayv4}:${netmaskv4}::eth0:none" - ]; - - initrd.network = { - enable = true; - ssh = { - # ssh_config: - # Host ingeborg-unlock - # User root - # HostName ingeborg.sterni.lv - # AddressFamily inet # kernel commandline only gives ipv4 - # Port 22 - # UserKnownHostsFile /home/lukas/.ssh/initrd_known_hosts - enable = true; - authorizedKeys = depot.users.sterni.keys.all; - hostKeys = [ - "/etc/nixos/unlock_rsa_key_openssh" - "/etc/nixos/unlock_ed25519_key_openssh" - ]; - }; - postCommands = '' - echo 'cryptsetup-askpass' >> /root/.profile - ''; - }; - }; - - networking = { - usePredictableInterfaceNames = false; - useDHCP = false; - interfaces."eth0".useDHCP = false; - - hostName = "ingeborg"; - - firewall = { - enable = true; - allowPing = true; - allowedTCPPorts = [ 22 ]; - }; - }; - - systemd.network = { - enable = true; - networks."eth0".extraConfig = '' - [Match] - Name = eth0 - - [Network] - Address = ${ipv6} - Gateway = fe80::1 - Address = ${ipv4}/27 - Gateway = ${gatewayv4} - ''; - }; - }; -} diff --git a/users/sterni/machines/ingeborg/quassel.nix b/users/sterni/machines/ingeborg/quassel.nix deleted file mode 100644 index cd8dacc91..000000000 --- a/users/sterni/machines/ingeborg/quassel.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ depot, ... }: - -{ - imports = [ - (depot.path.origSrc + "/ops/modules/quassel.nix") - ]; - - config = { - services.depot.quassel = { - enable = true; - acmeHost = "sterni.lv"; - bindAddresses = [ - "0.0.0.0" - "::" - ]; - }; - }; -} diff --git a/users/sterni/machines/ingeborg/tv.nix b/users/sterni/machines/ingeborg/tv.nix deleted file mode 100644 index 016ad256e..000000000 --- a/users/sterni/machines/ingeborg/tv.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ pkgs, ... }: - -{ - config = { - # TODO(sterni): smb or nfs may be a faster alternative? - services.openssh.allowSFTP = true; - - users.users.tv = { - group = "users"; - isNormalUser = true; - }; - }; -} diff --git a/users/sterni/mblog/.gitignore b/users/sterni/mblog/.gitignore deleted file mode 100644 index ae957fcad..000000000 --- a/users/sterni/mblog/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# local test data -test-msg - -# sly C-c C-k -*.fasl diff --git a/users/sterni/mblog/LICENSE b/users/sterni/mblog/LICENSE deleted file mode 100644 index f288702d2..000000000 --- a/users/sterni/mblog/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - <program> Copyright (C) <year> <name of author> - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<https://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<https://www.gnu.org/licenses/why-not-lgpl.html>. diff --git a/users/sterni/mblog/cli.lisp b/users/sterni/mblog/cli.lisp deleted file mode 100644 index 5046db40d..000000000 --- a/users/sterni/mblog/cli.lisp +++ /dev/null @@ -1,75 +0,0 @@ -;; SPDX-License-Identifier: GPL-3.0-only -;; SPDX-FileCopyrightText: Copyright (C) 2022-2024 by sterni - -(in-package :cli) -(declaim (optimize (safety 3))) - -;; TODO(sterni): nicer messages for various errors signaled? - -(defun partition-by (f seq) - "Split SEQ into two lists, returned as multiple values. The first list - contains all elements for which F returns T, the second one the remaining - elements." - (loop for x in seq - if (funcall f x) - collecting x into yes - else - collecting x into no - finally (return (values yes no)))) - -(defparameter +help+ '(("mnote-html" . "FILE [FILE [ ... ]]") - ("mblog" . "MAILDIR OUT"))) - -(defun mnote-html (name flags &rest args) - "Convert all note mime messages given as ARGS to HTML fragments." - (declare (ignore name flags)) - (loop for arg in args - do (mail-note-html-fragment - (make-mail-note (mime:mime-message (pathname arg))) - *standard-output*))) - -(defun mblog (name flags maildir outdir) - "Read a MAILDIR and build an mblog in OUTDIR " - (declare (ignore name flags)) - (build-mblog (pathname maildir) (pathname outdir))) - -(defun display-help (name flags &rest args) - "Print help message for current executable." - (declare (ignore args flags)) - (format *error-output* "Usage: ~A ~A~%" - name - (or (cdr (assoc name +help+ :test #'string=)) - (concatenate 'string "Unknown executable: " name)))) - -(defun usage-error (name flags &rest args) - "Print help and exit with a non-zero exit code." - (format *error-output* "~A: usage error~%" name) - (display-help name args flags) - (uiop:quit 100)) - -(defun main () - "Dispatch to correct main function based on arguments and UIOP:ARGV0." - (config:init-from-env) - (multiple-value-bind (flags args) - (partition-by (lambda (x) (starts-with #\- x)) - (uiop:command-line-arguments)) - - (let ((prog-name (pathname-name (pathname (uiop:argv0)))) - (help-requested-p (find-if (lambda (x) - (member x '("-h" "--help" "--usage") - :test #'string=)) - flags))) - (apply - (if help-requested-p - #'display-help - (cond - ((and (string= prog-name "mnote-html") - (null flags)) - #'mnote-html) - ((and (string= prog-name "mblog") - (null flags) - (= 2 (length args))) - #'mblog) - (t #'usage-error))) - (append (list prog-name flags) - args))))) diff --git a/users/sterni/mblog/config.lisp b/users/sterni/mblog/config.lisp deleted file mode 100644 index 0d4cbfe8a..000000000 --- a/users/sterni/mblog/config.lisp +++ /dev/null @@ -1,31 +0,0 @@ -;; SPDX-License-Identifier: GPL-3.0-only -;; SPDX-FileCopyrightText: Copyright (C) 2023 by sterni - -(in-package :config) - -(eval-when (:compile-toplevel :load-toplevel) - (defun plist-to-alist (lst) - (loop for (name . (default . (parser . nil))) on lst by #'cdddr - collect (cons name (list default parser)))) - - (defun symbol-to-env-var-name (symbol) - (concatenate 'string - "MBLOG_" - (string-upcase - (remove #\* (substitute #\_ #\- (string symbol))))))) - -(defmacro define-configuration-variables (&rest args) - (let ((vars (plist-to-alist args)) - (val-var-sym (gensym))) - `(progn - ,@(loop for (name . (default nil)) in vars - collect `(defvar ,name ,default)) - - (defun init-from-env () - ,@(loop for (name . (nil parser)) in vars - collect - `(when-let ((,val-var-sym (getenv ,(symbol-to-env-var-name name)))) - (setf ,name (funcall ,parser ,val-var-sym)))))))) - -(define-configuration-variables - *general-buffer-size* (min 4096 qbase64:+max-bytes-length+) #'parse-integer) diff --git a/users/sterni/mblog/default.nix b/users/sterni/mblog/default.nix deleted file mode 100644 index c3c19591e..000000000 --- a/users/sterni/mblog/default.nix +++ /dev/null @@ -1,45 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-only -# SPDX-FileCopyrightText: Copyright (C) 2022-2024 by sterni -{ depot, pkgs, ... }: - -(depot.nix.buildLisp.program { - name = "mblog"; - - srcs = [ - ./packages.lisp - ./config.lisp - ./maildir.lisp - ./mail-note/html-transformer.lisp - ./mail-note/note.lisp - ./mblog.lisp - ./cli.lisp - ]; - - deps = [ - { - sbcl = depot.nix.buildLisp.bundled "uiop"; - default = depot.nix.buildLisp.bundled "asdf"; - } - depot.lisp.klatre - depot.third_party.lisp.alexandria - depot.third_party.lisp.closure-html - depot.third_party.lisp.cl-date-time-parser - depot.third_party.lisp.cl-who - depot.third_party.lisp.local-time - depot.third_party.lisp.mime4cl - ]; - - main = "cli:main"; - - brokenOn = [ - "ecl" # closure-common fails to start up - ]; -}).overrideAttrs (super: { - # The built binary dispatches based on argv[0]. Building two executables would - # waste a lot of space. - buildCommand = '' - ${super.buildCommand} - - ln -s "$out/bin/mblog" "$out/bin/mnote-html" - ''; -}) diff --git a/users/sterni/mblog/golden/default.nix b/users/sterni/mblog/golden/default.nix deleted file mode 100644 index a35cb5b21..000000000 --- a/users/sterni/mblog/golden/default.nix +++ /dev/null @@ -1,44 +0,0 @@ -# SPDX-License-Identifier: GPL-3.0-only -# SPDX-FileCopyrightText: Copyright (C) 2024 by sterni -{ depot, pkgs, lib, ... }: - -let - maildir = pkgs.runCommandNoCC "mblog-golden-example-maildir" { } '' - mkdir -p "$out/cur" - cp --reflink=auto \ - "${depot.path.origSrc + "/third_party/lisp/mime4cl/test/samples/mail-note-from-notes-app.msg"}" \ - "$out/cur/1732277542.274467_1.wolfgang,U=1:2,S" - cp --reflink=auto \ - "${depot.path.origSrc + "/third_party/lisp/mime4cl/test/samples/mail-note-from-notemap.msg"}" \ - "$out/cur/1735167350.823243_1.wolfgang,U=32:2,S" - ''; - - # Make golden test based on the given mblog derivation and add subtarget - # golden tests for all meta.ci.targets. - makeGoldenTest = mblog: - pkgs.runCommand "mblog-golden-tests" - { - passthru = { - inherit maildir; - } // lib.mapAttrs (_: makeGoldenTest) ( - lib.attrsets.getAttrs mblog.meta.ci.targets mblog - ); - - nativeBuildInputs = [ - mblog - ]; - - meta.ci = { - inherit (mblog.meta.ci) targets; - }; - } - '' - mkdir -p actual - mblog ${maildir} actual - - diff --color=always -ru ${./expected} actual - touch "$out" - ''; -in - -makeGoldenTest depot.users.sterni.mblog diff --git a/users/sterni/mblog/golden/expected/d2ccdc74-830c-41ee-9d64-2221f1c35449/index.html b/users/sterni/mblog/golden/expected/d2ccdc74-830c-41ee-9d64-2221f1c35449/index.html deleted file mode 100644 index 4abafc462..000000000 --- a/users/sterni/mblog/golden/expected/d2ccdc74-830c-41ee-9d64-2221f1c35449/index.html +++ /dev/null @@ -1,4 +0,0 @@ -<!DOCTYPE html> -<html><head><meta charset='utf-8'><meta viewport='width=device-width'><title>test.txt
    grüße from notemap - -
    \ No newline at end of file diff --git a/users/sterni/mblog/golden/expected/d81cb91d-c210-46b1-835a-6a7c34db666b/IMG_1637.JPG b/users/sterni/mblog/golden/expected/d81cb91d-c210-46b1-835a-6a7c34db666b/IMG_1637.JPG deleted file mode 100644 index f0811418d..000000000 Binary files a/users/sterni/mblog/golden/expected/d81cb91d-c210-46b1-835a-6a7c34db666b/IMG_1637.JPG and /dev/null differ diff --git a/users/sterni/mblog/golden/expected/d81cb91d-c210-46b1-835a-6a7c34db666b/index.html b/users/sterni/mblog/golden/expected/d81cb91d-c210-46b1-835a-6a7c34db666b/index.html deleted file mode 100644 index 8f82f7ae8..000000000 --- a/users/sterni/mblog/golden/expected/d81cb91d-c210-46b1-835a-6a7c34db666b/index.html +++ /dev/null @@ -1,2 +0,0 @@ - -example note
    example note

    bold italic bold & italic strikethrough


    It is technically possible to create arbitrary (?) HTML markup via copy & paste from e.g. a browser. Let’s not test that for now.
    \ No newline at end of file diff --git a/users/sterni/mblog/golden/expected/index.html b/users/sterni/mblog/golden/expected/index.html deleted file mode 100644 index 6fe6846ab..000000000 --- a/users/sterni/mblog/golden/expected/index.html +++ /dev/null @@ -1,2 +0,0 @@ - -mblog

    mblog

    test.txt2024-12-25T22·54+00
    example note2024-11-22T11·49+00
    \ No newline at end of file diff --git a/users/sterni/mblog/golden/expected/style.css b/users/sterni/mblog/golden/expected/style.css deleted file mode 100644 index 3babfdc23..000000000 --- a/users/sterni/mblog/golden/expected/style.css +++ /dev/null @@ -1,13 +0,0 @@ - -header, main { - width: 100%; - max-width: 800px; -} - -main img { - max-width: 100%; -} - -a:link, a:visited { - color: blue; -} diff --git a/users/sterni/mblog/mail-note/html-transformer.lisp b/users/sterni/mblog/mail-note/html-transformer.lisp deleted file mode 100644 index 65d07e0c1..000000000 --- a/users/sterni/mblog/mail-note/html-transformer.lisp +++ /dev/null @@ -1,130 +0,0 @@ -;; SPDX-License-Identifier: GPL-3.0-only -;; SPDX-FileCopyrightText: Copyright (C) 2022, 2024 by sterni - -(in-package :mail-note) -(declaim (optimize (safety 3))) - -;; Throw away these tags and all of their children -(defparameter +discard-tags-with-children+ '("HEAD")) -;; Only “strip” these tags and leave their content as is -(defparameter +discard-tags-only+ '("BODY" "HTML")) - -;; This is basically the same as cxml's PROXY-HANDLER. -;; Couldn't be bothered to make a BROADCAST-HANDLER because I -;; only need to pass through to one handler. It accepts every -;; event and passes it on to NEXT-HANDLER. This is useful for -;; subclassing mostly where an event can be modified or passed -;; on as is via CALL-NEXT-METHOD. -(defclass hax-proxy-handler (hax:default-handler) - ((next-handler - :initarg :next-handler - :accessor proxy-next-handler))) - -;; Define the trivial handlers which just call themselves for NEXT-HANDLER -(macrolet ((def-proxy-handler (name (&rest args)) - `(defmethod ,name ((h hax-proxy-handler) ,@args) - (,name (proxy-next-handler h) ,@args)))) - (def-proxy-handler hax:start-document (name p-id s-id)) - (def-proxy-handler hax:end-document ()) - (def-proxy-handler hax:start-element (name attrs)) - (def-proxy-handler hax:end-element (name)) - (def-proxy-handler hax:characters (data)) - (def-proxy-handler hax:unescaped (data)) - (def-proxy-handler hax:comment (data))) - -(defclass mail-note-transformer (hax-proxy-handler) - ((cid-lookup - :initarg :cid-lookup - :initform (lambda (cid) nil) - :accessor transformer-cid-lookup) - (discard-until - :initarg :discard-until - :initform nil - :accessor transformer-discard-until) - (depth - :initarg :depth - :initform 0 - :accessor transformer-depth)) - (:documentation - "HAX handler that strips unnecessary tags from the HTML of a com.apple.mail-note - and resolves references to attachments to IMG tags.")) - -;; Define the “boring” handlers which just call the next method (i. e. the next -;; handler) unless discard-until is not nil in which case the event is dropped. -(macrolet ((def-filter-handler (name (&rest args)) - `(defmethod ,name ((h mail-note-transformer) ,@args) - (when (not (transformer-discard-until h)) - (call-next-method))))) - (def-filter-handler hax:start-document (name p-id s-id)) - (def-filter-handler hax:end-document ()) - (def-filter-handler hax:characters (data)) - (def-filter-handler hax:unescaped (data)) - (def-filter-handler hax:comment (data))) - -(defun parse-content-id (attrlist) - (when-let (data (find-if (lambda (x) - (string-equal (hax:attribute-name x) "DATA")) - attrlist)) - (multiple-value-bind (starts-with-cid-p suffix) - (starts-with-subseq "cid:" (hax:attribute-value data) - :return-suffix t :test #'char=) - (if starts-with-cid-p suffix data)))) - -(defmethod hax:start-element ((handler mail-note-transformer) name attrs) - (with-accessors ((discard-until transformer-discard-until) - (next-handler proxy-next-handler) - (cid-lookup transformer-cid-lookup) - (depth transformer-depth)) - handler - - (cond - ;; If we are discarding, any started element is dropped, - ;; since the end-condition only is reached via END-ELEMENT. - (discard-until nil) - ;; If we are not discarding any outer elements, we can set - ;; up a new discard condition if we encounter an appropriate - ;; element. - ((member name +discard-tags-with-children+ :test #'string-equal) - (setf discard-until (cons name depth))) - ;; Only drop this event, must be mirrored in END-ELEMENT to - ;; avoid invalidly nested HTML. - ((member name +discard-tags-only+ :test #'string-equal) nil) - ;; If we encounter an object tag, we drop it and its contents, - ;; but only after inspecting its attributes and emitting new - ;; events representing an img tag which includes the respective - ;; attachment via its filename. - ((string-equal name "OBJECT") - (progn - (setf discard-until (cons "OBJECT" depth)) - ;; TODO(sterni): check type and only resolve images, raise error - ;; otherwise. We should only encounter images anyways, since - ;; other types are only supported for iCloud which doesn't seem - ;; to use IMAP for sync these days. - (when-let* ((cid (parse-content-id attrs)) - (file (apply cid-lookup (list cid))) - (src (hax:make-attribute "SRC" file))) - (hax:start-element next-handler "IMG" (list src)) - (hax:end-element next-handler "IMG")))) - ;; In all other cases, we use HAX-PROXY-HANDLER to pass the event on. - (t (call-next-method))) - (setf depth (1+ depth)))) - -(defmethod hax:end-element ((handler mail-note-transformer) name) - (with-accessors ((discard-until transformer-discard-until) - (depth transformer-depth)) - handler - - (setf depth (1- depth)) - (cond - ;; If we are discarding and encounter the same tag again at the same - ;; depth, we can stop, but still have to discard the current tag. - ((and discard-until - (string-equal (car discard-until) name) - (= (cdr discard-until) depth)) - (setf discard-until nil)) - ;; In all other cases, we drop properly. - (discard-until nil) - ;; Mirrored tag stripping as in START-ELEMENT - ((member name +discard-tags-only+ :test #'string-equal) nil) - ;; In all other cases, we use HAX-PROXY-HANDLER to pass the event on. - (t (call-next-method))))) diff --git a/users/sterni/mblog/mail-note/note.lisp b/users/sterni/mblog/mail-note/note.lisp deleted file mode 100644 index aea8ff0b4..000000000 --- a/users/sterni/mblog/mail-note/note.lisp +++ /dev/null @@ -1,118 +0,0 @@ -;; SPDX-License-Identifier: GPL-3.0-only -;; SPDX-FileCopyrightText: Copyright (C) 2022-2024 by sterni - -(in-package :mail-note) -(declaim (optimize (safety 3))) - -;;; util - -(defun html-escape-stream (in out) - "Escape characters read from stream IN and write them to - stream OUT escaped using WHO:ESCAPE-STRING-MINIMAL." - (let ((buf (make-string *general-buffer-size*))) - (loop for len = (read-sequence buf in) - while (> len 0) - do (write-string (who:escape-string-minimal (subseq buf 0 len)) out)))) - -(defun cid-header-value (cid) - "Takes a Content-ID as present in Mail Notes' tags and properly - surrounds them with angle brackets for a MIME header" - (concatenate 'string "<" cid ">")) - -(defun find-mime-message-date (message) - (when-let ((date-string (car (mime:mime-message-header-values "Date" message)))) - (date-time-parser:parse-date-time date-string))) - -;;; main implementation - -(defun mail-note-mime-subtype-p (x) - (member x '("plain" "html") :test #'string-equal)) - -(deftype mail-note-mime-subtype () - '(satisfies mail-note-mime-subtype-p)) - -(defclass mail-note (mime:mime-message) - ((text-part - :type mime:mime-text - :initarg :text-part - :reader mail-note-text-part) - (subject - :type string - :initarg :subject - :reader mail-note-subject) - (uuid - :type string - :initarg :uuid - :reader mail-note-uuid) - (time - :type integer - :initarg :time - :reader mail-note-time) - (mime-subtype - :type mail-note-mime-subtype - :initarg :mime-subtype - :reader mail-note-mime-subtype)) - (:documentation - "Representation of a Mail Note, e.g. created using Apple's Notes App via the IMAP backend")) - -(defun mail-note-p (msg) - "Checks X-Uniform-Type-Identifier of a MIME:MIME-MESSAGE - to determine if a given mime message claims to be an (Apple) Mail Note." - (when-let (uniform-id (car (mime:mime-message-header-values - "X-Uniform-Type-Identifier" - msg))) - (string-equal uniform-id "com.apple.mail-note"))) - -(defun make-mail-note (msg) - (check-type msg mime-message) - - (unless (mail-note-p msg) - (error "Passed message is not a Mail Note according to headers")) - - (let ((text-part (mime:find-mime-text-part msg)) - (subject (car (mime:mime-message-header-values "Subject" msg :decode t))) - (uuid (when-let ((val (car (mime:mime-message-header-values - "X-Universally-Unique-Identifier" - msg)))) - (string-downcase val))) - (time (find-mime-message-date msg))) - ;; The idea here is that we don't need to check a lot manually, instead - ;; the type annotation are going to do this for us (with sufficient safety?) - (change-class msg 'mail-note - :text-part text-part - :subject subject - :uuid uuid - :time time - :mime-subtype (mime:mime-subtype text-part)))) - -(defgeneric mail-note-html-fragment (note out) - (:documentation - "Takes an MAIL-NOTE and writes its text content as HTML to - the OUT stream. The tags are resolved to which - refer to the respective attachment's filename as a relative path, - but extraction of the attachments must be done separately. The - surrounding and tags are stripped and - discarded completely, so only a fragment which can be included - in custom templates remains.")) - -(defmethod mail-note-html-fragment ((note mail-note) (out stream)) - (let ((text (mail-note-text-part note))) - (cond - ;; notemap creates text/plain notes we need to handle properly. - ;; Additionally we *could* check X-Mailer which notemap sets - ((string-equal (mail-note-mime-subtype note) "plain") - (html-escape-stream (mime:mime-body-stream text) out)) - ;; Notes.app creates text/html parts - ((string-equal (mail-note-mime-subtype note) "html") - (closure-html:parse - (mime:mime-body-stream text) - (make-instance - 'mail-note-transformer - :cid-lookup - (lambda (cid) - (when-let* ((part (mime:find-mime-part-by-id note (cid-header-value cid))) - (file (mime:mime-part-file-name part))) - file)) - :next-handler - (closure-html:make-character-stream-sink out)))) - (t (error "Internal error: unexpected MIME subtype"))))) diff --git a/users/sterni/mblog/maildir.lisp b/users/sterni/mblog/maildir.lisp deleted file mode 100644 index 9acd2a401..000000000 --- a/users/sterni/mblog/maildir.lisp +++ /dev/null @@ -1,22 +0,0 @@ -;; SPDX-License-Identifier: GPL-3.0-only -;; SPDX-FileCopyrightText: Copyright (C) 2022 by sterni - -(in-package :maildir) -(declaim (optimize (safety 3))) - -;; https://cr.yp.to/proto/maildir.html -;; http://qmail.org/qmail-manual-html/man5/maildir.html -(defun list (dir) - "Returns a list of pathnames to messages in a maildir. The messages are -returned in no guaranteed order. Note that this function doesn't fully -implement the behavior prescribed by maildir(5): It only looks at `cur` -and `new` and won't clean up `tmp` nor move files from `new` to `cur`, -since it is strictly read-only. In this, it follows mlist(1)." - (flet ((subdir-contents (subdir) - (directory - (merge-pathnames - (make-pathname :directory `(:relative ,subdir) - :name :wild :type :wild) - dir)))) - (mapcan #'subdir-contents '("cur" "new")))) - diff --git a/users/sterni/mblog/mblog.lisp b/users/sterni/mblog/mblog.lisp deleted file mode 100644 index 69c86e8c1..000000000 --- a/users/sterni/mblog/mblog.lisp +++ /dev/null @@ -1,147 +0,0 @@ -;; SPDX-License-Identifier: GPL-3.0-only -;; SPDX-FileCopyrightText: Copyright (C) 2022-2024 by sterni -;; SPDX-FileCopyrightText: Copyright (C) 2006-2010 by Walter C. Pelissero - -(in-package :mblog) - -;; util - -;; Taken from SCLF, written by Walter C. Pelissero -(defun pathname-as-directory (pathname) - "Converts PATHNAME to directory form and return it." - (setf pathname (pathname pathname)) - (if (pathname-name pathname) - (make-pathname :directory (append (or (pathname-directory pathname) - '(:relative)) - (list (file-namestring pathname))) - :name nil - :type nil - :defaults pathname) - pathname)) - -(defmacro with-overwrite-file ((&rest args) &body body) - "Like WITH-OPEN-FILE, but creates/supersedes the given file for writing." - `(with-open-file (,@args :direction :output - :if-exists :supersede - :if-does-not-exist :create) - ,@body)) - -;; CSS - -(defvar *style* " -header, main { - width: 100%; - max-width: 800px; -} - -main img { - max-width: 100%; -} - -a:link, a:visited { - color: blue; -} -") - -;; Templating - -(eval-when (:compile-toplevel :load-toplevel) - (setf (who:html-mode) :html5)) - -(defmacro render-page ((stream title &key root) &body body) - "Surround BODY with standard mblog document skeleton and render it to STREAM - using CL-WHO. If :ROOT is T, assume that the page is the top level index page. - Otherwise it is assumed to be one level below the index page." - `(who:with-html-output (,stream nil :prologue t) - (:html - (:head - (:meta :charset "utf-8") - (:meta :viewport "width=device-width") - (:title (who:esc ,title)) - (:link :rel "stylesheet" - :type "text/css" - :href ,(concatenate 'string (if root "" "../") "style.css"))) - (:body - (:header - (:nav - (:a :href ,(who:escape-string (if root "" "..")) "index"))) - (:main ,@body))))) - -;; Build Logic - -(defun build-note-page (note note-dir) - "Convert NOTE to HTML and write it to index.html in NOTE-DIR alongside any - extra attachments NOTE contains." - (with-overwrite-file (html-stream (merge-pathnames "index.html" note-dir)) - (render-page (html-stream (mail-note-subject note)) - (:article - (mail-note-html-fragment note html-stream)))) - - (mime:do-parts (part note) - (unless (string= (mime:mime-id part) - (mime:mime-id (mail-note-text-part note))) - (let ((attachment-in (mime:mime-body-stream part)) - (attachment-dst (merge-pathnames - (mime:mime-part-file-name part) - note-dir))) - - (format *error-output* "Writing attachment ~A~%" attachment-dst) - - (with-overwrite-file (attachment-out attachment-dst - :element-type - (stream-element-type attachment-in)) - (redirect-stream attachment-in attachment-out - :buffer-size *general-buffer-size*))))) - - (values)) - -(defun build-index-page (notes-list destination) - "Write an overview page linking all notes in NOTE-LIST in the given order to - DESTINATION. The notes are assumed to be in a sibling directory named like the - each note's UUID." - (with-overwrite-file (listing-stream destination) - (render-page (listing-stream "mblog" :root t) - (:h1 "mblog") - (:table - (dolist (note notes-list) - (who:htm - (:tr - (:td (:a :href (who:escape-string (mail-note-uuid note)) - (who:esc (mail-note-subject note)))) - (:td (who:esc - (klatre:format-dottime - (universal-to-timestamp (mail-note-time note))))))))))) - (values)) - -(defun build-mblog (notes-dir html-dir) - "Take MIME messages from maildir NOTES-DIR and build a complete mblog in HTML-DIR." - (setf notes-dir (pathname-as-directory notes-dir)) - (setf html-dir (pathname-as-directory html-dir)) - - ;; TODO(sterni): avoid rewriting if nothing was updated - ;; TODO(sterni): clean up deleted things - ;; TODO(sterni): atom feed - - (let ((all-notes '())) - (dolist (message-path (maildir:list notes-dir)) - (let* ((note (make-mail-note (mime:mime-message message-path))) - (note-dir (merge-pathnames (make-pathname - :directory - `(:relative ,(mail-note-uuid note))) - html-dir))) - - (format *error-output* "Writing note message ~A to ~A~%" - message-path note-dir) - (ensure-directories-exist note-dir) - (build-note-page note note-dir) - (push note all-notes))) - - ;; reverse sort the entries by time for the index page - (setf all-notes (sort all-notes #'> :key #'mail-note-time)) - - (build-index-page all-notes (merge-pathnames "index.html" html-dir)) - - (with-overwrite-file (css-stream (merge-pathnames "style.css" html-dir)) - (write-string *style* css-stream)) - - (values))) diff --git a/users/sterni/mblog/packages.lisp b/users/sterni/mblog/packages.lisp deleted file mode 100644 index 5e9d2fe14..000000000 --- a/users/sterni/mblog/packages.lisp +++ /dev/null @@ -1,64 +0,0 @@ -;; SPDX-License-Identifier: GPL-3.0-only -;; SPDX-FileCopyrightText: Copyright (C) 2022-2024 by sterni - -(defpackage :maildir - (:use :common-lisp) - (:shadow :list) - (:export :list) - (:documentation - "Very incomplete package for dealing with maildir(5).")) - -(defpackage :config - (:use - :common-lisp) - (:import-from :uiop :getenv) - (:import-from :alexandria :when-let) - (:export - :init-from-env - :*general-buffer-size*)) - -(defpackage :mail-note - (:use - :common-lisp - :closure-html - :cl-date-time-parser - :mime4cl) - (:import-from :config :*general-buffer-size*) - (:import-from - :alexandria - :when-let* - :when-let - :starts-with-subseq - :ends-with-subseq) - (:import-from :who :escape-string-minimal) - (:export - :mail-note - :mail-note-uuid - :mail-note-subject - :mail-note-time - :mail-note-text-part - :make-mail-note - :mail-note-html-fragment)) - -(defpackage :mblog - (:use - :common-lisp - :klatre - :who - :maildir - :mail-note - :config) - (:export :build-mblog) - (:import-from :local-time :universal-to-timestamp) - (:import-from :mime4cl :redirect-stream) - (:shadowing-import-from :common-lisp :list)) - -(defpackage :cli - (:use - :common-lisp - :uiop - :mail-note - :config - :mblog) - (:import-from :alexandria :starts-with) - (:export :main)) diff --git a/users/sterni/mn2html/.gitignore b/users/sterni/mn2html/.gitignore deleted file mode 100644 index eb5a316cb..000000000 --- a/users/sterni/mn2html/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/users/sterni/mn2html/Cargo.lock b/users/sterni/mn2html/Cargo.lock deleted file mode 100644 index 19de2c57e..000000000 --- a/users/sterni/mn2html/Cargo.lock +++ /dev/null @@ -1,534 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "amn2html" -version = "0.1.0" -dependencies = [ - "lol_html", - "mail-parser", - "memmap2", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "matches", - "phf", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.90", -] - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.90", -] - -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "foldhash" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.168" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "lol_html" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2872b88213f3cd4b04f719ec8f2e0b37c98882a7c4aa6fc13ba2f19f5eba1bd2" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cssparser", - "encoding_rs", - "hashbrown", - "lazy_static", - "lazycell", - "memchr", - "mime", - "selectors", - "thiserror", -] - -[[package]] -name = "mail-parser" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c3b9e5d8b17faf573330bbc43b37d6e918c0a3bf8a88e7d0a220ebc84af9fc" -dependencies = [ - "encoding_rs", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memmap2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" -dependencies = [ - "libc", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros", - "phf_shared", - "proc-macro-hack", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom", - "libc", - "rand_chacha", - "rand_core", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf", - "phf_codegen", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] diff --git a/users/sterni/mn2html/Cargo.toml b/users/sterni/mn2html/Cargo.toml deleted file mode 100644 index 6c959db4a..000000000 --- a/users/sterni/mn2html/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "mn2html" -version = "0.0.0" -edition = "2021" -license = "GPL-3.0-only" - -[dependencies] -lol_html = "2.1.0" -mail-parser = { version = "0.9.4", features = [ "encoding_rs" ] } -memmap2 = "0.9.5" - -[[bin]] -name = "mn2html" -path = "mn2html.rs" diff --git a/users/sterni/mn2html/README.md b/users/sterni/mn2html/README.md deleted file mode 100644 index bec557f19..000000000 --- a/users/sterni/mn2html/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# mn2html - -Convert mail notes authored e.g. by the iOS/macOS Notes application, -into HTML suitable for standard browsers. Instead of full documents, -mn2html emits HTML fragments that can easily be embedded into other -documents or postprocessed using a templating engine. - -## History - -mn2html is a reimplementation mnote-html from //users/sterni/mblog. -The reason for this was mainly avoiding the startup cost associated -with Common Lisp programs, so the program would be suitable for -shell scripting. - -## Tasks - -- [ ] Properly handle `text/plain` bodies (from e.g. notemap) -- [ ] Add man page -- [ ] Help screen -- [ ] Improve error reporting diff --git a/users/sterni/mn2html/default.nix b/users/sterni/mn2html/default.nix deleted file mode 100644 index d6f2c21a4..000000000 --- a/users/sterni/mn2html/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ pkgs, lib, ... }: - -pkgs.rustPlatform.buildRustPackage rec { - pname = "mn2hmtl"; - version = "canon"; - - src = lib.fileset.toSource { - root = ./.; - fileset = lib.fileset.unions [ - ./Cargo.lock - ./Cargo.toml - ./mn2html.rs - ]; - }; - - cargoLock.lockFile = ./Cargo.lock; - - passthru.shell = pkgs.mkShell { - name = "${pname}-shell"; - nativeBuildInputs = [ - pkgs.buildPackages.cargo - pkgs.buildPackages.rustc - ]; - }; -} diff --git a/users/sterni/mn2html/mn2html.rs b/users/sterni/mn2html/mn2html.rs deleted file mode 100644 index cda8f2993..000000000 --- a/users/sterni/mn2html/mn2html.rs +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-FileCopyrightText: Copyright © 2024 sterni -// SPDX-License-Identifier: GPL-3.0-only -use lol_html::html_content::ContentType; -use lol_html::{element, HtmlRewriter, Settings}; -use mail_parser::{Message, MessageParser, MimeHeaders}; -use memmap2::Mmap; - -use std::collections::HashMap; -use std::env; -use std::error::Error; -use std::fmt; -use std::fs::File; -use std::io::Write; - -type CidMap<'a> = HashMap<&'a str, &'a str>; - -#[derive(Debug)] -enum Mn2htmlError { - MimeParseFail, - NoMailNote, - MissingAttachment(String), -} - -impl fmt::Display for Mn2htmlError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Mn2htmlError::MimeParseFail => { - write!(f, "Could not parse given file as a MIME message") - } - Mn2htmlError::NoMailNote => { - write!(f, "Given MIME message does not appear to be a Mail Note") - } - Mn2htmlError::MissingAttachment(cid) => write!( - f, - "Given object's Content-Id {} doesn't match any attachment", - cid - ), - } - } -} - -impl Error for Mn2htmlError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - None - } -} - -fn warn(msg: &str) { - eprintln!("mn2html: {}", msg); -} - -fn main() -> Result<(), Box> { - for arg in env::args_os().skip(1) { - // TODO(sterni): flags, --help and such - let msg_file = File::open(arg)?; - let msg_raw = unsafe { Mmap::map(&msg_file) }?; - - let msg_parsed = MessageParser::default() - .parse(msg_raw.as_ref()) - .ok_or(Mn2htmlError::MimeParseFail)?; - - if !matches!( - msg_parsed - .header("X-Uniform-Type-Identifier") - .and_then(|h| h.as_text()), - Some("com.apple.mail-note") - ) { - return Err(Box::new(Mn2htmlError::NoMailNote)); - } - - let cid_map = index_attachments(&msg_parsed); - let html_body = msg_parsed - .html_bodies() - .nth(0) - .ok_or(Mn2htmlError::NoMailNote)? - .contents(); - - rewrite_html(html_body, &cid_map)?; - } - - Ok(()) -} - -// At some point, it was a consideration to move this out of the Rust program. -// mn2html would have been a shell script with mblaze(7) tools finding the -// attachments and their content ideas passing the information to a Rust HTML -// rewriter via CLI args. It is unclear how much (if at all?) slower this would -// have been. In the end, it just seemed cleaner to do it in the Rust program, -// especially since the HTML rewriter would not really have been useful on its -// own. -fn index_attachments<'a>(msg: &'a Message) -> CidMap<'a> { - let mut map = HashMap::new(); - for a in msg.attachments() { - match (a.content_id(), a.attachment_name()) { - (Some(cid), Some(filename)) => { - if let Some(_) = map.insert(cid, filename) { - warn("multiple attachments share the same Content-Id"); - } - } - (_, _) => warn("attachment without Content-Id and/or filename in Content-Disposition"), - } - } - - map -} - -fn rewrite_html(html_body: &[u8], cid_map: &CidMap) -> Result<(), Box> { - let mut stdout = std::io::stdout(); - let mut rewriter = HtmlRewriter::new( - Settings { - element_content_handlers: vec![ - element!("head", |el| { - el.remove(); - Ok(()) - }), - element!("body", |el| { - el.remove_and_keep_content(); - Ok(()) - }), - element!("html", |el| { - el.remove_and_keep_content(); - Ok(()) - }), - element!("object[type][data]", |el| { - if el - .get_attribute("type") - .expect("element! matched object[type] without type attribute") - != "application/x-apple-msg-attachment" - { - warn("encountered object with unknown type attribute, ignoring"); - return Ok(()); - } - - match el - .get_attribute("data") - .expect("element! matched object[data] without data attribute") - .split_at_checked(4) - { - Some(("cid:", cid)) => match cid_map.get(cid) { - Some(filename) => el.replace( - &format!(r#""#, filename), - ContentType::Html, - ), - _ => { - return Err(Box::new(Mn2htmlError::MissingAttachment( - cid.to_string(), - ))) - } - }, - _ => warn("encountered object with malformed data attribute, ignoring"), - }; - - Ok(()) - }), - ], - ..Settings::new() - }, - |c: &[u8]| stdout.write_all(c).expect("Can't write to stdout"), - ); - - rewriter.write(html_body)?; - rewriter.end()?; - - Ok(()) -} diff --git a/users/sterni/modules/backup-minecraft-fabric.nix b/users/sterni/modules/backup-minecraft-fabric.nix deleted file mode 100644 index 5dad2b882..000000000 --- a/users/sterni/modules/backup-minecraft-fabric.nix +++ /dev/null @@ -1,126 +0,0 @@ -# Companion module to minecraft-fabric.nix which automatically and regularly -# creates backups of all minecraft servers' worlds to a shared borg(1) -# repository. -# -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2023 sterni -{ pkgs, depot, config, lib, ... }: - -let - inherit (depot.nix) getBins; - - bins = getBins pkgs.borgbackup [ "borg" ] - // getBins pkgs.mcrcon [ "mcrcon" ] - // getBins pkgs.systemd [ "systemd-creds" ]; - - unvaried = ls: builtins.all (l: l == builtins.head ls) ls; - - cfg = config.services.backup-minecraft-fabric-servers; - - instances = lib.filterAttrs (_: i: i.enable) config.services.minecraft-fabric-server; - users = lib.mapAttrsToList (_: i: i.user) instances; - groups = lib.mapAttrsToList (_: i: i.group) instances; - - mkBackupScript = instanceName: instanceCfg: - let - archivePrefix = "minecraft-fabric-${instanceName}-world-${builtins.baseNameOf instanceCfg.world}-"; - in - - pkgs.writeShellScript "backup-minecraft-fabric-${instanceName}" '' - export MCRCON_HOST="localhost" - export MCRCON_PORT="${toString instanceCfg.serverProperties."rcon.port"}" - # Unfortunately, mcrcon can't read the password from a file - export MCRCON_PASS="$(${bins.systemd-creds} cat "${instanceName}-rcon-password")" - - ${bins.mcrcon} save-all - unset MCRCON_PASS - - # Give the server plenty of time to save - sleep 60 - - ${bins.borg} ${lib.escapeShellArgs [ - "create" - "--verbose" "--filter" "AMEU" "--list" - "--stats" "--show-rc" - "--compression" "zlib" - "${cfg.repository}::${archivePrefix}{now}" - instanceCfg.world - ]} - - ${bins.borg} ${lib.escapeShellArgs [ - "prune" - "--list" - "--show-rc" - "--glob-archives" "${archivePrefix}*" - "--keep-hourly" "168" - "--keep-daily" "31" - "--keep-monthly" "6" - "--keep-yearly" "2" - cfg.repository - ]} - - ${bins.borg} compact ${lib.escapeShellArg cfg.repository} - ''; -in - -{ - imports = [ - ./minecraft-fabric.nix - ]; - - options = { - services.backup-minecraft-fabric-servers = { - enable = lib.mkEnableOption "backups of all Minecraft fabric servers"; - - repository = lib.mkOption { - type = lib.types.path; - description = "Path to the borg(1) repository to use for all backups."; - default = "/var/lib/backup/minecraft-fabric"; - }; - }; - }; - - config = lib.mkIf (cfg.enable && builtins.length (builtins.attrNames instances) > 0) { - assertions = [ - { - assertion = unvaried users && unvaried groups; - message = "all instances under services.minecraft-fabric-server must use the same user and group"; - } - ]; - - environment.systemPackages = [ - pkgs.borgbackup - ]; - - systemd = { - services.backup-minecraft-fabric-servers = { - description = "Backup world of all fabric based Minecraft servers"; - wantedBy = [ ]; - after = builtins.map - (name: "minecraft-fabric-${name}.service") - (builtins.attrNames instances); - - script = lib.concatStrings (lib.mapAttrsToList mkBackupScript instances); - - serviceConfig = { - Type = "oneshot"; - User = builtins.head users; - Group = builtins.head groups; - LoadCredential = lib.mapAttrsToList - (instanceName: instanceCfg: "${instanceName}-rcon-password:${instanceCfg.rconPasswordFile}") - instances; - }; - }; - - timers.backup-minecraft-fabric-servers = { - description = "Regularly backup Minecraft fabric servers"; - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = "*-*-* 00/3:00:00"; - Persistent = true; - RandomizedDelaySec = "1h"; - }; - }; - }; - }; -} diff --git a/users/sterni/modules/common.nix b/users/sterni/modules/common.nix deleted file mode 100644 index 1ea1501f2..000000000 --- a/users/sterni/modules/common.nix +++ /dev/null @@ -1,81 +0,0 @@ -# This module is common in the weakest sense, i.e. contains common settings to -# all my machines contained in depot—as opposed to common to all my potential -# machines. Consequently, this module is currently very server-centric. -{ pkgs, lib, depot, config, ... }: - -let - me = "lukas"; -in - -{ - config = { - - # More common - - time.timeZone = "Europe/Berlin"; - - nix = { - package = pkgs.nix_2_3; - settings = { - trusted-public-keys = lib.mkAfter [ - "headcounter.org:/7YANMvnQnyvcVB6rgFTdb8p5LG1OTXaO+21CaOSBzg=" - ]; - substituters = lib.mkAfter [ - "https://hydra.build" - ]; - trusted-users = [ me ]; - }; - }; - tvl.cache.enable = true; - - programs.fish.enable = true; - - users = { - users = { - root.openssh.authorizedKeys.keys = depot.users.sterni.keys.all; - ${me} = { - isNormalUser = true; - extraGroups = [ "wheel" "http" "git" ]; - openssh.authorizedKeys.keys = depot.users.sterni.keys.all; - shell = pkgs.fish; - }; - }; - }; - - # Less common - - services = { - journald.extraConfig = '' - SystemMaxUse=10G - ''; - - openssh.enable = true; - # TODO(sterni): consider porting to reaction - fail2ban.enable = true; - }; - - programs = { - mosh.enable = true; - tmux.enable = true; - }; - - environment.systemPackages = [ - pkgs.wget - pkgs.git - pkgs.stow - pkgs.htop - pkgs.foot.terminfo - pkgs.vim - pkgs.smartmontools - ]; - - security.acme = { - defaults.email = builtins.getAttr "email" ( - builtins.head ( - builtins.filter (attrs: attrs.username == "sterni") depot.ops.users - ) - ); - acceptTerms = true; - }; - }; -} diff --git a/users/sterni/modules/default.nix b/users/sterni/modules/default.nix deleted file mode 100644 index 5cc8be3cc..000000000 --- a/users/sterni/modules/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -# Stop readTree from looking at this directory -_: { } diff --git a/users/sterni/modules/minecraft-fabric.nix b/users/sterni/modules/minecraft-fabric.nix deleted file mode 100644 index adeca1084..000000000 --- a/users/sterni/modules/minecraft-fabric.nix +++ /dev/null @@ -1,566 +0,0 @@ -# Declarative, but low Nix module for a modded minecraft server using the -# fabric mod loader. That is to say, the build of the final server JAR -# is not encapsulated in a derivation. -# -# The module has the following interesting properties: -# -# * The fabric installer is executed on each server startup to assemble the -# patched server.jar. This is unfortunately necessary, as it seems to be -# difficult to do so in a derivation (fabric-installer accesses the network, -# the build doesn't seem to be reproducible). At least this avoids the -# question of the patched jar's redistributability. -# * RCON is used for starting and stopping which should prevent data loss, -# since we can issue a manual save command. -# * The entire runtime directory of the server is assembled from scratch on -# each start, so only blessed state (like the world) and declarative -# configuration (whitelist.json, server.properties, ...) survive. -# * It supports more than one server running on the same machine. -# -# Missing features: -# -# * Support for bans -# * Support for mutable whitelist, ops, … -# * Op levels -# -# SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2022-2024 sterni - -{ lib, pkgs, config, depot, ... }: - -let - # - # Dependencies - # - inherit (depot.nix.utils) storePathName; - inherit (depot.nix) getBins; - - bins = getBins pkgs.mcrcon [ "mcrcon" ] - // getBins pkgs.jre [ "java" ] - // getBins pkgs.diffutils [ "diff" ] - // getBins pkgs.moreutils [ "sponge" ] - // getBins pkgs.extrace [ "pwait" ] - // getBins pkgs.util-linux [ "flock" ]; - - # - # Needed JARs - # - fetchJar = { pname, version, url, sha256, passthru ? { } }: - pkgs.fetchurl { - name = "${pname}-${version}.jar"; - inherit url sha256; - passthru = passthru // { inherit version; }; - }; - - fabricInstallerJar = - fetchJar rec { - pname = "fabric-installer"; - version = "1.0.0"; - url = "https://maven.fabricmc.net/net/fabricmc/fabric-installer/${version}/fabric-installer-${version}.jar"; - sha256 = "0yrlzly1g5a80df27jvrbhxbp10xqxfyk64q0s0j13kz78fmnzkx"; - }; - - # log4j workaround for Minecraft Server >= 1.12 && < 1.17 - log4jFix_112_116 = pkgs.fetchurl { - url = "https://launcher.mojang.com/v1/objects/02937d122c86ce73319ef9975b58896fc1b491d1/log4j2_112-116.xml"; - sha256 = "1paha357xbaffl38ckzgdh4l5iib2ydqbv7jsg67nj31nlalclr9"; - }; - - serverJars = { - # Manually updated list of known minecraft `server.jar`s for now. - # Making this comprehensive isn't that interesting for now, since the module - # is annoying to use outside of depot anyways as it uses //nix. - "1.16.5" = fetchJar { - pname = "server"; - version = "1.16.5"; - url = "https://launcher.mojang.com/v1/objects/1b557e7b033b583cd9f66746b7a9ab1ec1673ced/server.jar"; - sha256 = "19ix6x5ij4jcwqam1dscnqwm0m251gysc2j793wjcrb9sb3jkwsq"; - passthru = { - baseJvmOpts = [ - "-Dlog4j.configurationFile=${log4jFix_112_116}" - ]; - }; - }; - "1.17" = fetchJar { - pname = "server"; - version = "1.17"; - url = "https://launcher.mojang.com/v1/objects/0a269b5f2c5b93b1712d0f5dc43b6182b9ab254e/server.jar"; - sha256 = "0jqz7hpx7zvjj2n5rfrh8jmdj6ziqyp8c9nq4sr4jmkbky6hsfbv"; - passthru.baseJvmOpts = [ - "-Dlog4j2.formatMsgNoLookups=true" - ]; - }; - "1.17.1" = fetchJar { - pname = "server"; - version = "1.17.1"; - url = "https://launcher.mojang.com/v1/objects/a16d67e5807f57fc4e550299cf20226194497dc2/server.jar"; - sha256 = "0pzmzagvrrapjsnd8xg4lqwynwnb5rcqk2n9h2kzba8p2fs13hp8"; - passthru.baseJvmOpts = [ - "-Dlog4j2.formatMsgNoLookups=true" - ]; - }; - "1.18" = fetchJar { - pname = "server"; - version = "1.18"; - url = "https://launcher.mojang.com/v1/objects/3cf24a8694aca6267883b17d934efacc5e44440d/server.jar"; - sha256 = "0vvycjcfq96z7cl5dsrq98k9b7j7l4x0y9nflrcqmcvink7fs5w4"; - passthru.baseJvmOpts = [ - "-Dlog4j2.formatMsgNoLookups=true" - ]; - }; - "1.18.1" = fetchJar { - pname = "server"; - version = "1.18.1"; - url = "https://launcher.mojang.com/v1/objects/125e5adf40c659fd3bce3e66e67a16bb49ecc1b9/server.jar"; - sha256 = "1pyvym6xzjb1siizzj4ma7lpb05qhgxnzps8lmlbk00lv0515kgb"; - }; - "1.18.2" = fetchJar { - pname = "server"; - version = "1.18.2"; - url = "https://launcher.mojang.com/v1/objects/c8f83c5655308435b3dcf03c06d9fe8740a77469/server.jar"; - sha256 = "0hx330bnadixph44sip0h5h986m11qxbdba6lbgwz4da6lg9vgjp"; - }; - "1.19" = fetchJar { - pname = "server"; - version = "1.19"; - url = "https://launcher.mojang.com/v1/objects/e00c4052dac1d59a1188b2aa9d5a87113aaf1122/server.jar"; - sha256 = "1cnjrqr2vn8gppd1y1lcdrc46fd7m1b3zl28zpbw72fgy1bd1vyy"; - }; - "1.19.1" = fetchJar { - pname = "server"; - version = "1.19.1"; - url = "https://piston-data.mojang.com/v1/objects/8399e1211e95faa421c1507b322dbeae86d604df/server.jar"; - sha256 = "0jnlb5z8a7qi6p6bbwnmdl77b8kq83ryfdp58dhx8kg2hf6lbfx8"; - }; - "1.19.2" = fetchJar { - pname = "server"; - version = "1.19.2"; - url = "https://piston-data.mojang.com/v1/objects/f69c284232d7c7580bd89a5a4931c3581eae1378/server.jar"; - sha256 = "15jdxh5zvsgvvk9hnv47swgjfg8fr653g6nx99q1rxpmkq32frxj"; - }; - "1.19.3" = fetchJar { - pname = "server"; - version = "1.19.3"; - url = "https://piston-data.mojang.com/v1/objects/c9df48efed58511cdd0213c56b9013a7b5c9ac1f/server.jar"; - sha256 = "06qykz3nq7qmfw4phs3wvq3nk28clg8s3qrs37856aai8b8kmgaf"; - }; - # Starting with 1.19.4 we could use --pidFile for systemd's PIDFile=, but as - # the service doesn't fork, there seems to be no point. - "1.19.4" = fetchJar { - pname = "server"; - version = "1.19.4"; - url = "https://piston-data.mojang.com/v1/objects/8f3112a1049751cc472ec13e397eade5336ca7ae/server.jar"; - sha256 = "0lrzpqd6zjvqh9g2byicgh66n43z0hwzp863r22ifx2hll6s2955"; - }; - # https://feedback.minecraft.net/hc/en-us/articles/16499677456781-Minecraft-Java-Edition-1-20-Trails-Tales - "1.20" = fetchJar { - name = "server"; - version = "1.20"; - url = "https://piston-data.mojang.com/v1/objects/15c777e2cfe0556eef19aab534b186c0c6f277e1/server.jar"; - sha256 = "0sym07vqrlbhyxxhlpz73ls0jh0g9qcl4plaa1scx0n1rr1cahgz"; - }; - # https://www.minecraft.net/en-us/article/minecraft--java-edition-1-20-1 - "1.20.1" = fetchJar { - pname = "server"; - version = "1.20.1"; - url = "https://piston-data.mojang.com/v1/objects/84194a2f286ef7c14ed7ce0090dba59902951553/server.jar"; - sha256 = "1q3r3c95vkai477r3gsmf2p0pmyl4zfn0qwl8y0y60m1qnfkmxrs"; - }; - # https://www.minecraft.net/en-us/article/minecraft-java-edition-1-20-2 - "1.20.2" = fetchJar { - pname = "server"; - version = "1.20.2"; - url = "https://piston-data.mojang.com/v1/objects/5b868151bd02b41319f54c8d4061b8cae84e665c/server.jar"; - sha256 = "1s7ag1p8v0vyzc6a8mjkd3rcf065hjb4avqa3zj4dbb9hn1y9bhx"; - }; - # https://www.minecraft.net/en-us/article/minecraft-java-edition-1-20-3 - "1.20.3" = fetchJar { - pname = "server"; - version = "1.20.3"; - url = "https://piston-data.mojang.com/v1/objects/4fb536bfd4a83d61cdbaf684b8d311e66e7d4c49/server.jar"; - sha256 = "1blb2cp1nlm0yr7yjhazj33g0hjlgfawx2v7y16h70pijfz8kv9n"; - }; - # https://www.minecraft.net/en-us/article/minecraft-java-edition-1-20-4 - "1.20.4" = fetchJar { - pname = "server"; - version = "1.20.4"; - url = "https://piston-data.mojang.com/v1/objects/8dd1a28015f51b1803213892b50b7b4fc76e594d/server.jar"; - sha256 = "0qykf9a3nacklqsyb30kg9m79nw462la6rf92gsdssdakprscgy0"; - }; - # https://www.minecraft.net/en-us/article/minecraft-java-edition-1-21 - # Has a known exploit, fixed in 1.21.1 - "1.21" = fetchJar { - pname = "server"; - version = "1.21"; - url = "https://piston-data.mojang.com/v1/objects/450698d1863ab5180c25d7c804ef0fe6369dd1ba/server.jar"; - sha256 = "0gzmpifl6l1cq11lpjd5gadw50095wgyxlm2gkpzkngrhvd98qy9"; - }; - # https://www.minecraft.net/en-us/article/minecraft-java-edition-1-21-1 - "1.21.1" = fetchJar { - pname = "server"; - version = "1.21.1"; - url = "https://piston-data.mojang.com/v1/objects/59353fb40c36d304f2035d51e7d6e6baa98dc05c/server.jar"; - sha256 = "1fxl66938ixks6imz8c5bry69z0kh6iawq1fiwca1kck7rlmbg73"; - }; - # https://www.minecraft.net/en-us/article/minecraft-java-edition-1-21-2 - "1.21.2" = fetchJar { - pname = "server"; - version = "1.21.2"; - url = "https://piston-data.mojang.com/v1/objects/7bf95409b0d9b5388bfea3704ec92012d273c14c/server.jar"; - sha256 = "13a1j3vw0hy9c6wm3m2yzg6g99ikdsasap728pvi62ivna1cmjrv"; - }; - # https://www.minecraft.net/en-us/article/minecraft-java-edition-1-21-3 (bug fixes for 1.21.2) - "1.21.3" = fetchJar { - pname = "server"; - version = "1.21.3"; - url = "https://piston-data.mojang.com/v1/objects/45810d238246d90e811d896f87b14695b7fb6839/server.jar"; - sha256 = "1ddgz0dh830869v82q0cp3zkyanl1p45f7ccbvgrr0y00advhlz1"; - }; - }; - - # - # mods directory for fabric - # - makeModFolder = name: mods: - pkgs.runCommand "${name}-fabric-mod-folder" { } ( - '' - mkdir -p "$out" - '' + lib.concatMapStrings - (mod: '' - test -f "${mod}" || { - printf 'Not a regular file: %s\n' "${mod}" >&2 - exit 1 - } - ln -s "${mod}" "$out/${storePathName mod}" - '') - mods - ); - - # - # Create a server.properties file - # - propertyValue = v: - if builtins.isBool v - then lib.boolToString v - else toString v; - - serverPropertiesFile = name: instanceCfg: - let - serverProperties' = - builtins.removeAttrs instanceCfg.serverProperties [ - "rcon.password" - ] // { - enable-rcon = true; - }; - in - pkgs.writeText "${name}-server.properties" ('' - # created by minecraft-fabric.nix - '' + lib.concatStrings (lib.mapAttrsToList - (key: value: '' - ${key}=${propertyValue value} - '') - serverProperties')); - - # - # Create JSON “state” files - # - writeJson = name: data: pkgs.writeText "${name}.json" (builtins.toJSON data); - - toWhitelist = name: uuid: { inherit name uuid; }; - - whitelistFile = name: instanceCfg: - writeJson "${name}-whitelist" ( - lib.mapAttrsToList toWhitelist instanceCfg.whitelist - ); - - opsFile = name: instanceCfg: - writeJson "${name}-ops" ( - lib.mapAttrsToList - (name: value: - toWhitelist name value // { - level = 4; - bypassesPlayerLimit = true; - } - ) - instanceCfg.ops - ); - - # - # Service start and stop scripts - # - stopScript = name: instanceCfg: - pkgs.writeShellScript "minecraft-fabric-${name}-stop" '' - set -eu - - # Before shutting down, display the diff between prescribed and used - # server.properties file for debugging purposes; filter out credential - actualProperties="''${RUNTIME_DIRECTORY}/server.properties" - sort "$actualProperties" | ${bins.sponge} "$actualProperties" - ( ${bins.diff} -u "${serverPropertiesFile name instanceCfg}" \ - "$actualProperties" \ - || true ) | grep -v rcon.password - - export MCRCON_HOST=localhost - export MCRCON_PORT=${lib.escapeShellArg instanceCfg.serverProperties."rcon.port"} - # Unfortunately, mcrcon can't read the password from a file - export MCRCON_PASS="$(cat "''${RCON_PASSWORD}")" - - # Send stop request - "${bins.mcrcon}" 'say Server is stopping' save-all stop - - # Wait for service to come down (systemd SIGTERMs right after ExecStop) - "${bins.flock}" "''${RUNTIME_DIRECTORY}" true - ''; - - startScript = name: instanceCfg: - let - serverJar = serverJars.${instanceCfg.version} or - (throw "Don't have server.jar for Minecraft Server ${instanceCfg.version}"); - - in - - pkgs.writeShellScript "minecraft-fabric-${name}-start" '' - set -eu - - cd "''${RUNTIME_DIRECTORY}" - - copyFromStore() { - install -m600 "$1" "$2" - } - - # Check if world is available - if test ! -d "${instanceCfg.world}"; then - echo "Could not find world, generating new one" >&2 - mkdir -p "${instanceCfg.world}" - fi - - # Put required files into place - echo eula=true > eula.txt - ln -s "${instanceCfg.world}" "${instanceCfg.level-name or "world"}" - copyFromStore "${serverJar}" server.jar - copyFromStore "${whitelistFile name instanceCfg}" whitelist.json - copyFromStore "${opsFile name instanceCfg}" ops.json - ln -s "${makeModFolder name instanceCfg.mods}" mods - - # Create config and set password from credentials (echo hopefully doesn't leak) - copyFromStore "${serverPropertiesFile name instanceCfg}" server.properties - echo "rcon.password=$(cat "$RCON_PASSWORD")" >> server.properties - - # Build patched jar - "${bins.java}" -jar "${fabricInstallerJar}" \ - server -mcversion "${instanceCfg.version}" - - # Lock is held as long as the server is running, so that we can wait for - # the actual shutdown in the stop script without relying on $MAINPID. - exec "${bins.flock}" "''${RUNTIME_DIRECTORY}" \ - "${bins.java}" \ - ${lib.escapeShellArgs (serverJar.baseJvmOpts or [ ] ++ instanceCfg.jvmOpts)} \ - -jar fabric-server-launch.jar nogui - ''; - - # - # Option types - # - impurePath = lib.types.path // { - name = "impurePath"; - check = x: - lib.types.path.check x - && !(builtins.isPath x) - && !(lib.hasPrefix builtins.storeDir (toString x)); - }; - - - instanceType = lib.types.submodule { - options = { - enable = lib.mkEnableOption "Minecraft server instance with the fabric mod loader"; - - version = lib.mkOption { - type = lib.types.str; - description = "Minecraft Server version to use."; - example = "1.16.5"; - }; - - mods = lib.mkOption { - type = with lib.types; listOf package; - description = "List of fabric mod JARs to load."; - default = [ ]; - }; - - world = lib.mkOption { - type = impurePath; - description = "Path to the Minecraft world folder to use."; - example = "/var/minecraft/world"; - }; - - jvmOpts = lib.mkOption { - type = with lib.types; listOf str; - default = [ ]; - example = [ - "-Xmx2048M" - "-Xms2048M" - ]; - description = '' - Options to pass to - - java - 1 - - in order to tweak the runtime of the JVM. - ''; - }; - - user = lib.mkOption { - type = lib.types.str; - default = "minecraft"; - description = '' - Name of an existing user to run the server as. Needs to have write - access to the specified world. - ''; - }; - - group = lib.mkOption { - type = lib.types.str; - default = "users"; - description = '' - Name of an existing group to run the server under. - ''; - }; - - rconPasswordFile = lib.mkOption { - type = impurePath; - description = '' - File (outised the store) that stores the password to use for Minecraft's - RCON interface. - ''; - example = "/var/secrets/minecraft-rcon"; - }; - - whitelist = lib.mkOption { - type = with lib.types; attrsOf str; - description = '' - Attribute set mapping whitelisted user names to their user ids. - ''; - example = { - sternenseemann = "d8e48069-1905-4886-a5da-a4ee917ee254"; - }; - }; - - ops = lib.mkOption { - type = with lib.types; attrsOf str; - description = '' - Attribute set mapping op-ed user names to their user ids. - Setting permission levels is not possible at the moment, - set to 4 by default. - ''; - example = { - sternenseemann = "d8e48069-1905-4886-a5da-a4ee917ee254"; - }; - }; - - serverProperties = lib.mkOption { - type = lib.types.submodule { - freeformType = lib.types.attrs; - - # Only options the module needs to access are declared explicitly - options = { - server-port = lib.mkOption { - type = lib.types.port; - default = 25565; - description = '' - Port to listen on. - ''; - }; - - "rcon.port" = lib.mkOption { - type = lib.types.port; - default = 25575; - description = '' - Port to use for the RCON control mechanism. - ''; - }; - }; - }; - }; - }; - }; - - cfg = config.services.minecraft-fabric-server; - - serverPorts = lib.mapAttrsToList - (_: instanceCfg: - instanceCfg.serverProperties.server-port - ) - cfg; - - rconPorts = lib.mapAttrsToList - (_: instanceCfg: - instanceCfg.serverProperties."rcon.port" - ) - cfg; -in - -{ - options = { - services.minecraft-fabric-server = lib.mkOption { - type = with lib.types; attrsOf instanceType; - default = { }; - description = "Minecraft server instances with the fabric mod loader"; - }; - }; - - config = { - assertions = [ - { - assertion = builtins.all (instance: !instance.enable) (builtins.attrValues cfg) - || pkgs.config.allowUnfreeRedistributable or false - || pkgs.config.allowUnfree or false; - message = lib.concatStringsSep " " [ - "You need to allow unfree software for minecraft," - "as you'll implicitly agree to Mojang's EULA." - ]; - } - { - assertion = - let - allPorts = serverPorts ++ rconPorts; - in - lib.unique allPorts == allPorts; - message = "All assigned ports need to be unique."; - } - ]; - - systemd.services = lib.mapAttrs' - (name: instanceCfg: - { - name = "minecraft-fabric-${name}"; - value = { - description = "Minecraft server ${name} with the fabric mod loader"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - inherit (instanceCfg) enable; - - environment = { - # Workaround for https://github.com/systemd/systemd/issues/34805 - "RCON_PASSWORD" = "%d/rcon-password"; - }; - - serviceConfig = { - Type = "exec"; - User = instanceCfg.user; - Group = instanceCfg.group; - ExecStart = startScript name instanceCfg; - ExecStop = stopScript name instanceCfg; - RuntimeDirectory = "minecraft-fabric-${name}"; - LoadCredential = "rcon-password:${instanceCfg.rconPasswordFile}"; - RestartSec = "40s"; - }; - }; - } - ) - cfg; - - networking.firewall = { - allowedTCPPorts = serverPorts; - allowedUDPPorts = serverPorts; - }; - }; -} diff --git a/users/sterni/nix/build/gopherHole/default.nix b/users/sterni/nix/build/gopherHole/default.nix deleted file mode 100644 index 65a6bd5f4..000000000 --- a/users/sterni/nix/build/gopherHole/default.nix +++ /dev/null @@ -1,107 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - inherit (pkgs) - runCommand - writeText - ; - - buildGopherHole = depot.users.sterni.nix.build.gopherHole; - - fileTypes = { - # RFC1436 - text = "0"; - menu = "1"; - cso = "2"; - error = "3"; - binhex = "4"; - dos = "5"; - uuencoded = "6"; - index-server = "7"; - telnet = "8"; - binary = "9"; - mirror = "+"; - gif = "g"; - image = "I"; - tn3270 = "T"; - # non-standard - info = "i"; - html = "h"; - }; - - buildFile = { file, name, fileType ? fileTypes.text }: - runCommand name - { - passthru = { - # respect the file type the file derivation passes - # through. otherwise use explicitly set type or - # default value. - fileType = file.fileType or fileType; - }; - } '' - ln -s ${file} "$out" - ''; - - buildGopherMap = dir: - let - /* strings constitute an info line or an empty line - if their length is zero. sets that contain a menu - value have that added to the gophermap as-is. - - all other entries should be a set which can be built using - buildGopherHole and is linked by their name. The resulting - derivation is expected to passthru a fileType containing the - gopher file type char of themselves. - */ - gopherMapLine = e: - if builtins.isString e - then e - else if e ? menu - then e.menu - else - let - drv = buildGopherHole e; - title = e.title or e.name; - in - "${drv.fileType}${title}\t${drv.name}"; - in - writeText ".gophermap" (lib.concatMapStringsSep "\n" gopherMapLine dir); - - buildDir = - { dir, name, ... }: - - let - # filter all entries out that have to be symlinked: - # sets with the file or dir attribute - drvOnly = builtins.map buildGopherHole (builtins.filter - (x: !(builtins.isString x) && (x ? dir || x ? file)) - dir); - gopherMap = buildGopherMap dir; - in - runCommand name - { - passthru = { - fileType = fileTypes.dir; - }; - } - ('' - mkdir -p "$out" - ln -s "${gopherMap}" "$out/.gophermap" - '' + lib.concatMapStrings - (drv: '' - ln -s "${drv}" "$out/${drv.name}" - '') - drvOnly); -in - -{ - # Dispatch into different file / dir handling code - # which is mutually recursive with this function. - __functor = _: args: - if args ? file then buildFile args - else if args ? dir then buildDir args - else builtins.throw "Unrecognized gopher hole item type: " - + lib.generators.toPretty { } args; - - inherit fileTypes; -} diff --git a/users/sterni/nix/build/manPages/default.nix b/users/sterni/nix/build/manPages/default.nix deleted file mode 100644 index 746ed2518..000000000 --- a/users/sterni/nix/build/manPages/default.nix +++ /dev/null @@ -1,103 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - inherit (pkgs) - gzip - mandoc - coreutils - ; - - inherit (depot.nix) - runExecline - getBins - ; - - bins = getBins mandoc [ "mandoc" ] - // getBins gzip [ "gzip" ] - // getBins coreutils [ "mkdir" "ln" "cp" ] - ; - - defaultGzip = true; - - basename = gzip: { name, section, ... }: - "${name}.${toString section}${lib.optionalString gzip ".gz"}"; - - manDir = { section, ... }: - "\${out}/share/man/man${toString section}"; - - target = gzip: args: - "${manDir args}/${basename gzip args}"; - - buildManPage = - { requireLint ? false - , gzip ? defaultGzip - , ... - }: - { content - , ... - }@page: - let - source = builtins.toFile (basename false page) content; - in - runExecline (basename gzip page) { } ([ - (if requireLint then "if" else "foreground") - [ - bins.mandoc - "-mdoc" - "-T" - "lint" - source - ] - "importas" - "out" - "out" - ] ++ (if gzip then [ - "redirfd" - "-w" - "1" - "$out" - bins.gzip - "-c" - source - ] else [ - bins.cp - "--reflink=auto" - source - "$out" - ])); - - buildManPages = - name: - { derivationArgs ? { } - , gzip ? defaultGzip - , ... - }@args: - pages: - runExecline "${name}-man-pages" - { - inherit derivationArgs; - } - ([ - "importas" - "out" - "out" - ] ++ lib.concatMap - ({ name, section, content }@page: [ - "if" - [ bins.mkdir "-p" (manDir page) ] - "if" - [ - bins.ln - "-s" - (buildManPage args page) - (target gzip page) - ] - ]) - pages); - -in -{ - __functor = _: buildManPages; - - single = buildManPage; -} diff --git a/users/sterni/nix/build/toPlainText/default.nix b/users/sterni/nix/build/toPlainText/default.nix deleted file mode 100644 index c59e372d3..000000000 --- a/users/sterni/nix/build/toPlainText/default.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ pkgs, depot, lib, ... }: - -{ fmt ? null -, passthru ? { } -, ... -}@args: - -let - inherit (depot.nix) getBins utils; - - bins = getBins pkgs.lowdown [ - "lowdown" - ] // getBins pkgs.mandoc [ - "mandoc" - ] // getBins pkgs.gnused [ - "sed" - ]; - - actions = { - mdoc = '' - ${bins.mandoc} -T utf8 "${thing}" > "$out" - ''; - - # Use lowdown's terminal target, but strip all ANSI SGR escape sequences - markdown = '' - ${bins.lowdown} -Tterm "${thing}" \ - | ${bins.sed} -e 's|\\x1b\\[[;0-9]*m||g' \ - > "$out" - ''; - - plain = '' - cp --reflink=auto "${thing}" "$out" - ''; - }; - - thingType = builtins.head ( - builtins.filter (x: x != null) ( - builtins.map (t: if args ? ${t} then t else null) ( - builtins.attrNames actions - ) - ) - ); - - thing = args.${thingType}; - name = args.name or utils.storePathName thing; -in - -pkgs.runCommand name -{ - inherit passthru; -} - ( - actions.${thingType} + lib.optionalString (fmt != null) '' - fmt -w "${lib.escapeShellArg (toString fmt)}" "$out" - '' - ) diff --git a/users/sterni/nix/build/website/default.nix b/users/sterni/nix/build/website/default.nix deleted file mode 100644 index e0a5ed75d..000000000 --- a/users/sterni/nix/build/website/default.nix +++ /dev/null @@ -1,50 +0,0 @@ -# Experimental Nix Static Website Authoring Tool -# -# Proof of Concept for a Nix library that allows for authoring static websites -# in Nix in a relatively ad hoc way, i.e. no specific markup or structure -# requirements. In particular, the library can help with creating relative -# references between files/pages so that the website is fully relocatable via -# (relativeToRoot). I use this for fairly trivial websites at the moment though -# I'm not happy with the relative linking feature yet. The API is probably going -# to be redesigned to improve this—you have been warned. -{ depot, pkgs, lib, ... }: - -# TODO(sterni): implement generic deploy script -# TODO(sterni): port orgPage to depot -# TODO(sterni): replace relativeToRoot with a fixpoint that exposes (relative) urls -let - inherit (lib) - isDerivation - ; - - inherit (depot.nix) - writeTree - utils - ; - - minify = type: file: pkgs.runCommandNoCC (utils.storePathName file) - { - nativeBuildInputs = [ pkgs.buildPackages.minify ]; - env = { inherit file; }; - } - '' - minify --type ${type} < "$file" > "$out" - ''; - - makeWebsite = name: { args ? { } }: tree: - let - callTree = relativeToRoot: tree: - if builtins.isFunction tree then - tree (args // { inherit relativeToRoot; }) - else if builtins.isAttrs tree && !(isDerivation tree) then - builtins.mapAttrs (_: v: callTree "${relativeToRoot}../" v) tree - else - tree; - in - writeTree name (builtins.mapAttrs (_: callTree "") tree); -in - -{ - __functor = _: makeWebsite; - inherit makeWebsite minify; -} diff --git a/users/sterni/nix/char/all-chars.bin b/users/sterni/nix/char/all-chars.bin deleted file mode 100644 index 017b909e8..000000000 --- a/users/sterni/nix/char/all-chars.bin +++ /dev/null @@ -1,2 +0,0 @@ - -  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ \ No newline at end of file diff --git a/users/sterni/nix/char/default.nix b/users/sterni/nix/char/default.nix deleted file mode 100644 index 9c6ce2fb2..000000000 --- a/users/sterni/nix/char/default.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ depot, lib, pkgs, ... }: - -let - - inherit (depot.users.sterni.nix.flow) - cond - ; - - inherit (depot.nix) - yants - ; - - inherit (depot.users.sterni.nix) - string - ; - - # A char is the atomic element of a nix string - # which is essentially an array of arbitrary bytes - # as long as they are not a NUL byte. - # - # A char is neither a byte nor a unicode codepoint! - char = yants.restrict "char" (s: builtins.stringLength s == 1) yants.string; - - # integer representation of char - charval = yants.restrict "charval" (i: i >= 1 && i < 256) yants.int; - - allChars = builtins.readFile ./all-chars.bin; - - # Originally I searched a list for this, but came to the - # conclusion that this can never be fast enough in Nix. - # We therefore use a solution similar to infinisil's. - ordMap = builtins.listToAttrs - (lib.imap1 (i: v: { name = v; value = i; }) - (string.toChars allChars)); - - # Note on performance: - # chr and ord have been benchmarked using the following cases: - # - # builtins.map ord (lib.stringToCharacters allChars) - # builtins.map chr (builtins.genList (int.add 1) 255 - # - # The findings are as follows: - # 1. Searching through either strings using recursion is - # unbearably slow in Nix, leading to evaluation times - # of up to 3s for the following very small test case. - # This is why we use the trusty attribute set for ord. - # 2. String indexing is much faster than list indexing which - # is why we use the former for chr. - ord = c: ordMap."${c}"; - - chr = i: string.charAt (i - 1) allChars; - - asciiAlpha = c: - let - v = ord c; - in - (v >= 65 && v <= 90) - || (v >= 97 && v <= 122); - - asciiNum = c: - let - v = ord c; - in - v >= 48 && v <= 57; - - asciiAlphaNum = c: asciiAlpha c || asciiNum c; - -in -{ - inherit - allChars - char - charval - ord - chr - asciiAlpha - asciiNum - asciiAlphaNum - ; - - # originally I generated a nix file containing a list of - # characters, but infinisil uses a better way which I adapt - # which is using builtins.readFile instead of import. - __generateAllChars = pkgs.runCommandCC "generate-all-chars" - { - source = '' - #include - - int main(void) { - for(int i = 1; i <= 0xff; i++) { - putchar(i); - } - } - ''; - passAsFile = [ "source" ]; - } '' - $CC -o "$out" -x c "$sourcePath" - ''; -} diff --git a/users/sterni/nix/char/tests/default.nix b/users/sterni/nix/char/tests/default.nix deleted file mode 100644 index cb17b74c5..000000000 --- a/users/sterni/nix/char/tests/default.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.nix.runTestsuite) - it - assertEq - runTestsuite - ; - - inherit (depot.users.sterni.nix) - char - string - num - fun - ; - - charList = string.toChars char.allChars; - - testAllCharConversion = it "tests conversion of all chars" [ - (assertEq "char.chr converts to char.allChars" - (builtins.genList (fun.rl char.chr (num.add 1)) 255) - charList) - (assertEq "char.ord converts from char.allChars" - (builtins.genList (num.add 1) 255) - (builtins.map char.ord charList)) - ]; - -in -runTestsuite "char" [ - testAllCharConversion -] diff --git a/users/sterni/nix/float/default.nix b/users/sterni/nix/float/default.nix deleted file mode 100644 index ecb6465c8..000000000 --- a/users/sterni/nix/float/default.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.users.sterni.nix) - num - ; -in - -rec { - # In C++ Nix, the required builtins have been added in version 2.4 - ceil = builtins.ceil or (throw "Nix implementation is missing builtins.ceil"); - floor = builtins.floor or (throw "Nix implementation is missing builtins.floor"); - - truncate = f: if f >= 0 then floor f else ceil f; - round = f: - let - s = num.sign f; - a = s * f; - in - s * (if a >= floor a + 0.5 then ceil a else floor a); - - intToFloat = i: i * 1.0; -} diff --git a/users/sterni/nix/float/tests/default.nix b/users/sterni/nix/float/tests/default.nix deleted file mode 100644 index 75e2a1bfa..000000000 --- a/users/sterni/nix/float/tests/default.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ depot, lib, ... }: - -let - - inherit (depot.nix.runTestsuite) - runTestsuite - it - assertEq - ; - - inherit (depot.users.sterni.nix) - float - ; - - testsBuiltins = it "tests builtin operations" [ - (assertEq "ceil pos" (float.ceil 1.5) 2) - (assertEq "ceil neg" (float.ceil (-1.5)) (-1)) - (assertEq "floor pos" (float.floor 1.5) 1) - (assertEq "floor neg" (float.floor (-1.5)) (-2)) - ]; - - testsConversionFrom = it "tests integer to float conversion" [ - (assertEq "float.intToFloat is identity for floats" (float.intToFloat 1.3) 1.3) - (assertEq "float.intToFloat converts ints" - (builtins.all - (val: builtins.isFloat val) - (builtins.map float.intToFloat (builtins.genList (i: i - 500) 1000))) - true) - ]; - - exampleFloats = [ 0.5 0.45 0.3 0.1 200 203.457847 204.65547 (-1.5) (-2) (-1.3) (-0.45) ]; - testsConversionTo = it "tests float to integer conversion" [ - (assertEq "round" - (builtins.map float.round exampleFloats) - [ 1 0 0 0 200 203 205 (-2) (-2) (-1) 0 ]) - (assertEq "truncate towards zero" - (builtins.map float.truncate exampleFloats) - [ 0 0 0 0 200 203 204 (-1) (-2) (-1) 0 ]) - ]; -in - -runTestsuite "nix.num" ([ - testsConversionFrom -] - # Skip for e.g. C++ Nix < 2.4 -++ lib.optionals (builtins ? ceil && builtins ? floor) [ - testsConversionTo - testsBuiltins -]) diff --git a/users/sterni/nix/flow/default.nix b/users/sterni/nix/flow/default.nix deleted file mode 100644 index 4bef0abb9..000000000 --- a/users/sterni/nix/flow/default.nix +++ /dev/null @@ -1,83 +0,0 @@ -{ depot, ... }: - -let - - inherit (depot.nix) - yants - ; - - inherit (depot.users.sterni.nix) - fun - ; - - # we must avoid evaluating any of the sublists - # as they may contain conditions that throw - condition = yants.restrict "condition" - (ls: builtins.length ls == 2) - (yants.list yants.any); - - /* Like the common lisp macro: takes a list - of two elemented lists whose first element - is a boolean. The second element of the - first list that has true as its first - element is returned. - - Type: [ [ bool a ] ] -> a - - Example: - - cond [ - [ (builtins.isString true) 12 ] - [ (3 == 2) 13 ] - [ true 42 ] - ] - - => 42 - */ - cond = conds: switch true conds; - - /* Generic pattern match-ish construct for nix. - Takes a bunch of lists which are of length - two and checks the first element for either - a predicate or a value. The second value of - the first list which either has a value equal - to or a function that evaluates to true for - the given value. - - Type: a -> [ [ (function | a) b ] ] -> b - - Example: - - switch "foo" [ - [ "smol" "SMOL!!!" ] - [ (x: builtins.stringLength x <= 3) "smol-ish" ] - [ (fun.const true) "not smol" ] - ] - - => "smol-ish" - */ - switch = x: conds: - if builtins.length conds == 0 - then builtins.throw "exhausted all conditions" - else - let - c = condition (builtins.head conds); - s = builtins.head c; - b = - if builtins.isFunction s - then s x - else x == s; - in - if b - then builtins.elemAt c 1 - else switch x (builtins.tail conds); - - - -in -{ - inherit - cond - switch - ; -} diff --git a/users/sterni/nix/flow/tests/default.nix b/users/sterni/nix/flow/tests/default.nix deleted file mode 100644 index 9f974a61c..000000000 --- a/users/sterni/nix/flow/tests/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ depot, ... }: - -let - - inherit (depot.nix.runTestsuite) - runTestsuite - it - assertEq - assertThrows - ; - - inherit (depot.users.sterni.nix.flow) - cond - match - ; - - dontEval = builtins.throw "this should not get evaluated"; - - testCond = it "tests cond" [ - (assertThrows "malformed cond list" - (cond [ [ true 1 2 ] [ false 1 ] ])) - (assertEq "last is true" "last" - (cond [ - [ false dontEval ] - [ false dontEval ] - [ true "last" ] - ])) - (assertEq "first is true" 1 - (cond [ - [ true 1 ] - [ true dontEval ] - [ true dontEval ] - ])) - ]; - -in -runTestsuite "nix.flow" [ - testCond -] diff --git a/users/sterni/nix/fun/default.nix b/users/sterni/nix/fun/default.nix deleted file mode 100644 index 824cebfed..000000000 --- a/users/sterni/nix/fun/default.nix +++ /dev/null @@ -1,255 +0,0 @@ -{ depot, lib, ... }: - -let - - inherit (lib) - id - ; - - # Simple function composition, - # application is right to left. - rl = f1: f2: - (x: f1 (f2 x)); - - # Compose a list of functions, - # application is right to left. - rls = fs: - builtins.foldl' (fOut: f: lr f fOut) id fs; - - # Simple function composition, - # application is left to right. - lr = f1: f2: - (x: f2 (f1 x)); - - # Compose a list of functions, - # application is left to right - lrs = x: fs: - builtins.foldl' (v: f: f v) x fs; - - # Warning: cursed function - # - # Check if a function has an attribute - # set pattern with an ellipsis as its argument. - # - # s/o to puck for discovering that you could use - # builtins.toXML to introspect functions more than - # you should be able to in Nix. - hasEllipsis = f: - builtins.isFunction f && - builtins.match ".*.*" - (builtins.toXML f) != null; - - /* Return the number of arguments the given function accepts or 0 if the value - is not a function. - - Example: - - argCount argCount - => 1 - - argCount builtins.add - => 2 - - argCount pkgs.stdenv.mkDerivation - => 1 - */ - argCount = f: - let - # N.B. since we are only interested if the result of calling is a function - # as opposed to a normal value or evaluation failure, we never need to - # check success, as value will be false (i.e. not a function) in the - # failure case. - called = builtins.tryEval ( - f (builtins.throw "You should never see this error message") - ); - in - if !(builtins.isFunction f || builtins.isFunction (f.__functor or null)) - then 0 - else 1 + argCount called.value; - - /* Call a given function with a given list of arguments. - - Example: - - apply builtins.sub [ 20 10 ] - => 10 - */ - apply = f: args: - builtins.foldl' (f: x: f x) f args; - - # TODO(sterni): think of a better name for unapply - /* Collect n arguments into a list and pass them to the given function. - Allows calling a function that expects a list by feeding it the list - elements individually as function arguments - the limitation is - that the list must be of constant length. - - This is mainly useful for functions that wrap other, arbitrary functions - in conjunction with argCount and apply, since lists of arguments are - easier to deal with usually. - - Example: - - (unapply 3 lib.id) 1 2 3 - => [ 1 2 3 ] - - (unapply 5 lib.reverse) 1 2 null 4 5 - => [ 5 4 null 2 1 ] - - # unapply and apply compose the identity relation together - - unapply (argCount f) (apply f) - # is equivalent to f (if the function has a constant number of arguments) - - (unapply 2 (apply builtins.sub)) 20 10 - => 10 - */ - unapply = - let - unapply' = acc: n: f: x: - if n == 1 - then f (acc ++ [ x ]) - else unapply' (acc ++ [ x ]) (n - 1) f; - in - unapply' [ ]; - - /* Optimize a tail recursive Nix function by intercepting the recursive - function application and expressing it in terms of builtins.genericClosure - instead. The main benefit of this optimization is that even a naively - written recursive algorithm won't overflow the stack. - - For this to work the following things prerequisites are necessary: - - - The passed function needs to be a fix point for its self reference, - i. e. the argument to tailCallOpt needs to be of the form - `self: # function body that uses self to call itself`. - This is because tailCallOpt needs to manipulate the call to self - which otherwise wouldn't be possible due to Nix's lexical scoping. - - - The passed function may only call itself as a tail call, all other - forms of recursions will fail evaluation. - - This function was mainly written to prove that builtins.genericClosure - can be used to express any (tail) recursive algorithm. It can be used - to avoid stack overflows for deeply recursive, but naively written - functions (in the context of Nix this mainly means using recursion - instead of (ab)using more performant and less limited builtins). - A better alternative to using this function is probably translating - the algorithm to builtins.genericClosure manually. Also note that - using tailCallOpt doesn't mean that the stack won't ever overflow: - Data structures, especially lazy ones, can still cause all the - available stack space to be consumed. - - The optimization also only concerns avoiding stack overflows, - tailCallOpt will make functions slower if anything. - - Type: (F -> F) -> F where F is any tail recursive function. - - Example: - - let - label' = self: acc: n: - if n == 0 - then "This is " + acc + "cursed." - else self (acc + "very ") (n - 1); - - # Equivalent to a naive recursive implementation in Nix - label = (lib.fix label') ""; - - labelOpt = (tailCallOpt label') ""; - in - - label 5 - => "This is very very very very very cursed." - - labelOpt 5 - => "This is very very very very very cursed." - - label 10000 - => error: stack overflow (possible infinite recursion) - - labelOpt 10000 - => "This is very very very very very very very very very… - */ - tailCallOpt = f: - let - argc = argCount (lib.fix f); - - # This function simulates being f for f's self reference. Instead of - # recursing, it will just return the arguments received as a specially - # tagged set, so the recursion step can be performed later. - fakef = unapply argc (args: { - __tailCall = true; - inherit args; - }); - # Pass fakef to f so that it'll be called instead of recursing, ensuring - # only one recursion step is performed at a time. - encodedf = f fakef; - - opt = args: - let - steps = builtins.genericClosure { - # This is how we encode a (tail) call: A set with final == false - # and the list of arguments to pass to be found in args. - startSet = [ - { - key = 0; - final = false; - inherit args; - } - ]; - - operator = - { key, final, ... }@state: - let - # Plumbing to make genericClosure happy - newId = { - key = key + 1; - }; - - # Perform recursion step - call = apply encodedf state.args; - - # If call encodes a new call, return the new encoded call, - # otherwise signal that we're done. - newState = - if builtins.isAttrs call && call.__tailCall or false - then newId // { - final = false; - inherit (call) args; - } else newId // { - final = true; - value = call; - }; - in - - if final - then [ ] # end condition for genericClosure - else [ newState ]; - }; - in - # The returned list contains intermediate steps we ignore. - (builtins.head (builtins.filter (x: x.final) steps)).value; - in - unapply argc opt; -in - -{ - inherit (lib) - fix - flip - const - ; - - inherit - id - rl - rls - lr - lrs - hasEllipsis - argCount - tailCallOpt - apply - unapply - ; -} diff --git a/users/sterni/nix/fun/tests/default.nix b/users/sterni/nix/fun/tests/default.nix deleted file mode 100644 index 6b1e6fcc7..000000000 --- a/users/sterni/nix/fun/tests/default.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.nix.runTestsuite) - runTestsuite - it - assertEq - ; - - inherit (depot.nix) escapeExecline; - - inherit (depot.users.sterni.nix) - fun - ; - - hasEllipsisTests = it "checks fun.hasEllipsis" [ - (assertEq "Malicious string" false - (fun.hasEllipsis (builtins.toXML ({ foo, ... }: 12)))) - (assertEq "No function" false - (fun.hasEllipsis 23)) - (assertEq "No attribute set pattern" false - (fun.hasEllipsis (a: a + 2))) - (assertEq "No ellipsis" false - (fun.hasEllipsis ({ foo, bar }: foo + bar))) - (assertEq "Ellipsis" true - (fun.hasEllipsis ({ depot, pkgs, ... }: 42))) - ]; - - argCountTests = it "checks fun.argCount" [ - (assertEq "builtins.sub has two arguments" 2 - (fun.argCount builtins.sub)) - (assertEq "fun.argCount has one argument" 1 - (fun.argCount fun.argCount)) - (assertEq "runTestsuite has two arguments" 2 - (fun.argCount runTestsuite)) - ]; - - applyTests = it "checks that fun.apply is equivalent to calling" [ - (assertEq "fun.apply builtins.sub" (builtins.sub 23 42) - (fun.apply builtins.sub [ 23 42 ])) - (assertEq "fun.apply escapeExecline" (escapeExecline [ "foo" [ "bar" ] ]) - (fun.apply escapeExecline [ [ "foo" [ "bar" ] ] ])) - ]; - - unapplyTests = it "checks fun.unapply" [ - (assertEq "fun.unapply 3 accepts 3 args" 3 - (fun.argCount (fun.unapply 3 fun.id))) - (assertEq "fun.unapply 73 accepts 73 args" 73 - (fun.argCount (fun.unapply 73 fun.id))) - (assertEq "fun.unapply 1 accepts 73 args" 1 - (fun.argCount (fun.unapply 1 fun.id))) - (assertEq "fun.unapply collects arguments correctly" - (fun.unapply 5 fun.id 1 2 3 4 5) - [ 1 2 3 4 5 ]) - (assertEq "fun.unapply calls the given function correctly" 1 - (fun.unapply 1 builtins.head 1)) - ]; - - fac' = self: acc: n: if n == 0 then acc else self (n * acc) (n - 1); - - facPlain = fun.fix fac' 1; - facOpt = fun.tailCallOpt fac' 1; - - tailCallOptTests = it "checks fun.tailCallOpt" [ - (assertEq "optimized and unoptimized factorial have the same base case" - (facPlain 0) - (facOpt 0)) - (assertEq "optimized and unoptimized factorial have same value for 1" - (facPlain 1) - (facOpt 1)) - (assertEq "optimized and unoptimized factorial have same value for 100" - (facPlain 100) - (facOpt 100)) - ]; -in -runTestsuite "nix.fun" [ - hasEllipsisTests - argCountTests - applyTests - unapplyTests - tailCallOptTests -] diff --git a/users/sterni/nix/html/README.md b/users/sterni/nix/html/README.md deleted file mode 100644 index d636244c9..000000000 --- a/users/sterni/nix/html/README.md +++ /dev/null @@ -1,148 +0,0 @@ -# html.nix — _the_ most cursed Nix HTML DSL - -A quick example to show you what it looks like: - -```nix -# Note: this example is for standalone usage out of depot -{ pkgs ? import {} }: - -let - # zero dependency, one file implementation - htmlNix = import ./path/to/html.nix { }; - - # make the magic work - inherit (htmlNix) __findFile esc; -in - -pkgs.writeText "example.html" ( {} [ - ( {} [ - ( { charset = "utf-8"; } null) - ( {} (esc "hello world")) - ]) - (<body> {} [ - (<h1> {} (esc "hello world")) - (<p> { class = "intro"; } (esc '' - welcome to the land of sillyness! - '')) - (<ul> {} [ - (<li> {} [ - (esc "check out ") - (<a> { href = "https://code.tvl.fyi"; } "depot") - ]) - (<li> {} [ - (esc "find ") - (<a> { href = "https://cl.tvl.fyi/q/hashtag:cursed"; } "cursed things") - ]) - ]) - ]) -]) -``` - -Convince yourself it works: - -```console -$ $BROWSER $(nix-build example.nix) -``` - -Alternatively, in depot: - -```console -$ $BROWSER $(nix-build -A users.sterni.nix.html.tests) -``` - -## Creating tags - -An empty tag is passed `null` as its content argument: - -```nix -<link> { - rel = "stylesheet"; - href = "/main.css"; - type = "text/css"; -} null - -# => "<link href=\"/main.css\" rel=\"stylesheet\" type=\"text/css\"/>" -``` - -Content is expected to be HTML: - -```nix -<div> { class = "foo"; } "<strong>hi</strong>" - -# => "<div class=\"foo\"><strong>hi</strong></div>" -``` - -If it's not, be sure to escape it: - -```nix -<p> {} (esc "A => B") - -# => "<p>A => B</p>" -``` - -Nesting tags works of course: - -```nix -<div> {} (<strong> {} (<em> {} "hi")) - -# => "<div><strong><em>hi</em></strong></div>" -``` - -If the content of a tag is a list, it's concatenated: - -```nix -<h1> {} [ - (esc "The ") - (<strong> {} "Nix") - (esc " ") - (<em> {} "Expression") - (esc " Language") -] - -# => "<h1>The <strong>Nix</strong> <em>Expression</em> Language</h1>" -``` - -More detailed documentation can be found in `nixdoc`-compatible -comments in the source file (`default.nix` in this directory). - -## How does this work? - -*Theoretically* expressions like `<nixpkgs>` are just ordinary paths — -their actual value is determined from `NIX_PATH`. `html.nix` works -because of how this is actually implemented: At [parse time][spath-parsing] -Nix transparently translates an expression like `<foo>` into -`__findFile __nixPath "foo"`: - -``` -nix-repl> <nixpkgs> -/nix/var/nix/profiles/per-user/root/channels/vuizvui/nixpkgs - -nix-repl> __findFile __nixPath "nixpkgs" -/nix/var/nix/profiles/per-user/root/channels/vuizvui/nixpkgs -``` - -This translation doesn't take any scoping issues into account -- -so we can just shadow `__findFile` and make it return anything, -even a function: - -``` -nix-repl> __findFile = nixPath: str: - /**/ if str == "double" then x: x * 2 - else if str == "triple" then x: x * 3 - else throw "what?" - -nix-repl> <double> 2 -4 - -nix-repl> <triple> 3 -9 - -nix-repl> <quadruple> 4 -error: what? -``` - -Exactly this is what we are doing in `html.nix`: -Using `let inherit (htmlNix) __findFile; in` we shadow the builtin `__findFile` -with a function which returns a function rendering a particular HTML tag. - -[spath-parsing]: https://github.com/NixOS/nix/blob/293220bed5a75efc963e33c183787e87e55e28d9/src/libexpr/parser.y#L410-L416 diff --git a/users/sterni/nix/html/default.nix b/users/sterni/nix/html/default.nix deleted file mode 100644 index 9ffecc1d4..000000000 --- a/users/sterni/nix/html/default.nix +++ /dev/null @@ -1,127 +0,0 @@ -# SPDX-FileCopyrightText: Copyright © 2021, 2024 sterni -# SPDX-License-Identifier: MIT -# -# This file provides a cursed HTML DSL for nix which works by overloading -# the NIX_PATH lookup operation via angle bracket operations, e. g. `<nixpkgs>`. - -{ ... }: - -let - /* Escape everything we have to escape in an HTML document if either - in a normal context or an attribute string (`<>&"'`). - - A shorthand for this function called `esc` is also provided. - - Type: string -> string - - Example: - - escapeMinimal "<hello>" - => "<hello>" - */ - escapeMinimal = builtins.replaceStrings - [ "<" ">" "&" "\"" "'" ] - [ "<" ">" "&" """ "'" ]; - - /* Return a string with a correctly rendered tag of the given name, - with the given attributes which are automatically escaped. - - If the content argument is `null`, the tag will have no children nor a - closing element. If the content argument is a string it is used as the - content as is (unescaped). If the content argument is a list, its - elements are concatenated (recursively if necessary). - - `renderTag` is only an internal function which is reexposed as `__findFile` - to allow for much neater syntax than calling `renderTag` everywhere: - - ```nix - { depot, ... }: - let - inherit (depot.users.sterni.nix.html) __findFile esc; - in - - <html> {} [ - (<head> {} (<title> {} (esc "hello world"))) - (<body> {} [ - (<h1> {} (esc "hello world")) - (<p> {} (esc "foo bar")) - ]) - ] - - ``` - - As you can see, the need to call a function disappears, instead the - `NIX_PATH` lookup operation via `<foo>` is overloaded, so it becomes - `renderTag "foo"` automatically. - - Since the content argument may contain the result of other `renderTag` - calls, we can't escape it automatically. Instead this must be done manually - using `esc`. - - If the tag is "html", e.g. in case of `<html> { } …`, "<!DOCTYPE html> will - be prepended to the normal rendering of the text. - - Type: string -> attrs<string> -> (list<string> | string | null) -> string - - Example: - - <link> { - rel = "stylesheet"; - href = "/css/main.css"; - type = "text/css"; - } null - - renderTag "link" { - rel = "stylesheet"; - href = "/css/main.css"; - type = "text/css"; - } null - - => "<link href=\"/css/main.css\" rel=\"stylesheet\" type=\"text/css\"/>" - - <p> {} [ - "foo " - (<strong> {} "bar") - ] - - renderTag "p" {} "foo <strong>bar</strong>" - => "<p>foo <strong>bar</strong></p>" - */ - renderTag = tag: attrs: content: - let - attrs' = builtins.concatStringsSep "" ( - builtins.map - (n: - " ${escapeMinimal n}=\"${escapeMinimal (toString attrs.${n})}\"" - ) - (builtins.attrNames attrs) - ); - content' = - if builtins.isList content - then builtins.concatStringsSep "" (flatten content) - else content; - in - (if tag == "html" then "<!DOCTYPE html>" else "") + - (if content == null - then "<${tag}${attrs'}/>" - else "<${tag}${attrs'}>${content'}</${tag}>"); - - /* Deprecated, does nothing. - */ - withDoctype = doc: builtins.trace - "WARN: withDoctype no longer does anything, `<html> { } [ … ]` takes care of rendering <!DOCTYPE html>" - doc; - - /* Taken from <nixpkgs/lib/lists.nix>. */ - flatten = x: - if builtins.isList x - then builtins.concatMap (y: flatten y) x - else [ x ]; - -in -{ - inherit escapeMinimal renderTag withDoctype; - - __findFile = _: renderTag; - esc = escapeMinimal; -} diff --git a/users/sterni/nix/html/tests/default.nix b/users/sterni/nix/html/tests/default.nix deleted file mode 100644 index 4c386f874..000000000 --- a/users/sterni/nix/html/tests/default.nix +++ /dev/null @@ -1,98 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.users.sterni.nix.html) - __findFile - esc - ; - - exampleDocument = <html> { lang = "en"; } [ - (<head> { } [ - (<meta> { charset = "utf-8"; } null) - (<title> { } "html.nix example document") - (<link> - { - rel = "license"; - href = "https://code.tvl.fyi/about/LICENSE"; - type = "text/html"; - } - null) - (<style> { } (esc '' - hgroup h2 { - font-weight: normal; - } - - dd { - margin: 0; - } - '')) - ]) - (<body> { } [ - (<main> { } [ - (<hgroup> { } [ - (<h1> { } (esc "html.nix")) - (<h2> { } [ - (<em> { } "the") - # test flattening - [ - (esc " ") - (esc "most") - [ (esc " cursed ") ] - (esc "HTML DSL ever!") - ] - ]) - ]) - (<dl> { } [ - (<dt> { } [ - (esc "Q: Wait, it's all ") - (<a> - { - href = "https://cl.tvl.fyi/q/hashtag:cursed"; - } - (esc "cursed")) - (esc " nix hacks?") - ]) - (<dd> { } (esc "A: Always has been. 🔫")) - (<dt> { } (esc "Q: Why does this work?")) - (<dd> { } [ - (esc "Because nix ") - (<a> - { - href = "https://github.com/NixOS/nix/blob/293220bed5a75efc963e33c183787e87e55e28d9/src/libexpr/parser.y#L410-L416"; - } - (esc "translates ")) - (<a> - { - href = "https://github.com/NixOS/nix/blob/293220bed5a75efc963e33c183787e87e55e28d9/src/libexpr/lexer.l#L100"; - } - (esc "SPATH tokens")) - (esc " like ") - (<code> { } (esc "<nixpkgs>")) - (esc " into calls to ") - (<code> { } (esc "__findFile")) - (esc " in the ") - (<em> { } (esc "current")) - (esc " scope.") - ]) - ]) - ]) - ]) - ]; -in - -pkgs.runCommand "html.nix.html" -{ - passAsFile = [ "exampleDocument" ]; - inherit exampleDocument; - nativeBuildInputs = [ pkgs.html5validator ]; -} '' - set -x - test "${esc "<> && \" \'"}" = "<> && " '" - - # slow as hell unfortunately - html5validator "$exampleDocumentPath" - - mv "$exampleDocumentPath" "$out" - - set +x -'' diff --git a/users/sterni/nix/int/default.nix b/users/sterni/nix/int/default.nix deleted file mode 100644 index 870744522..000000000 --- a/users/sterni/nix/int/default.nix +++ /dev/null @@ -1,114 +0,0 @@ -{ depot, lib, ... }: - -let - - inherit (depot.users.sterni.nix) - string - num - ; - - inherit (builtins) - bitOr - bitAnd - bitXor - ; - - exp = base: pow: - if pow > 0 - then base * (exp base (pow - 1)) - else if pow < 0 - then 1.0 / exp base (num.abs pow) - else 1; - - bitShiftR = bit: count: - if count == 0 - then bit - else (bitShiftR bit (count - 1)) / 2; - - bitShiftL = bit: count: - if count == 0 - then bit - else 2 * (bitShiftL bit (count - 1)); - - hexdigits = "0123456789ABCDEF"; - - toHex = int: - let - go = i: - if i == 0 - then "" - else go (bitShiftR i 4) - + string.charAt (bitAnd i 15) hexdigits; - sign = lib.optionalString (int < 0) "-"; - in - if int == 0 - then "0" - else "${sign}${go (num.abs int)}"; - - fromHexMap = builtins.listToAttrs - (lib.imap0 (i: c: { name = c; value = i; }) - (lib.stringToCharacters hexdigits)); - - fromHex = literal: - let - negative = string.charAt 0 literal == "-"; - start = if negative then 1 else 0; - len = builtins.stringLength literal; - # reversed list of all digits - digits = builtins.genList - (i: string.charAt (len - 1 - i) literal) - (len - start); - parsed = builtins.foldl' - (v: d: { - val = v.val + (fromHexMap."${d}" * v.mul); - mul = v.mul * 16; - }) - { val = 0; mul = 1; } - digits; - in - if negative - then -parsed.val - else parsed.val; - - # A nix integer is a 64bit signed integer - maxBound = 9223372036854775807; - - # fun fact: -9223372036854775808 is the lower bound - # for a nix integer (as you would expect), but you can't - # use it as an integer literal or you'll be greeted with: - # error: invalid integer '9223372036854775808' - # This is because all int literals when parsing are - # positive, negative "literals" are positive literals - # which are preceded by the arithmetric negation operator. - minBound = -9223372036854775807 - 1; - - odd = x: bitAnd x 1 == 1; - even = x: bitAnd x 1 == 0; - - quot' = builtins.div; # no typecheck - rem = a: b: - assert builtins.isInt a && builtins.isInt b; - let res = quot' a b; in a - (res * b); - quot = a: b: - assert builtins.isInt a && builtins.isInt b; - quot' a b; - -in -{ - inherit - maxBound - minBound - exp - odd - even - quot - rem - bitShiftR - bitShiftL - bitOr - bitAnd - bitXor - toHex - fromHex - ; -} diff --git a/users/sterni/nix/int/tests/default.nix b/users/sterni/nix/int/tests/default.nix deleted file mode 100644 index 80bd05b6b..000000000 --- a/users/sterni/nix/int/tests/default.nix +++ /dev/null @@ -1,455 +0,0 @@ -{ depot, lib, ... }: - -let - - inherit (depot.nix.runTestsuite) - runTestsuite - it - assertEq - ; - - inherit (depot.users.sterni.nix) - int - string - fun - ; - - testBounds = it "checks minBound and maxBound" [ - (assertEq "maxBound is the maxBound" true - (int.maxBound + 1 < int.maxBound)) - (assertEq "minBound is the minBound" true - (int.minBound - 1 > int.minBound)) - (assertEq "maxBound overflows to minBound" - (int.maxBound + 1) - int.minBound) - (assertEq "minBound overflows to maxBound" - (int.minBound - 1) - int.maxBound) - ]; - - expectedBytes = [ - "00" - "01" - "02" - "03" - "04" - "05" - "06" - "07" - "08" - "09" - "0A" - "0B" - "0C" - "0D" - "0E" - "0F" - "10" - "11" - "12" - "13" - "14" - "15" - "16" - "17" - "18" - "19" - "1A" - "1B" - "1C" - "1D" - "1E" - "1F" - "20" - "21" - "22" - "23" - "24" - "25" - "26" - "27" - "28" - "29" - "2A" - "2B" - "2C" - "2D" - "2E" - "2F" - "30" - "31" - "32" - "33" - "34" - "35" - "36" - "37" - "38" - "39" - "3A" - "3B" - "3C" - "3D" - "3E" - "3F" - "40" - "41" - "42" - "43" - "44" - "45" - "46" - "47" - "48" - "49" - "4A" - "4B" - "4C" - "4D" - "4E" - "4F" - "50" - "51" - "52" - "53" - "54" - "55" - "56" - "57" - "58" - "59" - "5A" - "5B" - "5C" - "5D" - "5E" - "5F" - "60" - "61" - "62" - "63" - "64" - "65" - "66" - "67" - "68" - "69" - "6A" - "6B" - "6C" - "6D" - "6E" - "6F" - "70" - "71" - "72" - "73" - "74" - "75" - "76" - "77" - "78" - "79" - "7A" - "7B" - "7C" - "7D" - "7E" - "7F" - "80" - "81" - "82" - "83" - "84" - "85" - "86" - "87" - "88" - "89" - "8A" - "8B" - "8C" - "8D" - "8E" - "8F" - "90" - "91" - "92" - "93" - "94" - "95" - "96" - "97" - "98" - "99" - "9A" - "9B" - "9C" - "9D" - "9E" - "9F" - "A0" - "A1" - "A2" - "A3" - "A4" - "A5" - "A6" - "A7" - "A8" - "A9" - "AA" - "AB" - "AC" - "AD" - "AE" - "AF" - "B0" - "B1" - "B2" - "B3" - "B4" - "B5" - "B6" - "B7" - "B8" - "B9" - "BA" - "BB" - "BC" - "BD" - "BE" - "BF" - "C0" - "C1" - "C2" - "C3" - "C4" - "C5" - "C6" - "C7" - "C8" - "C9" - "CA" - "CB" - "CC" - "CD" - "CE" - "CF" - "D0" - "D1" - "D2" - "D3" - "D4" - "D5" - "D6" - "D7" - "D8" - "D9" - "DA" - "DB" - "DC" - "DD" - "DE" - "DF" - "E0" - "E1" - "E2" - "E3" - "E4" - "E5" - "E6" - "E7" - "E8" - "E9" - "EA" - "EB" - "EC" - "ED" - "EE" - "EF" - "F0" - "F1" - "F2" - "F3" - "F4" - "F5" - "F6" - "F7" - "F8" - "F9" - "FA" - "FB" - "FC" - "FD" - "FE" - "FF" - ]; - - hexByte = i: string.fit { width = 2; char = "0"; } (int.toHex i); - - hexInts = [ - { left = 0; right = "0"; } - { left = 1; right = "1"; } - { left = 11; right = "B"; } - { left = 123; right = "7B"; } - { left = 9000; right = "2328"; } - { left = 2323; right = "913"; } - { left = 4096; right = "1000"; } - { left = int.maxBound; right = "7FFFFFFFFFFFFFFF"; } - { left = int.minBound; right = "-8000000000000000"; } - ]; - - testHex = it "checks conversion to hex" (lib.flatten [ - (lib.imap0 - (i: hex: [ - (assertEq "hexByte ${toString i} == ${hex}" (hexByte i) hex) - (assertEq "${toString i} == fromHex ${hex}" i (int.fromHex hex)) - ]) - expectedBytes) - (builtins.map - ({ left, right }: [ - (assertEq "toHex ${toString left} == ${right}" (int.toHex left) right) - (assertEq "${toString left} == fromHex ${right}" left (int.fromHex right)) - ]) - hexInts) - ]); - - testBasic = it "checks basic int operations" [ - (assertEq "122 is even" (int.even 122 && !(int.odd 122)) true) - (assertEq "123 is odd" (int.odd 123 && !(int.even 123)) true) - ]; - - expNumbers = [ - { left = -3; right = 0.125; } - { left = -2; right = 0.25; } - { left = -1; right = 0.5; } - { left = 0; right = 1; } - { left = 1; right = 2; } - { left = 2; right = 4; } - { left = 3; right = 8; } - { left = 4; right = 16; } - { left = 5; right = 32; } - { left = 16; right = 65536; } - ]; - - testExp = it "checks exponentiation" - (builtins.map - ({ left, right }: - assertEq - "2 ^ ${toString left} == ${toString right}" - (int.exp 2 left) - right) - expNumbers); - - shifts = [ - { a = 2; b = 5; c = 64; op = "<<"; } - { a = -2; b = 5; c = -64; op = "<<"; } - { a = 123; b = 4; c = 1968; op = "<<"; } - { a = 1; b = 8; c = 256; op = "<<"; } - { a = 256; b = 8; c = 1; op = ">>"; } - { a = 374; b = 2; c = 93; op = ">>"; } - { a = 2; b = 2; c = 0; op = ">>"; } - { a = 99; b = 9; c = 0; op = ">>"; } - ]; - - checkShift = { a, b, c, op }@args: - let - f = string.match op { - "<<" = int.bitShiftL; - ">>" = int.bitShiftR; - }; - in - assertEq "${toString a} ${op} ${toString b} == ${toString c}" (f a b) c; - - checkShiftRDivExp = n: - assertEq "${toString n} >> 5 == ${toString n} / 2 ^ 5" - (int.bitShiftR n 5) - (n / (int.exp 2 5)); - - checkShiftLMulExp = n: - assertEq "${toString n} >> 6 == ${toString n} * 2 ^ 6" - (int.bitShiftL n 5) - (n * (int.exp 2 5)); - - testBit = it "checks bitwise operations" (lib.flatten [ - (builtins.map checkShift shifts) - (builtins.map checkShiftRDivExp [ - 1 - 2 - 3 - 5 - 7 - 23 - 1623 - 238 - 34 - 348 - 2834 - 834 - 348 - ]) - (builtins.map checkShiftLMulExp [ - 1 - 2 - 3 - 5 - 7 - 23 - 384 - 3 - 2 - 5991 - 85109 - 38 - ]) - ]); - - divisions = [ - { a = 2; b = 1; c = 2; rem = 0; } - { a = 2; b = 2; c = 1; rem = 0; } - { a = 20; b = 10; c = 2; rem = 0; } - { a = 12; b = 5; c = 2; rem = 2; } - { a = 23; b = 4; c = 5; rem = 3; } - ]; - - checkQuot = n: { a, b, c, rem }: [ - (assertEq "${n}: quot result" (int.quot a b) c) - (assertEq "${n}: rem result" (int.rem a b) rem) - (assertEq "${n}: quotRem law" ((int.quot a b) * b + (int.rem a b)) a) - ]; - - testQuotRem = it "checks integer quotient and remainder" - (lib.flatten [ - (builtins.map (checkQuot "+a / +b") divisions) - (builtins.map - (fun.rl (checkQuot "-a / +b") (x: x // { - a = -x.a; - c = -x.c; - rem = -x.rem; - })) - divisions) - (builtins.map - (fun.rl (checkQuot "+a / -b") (x: x // { - b = -x.b; - c = -x.c; - })) - divisions) - (builtins.map - (fun.rl (checkQuot "-a / -b") (x: x // { - a = -x.a; - b = -x.b; - rem = -x.rem; - })) - divisions) - ]); - -in -runTestsuite "nix.int" [ - testBounds - testHex - testBasic - testExp - testBit - testQuotRem -] diff --git a/users/sterni/nix/list/default.nix b/users/sterni/nix/list/default.nix deleted file mode 100644 index 568a76d63..000000000 --- a/users/sterni/nix/list/default.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ ... }: - -{ - /* For a list of length n that consists of lists of length m, - return a list of length m containing lists of length n - so that - - builtins.elemAt (builtins.elemAt orig a) b - == builtins.elemAt (builtins.elemAt transposed b) a - - Essentially, if you think of the nested list as an array with two - dimensions, the two index axes are swapped. - - The length of the inner lists m is determined based on the first element - and assumed to be used for all other lists. Malformed input data may - cause the function to crash or lose data. - - Type: <n>[ <m>[ ] ] -> <m>[ <n>[ ] ] - */ - transpose = list: - let - innerLength = builtins.length (builtins.head list); - outerLength = builtins.length list; - in - builtins.genList - (inner: builtins.genList - (outer: builtins.elemAt (builtins.elemAt list outer) inner) - outerLength) - innerLength; -} diff --git a/users/sterni/nix/misc/default.nix b/users/sterni/nix/misc/default.nix deleted file mode 100644 index 1de9c973e..000000000 --- a/users/sterni/nix/misc/default.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ ... }: - -let - /* Returns true if it is being evaluated using restrict-eval, false if not. - It's more robust than using `builtins.getEnv` since it isn't fooled by - `env -i`. - - See https://github.com/NixOS/nix/issues/6579 for a description of the - behavior. Precise cause in the evaluator / store implementation is unclear. - - Type: bool - */ - inRestrictedEval = builtins.pathExists (toString ./guinea-pig + "/."); -in - -{ - inherit inRestrictedEval; -} diff --git a/users/sterni/nix/misc/guinea-pig b/users/sterni/nix/misc/guinea-pig deleted file mode 120000 index 73537e478..000000000 --- a/users/sterni/nix/misc/guinea-pig +++ /dev/null @@ -1 +0,0 @@ -default.nix \ No newline at end of file diff --git a/users/sterni/nix/num/default.nix b/users/sterni/nix/num/default.nix deleted file mode 100644 index 81e2f8377..000000000 --- a/users/sterni/nix/num/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ ... }: - -rec { - inherit (builtins) - mul - div - add - sub - ; - - sign = i: if i < 0 then -1 else 1; - abs = i: if i < 0 then -i else i; - - inRange = a: b: x: x >= a && x <= b; - - sum = builtins.foldl' (a: b: a + b) 0; -} diff --git a/users/sterni/nix/num/tests/default.nix b/users/sterni/nix/num/tests/default.nix deleted file mode 100644 index ca5f861de..000000000 --- a/users/sterni/nix/num/tests/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ depot, ... }: - -let - - inherit (depot.nix.runTestsuite) - runTestsuite - it - assertEq - ; - - inherit (depot.users.sterni.nix) - num - ; - - testsBasic = it "tests basic operations" [ - (assertEq "abs -4959" (num.abs (-4959)) 4959) - (assertEq "sum" (num.sum [ 123 321 1.5 ]) (123 + 321 + 1.5)) - (assertEq "inRange" - (builtins.map (num.inRange 1.0 5) [ 0 0.5 3 4 4.5 5.5 5 6 ]) - [ false false true true true false true false ]) - ]; -in - -runTestsuite "nix.num" [ - testsBasic -] diff --git a/users/sterni/nix/string/default.nix b/users/sterni/nix/string/default.nix deleted file mode 100644 index 381c8ddff..000000000 --- a/users/sterni/nix/string/default.nix +++ /dev/null @@ -1,121 +0,0 @@ -{ depot, lib, ... }: - -let - - inherit (depot.users.sterni.nix.char) - chr - ord - ; - - inherit (depot.users.sterni.nix) - int - flow - ; - - take = n: s: - builtins.substring 0 n s; - - drop = n: s: - builtins.substring n int.maxBound s; - - charAt = i: s: - let - r = builtins.substring i 1 s; - in - if r == "" then null else r; - - charIndex = char: s: - let - len = builtins.stringLength s; - go = i: - flow.cond [ - [ (i >= len) null ] - [ (charAt i s == char) i ] - [ true (go (i + 1)) ] - ]; - in - go 0; - - toChars = lib.stringToCharacters; - fromChars = lib.concatStrings; - - toBytes = str: - builtins.map ord (toChars str); - - fromBytes = is: lib.concatMapStrings chr is; - - pad = { left ? 0, right ? 0, char ? " " }: s: - let - leftS = fromChars (builtins.genList (_: char) left); - rightS = fromChars (builtins.genList (_: char) right); - in - "${leftS}${s}${rightS}"; - - fit = { char ? " ", width, side ? "left" }: s: - let - diff = width - builtins.stringLength s; - in - if diff <= 0 - then s - else pad { inherit char; "${side}" = diff; } s; - - # pattern matching for strings only - match = val: matcher: matcher."${val}"; - - /* Bare-bones printf implementation. Supported format specifiers: - - * `%%` escapes `%` - * `%s` is substituted by a string - - As expected, the first argument is a format string and the values - for its format specifiers need to provided as the next arguments - in order. - - Type: string -> (printfVal : either string (a -> printfVal)) - */ - printf = formatString: - let - specifierWithArg = token: builtins.elem token [ - "%s" - ]; - isSpecifier = lib.hasPrefix "%"; - - tokens = lib.flatten (builtins.split "(%.)" formatString); - argsNeeded = builtins.length (builtins.filter specifierWithArg tokens); - - format = args: (builtins.foldl' - ({ out ? "", argIndex ? 0 }: token: { - argIndex = argIndex + (if specifierWithArg token then 1 else 0); - out = - if token == "%s" then out + builtins.elemAt args argIndex - else if token == "%%" then out + "%" - else if isSpecifier token then throw "Unsupported format specifier ${token}" - else out + token; - }) - { } - tokens).out; - - accumulateArgs = argCount: args: - if argCount > 0 - then arg: accumulateArgs (argCount - 1) (args ++ [ arg ]) - else format args; - in - accumulateArgs argsNeeded [ ]; - -in -{ - inherit - take - drop - charAt - charIndex - toBytes - fromBytes - toChars - fromChars - pad - fit - match - printf - ; -} diff --git a/users/sterni/nix/string/tests/default.nix b/users/sterni/nix/string/tests/default.nix deleted file mode 100644 index e9015e95d..000000000 --- a/users/sterni/nix/string/tests/default.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ depot, ... }: - -let - - inherit (depot.users.sterni.nix) - string - ; - - inherit (depot.nix.runTestsuite) - it - assertEq - runTestsuite - ; - - testTakeDrop = it "tests take and drop" [ - (assertEq "take" - (string.take 5 "five and more") - "five ") - (assertEq "drop" - (string.drop 2 "coin") - "in") - (assertEq "take out of bounds" - (string.take 100 "foo") - "foo") - (assertEq "drop out of bounds" - (string.drop 42 "lol") - "") - ]; - - testIndexing = it "tests string indexing" [ - (assertEq "normal charAt" - (string.charAt 3 "helo") - "o") - (assertEq "out of bounds charAt" - (string.charAt 5 "helo") - null) - ]; - - testFinding = it "tests finding in strings" [ - (assertEq "normal charIndex" - (string.charIndex "d" "abcdefghijkl") - 3) - (assertEq "charIndex no match" - (string.charIndex "w" "zZzZzzzZZZ") - null) - ]; - - dontEval = builtins.throw "this should not get evaluated"; - - testMatch = it "tests match" [ - (assertEq "basic match usage" 42 - (string.match "answer" { - "answer" = 42; - "banana" = dontEval; - "maleur" = dontEval; - })) - ]; - - f = "f"; - testPrintf = it "prints f" [ - (assertEq "basic %s usage" "print ${f}" (string.printf "print %s" f)) - (assertEq "% escaping" "100%" (string.printf "100%%")) - ]; - -in -runTestsuite "nix.string" [ - testTakeDrop - testIndexing - testFinding - testMatch - testPrintf -] diff --git a/users/sterni/nix/url/default.nix b/users/sterni/nix/url/default.nix deleted file mode 100644 index 4a401873a..000000000 --- a/users/sterni/nix/url/default.nix +++ /dev/null @@ -1,100 +0,0 @@ -{ depot, lib, ... }: - -let - - inherit (depot.users.sterni.nix) - char - int - string - flow - ; - - reserved = c: builtins.elem c [ - "!" - "#" - "$" - "&" - "'" - "(" - ")" - "*" - "+" - "," - "/" - ":" - ";" - "=" - "?" - "@" - "[" - "]" - ]; - - unreserved = c: char.asciiAlphaNum c - || builtins.elem c [ "-" "_" "." "~" ]; - - percentEncode = c: - if unreserved c - then c - else "%" + (string.fit - { - width = 2; - char = "0"; - side = "left"; - } - (int.toHex (char.ord c))); - - encode = { leaveReserved ? false }: s: - let - chars = lib.stringToCharacters s; - tr = c: - if leaveReserved && reserved c - then c - else percentEncode c; - in - lib.concatStrings (builtins.map tr chars); - - decode = s: - let - tokens = builtins.split "%" s; - decodeStep = - { result ? "" - , inPercent ? false - }: s: - flow.cond [ - [ - (builtins.isList s) - { - inherit result; - inPercent = true; - } - ] - [ - inPercent - { - inPercent = false; - # first two characters came after an % - # the rest is the string until the next % - result = result - + char.chr (int.fromHex (string.take 2 s)) - + (string.drop 2 s); - } - ] - [ - (!inPercent) - { - result = result + s; - } - ] - ]; - - in - (builtins.foldl' decodeStep { } tokens).result; - -in -{ - inherit - encode - decode - ; -} diff --git a/users/sterni/nix/url/tests/default.nix b/users/sterni/nix/url/tests/default.nix deleted file mode 100644 index 4eb6f95cc..000000000 --- a/users/sterni/nix/url/tests/default.nix +++ /dev/null @@ -1,58 +0,0 @@ -{ depot, ... }: - -let - - inherit (depot.nix.runTestsuite) - it - assertEq - runTestsuite - ; - - inherit (depot.users.sterni.nix) - url - ; - - checkEncoding = args: { left, right }: - assertEq "encode ${builtins.toJSON left} == ${builtins.toJSON right}" - (url.encode args left) - right; - - checkDecoding = { left, right }: - assertEq "${builtins.toJSON left} == decode ${builtins.toJSON right}" - (url.decode left) - right; - - unreserved = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_~"; - - encodeExpected = [ - { left = "Laguna Beach"; right = "Laguna%20Beach"; } - { left = "👾 Exterminate!"; right = "%F0%9F%91%BE%20Exterminate%21"; } - { left = unreserved; right = unreserved; } - { - left = "`!@#$%^&*()+={}[]:;'\\|<>,?/ \""; - right = "%60%21%40%23%24%25%5E%26%2A%28%29%2B%3D%7B%7D%5B%5D%3A%3B%27%5C%7C%3C%3E%2C%3F%2F%20%22"; - } - ]; - - testEncode = it "checks url.encode" - (builtins.map (checkEncoding { }) encodeExpected); - - testDecode = it "checks url.decode" - (builtins.map checkDecoding encodeExpected); - - testLeaveReserved = it "checks that leaveReserved is like id for valid URLs" - (builtins.map (x: checkEncoding { leaveReserved = true; } { left = x; right = x; }) [ - "ftp://ftp.is.co.za/rfc/rfc1808.txt" - "http://www.ietf.org/rfc/rfc2396.txt" - "ldap://[2001:db8::7]/c=GB?objectClass?one" - "mailto:John.Doe@example.com" - "news:comp.infosystems.www.servers.unix" - "tel:+1-816-555-1212" - "telnet://192.0.2.16:80/" - "urn:oasis:names:specification:docbook:dtd:xml:4.1.2" - ]); -in -runTestsuite "nix.url" [ - testEncode - testLeaveReserved -] diff --git a/users/sterni/nix/utf8/default.nix b/users/sterni/nix/utf8/default.nix deleted file mode 100644 index e76695f12..000000000 --- a/users/sterni/nix/utf8/default.nix +++ /dev/null @@ -1,326 +0,0 @@ -{ depot, lib, ... }: - -let - - inherit (depot.users.sterni.nix) - char - flow - fun - num - int - string - util - ; - - /* (Internal) function to determine the amount - bytes left in a UTF-8 byte sequence from the - first byte. - - This function will throw if the given first - byte is ill-formed, but will not detect all - cases of ill-formed-ness. - - Based on table 3-6. from The Unicode Standard, - Version 13.0, section 3.9. - - Type: integer -> integer - */ - byteCount = i: flow.cond [ - [ (int.bitAnd i 128 == 0) 1 ] - [ (int.bitAnd i 224 == 192) 2 ] - [ (int.bitAnd i 240 == 224) 3 ] - [ (int.bitAnd i 248 == 240) 4 ] - [ true (builtins.throw "Ill-formed first byte ${int.toHex i}") ] - ]; - - /* (Internal) function to check if a given byte in - an UTF-8 byte sequence is well-formed. - - Based on table 3-7. from The Unicode Standard, - Version 13.0, section 3.9. - - Type: integer -> integer -> integer -> bool - */ - wellFormedByte = - # first byte's integer value - first: - # byte position as an index starting with 0 - pos: - let - defaultRange = num.inRange 128 191; - - secondBytePredicate = flow.switch first [ - [ (num.inRange 194 223) defaultRange ] # C2..DF - [ 224 (num.inRange 160 191) ] # E0 - [ (num.inRange 225 236) defaultRange ] # E1..EC - [ 237 (num.inRange 128 159) ] # ED - [ (num.inRange 238 239) defaultRange ] # EE..EF - [ 240 (num.inRange 144 191) ] # F0 - [ (num.inRange 241 243) defaultRange ] # F1..F3 - [ 244 (num.inRange 128 143) ] # F4 - [ (fun.const true) null ] - ]; - - firstBytePredicate = byte: assert first == byte; - first < 128 || secondBytePredicate != null; - in - # Either ASCII or in one of the byte ranges of Table 3-6. - if pos == 0 then firstBytePredicate - # return predicate according to Table 3-6. - else if pos == 1 then assert secondBytePredicate != null; secondBytePredicate - # 3rd and 4th byte have only one validity rule - else defaultRange; - - /* Iteration step for decoding an UTF-8 byte sequence. - It decodes incrementally, i. e. it has to be fed - one byte at a time and then returns either a - new state or a final result. - - If the resulting attribute set contains the attribute - result, it is finished and the decoded codepoint is - contained in that attribute. In all other cases, - pass the returned set to step again along with - a new byte. The initial state to pass is the empty - set. - - Extra attributes are always passed through, so you - can pass extra state. Be sure not to use result, - pos, code, first or count. - - This function will throw with a fairly detailed - message if it encounters ill-formed bytes. - - The implementation is based on The Unicode Standard, - Version 13.0, section 3.9, especially table 3-6. - - Type: { ... } -> string -> ({ result :: integer, ... } | { ... }) - - Example: utf8.step {} "f" - => { result = 102; } - */ - step = { pos ? 0, code ? 0, ... }@args: byte: - let - value = char.ord byte; - # first byte is context for well-formed-ness - first = args.first or value; - count = args.count or (byteCount first); - newCode = - if count == 1 - then int.bitAnd 127 first # ascii character - else # multi byte UTF-8 sequence - let - # Calculate the bitmask for extracting the - # codepoint data in the current byte. - # If the codepoint is not ASCII, the bits - # used for codepoint data differ depending - # on the byte position and overall byte - # count. The first byte always ignores - # the (count + 1) most significant bits. - # For all subsequent bytes, the 2 most - # significant bits need to be ignored. - # See also table 3-6. - mask = - if pos == 0 - then int.exp 2 (8 - (count + 1)) - 1 - else 63; - # UTF-8 uses the 6 least significant bits in all - # subsequent bytes after the first one. Therefore - # We can determine the amount we need to shift - # the current value by the amount of bytes left. - offset = (count - (pos + 1)) * 6; - in - code + (int.bitShiftL (int.bitAnd mask value) offset); - illFormedMsg = - "Ill-formed byte ${int.toHex value} at position ${toString pos} in ${toString count} byte UTF-8 sequence"; - in - if !(wellFormedByte first pos value) then builtins.throw illFormedMsg - else if pos + 1 == count - then (builtins.removeAttrs args [ - # allow extra state being passed through - "count" - "code" - "pos" - "first" - ]) // { result = newCode; } - else (builtins.removeAttrs args [ "result" ]) // { - inherit count first; - code = newCode; - pos = pos + 1; - }; - - /* Decode an UTF-8 string into a list of codepoints. - - Throws if the string is ill-formed UTF-8. - - Type: string -> [ integer ] - */ - # TODO(sterni): option to fallback to replacement char instead of failure - decode = s: - let - stringLength = builtins.stringLength s; - iterResult = builtins.genericClosure { - startSet = [ - { - key = "start"; - stringIndex = -1; - state = { }; - codepoint = null; - } - ]; - operator = { state, stringIndex, ... }: - let - # updated values for current iteration step - newIndex = stringIndex + 1; - newState = step state (builtins.substring newIndex 1 s); - in - lib.optional (newIndex < stringLength) { - # unique keys to make genericClosure happy - key = toString newIndex; - # carryover state for the next step - stringIndex = newIndex; - state = newState; - # actual payload for later, steps with value null are filtered out - codepoint = newState.result or null; - }; - }; - in - # extract all steps that yield a code point into a list - builtins.map (v: v.codepoint) ( - builtins.filter - ( - { codepoint, stringIndex, state, ... }: - - let - # error message in case we are missing bytes at the end of input - earlyEndMsg = - if state ? count && state ? pos - then "Missing ${toString (with state; count - pos)} bytes at end of input" - else "Unexpected end of input"; - in - - # filter out all iteration steps without a codepoint value - codepoint != null - # if we are at the iteration step of a non-empty input string, throw - # an error if no codepoint was returned, as it indicates an incomplete - # UTF-8 sequence. - || (stringLength > 0 && stringIndex == stringLength - 1 && throw earlyEndMsg) - - ) - iterResult - ); - - /* Pretty prints a Unicode codepoint in the U+<HEX> notation. - - Type: integer -> string - */ - formatCodepoint = cp: "U+" + string.fit - { - width = 4; - char = "0"; - } - (int.toHex cp); - - encodeCodepoint = cp: - let - # Find the amount of bytes needed to encode the given codepoint. - # Note that this doesn't check if the Unicode codepoint is allowed, - # but rather allows all theoretically UTF-8-encodeable ones. - count = flow.switch cp [ - [ (num.inRange 0 127) 1 ] # 00000000 0xxxxxxx - [ (num.inRange 128 2047) 2 ] # 00000yyy yyxxxxxx - [ (num.inRange 2048 65535) 3 ] # zzzzyyyy yyxxxxxx - [ (num.inRange 65536 1114111) 4 ] # 000uuuuu zzzzyyyy yyxxxxxx, - # capped at U+10FFFF - - [ (fun.const true) (builtins.throw invalidCodepointMsg) ] - ]; - - invalidCodepointMsg = "${formatCodepoint cp} is not a Unicode codepoint"; - - # Extract the bit ranges x, y, z and u from the given codepoint - # according to Table 3-6. from The Unicode Standard, Version 13.0, - # section 3.9. u is split into uh and ul since they are used in - # different bytes in the end. - components = lib.mapAttrs - (_: { mask, offset }: - int.bitAnd (int.bitShiftR cp offset) mask - ) - { - x = { - mask = if count > 1 then 63 else 127; - offset = 0; - }; - y = { - mask = if count > 2 then 63 else 31; - offset = 6; - }; - z = { - mask = 15; - offset = 12; - }; - # u which belongs into the second byte - ul = { - mask = 3; - offset = 16; - }; - # u which belongs into the first byte - uh = { - mask = 7; - offset = 18; - }; - }; - inherit (components) x y z ul uh; - - # Finally construct the byte sequence for the given codepoint. This is - # usually done by using the component and adding a few bits as a prefix - # which depends on the length of the sequence. The longer the sequence, - # the further back each component is pushed. To simplify this, we - # always construct a 4 element list and take the last `count` elements. - # Thanks to laziness the bogus values created by this are never evaluated. - # - # Based on table 3-6. from The Unicode Standard, - # Version 13.0, section 3.9. - bytes = lib.sublist (4 - count) count [ - # 11110uuu - (uh + 240) - # 10uuzzzz or 1110zzzz - (z + (if count > 3 then 128 + int.bitShiftL ul 4 else 224)) - # 10yyyyyy or 110yyyyy - (y + (if count > 2 then 128 else 192)) - # 10xxxxxx or 0xxxxxxx - (x + (if count > 1 then 128 else 0)) - ]; - - firstByte = builtins.head bytes; - - unableToEncodeMessage = "Can't encode ${formatCodepoint cp} as UTF-8"; - - in - string.fromBytes ( - builtins.genList - (i: - let - byte = builtins.elemAt bytes i; - in - if wellFormedByte firstByte i byte - then byte - else builtins.throw unableToEncodeMessage - ) - count - ); - - /* Encode a list of Unicode codepoints into an UTF-8 string. - - Type: [ integer ] -> string - */ - encode = lib.concatMapStrings encodeCodepoint; - -in -{ - inherit - encode - decode - step - formatCodepoint - ; -} diff --git a/users/sterni/nix/utf8/tests/default.nix b/users/sterni/nix/utf8/tests/default.nix deleted file mode 100644 index 40783eab2..000000000 --- a/users/sterni/nix/utf8/tests/default.nix +++ /dev/null @@ -1,148 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - - inherit (pkgs) - runCommandLocal - ; - - inherit (depot.nix.runTestsuite) - runTestsuite - it - assertEq - assertThrows - assertDoesNotThrow - ; - - inherit (depot.nix.writers) - rustSimple - ; - - inherit (depot.users.sterni.nix) - int - utf8 - string - char - ; - - rustDecoder = rustSimple - { - name = "utf8-decode"; - } '' - use std::io::{self, Read}; - fn main() -> std::io::Result<()> { - let mut buffer = String::new(); - io::stdin().read_to_string(&mut buffer)?; - - print!("[ "); - - for c in buffer.chars() { - print!("{} ", u32::from(c)); - } - - print!("]"); - - Ok(()) - } - ''; - - rustDecode = s: - let - expr = runCommandLocal "${s}-decoded" { } '' - printf '%s' ${lib.escapeShellArg s} | ${rustDecoder} > $out - ''; - in - import expr; - - hexDecode = l: - utf8.decode (string.fromBytes (builtins.map int.fromHex l)); - - hexEncode = l: utf8.encode (builtins.map int.fromHex l); - - testFailures = it "checks UTF-8 decoding failures" ([ - (assertThrows "truncated UTF-8 string throws" (hexDecode [ "F0" "9F" ])) - # examples from The Unicode Standard - (assertThrows "ill-formed: C0 AF" (hexDecode [ "C0" "AF" ])) - (assertThrows "ill-formed: E0 9F 80" (hexDecode [ "E0" "9F" "80" ])) - (assertEq "well-formed: F4 80 83 92" (hexDecode [ "F4" "80" "83" "92" ]) [ 1048786 ]) - (assertThrows "Codepoint out of range: 0xFFFFFF" (hexEncode [ "FFFFFF" ])) - (assertThrows "Codepoint out of range: -0x02" (hexEncode [ "-02" ])) - ] ++ builtins.genList - (i: - let - cp = i + int.fromHex "D800"; - in - assertThrows "Can't encode UTF-16 reserved characters: ${utf8.formatCodepoint cp}" - (utf8.encode [ cp ]) - ) - (int.fromHex "07FF")); - - testAscii = it "checks decoding of ascii strings" - (builtins.map - (s: assertEq "ASCII decoding is equal to UTF-8 decoding for \"${s}\"" - (string.toBytes s) - (utf8.decode s)) [ - "foo bar" - "hello\nworld" - "carriage\r\nreturn" - "1238398494829304 []<><>({})[]!!)" - (string.take 127 char.allChars) - ]); - - randomUnicode = [ - "" # empty string should yield empty list - "🥰👨‍👨‍👧‍👦🐈‍⬛👩🏽‍🦰" - # https://kermitproject.org/utf8.html - "ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ" - "An preost wes on leoden, Laȝamon was ihoten" - "Sîne klâwen durh die wolken sint geslagen," - "Τὴ γλῶσσα μοῦ ἔδωσαν ἑλληνικὴ" - "На берегу пустынных волн" - "ვეპხის ტყაოსანი შოთა რუსთაველი" - "யாமறிந்த மொழிகளிலே தமிழ்மொழி போல் இனிதாவது எங்கும் காணோம், " - "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸು " - ]; - - # https://kermitproject.org/utf8.html - glassSentences = [ - "Euro Symbol: €." - "Greek: Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα." - "Íslenska / Icelandic: Ég get etið gler án þess að meiða mig." - "Polish: Mogę jeść szkło, i mi nie szkodzi." - "Romanian: Pot să mănânc sticlă și ea nu mă rănește." - "Ukrainian: Я можу їсти шкло, й воно мені не пошкодить." - "Armenian: Կրնամ ապակի ուտել և ինծի անհանգիստ չըներ։" - "Georgian: მინას ვჭამ და არა მტკივა." - "Hindi: मैं काँच खा सकता हूँ, मुझे उस से कोई पीडा नहीं होती." - "Hebrew(2): אני יכול לאכול זכוכית וזה לא מזיק לי." - "Yiddish(2): איך קען עסן גלאָז און עס טוט מיר נישט װײ." - "Arabic(2): أنا قادر على أكل الزجاج و هذا لا يؤلمني." - "Japanese: 私はガラスを食べられます。それは私を傷つけません。" - "Thai: ฉันกินกระจกได้ แต่มันไม่ทำให้ฉันเจ็บ " - ]; - - testDecoding = it "checks decoding of UTF-8 strings against Rust's String" - (builtins.map - (s: assertEq "Decoding of “${s}” is correct" (utf8.decode s) (rustDecode s)) - (lib.flatten [ - glassSentences - randomUnicode - ])); - - testDecodingEncoding = it "checks that decoding and then encoding forms an identity" - (builtins.map - (s: assertEq "Decoding and then encoding “${s}” yields itself" - (utf8.encode (utf8.decode s)) - s) - (lib.flatten [ - glassSentences - randomUnicode - ])); - -in -runTestsuite "nix.utf8" [ - testFailures - testAscii - testDecoding - testDecodingEncoding -] diff --git a/users/sterni/nixpkgs-crate-holes/default.nix b/users/sterni/nixpkgs-crate-holes/default.nix deleted file mode 100644 index 1630ecb8f..000000000 --- a/users/sterni/nixpkgs-crate-holes/default.nix +++ /dev/null @@ -1,348 +0,0 @@ -{ depot, pkgs, lib, ... }: - -let - # dependency imports - - inherit (depot.nix) getBins; - inherit (depot.third_party) rustsec-advisory-db; - - bins = getBins pkgs.jq [ - "jq" - ] // getBins pkgs.coreutils [ - "cat" - "printf" - "tee" - "test" - "wc" - ] // getBins pkgs.gnugrep [ - "grep" - ] // getBins pkgs.cargo-audit [ - "cargo-audit" - ] // getBins pkgs.ansi2html [ - "ansi2html" - ] // { - eprintf = depot.tools.eprintf; - }; - - # list of maintainers we may @mention on GitHub - maintainerWhitelist = builtins.attrValues { - inherit (lib.maintainers) - sternenseemann - qyliss - jk - symphorien - erictapen - expipiplus1 - ; - }; - - # buildRustPackage handling - - /* Predicate by which we identify rust packages we are interested in, - i. e. built using `buildRustPackage`. - - Type :: drv -> bool - */ - isRustPackage = v: v ? cargoDeps; - - /* Takes a buildRustPackage derivation and returns a derivation which - builds extracts the `Cargo.lock` of its `cargoDeps` derivation or - `null` if it has none. - - Type: drv -> option<drv> - */ - # TODO(sterni): support cargoVendorDir? - extractCargoLock = drv: - if !(drv ? cargoDeps.outPath) - then null - else - pkgs.runCommand "${drv.name}-Cargo.lock" { } '' - if test -d "${drv.cargoDeps}"; then - cp "${drv.cargoDeps}/Cargo.lock" "$out" - fi - - if test -f "${drv.cargoDeps}"; then - tar -xO \ - --no-wildcards-match-slash --wildcards \ - -f "${drv.cargoDeps}" \ - '*/Cargo.lock' \ - > "$out" - fi - ''; - - # nixpkgs traversal - - # Condition for us to recurse: Either at top-level or recurseForDerivation. - recurseInto = path: x: path == [ ] || - (lib.isAttrs x && (x.recurseForDerivations or false)); - - # Returns the value or false if an eval error occurs. - tryEvalOrFalse = v: (builtins.tryEval v).value; - - /* Traverses nixpkgs as instructed by `recurseInto` and collects - the attribute and lockfile derivation of every rust package it - encounters into a list. - - Type :: attrs - -> list { - attr :: list<str>; - lock :: option<drv>; - maintainers :: list<maintainer>; - } - */ - allLockFiles = - let - go = path: x: - let - isDrv = tryEvalOrFalse (lib.isDerivation x); - doRec = tryEvalOrFalse (recurseInto path x); - isRust = tryEvalOrFalse (isRustPackage x); - in - if doRec then - lib.concatLists - ( - lib.mapAttrsToList (n: go (path ++ [ n ])) x - ) else if isDrv && isRust then [ - { - attr = path; - lock = extractCargoLock x; - maintainers = x.meta.maintainers or [ ]; - } - ] else [ ]; - in - go [ ]; - - # Report generation and formatting - - reportFor = { attr, lock, maintainers ? [ ] }: - let - # naïve attribute path to Nix syntax conversion - strAttr = lib.concatStringsSep "." attr; - strMaintainers = lib.concatMapStringsSep " " (m: "@${m.github}") ( - builtins.filter (x: builtins.elem x maintainerWhitelist) maintainers - ); - in - if lock == null - then pkgs.emptyFile - else - depot.nix.runExecline "${strAttr}-vulnerability-report" { } [ - "foreground" - [ - "importas" - "out" - "out" - "redirfd" - "-w" - "1" - "$out" - depot.tools.rust-crates-advisory.lock-file-report - strAttr - lock - "true" - strMaintainers - ] - # ignore exit status of report - "exit" - "0" - ]; - - # GHMF in issues splits paragraphs on newlines - description = lib.concatMapStringsSep "\n\n" - ( - builtins.replaceStrings [ "\n" ] [ " " ] - ) [ - '' - The vulnerability report below was generated by - [nixpkgs-crate-holes](https://code.tvl.fyi/tree/users/sterni/nixpkgs-crate-holes) - which extracts the `Cargo.lock` file of each package in nixpkgs with a - `cargoDeps` attribute and passes it to - [cargo-audit](https://github.com/RustSec/rustsec/tree/main/cargo-audit) - using RustSec's - [advisory-db at ${builtins.substring 0 7 rustsec-advisory-db.rev}](https://github.com/RustSec/advisory-db/tree/${rustsec-advisory-db.rev}/). - '' - '' - Feel free to report any problems or suggest improvements (I have an email - address on my profile and hang out on Matrix/libera.chat as sterni)! - Tick off any reports that have been fixed in the meantime. - '' - '' - Note: A vulnerability in a dependency does not necessarily mean the dependent - package is vulnerable, e. g. when a vulnerable function isn't used. - '' - ]; - - runInstructions = '' - <details> - <summary> - Generating Cargo.lock vulnerability reports - - </summary> - - If you have a checkout of [depot](https://code.tvl.fyi/about/), you can generate this report using: - - ``` - nix-build -A users.sterni.nixpkgs-crate-holes.full \ - --argstr nixpkgsPath /path/to/nixpkgs - ``` - - If you want a more detailed report for a single attribute of nixpkgs, use: - - ``` - nix-build -A users.sterni.nixpkgs-crate-holes.single \ - --argstr nixpkgsPath /path/to/nixpkgs --arg attr '[ "ripgrep" ]' - ``` - - </details> - ''; - - defaultNixpkgsArgs = { allowBroken = false; }; - - reportForNixpkgs = - { nixpkgsPath - , nixpkgsArgs ? defaultNixpkgsArgs - }@args: - - let - reports = builtins.map reportFor ( - allLockFiles (import nixpkgsPath nixpkgsArgs) - ); - in - - depot.nix.runExecline "nixpkgs-rust-pkgs-vulnerability-report.md" - { - stdin = lib.concatMapStrings (report: "${report}\n") reports; - } [ - "importas" - "out" - "out" - "redirfd" - "-w" - "1" - "$out" - # Print introduction paragraph for the issue - "if" - [ bins.printf "%s\n\n" description ] - # Print all reports - "foreground" - [ - "forstdin" - "-E" - "report" - bins.cat - "$report" - ] - # Print stats at the end (mostly as a gimmick), we already know how many - # attributes there are and count the attributes with vulnerability by - # finding the number of checkable list entries in the output. - "backtick" - "-E" - "vulnerableCount" - [ - "pipeline" - [ - bins.grep - "^- \\[ \\]" - "$out" - ] - bins.wc - "-l" - ] - "if" - [ - bins.printf - "\n%s of %s checked attributes have vulnerable dependencies.\n\n" - "$vulnerableCount" - (toString (builtins.length reports)) - ] - "if" - [ - bins.printf - "%s\n\n" - runInstructions - ] - ]; - - singleReport = - { - # Attribute to check: string or list of strings (attr path) - attr - # Path to importable nixpkgs checkout - , nixpkgsPath - # Arguments to pass to nixpkgs - , nixpkgsArgs ? defaultNixpkgsArgs - }: - - let - attr' = if builtins.isString attr then [ attr ] else attr; - drv = lib.getAttrFromPath attr' (import nixpkgsPath nixpkgsArgs); - lockFile = extractCargoLock drv; - strAttr = lib.concatStringsSep "." attr'; - in - - depot.nix.runExecline "${strAttr}-report.html" { } [ - "importas" - "out" - "out" - "backtick" - "-I" - "-E" - "-N" - "report" - [ - bins.cargo-audit - "audit" - "--quiet" - "-n" - "--db" - rustsec-advisory-db - "-f" - lockFile - ] - "pipeline" - [ - "ifte" - [ - bins.printf - "%s" - "$report" - ] - [ - bins.printf - "%s\n" - "No vulnerabilities found" - ] - bins.test - "-n" - "$report" - ] - "pipeline" - [ - bins.tee - "/dev/stderr" - ] - "redirfd" - "-w" - "1" - "$out" - bins.ansi2html - ]; - -in -{ - full = reportForNixpkgs; - single = singleReport; - - inherit - extractCargoLock - allLockFiles - ; - - # simple sanity check, doesn't cover everything, but testing the full report - # is quite expensive in terms of evaluation. - testSingle = singleReport { - nixpkgsPath = depot.third_party.nixpkgs.path; - attr = [ "ripgrep" ]; - }; - - meta.ci.targets = [ "testSingle" ]; -} diff --git a/users/sterni/secrets/default.nix b/users/sterni/secrets/default.nix deleted file mode 100644 index 5550103c5..000000000 --- a/users/sterni/secrets/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ depot, ... }: - -depot.ops.secrets.mkSecrets ./. (import ./secrets.nix) diff --git a/users/sterni/secrets/minecraft-rcon.age b/users/sterni/secrets/minecraft-rcon.age deleted file mode 100644 index 6531a74b8..000000000 Binary files a/users/sterni/secrets/minecraft-rcon.age and /dev/null differ diff --git a/users/sterni/secrets/netdata-htpasswd.age b/users/sterni/secrets/netdata-htpasswd.age deleted file mode 100644 index 3e13a74bf..000000000 --- a/users/sterni/secrets/netdata-htpasswd.age +++ /dev/null @@ -1,7 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 aXKGcg 7NJ/tDM/OcSOfQPYDTCtanHGSx0S4Awh46yVd6En+gM -6EVvqfDHsozsS85uAUz7wkYWXR0/Q2OETPSRVlMQ7F4 --> ssh-ed25519 OaL1CA oqGrI9yqsDCrzQ8Axz3TX2ebbzWhYSCojYLMlOxl/Eo -+tgAb1bkK1TdoHesJu2Ui8VMSMNLtA5U5/ia+Ntruas ---- 8Th6voNgkxciDPXDn6vVFemwZNNTukp40sriXYDRS5E -d6+ة;Ѵ6 7N :bQd˯ N -2\Ga K c \ No newline at end of file diff --git a/users/sterni/secrets/secrets.nix b/users/sterni/secrets/secrets.nix deleted file mode 100644 index 469f57ed9..000000000 --- a/users/sterni/secrets/secrets.nix +++ /dev/null @@ -1,16 +0,0 @@ -let - nonremote = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJk+KvgvI2oJTppMASNUfMcMkA2G5ZNt+HnWDzaXKLlo" - ]; - - ingeborg = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAHQn/j6NCYucpM7qIEIslVJxiFeUEKa0hi+HobTz/12" - ]; -in - -{ - "warteraum-salt.age".publicKeys = nonremote ++ ingeborg; - "warteraum-tokens.age".publicKeys = nonremote ++ ingeborg; - "minecraft-rcon.age".publicKeys = nonremote ++ ingeborg; - "netdata-htpasswd.age".publicKeys = nonremote ++ ingeborg; -} diff --git a/users/sterni/secrets/warteraum-salt.age b/users/sterni/secrets/warteraum-salt.age deleted file mode 100644 index 61fa5e616..000000000 Binary files a/users/sterni/secrets/warteraum-salt.age and /dev/null differ diff --git a/users/sterni/secrets/warteraum-tokens.age b/users/sterni/secrets/warteraum-tokens.age deleted file mode 100644 index e1bf32269..000000000 --- a/users/sterni/secrets/warteraum-tokens.age +++ /dev/null @@ -1,11 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 aXKGcg G96nS/CgSFqyum5QtOwyCo2d7PRIx7pcQBVyFjtErUE -gkQuhegobZ68Z76h93G57/trz7ixSkpa7Dz+OYMzAIw --> ssh-ed25519 OaL1CA u9p+ejyLs4cWgB/LjR8XIIE3tRPf+a5Kqwl0nA8pDio -ZfPVZIcqgyep7C68sTybGFa+7HFDwwoDQwAmoDszua4 --> |WcGV<-grease >a*ke{l }9Iv) ]qz -Ehf2eOTQe0t7mnbgNEjJBtRSNRl+MlgEIiziu9YU206yMQXSLrm04PPo9ycw5x/k -N/5r/M36qnKJfZUVbtcFom85+UYOQDRnfXXvPyTrsA ---- hRzM1BnEG2VPMV6DTZF2j4WZk/2uM65yAFDK3F0rSQc -(iٺ)QZq(gl:Sٺǒ@+fۣ -RNoI}{f \ No newline at end of file diff --git a/users/tazjin/OWNERS b/users/tazjin/OWNERS deleted file mode 100644 index ba1c06534..000000000 --- a/users/tazjin/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -tazjin diff --git a/users/tazjin/aoc2019/default.nix b/users/tazjin/aoc2019/default.nix deleted file mode 100644 index a1798f400..000000000 --- a/users/tazjin/aoc2019/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -# Solutions for Advent of Code 2019, written in Emacs Lisp. -# -# For each day a new file is created as "solution-day$n.el". -{ depot, ... }: - -let - inherit (builtins) attrNames filter head listToAttrs match readDir; - dir = readDir ./.; - matchSolution = match "solution-(.*)\.el"; - isSolution = f: (matchSolution f) != null; - getDay = f: head (matchSolution f); - - solutionFiles = filter (e: dir."${e}" == "regular" && isSolution e) (attrNames dir); - solutions = map - (f: - let day = getDay f; in { - name = day; - value = depot.nix.writeElispBin { - name = "aoc2019"; - deps = p: with p; [ dash s ht ]; - src = ./. + ("/" + f); - }; - }) - solutionFiles; -in -listToAttrs solutions diff --git a/users/tazjin/aoc2019/solution-day1.el b/users/tazjin/aoc2019/solution-day1.el deleted file mode 100644 index d805c22ec..000000000 --- a/users/tazjin/aoc2019/solution-day1.el +++ /dev/null @@ -1,28 +0,0 @@ -;; Advent of Code 2019 - Day 1 -(require 'dash) - -;; Puzzle 1: - -(defvar day-1/input - '(83285 96868 121640 51455 128067 128390 141809 52325 68310 140707 124520 149678 - 87961 52040 133133 52203 117483 85643 84414 86558 65402 122692 88565 61895 - 126271 128802 140363 109764 53600 114391 98973 124467 99574 69140 144856 - 56809 149944 138738 128823 82776 77557 51994 74322 64716 114506 124074 - 73096 97066 96731 149307 135626 121413 69575 98581 50570 60754 94843 72165 - 146504 53290 63491 50936 79644 119081 70218 85849 133228 114550 131943 - 67288 68499 80512 148872 99264 119723 68295 90348 146534 52661 99146 95993 - 130363 78956 126736 82065 77227 129950 97946 132345 107137 79623 148477 - 88928 118911 75277 97162 80664 149742 88983 74518)) - -(defun calculate-fuel (mass) - (- (/ mass 3) 2)) - -(message "Solution to day1/1: %d" (apply #'+ (-map #'calculate-fuel day-1/input))) - -;; Puzzle 2: -(defun calculate-recursive-fuel (mass) - (let ((fuel (calculate-fuel mass))) - (if (< fuel 0) 0 - (+ fuel (calculate-recursive-fuel fuel))))) - -(message "Solution to day1/2: %d" (apply #'+ (-map #'calculate-recursive-fuel day-1/input))) diff --git a/users/tazjin/aoc2019/solution-day2.el b/users/tazjin/aoc2019/solution-day2.el deleted file mode 100644 index 6ecac1e20..000000000 --- a/users/tazjin/aoc2019/solution-day2.el +++ /dev/null @@ -1,53 +0,0 @@ -;; -*- lexical-binding: t; -*- -;; Advent of Code 2019 - Day 2 -(require 'dash) -(require 'ht) - -(defvar day2/input - [1 0 0 3 1 1 2 3 1 3 4 3 1 5 0 3 2 1 9 19 1 19 5 23 1 13 23 27 1 27 6 31 - 2 31 6 35 2 6 35 39 1 39 5 43 1 13 43 47 1 6 47 51 2 13 51 55 1 10 55 - 59 1 59 5 63 1 10 63 67 1 67 5 71 1 71 10 75 1 9 75 79 2 13 79 83 1 9 - 83 87 2 87 13 91 1 10 91 95 1 95 9 99 1 13 99 103 2 103 13 107 1 107 10 - 111 2 10 111 115 1 115 9 119 2 119 6 123 1 5 123 127 1 5 127 131 1 10 - 131 135 1 135 6 139 1 10 139 143 1 143 6 147 2 147 13 151 1 5 151 155 1 - 155 5 159 1 159 2 163 1 163 9 0 99 2 14 0 0]) - -;; Puzzle 1 - -(defun day2/single-op (f state idx) - (let* ((a (aref state (aref state (+ 1 idx)))) - (b (aref state (aref state (+ 2 idx)))) - (p (aref state (+ 3 idx))) - (result (funcall f a b))) - (aset state p (funcall f a b)))) - -(defun day2/operate (state idx) - (pcase (aref state idx) - (99 (aref state 0)) - (1 (day2/single-op #'+ state idx) - (day2/operate state (+ 4 idx))) - (2 (day2/single-op #'* state idx) - (day2/operate state (+ 4 idx))) - (other (error "Unknown opcode: %s" other)))) - -(defun day2/program-with-inputs (noun verb) - (let* ((input (copy-tree day2/input t))) - (aset input 1 noun) - (aset input 2 verb) - (day2/operate input 0))) - -(message "Solution to day2/1: %s" (day2/program-with-inputs 12 2)) - -;; Puzzle 2 -(let* ((used (ht)) - (noun 0) - (verb 0) - (result (day2/program-with-inputs noun verb))) - (while (/= 19690720 result) - (setq noun (random 100)) - (setq verb (random 100)) - (unless (ht-get used (format "%d%d" noun verb)) - (ht-set used (format "%d%d" noun verb) t) - (setq result (day2/program-with-inputs noun verb)))) - - (message "Solution to day2/2: %s%s" noun verb)) diff --git a/users/tazjin/aoc2019/solution-day3.el b/users/tazjin/aoc2019/solution-day3.el deleted file mode 100644 index b7dfdd245..000000000 --- a/users/tazjin/aoc2019/solution-day3.el +++ /dev/null @@ -1,64 +0,0 @@ -;; -*- lexical-binding: t; -*- -;; Advent of Code 2019 - Day 3 - -(require 'cl-lib) -(require 'dash) -(require 'ht) -(require 's) - -(defvar day3/input/wire1 - "R1010,D422,L354,U494,L686,U894,R212,U777,L216,U9,L374,U77,R947,U385,L170,U916,R492,D553,L992,D890,L531,U360,R128,U653,L362,U522,R817,U198,L126,D629,L569,U300,L241,U145,R889,D196,L450,D576,L319,D147,R985,U889,L941,U837,L608,D77,L864,U911,L270,D869,R771,U132,L249,U603,L36,D328,L597,U992,L733,D370,L947,D595,L308,U536,L145,U318,R55,D773,R175,D505,R483,D13,R780,U778,R445,D107,R490,U245,L587,U502,R446,U639,R150,U35,L455,D522,R866,U858,R394,D975,R513,D378,R58,D646,L374,D675,R209,U228,R530,U543,L480,U677,L912,D164,L573,U587,L784,D626,L994,U250,L215,U985,R684,D79,L877,U811,L766,U617,L665,D246,L408,U800,L360,D272,L436,U138,R240,U735,L681,U68,L608,D59,R532,D808,L104,U968,R887,U819,R346,U698,L317,U582,R516,U55,L303,U607,L457,U479,L510,D366,L583,U519,R878,D195,R970,D267,R842,U784,R9,D946,R833,D238,L232,D94,L860,D47,L346,U951,R491,D745,R849,U273,R263,U392,L341,D808,R696,U326,R886,D296,L865,U833,R241,U644,R729,D216,R661,D712,L466,D699,L738,U5,L556,D693,R912,D13,R48,U63,L877,U628,L689,D929,R74,U924,R612,U153,R417,U425,L879,D378,R79,D248,L3,U519,R366,U281,R439,D823,R149,D668,R326,D342,L213,D735,R504,U265,L718,D842,L565,U105,L214,U963,R518,D681,R642,U170,L111,U6,R697,U572,R18,U331,L618,D255,R534,D322,L399,U595,L246,U651,L836,U757,R417,D795,R291,U759,L568,U965,R828,D570,R350,U317,R338,D173,L74,D833,L650,D844,L70,U913,R594,U407,R674,D684,L481,D564,L128,D277,R851,D274,L435,D582,R469,U729,R387,D818,R443,U504,R414,U8,L842,U845,R275,U986,R53,U660,R661,D225,R614,U159,R477") - -(defvar day3/input/wire2 - "L1010,D698,R442,U660,L719,U702,L456,D86,R938,D177,L835,D639,R166,D285,L694,U468,L569,D104,L234,D574,L669,U299,L124,D275,L179,D519,R617,U72,L985,D248,R257,D276,L759,D834,R490,U864,L406,U181,R911,U873,R261,D864,R260,U759,R648,U158,R308,D386,L835,D27,L745,U91,R840,U707,R275,U543,L663,U736,L617,D699,R924,U103,R225,U455,R708,U319,R569,U38,R315,D432,L179,D975,R519,D546,L295,U680,L685,U603,R262,D250,R7,U171,R261,U519,L832,U534,L471,U431,L474,U886,R10,D179,L79,D555,R452,U452,L832,U863,L367,U538,L237,D160,R441,U605,R942,U259,L811,D552,R646,D353,L225,D94,L35,D307,R752,U23,R698,U610,L379,D932,R698,D751,R178,D347,R325,D156,R471,D555,R558,D593,R773,U2,L955,U764,L735,U438,R364,D640,L757,U534,R919,U409,R361,U407,R336,D808,R877,D648,R610,U198,R340,U94,R795,D667,R811,U975,L965,D224,R565,D681,L64,U567,R621,U922,L665,U329,R242,U592,L727,D481,L339,U402,R213,D280,R656,U169,R976,D962,L294,D505,L251,D689,L497,U133,R230,D441,L90,D220,L896,D657,L500,U331,R502,U723,R762,D613,L447,D256,L226,U309,L935,U384,L740,D459,R309,D707,R952,D747,L304,D105,R977,D539,R941,D21,R291,U216,R132,D543,R515,U453,L854,D42,R982,U102,L469,D639,R559,D68,R302,U734,R980,D214,R107,D191,L730,D793,L63,U17,R807,U196,R412,D592,R330,D941,L87,D291,L44,D94,L272,D780,R968,U837,L712,D704,R163,U981,R537,U778,R220,D303,L196,D951,R163,D446,R11,D623,L72,D778,L158,U660,L189,D510,L247,D716,L89,U887,L115,U114,L36,U81,R927,U293,L265,U183,R331,D267,R745,D298,L561,D918,R299,U810,L322,U679,L739,D854,L581,U34,L862,D779,R23") - -;; Puzzle 1 - -(defun wire-from (raw) - (-map (lambda (s) - (cons (substring s 0 1) (string-to-number (substring s 1)))) - (s-split "," raw))) - -(defun day3/move (x y next) - (cl-flet ((steps (by op) - (-map op (reverse (number-sequence 1 by))))) - (pcase next - (`("L" . ,by) (steps by (lambda (n) (cons (- x n) y)))) - (`("R" . ,by) (steps by (lambda (n) (cons (+ x n) y)))) - (`("U" . ,by) (steps by (lambda (n) (cons x (+ y n))))) - (`("D" . ,by) (steps by (lambda (n) (cons x (- y n)))))))) - -(defun day3/wire-points (wire) - (let ((points (ht)) - (point-list (-reduce-from - (lambda (acc point) - (-let* (((x . y) (car acc)) - (next (day3/move x y point))) - (-concat next acc))) - '((0 . 0)) wire))) - (-map (-lambda ((s . p)) (ht-set! points p s)) - (-zip (reverse (number-sequence 0 (- (length point-list) 1))) point-list)) - (ht-remove! points '(0 . 0)) - points)) - -(defun day3/closest-intersection (crossed-points) - (car (-sort #'< - (-map (-lambda ((x . y)) - (+ (abs x) (abs y))) - crossed-points)))) - -(defun day3/minimum-steps (wire1 wire2 crossed) - (car (-sort #'< - (-map (-lambda (p) - (+ (ht-get wire1 p) (ht-get wire2 p))) - crossed)))) - -;; Example: -(let* ((wire1-points (day3/wire-points (wire-from day3/input/wire1))) - (wire2-points (day3/wire-points (wire-from day3/input/wire2))) - (crossed-points (-filter (lambda (p) (ht-contains? wire1-points p)) - (ht-keys wire2-points)))) - (message "Solution for day3/1: %d" (day3/closest-intersection crossed-points)) - (message "Solution for day3/2: %d" (day3/minimum-steps wire1-points - wire2-points - crossed-points))) diff --git a/users/tazjin/aoc2019/solution-day4.el b/users/tazjin/aoc2019/solution-day4.el deleted file mode 100644 index 2805f3f4e..000000000 --- a/users/tazjin/aoc2019/solution-day4.el +++ /dev/null @@ -1,73 +0,0 @@ -;; -*- lexical-binding: t; -*- -;; Advent of Code 2019 - Day 4 - -(require 'cl-lib) -(require 'dash) - -;; Puzzle 1 - -(defun day4/to-digits (num) - "Convert NUM to a list of its digits." - (cl-labels ((steps (n digits) - (if (= n 0) digits - (steps (/ n 10) (cons (% n 10) digits))))) - (steps num '()))) - -(defvar day4/input (-map #'day4/to-digits (number-sequence 128392 643281))) - -(defun day4/filter-password (digits) - "Determines whether the given rules match the supplied - number." - - (and - ;; It is a six digit number - (= 6 (length digits)) - - ;; Value is within the range given in puzzle input - ;; (noop because the range is generated from the input) - - ;; Two adjacent digits are the same (like 22 in 122345). - (car (-reduce-from (-lambda ((acc . prev) next) - (cons (or acc (= prev next)) next)) - '(nil . 0) digits)) - - ;; Going from left to right, the digits never decrease; they only - ;; ever increase or stay the same (like 111123 or 135679). - (car (-reduce-from (-lambda ((acc . prev) next) - (cons (and acc (>= next prev)) next)) - '(t . 0) digits)))) - -;; Puzzle 2 -;; -;; Additional criteria: If there's matching digits, they're not in a group. - -(cl-defstruct day4/acc state prev count) - -(defun day4/filter-longer-groups (digits) - (let ((res (-reduce-from - (lambda (acc next) - (cond ;; sequence is broken and count was at 1 -> - ;; match! - ((and (= (day4/acc-count acc) 2) - (/= (day4/acc-prev acc) next)) - (setf (day4/acc-state acc) t)) - - ;; sequence continues, counter increment! - ((= (day4/acc-prev acc) next) - (setf (day4/acc-count acc) (+ 1 (day4/acc-count acc)))) - - ;; sequence broken, reset counter - ((/= (day4/acc-prev acc) next) - (setf (day4/acc-count acc) 1))) - - (setf (day4/acc-prev acc) next) - acc) - (make-day4/acc :prev 0 :count 0) digits))) - (or (day4/acc-state res) - (= 2 (day4/acc-count res))))) - -(let* ((simple (-filter #'day4/filter-password day4/input)) - (complex (-filter #'day4/filter-longer-groups simple))) - (message "Solution to day4/1: %d" (length simple)) - (message "Solution to day4/2: %d" (length complex))) - diff --git a/users/tazjin/aoc2020/default.nix b/users/tazjin/aoc2020/default.nix deleted file mode 100644 index cd89da7de..000000000 --- a/users/tazjin/aoc2020/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -# Solutions for Advent of Code 2020, written in Emacs Lisp. -# -# For each day a new file is created as "solution-day$n.el". -{ depot, pkgs, ... }: - -let - inherit (builtins) attrNames filter head listToAttrs match readDir; - dir = readDir ./.; - matchSolution = match "solution-(.*)\.el"; - isSolution = f: (matchSolution f) != null; - getDay = f: head (matchSolution f); - - solutionFiles = filter (e: dir."${e}" == "regular" && isSolution e) (attrNames dir); - solutions = map - (f: - let day = getDay f; in depot.nix.writeElispBin { - name = day; - deps = p: with p; [ dash s ht p.f ]; - src = ./. + ("/" + f); - }) - solutionFiles; -in -pkgs.symlinkJoin { - name = "aoc2020"; - paths = solutions; -} diff --git a/users/tazjin/aoc2020/solution-day1.el b/users/tazjin/aoc2020/solution-day1.el deleted file mode 100644 index a04f43d15..000000000 --- a/users/tazjin/aoc2020/solution-day1.el +++ /dev/null @@ -1,44 +0,0 @@ -;; Advent of Code 2020 - Day 1 -(require 'cl) -(require 'ht) -(require 'dash) - -(defmacro hash-set (&rest elements) - "Define a hash-table with empty values, for use as a set." - (cons 'ht (-map (lambda (x) (list x nil)) elements))) - -;; Puzzle 1: - -(defvar day1/input - (hash-set 1645 1995 1658 1062 1472 1710 1424 1823 1518 1656 1811 1511 1320 1521 1395 - 1996 1724 1666 1637 1504 1766 534 1738 1791 1372 1225 1690 1949 1495 1436 1166 - 1686 1861 1889 1887 997 1202 1478 833 1497 1459 1717 1272 1047 1751 1549 1204 - 1230 1260 1611 1506 1648 1354 1415 1615 1327 1622 1592 1807 1601 1026 1757 1376 - 1707 1514 1905 1660 1578 1963 1292 390 1898 1019 1580 1499 1830 1801 1881 1764 - 1442 1838 1088 1087 1040 1349 1644 1908 1697 1115 1178 1224 1810 1445 1594 1894 - 1287 1676 1435 1294 1796 1350 1685 1118 1488 1726 1696 1190 1538 1780 1806 1207 - 1346 1705 983 1249 1455 2002 1466 1723 1227 1390 1281 1715 1603 1862 1744 1774 - 1385 1312 1654 1872 1142 1273 1508 1639 1827 1461 1795 1533 1304 1417 1984 28 - 1693 1951 1391 1931 1179 1278 1400 1361 1369 1343 1416 1426 314 1510 1933 1239 - 1218 1918 1797 1255 1399 1229 723 1992 1595 1191 1916 1525 1605 1524 1869 1652 - 1874 1756 1246 1310 1219 1482 1429 1244 1554 1575 1123 1194 1408 1917 1613 1773 - 1809 1987 1733 1844 1423 1718 1714 1923 1503)) - -(message "Solution to day1/1: %s" - (cl-loop for first being the hash-keys of day1/input - for second = (- 2020 first) - when (ht-contains? day1/input second) - return (* first second))) - -;; Puzzle 2: - -(message "Solution to day1/1: %s" - (cl-loop for first being the hash-keys of day1/input - for result = - (cl-loop - for second being the elements of (-drop 1 (ht-keys day1/input)) - for third = (- 2020 first second) - when (ht-contains? day1/input third) - return (* first second third)) - - when result return result)) diff --git a/users/tazjin/aoc2020/solution-day2.el b/users/tazjin/aoc2020/solution-day2.el deleted file mode 100644 index 5993bf340..000000000 --- a/users/tazjin/aoc2020/solution-day2.el +++ /dev/null @@ -1,54 +0,0 @@ -;; Advent of Code 2020 - Day 2 - -(require 'cl-lib) -(require 'f) -(require 'ht) -(require 's) -(require 'seq) - -(defvar day2/input - ;; This one was too large to inline. - (s-lines (f-read "/tmp/aoc/day2.txt"))) - -(defun day2/count-letters (password) - (let ((table (ht-create))) - (cl-loop for char across password - for current = (ht-get table char) - do (ht-set table char - (if current (+ 1 current) 1))) - table)) - -(defun day2/parse (input) - (let* ((split (s-split " " input)) - (range (s-split "-" (car split)))) - (list (string-to-number (car range)) - (string-to-number (cadr range)) - (string-to-char (cadr split)) - (caddr split)))) - -(defun day2/count-with-validation (func) - (length (-filter - (lambda (password) - (and (not (seq-empty-p password)) - (apply func (day2/parse password)))) - day2/input))) - -;; Puzzle 1 - -(defun day2/validate-oldjob (min max char password) - (let ((count (ht-get (day2/count-letters password) char))) - (when count - (and (>= count min) - (<= count max))))) - -(message "Solution to day2/1: %s" - (day2/count-with-validation #'day2/validate-oldjob)) - -;; Puzzle 2 - -(defun day2/validate-toboggan (pos1 pos2 char password) - (xor (= char (aref password (- pos1 1))) - (= char (aref password (- pos2 1))))) - -(message "Solution to day2/2: %s" - (day2/count-with-validation #'day2/validate-toboggan)) diff --git a/users/tazjin/aoc2020/solution-day3.el b/users/tazjin/aoc2020/solution-day3.el deleted file mode 100644 index 80ea4a226..000000000 --- a/users/tazjin/aoc2020/solution-day3.el +++ /dev/null @@ -1,43 +0,0 @@ -;; Advent of Code 2020 - Day 3 - -(require 'cl-lib) -(require 'dash) -(require 'f) -(require 's) -(require 'seq) - -(setq day3/input - (-filter (lambda (s) (not (seq-empty-p s))) - (s-lines (f-read "/tmp/aoc/day3.txt")))) - -(setq day3/input-width (length (elt day3/input 0))) -(setq day3/input-height (length day3/input)) - -(defun day3/thing-at-point (x y) - "Pun intentional." - (when (>= day3/input-height y) - (let ((x-repeated (mod (- x 1) day3/input-width))) - (elt (elt day3/input (- y 1)) x-repeated)))) - -(defun day3/slope (x-steps y-steps) - "Produce the objects encountered through this slope until the - bottom of the map." - (cl-loop for x from 1 by x-steps - for y from 1 to day3/input-height by y-steps - collect (day3/thing-at-point x y))) - -;; Puzzle 1 - -(defun day3/count-trees (x-steps y-steps) - (cl-loop for thing being the elements of (day3/slope x-steps y-steps) - count (= thing ?#))) - -(message "Solution to day3/1: One encounters %s trees" (day3/count-trees 3 1)) - -;; Puzzle 2 - -(message "Solution to day3/2 %s" (* (day3/count-trees 1 1) - (day3/count-trees 3 1) - (day3/count-trees 5 1) - (day3/count-trees 7 1) - (day3/count-trees 1 2))) diff --git a/users/tazjin/aoc2020/solution-day4.el b/users/tazjin/aoc2020/solution-day4.el deleted file mode 100644 index 034a40a95..000000000 --- a/users/tazjin/aoc2020/solution-day4.el +++ /dev/null @@ -1,98 +0,0 @@ -;; Advent of Code 2020 - Day 4 - -(require 'cl-lib) -(require 's) -(require 'dash) -(require 'f) - -(cl-defstruct day4/passport - byr ;; Birth Year - iyr ;; Issue Year - eyr ;; Expiration Year - hgt ;; Height - hcl ;; Hair Color - ecl ;; Eye Color - pid ;; Passport ID - cid ;; Country ID - ) - -(defun day4/parse-passport (input) - (let* ((pairs (s-split " " (s-replace "\n" " " input) t)) - (slots - (-map - (lambda (pair) - (pcase-let ((`(,key ,value) (s-split ":" (s-trim pair)))) - (list (intern (format ":%s" key)) value))) - pairs))) - (apply #'make-day4/passport (-flatten slots)))) - -(defun day4/parse-passports (input) - (-map #'day4/parse-passport (s-split "\n\n" input t))) - -(setq day4/input (day4/parse-passports (f-read "/tmp/aoc/day4.txt"))) - -;; Puzzle 1 - -(defun day4/validate (passport) - "Check that all fields except CID are present." - (cl-check-type passport day4/passport) - (and (day4/passport-byr passport) - (day4/passport-iyr passport) - (day4/passport-eyr passport) - (day4/passport-hgt passport) - (day4/passport-hcl passport) - (day4/passport-ecl passport) - (day4/passport-pid passport))) - -(message "Solution to day4/1: %s" (cl-loop for passport being the elements of day4/input - count (day4/validate passport))) - -;; Puzzle 2 - -(defun day4/year-bound (min max value) - (and - (s-matches? (rx (= 4 digit)) value) - (<= min (string-to-number value) max))) - -(defun day4/check-unit (unit min max value) - (and - (string-match (rx (group (+? digit)) (literal unit)) value) - (<= min (string-to-number (match-string 1 value)) max))) - -(defun day4/properly-validate (passport) - "Opting for readable rather than clever here." - (and - (day4/validate passport) - - ;; byr (Birth Year) - four digits; at least 1920 and at most 2002. - (day4/year-bound 1920 2002 (day4/passport-byr passport)) - - ;; iyr (Issue Year) - four digits; at least 2010 and at most 2020. - (day4/year-bound 2010 2020 (day4/passport-iyr passport)) - - ;; eyr (Expiration Year) - four digits; at least 2020 and at most 2030. - (day4/year-bound 2020 2030 (day4/passport-eyr passport)) - - ;; hgt (Height) - a number followed by either cm or in: - ;; If cm, the number must be at least 150 and at most 193. - ;; If in, the number must be at least 59 and at most 76. - (or (day4/check-unit "cm" 150 193 (day4/passport-hgt passport)) - (day4/check-unit "in" 59 76 (day4/passport-hgt passport))) - - ;; hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f. - (s-matches? (rx ?# (= 6 hex)) (day4/passport-hcl passport)) - - ;; ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth. - (-contains? '("amb" "blu" "brn" "gry" "grn" "hzl" "oth") - (day4/passport-ecl passport)) - - ;; pid (Passport ID) - a nine-digit number, including leading zeroes. - (s-matches? (rx line-start (= 9 digit) line-end) - (day4/passport-pid passport)) - - ;; cid (Country ID) - ignored, missing or not. - )) - -(message "Solution to day4/2: %s" - (cl-loop for passport being the elements of day4/input - count (day4/properly-validate passport))) diff --git a/users/tazjin/aoc2020/solution-day5.el b/users/tazjin/aoc2020/solution-day5.el deleted file mode 100644 index 9bba32290..000000000 --- a/users/tazjin/aoc2020/solution-day5.el +++ /dev/null @@ -1,61 +0,0 @@ -;; Advent of Code 2020 - Day 5 - -(require 'cl-lib) -(require 'dash) -(require 'f) -(require 'ht) -(require 's) -(require 'seq) - -(defvar day5/input - (-filter (lambda (s) (not (seq-empty-p s))) - (s-lines (f-read "/tmp/aoc/day5.txt")))) - -(defun day5/lower (sequence) - (seq-subseq sequence 0 (/ (length sequence) 2))) - -(defun day5/upper (sequence) - (seq-subseq sequence (/ (length sequence) 2))) - -(defun day5/seat-id (column row) - (+ column (* 8 row))) - -(defun day5/find-seat (boarding-pass) - (let ((rows (number-sequence 0 127)) - (columns (number-sequence 0 7))) - (cl-loop for char across boarding-pass - do (pcase char - (?F (setq rows (day5/lower rows))) - (?B (setq rows (day5/upper rows))) - (?R (setq columns (day5/upper columns))) - (?L (setq columns (day5/lower columns)))) - finally return (day5/seat-id (car columns) (car rows))))) - -;; Puzzle 1 - -(message "Solution to day5/1: %s" - (cl-loop for boarding-pass in day5/input - maximize (day5/find-seat boarding-pass))) - -;; Puzzle 2 - -(defun day5/all-seats-in (row) - (-map (lambda (column) (day5/seat-id column row)) - (number-sequence 0 7))) - -(message "Solution to day5/2: %s" - (let ((all-seats (ht-create))) - (-each (-mapcat #'day5/all-seats-in (number-sequence 1 126)) - (lambda (seat) (ht-set all-seats seat nil))) - - (cl-loop for boarding-pass in day5/input - do (ht-remove all-seats (day5/find-seat boarding-pass)) - - ;; Remove seats that lack adjacent entries, those - ;; are missing on the plane. - finally return - (car - (-filter (lambda (seat) - (and (not (ht-contains? all-seats (- seat 1))) - (not (ht-contains? all-seats (+ seat 1))))) - (ht-keys all-seats)))))) diff --git a/users/tazjin/aoc2020/solution-day6.el b/users/tazjin/aoc2020/solution-day6.el deleted file mode 100644 index 8179c79af..000000000 --- a/users/tazjin/aoc2020/solution-day6.el +++ /dev/null @@ -1,40 +0,0 @@ -;; Advent of Code 2020 - Day 6 - -(require 'cl-lib) -(require 'dash) -(require 'f) -(require 'ht) -(require 's) - -(defvar day6/input (s-split "\n\n" (f-read "/tmp/aoc/day6.txt") t) - "Input, split into groups (with people in each group still distinct)") - -;; Puzzle 1 - -(defun day6/count-answers (group-answers) - "I suspect doing it this way will be useful in puzzle 2." - (let ((table (ht-create))) - (-each group-answers - (lambda (answer) - (cl-loop for char across answer - do (ht-set table char (+ 1 (or (ht-get table char) - 0)))))) - table)) - -(message "Solution to day6/1: %s" - (cl-loop for group being the elements of day6/input - sum (length - (ht-keys - (day6/count-answers (s-lines group)))))) - -;; Puzzle 2 - -(defun day6/count-unanimous-answers (answers) - (ht-reject (lambda (_key value) (not (= value (length answers)))) - (day6/count-answers answers))) - -(message "Solution to day6/2: %s" - (cl-loop for group being the elements of day6/input - sum (length - (ht-keys - (day6/count-unanimous-answers (s-split "\n" group t)))))) diff --git a/users/tazjin/aoc2020/solution-day7.el b/users/tazjin/aoc2020/solution-day7.el deleted file mode 100644 index 251a85fed..000000000 --- a/users/tazjin/aoc2020/solution-day7.el +++ /dev/null @@ -1,92 +0,0 @@ -;; Advent of Code 2020 - Day 7 - -(require 'cl-lib) -(require 'dash) -(require 'f) -(require 's) -(require 'ht) - -(defvar day7/input - (s-lines (s-chomp (f-read "/tmp/aoc/day7.txt")))) - -(defun day7/parse-bag (input) - (string-match (rx line-start - (group (one-or-more (or letter space))) - "s contain " - (group (one-or-more anything)) - "." line-end) - input) - (cons (match-string 1 input) - (-map - (lambda (content) - (unless (equal content "no other bags") - (progn - (string-match - (rx (group (one-or-more digit)) - space - (group (one-or-more anything) "bag")) - content) - (cons (match-string 2 content) - (string-to-number (match-string 1 content)))))) - (s-split ", " (match-string 2 input))))) - -(defun day7/id-or-next (table bag-type) - (unless (ht-contains? table bag-type) - (ht-set table bag-type (length (ht-keys table)))) - (ht-get table bag-type)) - -(defun day7/build-graph (input &optional flip) - "Represent graph mappings directionally using an adjacency - matrix, because that's probably easiest. - - By default an edge means 'contains', with optional argument - FLIP edges are inverted and mean 'contained by'." - - (let ((bag-mapping (ht-create)) - (graph (let ((length (length input))) - (apply #'vector - (-map (lambda (_) (make-vector length 0)) input))))) - (cl-loop for bag in (-map #'day7/parse-bag input) - for bag-id = (day7/id-or-next bag-mapping (car bag)) - do (-each (-filter #'identity (cdr bag)) - (pcase-lambda (`(,contained-type . ,count)) - (let ((contained-id (day7/id-or-next bag-mapping contained-type))) - (if flip - (aset (aref graph contained-id) bag-id count) - (aset (aref graph bag-id) contained-id count)))))) - (cons bag-mapping graph))) - -;; Puzzle 1 - -(defun day7/find-ancestors (visited graph start) - (ht-set visited start t) - (cl-loop for bag-count being the elements of (aref graph start) - using (index bag-id) - when (and (> bag-count 0) - (not (ht-contains? visited bag-id))) - do (day7/find-ancestors visited graph bag-id))) - -(message - "Solution to day7/1: %s" - (pcase-let* ((`(,mapping . ,graph) (day7/build-graph day7/input t)) - (shiny-gold-id (ht-get mapping "shiny gold bag")) - (visited (ht-create))) - (day7/find-ancestors visited graph shiny-gold-id) - (- (length (ht-keys visited)) 1))) - -;; Puzzle 2 - -(defun ht-find-by-value (table value) - (ht-find (lambda (_key item-value) (equal item-value value)) table)) - -(defun day7/count-contained-bags (mapping graph start) - (cl-loop for bag-count being the elements of (aref graph start) - using (index bag-id) - when (> bag-count 0) - sum (+ bag-count - (* bag-count (day7/count-contained-bags mapping graph bag-id))))) - -(message "Solution to day7/2: %s" - (pcase-let* ((`(,mapping . ,graph) (day7/build-graph day7/input)) - (shiny-gold-id (ht-get mapping "shiny gold bag"))) - (day7/count-contained-bags mapping graph shiny-gold-id))) diff --git a/users/tazjin/aoc2020/solution-day8.el b/users/tazjin/aoc2020/solution-day8.el deleted file mode 100644 index 591a07fbf..000000000 --- a/users/tazjin/aoc2020/solution-day8.el +++ /dev/null @@ -1,63 +0,0 @@ -;; Advent of Code 2020 - Day - -(require 'cl-lib) -(require 'dash) -(require 'f) -(require 's) - -(setq day8/input - (apply #'vector - (-map (lambda (s) - (pcase-let ((`(,op ,val) (s-split " " s t))) - (cons (intern op) (string-to-number val)))) - (s-lines (s-chomp (f-read "/tmp/aoc/day8.txt")))))) - -(defun day8/step (code position acc) - (if (>= position (length code)) - (cons 'final acc) - - (let ((current (aref code position))) - (aset code position :done) - (pcase current - (:done (cons 'loop acc)) - (`(nop . ,val) (cons (+ position 1) acc)) - (`(acc . ,val) (cons (+ position 1) (+ acc val))) - (`(jmp . ,val) (cons (+ position val) acc)))))) - -;; Puzzle 1 - -(message "Solution to day8/1: %s" - (let ((code (copy-sequence day8/input)) - (position 0) - (acc 0)) - (cl-loop for next = (day8/step code position acc) - when (equal 'loop (car next)) return (cdr next) - do (setq position (car next)) - do (setq acc (cdr next))))) - -;; Puzzle 2 - -(defun day8/flip-at (code pos) - (pcase (aref code pos) - (`(nop . ,val) (aset code pos `(jmp . ,val))) - (`(jmp . ,val) (aset code pos `(nop . ,val))) - (other (error "Unexpected flip op: %s" other)))) - -(defun day8/try-flip (flip-at code position acc) - (day8/flip-at code flip-at) - (cl-loop for next = (day8/step code position acc) - when (equal 'loop (car next)) return nil - when (equal 'final (car next)) return (cdr next) - do (setq position (car next)) - do (setq acc (cdr next)))) - -(message "Solution to day8/2: %s" - (let ((flip-options (cl-loop for op being the elements of day8/input - using (index idx) - for opcode = (car op) - when (or (equal 'nop opcode) - (equal 'jmp opcode)) - collect idx))) - (cl-loop for flip-at in flip-options - for result = (day8/try-flip flip-at (copy-sequence day8/input) 0 0) - when result return result))) diff --git a/users/tazjin/aoc2022/day1.rs b/users/tazjin/aoc2022/day1.rs deleted file mode 100644 index 078eb25f0..000000000 --- a/users/tazjin/aoc2022/day1.rs +++ /dev/null @@ -1,27 +0,0 @@ -// AoC 2022 - day 1. - -fn sum_elf(elf: &str) -> usize { - elf.lines() - .map(|s| s.parse::<usize>().expect("invalid input")) - .sum() -} - -fn group_by_elf(input: &str) -> Vec<usize> { - input.rsplit("\n\n").map(sum_elf).collect() -} - -fn top_elf(input: &str) -> usize { - group_by_elf(&input).into_iter().max().unwrap() -} - -fn top_n_elves(n: usize, input: &str) -> usize { - let mut by_elf = group_by_elf(input); - by_elf.sort_by(|a, b| b.cmp(a)); // high->low - (by_elf[..n]).iter().sum() -} - -fn main() { - let input = std::fs::read_to_string("input").expect("input should be in file named 'input'"); - println!("top elf: {}", top_elf(&input)); - println!("top 3 elves: {}", top_n_elves(3, &input)); -} diff --git a/users/tazjin/aoc2023/day1.el b/users/tazjin/aoc2023/day1.el deleted file mode 100644 index b1a7faff0..000000000 --- a/users/tazjin/aoc2023/day1.el +++ /dev/null @@ -1,52 +0,0 @@ -(require 's) -(require 'f) - -;; task 1 - -(defun digit-p (c) - (and (> c ?0) - (<= c ?9))) - -(defun aocd1-sum-values (lines) - (-sum - (-map (lambda (line) - (let ((digits (-filter #'digit-p (string-to-list line)))) - (string-to-number (string (-first-item digits) (-last-item digits))))) - lines))) - -(let ((lines (s-lines (s-trim (f-read "~/Downloads/input.txt"))))) - (aocd1-sum-values lines)) - -;; task 2 - -(defun replace-written-numbers (input) - (with-temp-buffer - (insert input) - (let ((start 1)) - (while (< start (point-max)) - (format-replace-strings - '(("oneight" . "18") - ("twone" . "21") - ("threeight" . "38") - ("fiveight" . "58") - ("sevenine" . "79") - ("eightwo" . "82") - ("eighthree" . "83") - ("nineight" . "98")) - nil start (min (+ 10 start) (point-max))) - (format-replace-strings - '(("one" . "1") - ("two" . "2") - ("three" . "3") - ("four" . "4") - ("five" . "5") - ("six" . "6") - ("seven" . "7") - ("eight" . "8") - ("nine" . "9")) - nil start (min (+ 5 start) (point-max))) - (setq start (1+ start)))) - (buffer-string))) - -(let ((lines (s-lines (s-trim (f-read "~/Downloads/input.txt"))))) - (aocd1-sum-values (-map #'replace-written-numbers lines))) diff --git a/users/tazjin/aoc2023/day2.el b/users/tazjin/aoc2023/day2.el deleted file mode 100644 index 9374d7862..000000000 --- a/users/tazjin/aoc2023/day2.el +++ /dev/null @@ -1,64 +0,0 @@ -(require 'dash) -(require 's) -(require 'f) - -(defvar aoc23-day2-example - - "Game 1: 3 blue, 4 red; 1 red, 2 green, 6 blue; 2 green -Game 2: 1 blue, 2 green; 3 green, 4 blue, 1 red; 1 green, 1 blue -Game 3: 8 green, 6 blue, 20 red; 5 blue, 4 red, 13 green; 5 green, 1 red -Game 4: 1 green, 3 red, 6 blue; 3 green, 6 red; 3 green, 15 blue, 14 red -Game 5: 6 red, 1 blue, 3 green; 2 blue, 1 red, 2 green") - -;; part 1 - -(cl-defstruct aoc23d2-set red green blue) - -(defun aoc23d2-parse-set (input) - (let ((set (make-aoc23d2-set :red 0 :green 0 :blue 0)) - (colours (-map #'s-trim (s-split "," input)))) - (cl-loop for colour in colours - do (pcase (s-split " " colour t) - (`(,num "red") (setf (aoc23d2-set-red set) (string-to-number num))) - (`(,num "green") (setf (aoc23d2-set-green set) (string-to-number num))) - (`(,num "blue") (setf (aoc23d2-set-blue set) (string-to-number num))))) - set)) - -(cl-defstruct aoc23d2-game id sets) - -(defun aoc23d2-parse-game (input) - (pcase-let* ((`(,id-str ,sets-str) (s-split-up-to ":" input 1 t)) - (game-id (string-to-number (s-chop-left (length "Game ") id-str))) - (sets (-map #'aoc23d2-parse-set (s-split ";" sets-str t)))) - (make-aoc23d2-game :id game-id :sets sets))) - -(defun aoc23d2-game-possible-p (game r g b) - (cl-every (lambda (set) - (and (<= (aoc23d2-set-red set) r) - (<= (aoc23d2-set-green set) g) - (<= (aoc23d2-set-blue set) b))) - (aoc23d2-game-sets game))) - -(let ((input (f-read "~/Downloads/input.txt"))) - (-sum - (-map #'aoc23d2-game-id - (-filter (lambda (g) (aoc23d2-game-possible-p g 12 13 14)) - (-map #'aoc23d2-parse-game (s-lines (s-trim input))))))) - -;; part 2 - -(defun aoc23d2-game-min-cubes-power (game) - (let ((r 0) - (g 0) - (b 0)) - (-each (aoc23d2-game-sets game) - (lambda (set) - (setq r (max r (aoc23d2-set-red set))) - (setq g (max g (aoc23d2-set-green set))) - (setq b (max b (aoc23d2-set-blue set))))) - (* (max 1 r) (max 1 g) (max 1 b)))) - -(let ((input (f-read "~/Downloads/input.txt"))) - (-sum - (-map #'aoc23d2-game-min-cubes-power - (-map #'aoc23d2-parse-game (s-lines (s-trim input)))))) diff --git a/users/tazjin/aoc2023/day3.el b/users/tazjin/aoc2023/day3.el deleted file mode 100644 index dd39c1b83..000000000 --- a/users/tazjin/aoc2023/day3.el +++ /dev/null @@ -1,110 +0,0 @@ -(defun aoc23d3-symbol-p (c) - (not (or (= c ? ) - (and (>= c ?0) - (<= c ?9))))) - -(defun rectangle-for-bounds (bounds) - (let* ((start (save-excursion - (goto-char (car bounds)) - (let ((col (current-column))) - (forward-line -1) - (move-to-column (max 0 (1- col)))) - (point))) - (end (save-excursion - (goto-char (cdr bounds)) - (let ((col (current-column))) - (forward-line 1) - (move-to-column (1+ col))) - (point)))) - (list start end))) - -(defun get-machine-part () - (interactive) - (when-let* ((num-raw (number-at-point)) - (num (abs num-raw)) - ;; handles negative number edge case (bounds contain the `-') - (bounds-raw (bounds-of-thing-at-point 'number)) - (bounds (if (< num-raw 0) - (cons (1- (car bounds-raw)) (cdr bounds-raw)) - bounds-raw)) - (rectangle (rectangle-for-bounds bounds)) - (neighbours (apply #'concat - (apply #'extract-rectangle rectangle)))) - (if (-any #'aoc23d3-symbol-p (string-to-list neighbours)) - (cons num rectangle) - (cons nil rectangle)))) - - -(defun find-machine-parts (input) - (with-temp-buffer - (insert input) - (goto-char (point-min)) - (save-excursion - (replace-string "." " ")) - - (cl-loop while (forward-word) - for result = (get-machine-part) - when (car result) collect (car result)))) - - -;; debugging - -(defvar aoc23d3-example "467..114.. -...*...... -..35..633. -......#... -617*...... -.....+.58. -..592..... -......755. -...$.*.... -.664.598..") - -(defvar aoc23d3-example2 "12.......*.. -+.........34 -.......-12.. -..78........ -..*....60... -78.......... -.......23... -....90*12... -............ -2.2......12. -.*.........* -1.1.......56") - -(defvar aoc23d3-example3 "243. -..*. -....") - -(defun aoc23d3-debug (p) - "Interactive debugger for the solution, can be bound to a key in -an input buffer. Dots should already have been replaced with -spaces." - (interactive "P") - (unless p - (goto-char aoc23d3-last)) - (rectangle-mark-mode 1) - (forward-word) - (setq aoc23d3-last (point)) - (pcase (get-machine-part) - (`(nil ,b ,e) (progn (set-mark b) - (goto-char e) - (set-face-attribute 'region nil :background "#FAA0A0"))) - (`(,num ,b ,e) (progn (set-mark b) - (goto-char e) - (set-face-attribute 'region nil :background "#d1ffbd"))) - (other (deactivate-mark)))) - -(cl-assert (= 4361 (-sum (find-machine-parts aoc23d3-example))) nil - "example from website is working") - -(cl-assert (= 413 (-sum (find-machine-parts aoc23d3-example2))) nil - "example from subreddit is working") - -(cl-assert (= 243 (-sum (find-machine-parts aoc23d3-example3))) nil - "example from telegram is working") - -;; day 1 (incomplete) - -(-sum (find-machine-parts (s-trim (f-read "~/Downloads/input.txt")))) diff --git a/users/tazjin/avatar.jpeg b/users/tazjin/avatar.jpeg deleted file mode 100644 index f6888e01c..000000000 Binary files a/users/tazjin/avatar.jpeg and /dev/null differ diff --git a/users/tazjin/blog/.skip-subtree b/users/tazjin/blog/.skip-subtree deleted file mode 100644 index e7fa50d49..000000000 --- a/users/tazjin/blog/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -Subdirectories contain blog posts and static assets only diff --git a/users/tazjin/blog/default.nix b/users/tazjin/blog/default.nix deleted file mode 100644 index 10de3c754..000000000 --- a/users/tazjin/blog/default.nix +++ /dev/null @@ -1,50 +0,0 @@ -{ depot, lib, pkgs, ... }: - -with depot.nix.yants; - -let - inherit (builtins) hasAttr filter; - - config = { - name = "tazjin's blog"; - baseUrl = "https://tazj.in/blog"; - staticUrl = "https://tazj.in/static/"; - - footer = '' - <p class="footer"> - <a class="uncoloured-link" href="https://tazj.in">homepage</a> - | - <a class="uncoloured-link" href="https://code.tvl.fyi/">code</a> - </p> - <p class="lod">ಠ_ಠ</p> - ''; - }; - - inherit (depot.web.blog) post includePost renderPost; - - posts = list post (import ./posts.nix); - - rendered = pkgs.runCommand "tazjins-blog" { } '' - mkdir -p $out - - ${lib.concatStringsSep "\n" (map (post: - "cp ${renderPost config post} $out/${post.key}.html" - ) posts)} - ''; - -in -{ - inherit rendered config; - - # Filter unlisted posts from the index - posts = filter includePost posts; - - # Generate embeddable nginx configuration for redirects from old post URLs - oldRedirects = lib.concatStringsSep "\n" (map - (post: '' - location ~* ^(/en)?/${post.oldKey} { - return 301 https://tazj.in/blog/${post.key}; - } - '') - (filter (hasAttr "oldKey") posts)); -} diff --git a/users/tazjin/blog/posts.nix b/users/tazjin/blog/posts.nix deleted file mode 100644 index a95a50d76..000000000 --- a/users/tazjin/blog/posts.nix +++ /dev/null @@ -1,78 +0,0 @@ -# This file defines all the blog posts. -[ - { - key = "reliably-switch-buffers"; - title = "Зачем reliably-switch-buffers?"; - content = ./posts/reliably-switch-buffers.md; - date = 1692882000; - } - { - key = "tvix-eval-talk-2023"; - title = "[доклад] tvix-eval, имплементация языка Nix на Rust"; - date = 1694102400; - content = ./posts/tvix-eval-talk-2023.md; - tagfilter = false; - } - { - key = "emacs-is-underrated"; - title = "Emacs is the most underrated tool"; - date = 1581286656; - content = ./posts/emacs-is-underrated.md; - draft = true; - } - { - key = "best-tools"; - title = "tazjin's best tools"; - date = 1576800001; - content = ./posts/best-tools.md; - } - { - key = "nixery-layers"; - title = "Nixery: Improved Layering Design"; - date = 1565391600; - content = ./posts/nixery-layers.md; - } - { - key = "reversing-watchguard-vpn"; - title = "Reverse-engineering WatchGuard Mobile VPN"; - date = 1486830338; - content = ./posts/reversing-watchguard-vpn.md; - oldKey = "1486830338"; - } - { - key = "make-object-t-again"; - title = "Make Object <T> Again!"; - date = 1476807384; - content = ./posts/make-object-t-again.md; - oldKey = "1476807384"; - } - { - key = "the-smu-problem"; - title = "The SMU-problem of messaging apps"; - date = 1450354078; - content = ./posts/the-smu-problem.md; - oldKey = "1450354078"; - } - { - key = "sick-in-sweden"; - title = "Being sick in Sweden"; - date = 1423995834; - content = ./posts/sick-in-sweden.md; - oldKey = "1423995834"; - listed = false; - } - { - key = "nsa-zettabytes"; - title = "The NSA's 5 zettabytes of data"; - date = 1375310627; - content = ./posts/nsa-zettabytes.md; - oldKey = "1375310627"; - } - { - key = "thoughts"; - title = "Some thoughts"; - date = 1665095948; - content = ./posts/thoughts.md; - listed = false; - } -] diff --git a/users/tazjin/blog/posts/best-tools.md b/users/tazjin/blog/posts/best-tools.md deleted file mode 100644 index afe61767b..000000000 --- a/users/tazjin/blog/posts/best-tools.md +++ /dev/null @@ -1,184 +0,0 @@ -In the spirit of various other "Which X do you use?"-pages I thought it would be -fun to have a little post here that describes which tools I've found to work -well for myself. - -When I say "tools" here, it's not about software - it's about real, physical -tools! - -If something goes on this list that's because I think it's seriously a -best-in-class type of product. - -<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc --> -- [Media & Tech](#media--tech) - - [Keyboard](#keyboard) - - [Speakers](#speakers) - - [Headphones](#headphones) - - [Earphones](#earphones) - - [Phone](#phone) -- [Other stuff](#other-stuff) - - [Toothbrush](#toothbrush) - - [Shavers](#shavers) - - [Shoulder bag](#shoulder-bag) - - [Wallet](#wallet) -<!-- markdown-toc end --> - ---------- - -# Media & Tech - -## Keyboard - -The best keyboard that money will buy you at the moment is the [Kinesis -Advantage][advantage]. There's a variety of contoured & similarly shaped -keyboards on the market, but the Kinesis is the only one I've tried that has -properly implemented the keywell concept. - -I struggle with RSI issues and the Kinesis actually makes it possible for me to -type for longer periods of time, which always leads to extra discomfort on -laptop keyboards and such. - -Honestly, the Kinesis is probably the best piece of equipment on this entire -list. I own several of them and there will probably be more in the future. They -last forever and your wrists will thank you in the future, even if you do not -suffer from RSI yet. - -Kinesis have announced a split version of the Advantage. Once that is -easily available, I will buy one and evaluate it. - -[advantage]: https://kinesis-ergo.com/shop/advantage2/ - -## Speakers - -There are two sets of speakers I use, unfortunately one pair has been in storage -since I left the UK. - -My original favourite speakers are the [Teufel Motiv 2][motiv-2], usually hooked -up to a Chromecast and a record player. I've had these for over a decade and -they're incredibly good, but unfortunately Teufel no longer makes them. Mine are -currently in a warehouse somewhere in London, and I don't know when I will see -them again ... - -It's possible to grab a pair on eBay occasionally, so keep an eye out if you're -interested! - -In my Moscow flat, I have a pair of [Wharfedale Diamond 12][diamond-12] -connected to a Philips amplifier older than myself. These provide an excellent, -balanced, "Wharfedale-sound". Some people find it needs some getting used to, -but don't want to go back after that initial phase. - -[motiv-2]: https://www.teufelaudio.com/uk/pc/motiv-2-p167.html -[diamond-12]: https://www.wharfedaleusa.com/collections/diamond-12 - -## Headphones - -I use the [Bose QC35][qc35] (note: link goes to a newer generation than the one -I own) for their outstanding noise cancelling functionality and decent sound. - -When I first bought them I didn't expect them to end up on this list as the -firmware had issues that made them only barely usable, but Bose has managed to -iron these problems out over time. - -I avoid using Bluetooth when outside and fortunately the QC35 come with an -optional cable that you can plug into any good old 3.5mm jack. - -[qc35]: https://www.bose.co.uk/en_gb/products/headphones/over_ear_headphones/quietcomfort-35-wireless-ii.html - -### Earphones - -Actually, to follow up on the above - most of the time I'm not using (over-ear) -headphones, but (in-ear) earphones - specifically the (**wired!!!**) [Apple -EarPods][earpods]. - -Apple will probably stop selling these soon because they've gotten into the -habit of cancelling all of their good products, so I have a stash of these -around. You will usually find no fewer than 3-4 of them lying around in my -flat. - -[earpods]: https://www.apple.com/uk/shop/product/MNHF2ZM/A/earpods-with-35mm-headphone-plug - -## Phone - -My current phone is the [Palm phone][palm-phone]. It's basically the smallest -smartphone on the market at about the size of a credit card. I picked this phone -because I am trying to not use a phone anymore, but some things simply require a -smartphone. - -The Palm has terrible battery life but is otherwise great. I always have it in -power saving mode and only turn on receiving calls when I'm expecting a call,. - -Previous phones I used and liked were: - -* [Unihertz Atom L][atom-l] - small-screen, rugged phone with headphone jack -* Original [iPhone SE][se] - perfect-sized phone, unfortunately with iOS - -[palm-phone]: https://palm.com/pages/product -[atom-l]: https://www.unihertz.com/products/atom-l -[se]: https://en.wikipedia.org/wiki/IPhone_SE - -# Other stuff - -## Toothbrush - -The [Philips Sonicare][sonicare] is excellent and well worth its price. - -I've had it for a few years and whereas I occasionally had minor teeth issues -before, they seem to be mostly gone now. According to my dentist the state of my -teeth is now usually pretty good and I draw a direct correlation back to this -thing. - -It has an app and stuff, but I just ignore that. - -I first got one of these in about 2014, and it lasted until 2020, at which point -I upgraded to whatever the current model was. - -[sonicare]: https://www.philips.co.uk/c-m-pe/electric-toothbrushes - -## Shavers - -The [Philipps SensoTouch 3D][sensotouch] is excellent. Super-comfortable close -face shave in no time and leaves absolutely no mess around, as far as I can -tell! I've had this for ~7 years and it's not showing any serious signs of aging -yet. - -Another bonus is that its battery time is effectively infinite (in the order of -months of use per charge). I've never had to worry when bringing it on a longer -trip! - -[sensotouch]: https://www.philips.co.uk/c-p/1250X_40/norelco-sensotouch-3d-wet-and-dry-electric-razor-with-precision-trimmer - -## Shoulder bag - -When I moved to London I wanted to stop using backpacks most of the time, as -those are just annoying to deal with when commuting on the tube. - -To work around this I wanted a good shoulder bag with a vertical format (to save -space), but it turned out that there's very few of those around that reach any -kind of quality standard. - -The one I settled on is the [Waterfield Muzetto][muzetto] leather bag. It's one -of those things that comes with a bit of a price tag attached, but it's well -worth it! - -**Unfortunately**, just like my speakers, this bag is now in storage somewhere -in the UK since I left the country. - -After moving to Moscow I quickly ran into the same problem as in London when -using the metro, but getting another Muzetto was kind of impractical. - -I couldn't find any other vertical messenger bags that I liked, and ended up -going for a more traditional one: The [Brialdi Ostin][ostin]. - -[muzetto]: https://www.sfbags.com/collections/shoulder-messenger-bags/products/muzetto-leather-bag -[ostin]: https://www.brialdi.ru/shop/handbags/brialdi_ostin_brown/ - -## Wallet - -My wallet is the [Bellroy Coin Wallet][coin-wallet]. It's the slimmest wallet I -could find that can deal with the volume of cards I (have to) carry around, as -well as with cash. - -I've used Bellroy wallets for a long time, with the [Slim Sleeve][slim-sleeve] -serving me in the days when I lived in no-cash countries. - -[coin-wallet]: https://bellroy.com/products/coin-wallet -[slim-sleeve]: https://bellroy.com/products/slim-sleeve-wallet/default/charcoal diff --git a/users/tazjin/blog/posts/emacs-is-underrated.md b/users/tazjin/blog/posts/emacs-is-underrated.md deleted file mode 100644 index afb8dc889..000000000 --- a/users/tazjin/blog/posts/emacs-is-underrated.md +++ /dev/null @@ -1,233 +0,0 @@ -TIP: Hello, and thanks for offering to review my draft! This post -intends to convey to people what the point of Emacs is. Not to convert -them to use it, but at least with opening their minds to the -possibility that it might contain valuable things. I don't know if I'm -on track in the right direction, and your input will help me figure it -out. Thanks! - -TODO(tazjin): Restructure sections: Intro -> Introspectability (and -story) -> text-based UIs (which lead to fluidity, muscle memory across -programs and "translatability" of workflows) -> Outro. It needs more -flow! - -TODO(tazjin): Highlight more that it's not about editing: People can -derive useful things from Emacs by just using magit/org/notmuch/etc.! - -TODO(tazjin): Note that there's value in trying Emacs even if people -don't end up using it, similar to how learning languages like Lisp or -Haskell helps grow as a programmer even without using them day-to-day. - -*Real post starts below!* - ---------- - -There are two kinds of people: Those who use Emacs, and those who -think it is a text editor. This post is aimed at those in the second -category. - -Emacs is the most critical piece of software I run. My [Emacs -configuration][emacs-config] has steadily evolved for almost a decade. -Emacs is my window manager, mail client, terminal, git client, -information management system and - perhaps unsurprisingly - text -editor. - -Before going into why I chose to invest so much into this program, -follow me along on a little thought experiment: - ----------- - -Lets say you use a proprietary spreadsheet program. You find that -there are features in it that *almost, but not quite* do what you -want. - -What can you do? You can file a feature request to the company that -makes it and hope they listen, but for the likes of Apple and -Microsoft chances are they won't and there is nothing you can do. - -Let's say you are also running an open-source program for image -manipulation. You again find that some of its features are subtly -different from what you would want them to do. - -Things look a bit different this time - after all, the program is -open-source! You can go and fetch its source code, figure out its -internal structure and wrangle various layers of code into submission -until you find the piece that implements the functionality you want to -change. If you know the language it is written in; you can modify the -feature. - -Now all that's left is figuring out its build system[^1], building and -installing it and moving over to the new version. - -Realistically you are not going to do this much in the real world. The -friction to contributing to projects, especially complex ones, is -often quite high. For minor inconveniences, you might often find -yourself just shrugging and working around them. - -What if it didn't have to be this way? - -------------- - -One of the core properties of Emacs is that it is *introspective* and -*self-documenting*. - -For example: A few years ago, I had just switched over to using -[EXWM][], the Emacs X Window Manager. To launch applications I was -using an Emacs program called Helm that let me select installed -programs interactively and press <kbd>RET</kbd> to execute them. - -This was very useful - until I discovered that if I tried to open a -second terminal window, it would display an error: - - Error: urxvt is already running - -Had this been dmenu, I might have had to go through the whole process -described above to fix the issue. But it wasn't dmenu - it was an -Emacs program, and I did the following things: - -1. I pressed <kbd>C-h k</kbd>[^2] (which means "please tell me what - the following key does"), followed by <kbd>s-d</kbd> (which was my - keybinding for launching programs). - -2. Emacs displayed a new buffer saying, roughly: - - ``` - s-d runs the command helm-run-external-command (found in global-map), - which is an interactive autoloaded compiled Lisp function in - ‘.../helm-external.el’. - - It is bound to s-d. - ``` - - I clicked on the filename. - -3. Emacs opened the file and jumped to the definition of - `helm-run-external-command`. After a few seconds of reading through - the code, I found this snippet: - - ```lisp - (if (get-process proc) - (if helm-raise-command - (shell-command (format helm-raise-command real-com)) - (error "Error: %s is already running" real-com)) - ;; ... the actual code to launch programs followed below ... - ) - ``` - -4. I deleted the outer if-expression which implemented the behaviour I - didn't want, pressed <kbd>C-M-x</kbd> to reload the code and saved - the file. - -The whole process took maybe a minute, and the problem was now gone. - -Emacs isn't just "open-source", it actively encourages the user to -modify it, discover what to modify and experiment while it is running. - -In some sense it is like the experience of the old Lisp machines, a -paradigm that we have completely forgotten. - ---------------- - -Circling back to my opening statement: If Emacs is not a text editor, -then what *is* it? - -The Emacs website says this: - -> [Emacs] is an interpreter for Emacs Lisp, a dialect of the Lisp -> programming language with extensions to support text editing - -The core of Emacs implements the language and the functionality needed -to evaluate and run it, as well as various primitives for user -interface construction such as buffers, windows and frames. - -Every other feature of Emacs is implemented *in Emacs Lisp*. - -The Emacs distribution ships with rudimentary text editing -functionality (and some language-specific support for the most popular -languages), but it also brings with it two IRC clients, a Tetris -implementation, a text-mode web browser, [org-mode][] and many other -tools. - -Outside of the core distribution there is a myriad of available -programs for Emacs: [magit][] (the famous git porcelain), text-based -[HTTP clients][], even interactive [Kubernetes frontends][k8s]. - -What all of these tools have in common is that they use text-based -user interfaces (UI elements like images are used only sparingly in -Emacs), and that they can be introspected and composed like everything -else in Emacs. - -If magit does not expose a git flag I need, it's trivial to add. If I -want a keybinding to jump from a buffer showing me a Kubernetes pod to -a magit buffer for the source code of the container, it only takes a -few lines of Emacs Lisp to implement. - -As proficiency with Emacs Lisp ramps up, the environment becomes -malleable like clay and evolves along with the user's taste and needs. -Muscle memory learned for one program translates seamlessly to others, -and the overall effect is an improvement in *workflow fluidity* that -is difficult to overstate. - -Also, workflows based on Emacs are *stable*. Moving my window -management to Emacs has meant that I'm not subject to the whim of some -third-party developer changing my window layouting features (as they -often do on MacOS). - -To illustrate this: Emacs has development history back to the 1970s, -continuous git history that survived multiple VCS migrations [since -1985][first-commit] (that's 22 years before git itself was released!) -and there is code[^3] implementing interactive functionality that has -survived unmodified in Emacs *since then*. - ---------------- - -Now, what is the point of this post? - -I decided to write this after a recent [tweet][] by @IanColdwater (in -the context of todo-management apps): - -> The fact that it's 2020 and the most viable answer to this appears -> to be Emacs might be the saddest thing I've ever heard - -What bothers me is that people see this as *sad*. Emacs being around -for this long and still being unparalleled for many of the UX -paradigms implemented by its programs is, in my book, incredible - and -not sad. - -How many other paradigms have survived this long? How many other tools -still have fervent followers, amazing [developer tooling][] and a -[vibrant ecosystem][] at this age? - -Steve Yegge [said it best][babel][^5]: Emacs has the Quality Without a -Name. - -What I wish you, the reader, should take away from this post is the -following: - -TODO(tazjin): Figure out what people should take away from this post. -I need to sleep on it. It's something about not dismissing tools just -because of their age, urging them to explore paradigms that might seem -unfamiliar and so on. Ideas welcome. - ---------------- - -[^1]: Wouldn't it be a joy if every project just used Nix? I digress ... -[^2]: These are keyboard shortcuts written in [Emacs Key Notation][ekn]. -[^3]: For example, [functionality for online memes][studly] that - wouldn't be invented for decades to come! -[^4]: ... and some things wrong, but that is an issue for a separate post! -[^5]: And I really *do* urge you to read that post's section on Emacs. - -[emacs-config]: https://git.tazj.in/tree/tools/emacs -[EXWM]: https://github.com/ch11ng/exwm -[helm]: https://github.com/emacs-helm/helm -[ekn]: https://www.gnu.org/software/emacs/manual/html_node/efaq/Basic-keys.html -[org-mode]: https://orgmode.org/ -[magit]: https://magit.vc -[HTTP clients]: https://github.com/pashky/restclient.el -[k8s]: https://github.com/jypma/kubectl -[first-commit]: http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=ce5584125c44a1a2fbb46e810459c50b227a95e2 -[studly]: http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=47bdd84a0a9d20aab934482a64b84d0db63e7532 -[tweet]: https://twitter.com/IanColdwater/status/1220824466525229056 -[developer tooling]: https://github.com/alphapapa/emacs-package-dev-handbook -[vibrant ecosystem]: https://github.com/emacs-tw/awesome-emacs -[babel]: https://sites.google.com/site/steveyegge2/tour-de-babel#TOC-Lisp diff --git a/users/tazjin/blog/posts/make-object-t-again.md b/users/tazjin/blog/posts/make-object-t-again.md deleted file mode 100644 index 420b57c0f..000000000 --- a/users/tazjin/blog/posts/make-object-t-again.md +++ /dev/null @@ -1,98 +0,0 @@ -A few minutes ago I found myself debugging a strange Java issue related -to Jackson, one of the most common Java JSON serialization libraries. - -The gist of the issue was that a short wrapper using some types from -[Javaslang](http://www.javaslang.io/) was causing unexpected problems: - -```java -public <T> Try<T> readValue(String json, TypeReference type) { - return Try.of(() -> objectMapper.readValue(json, type)); -} -``` - -The signature of this function was based on the original Jackson -`readValue` type signature: - -```java -public <T> T readValue(String content, TypeReference valueTypeRef) -``` - -While happily using my wrapper function I suddenly got an unexpected -error telling me that `Object` is incompatible with the type I was -asking Jackson to de-serialize, which got me to re-evaluate the above -type signature again. - -Lets look for a second at some code that will *happily compile* if you -are using Jackson\'s own `readValue`: - -```java -// This shouldn't compile! -Long l = objectMapper.readValue("\"foo\"", new TypeReference<String>(){}); -``` - -As you can see there we ask Jackson to decode the JSON into a `String` -as enclosed in the `TypeReference`, but assign the result to a `Long`. -And it compiles. And it failes at runtime with -`java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long`. -Huh? - -Looking at the Jackson `readValue` implementation it becomes clear -what\'s going on here: - -```java -@SuppressWarnings({ "unchecked", "rawtypes" }) -public <T> T readValue(String content, TypeReference valueTypeRef) - throws IOException, JsonParseException, JsonMappingException -{ - return (T) _readMapAndClose(/* whatever */); -} -``` - -The function is parameterised over the type `T`, however the only place -where `T` occurs in the signature is in the parameter declaration and -the function return type. Java will happily let you use generic -functions and types without specifying type parameters: - -```java -// Compiles fine! -final List myList = List.of(1,2,3); - -// Type is now myList : List<Object> -``` - -Meaning that those parameters default to `Object`. Now in the code above -Jackson also explicitly casts the return value of its inner function -call to `T`. - -What ends up happening is that Java infers the expected return type from -the context of the `readValue` and then happily uses the unchecked cast -to fit that return type. If the type hints of the context aren\'t strong -enough we simply get `Object` back. - -So what\'s the fix for this? It\'s quite simple: - -```java -public <T> T readValue(String content, TypeReference<T> valueTypeRef) -``` - -By also making the parameter appear in the `TypeReference` we \"bind\" -`T` to the type enclosed in the type reference. The cast can then also -safely be removed. - -The cherries on top of this are: - -1. `@SuppressWarnings({ "rawtypes" })` explicitly disables a - warning that would\'ve caught this - -2. the `readValue` implementation using the less powerful `Class` - class to carry the type parameter does this correctly: `public <T> - T readValue(String content, Class<T> valueType)` - -The big question I have about this is *why* does Jackson do it this way? -Obviously the warning did not just appear there by chance, so somebody -must have thought about this? - -If anyone knows what the reason is, I\'d be happy to hear from you. - -PS: Shoutout to David & Lucia for helping me not lose my sanity over -this. diff --git a/users/tazjin/blog/posts/nixery-layers.md b/users/tazjin/blog/posts/nixery-layers.md deleted file mode 100644 index d96fee00c..000000000 --- a/users/tazjin/blog/posts/nixery-layers.md +++ /dev/null @@ -1,272 +0,0 @@ -TIP: This blog post was originally published as a design document for -[Nixery][] and is not written in the same style -as other blog posts. - -Thanks to my colleagues at Google and various people from the Nix community for -reviewing this. - ------- - -# Nixery: Improved Layering - -**Authors**: tazjin@ - -**Reviewers**: so...@, en...@, pe...@ - -**Status**: Implemented - -**Last Updated**: 2019-08-10 - -## Introduction - -This document describes a design for an improved image layering method for use -in Nixery. The algorithm [currently used][grhmc] is designed for a slightly -different use-case and we can improve upon it by making use of more of the -available data. - -## Background / Motivation - -Nixery is a service that uses the [Nix package manager][nix] to build container -images (for runtimes such as Docker), that are served on-demand via the -container [registry protocols][]. A demo instance is available at -[nixery.dev][]. - -In practice this means users can simply issue a command such as `docker pull -nixery.dev/shell/git` and receive an image that was built ad-hoc containing a -shell environment and git. - -One of the major advantages of building container images via Nix (as described -for `buildLayeredImage` in [this blog post][grhmc]) is that the -content-addressable nature of container image layers can be used to provide more -efficient caching characteristics (caching based on layer content) than what is -common with Dockerfiles and other image creation methods (caching based on layer -creation method). - -However, this is constrained by the maximum number of layers supported in an -image (125). A naive approach such as putting each included package (any -library, binary, etc.) in its own layer quickly runs into this limitation due to -the large number of dependencies more complex systems tend to have. In addition, -users wanting to extend images created by Nixery (e.g. via `FROM nixery.dev/…`) -share this layer maximum with the created image - limiting extensibility if all -layers are used up by Nixery. - -In theory the layering strategy of `buildLayeredImage` should already provide -good caching characteristics, but in practice we are seeing many images with -significantly more packages than the number of layers configured, leading to -more frequent cache-misses than desired. - -The current implementation of `buildLayeredImage` inspects a graph of image -dependencies and determines the total number of references (direct & indirect) -to any node in the graph. It then sorts all dependencies by this popularity -metric and puts the first `n - 2` (for `n` being the maximum number of layers) -packages in their own layers, all remaining packages in one layer and the image -configuration in the final layer. - -## Design / Proposal - -## (Close-to) ideal layer-layout using more data - -We start out by considering what a close to ideal layout of layers would look -like for a simple use-case. - -![Ideal layout](/static/img/nixery/ideal_layout.webp) - -In this example, counting the total number of references to each node in the -graph yields the following result: - -| pkg | refs | -|-------|------| -| E | 3 | -| D | 2 | -| F | 2 | -| A,B,C | 1 | - -Assuming we are constrained to 4 layers, the current algorithm would yield these layers: - -``` -L1: E -L2: D -L3: F -L4: A, B, C -``` - -The initial proposal for this design is that additional data should be -considered in addition to the total number of references, in particular a -distinction should be made between direct and indirect references. Packages that -are only referenced indirectly should be merged with their parents. - -This yields the following table: - -| pkg | direct | indirect | -|-------|--------|----------| -| E | 3 | 3 | -| D | 2 | 2 | -| F | *1* | 2 | -| A,B,C | 1 | 1 | - -Despite having two indirect references, F is in fact only being referred to -once. Assuming that we have no other data available outside of this graph, we -have no reason to assume that F has any popularity outside of the scope of D. -This might yield the following layers: - -``` -L1: E -L2: D, F -L3: A -L4: B, C -``` - -D and F were grouped, while the top-level references (i.e. the packages -explicitly requested by the user) were split up. - -An assumption is introduced here to justify this split: The top-level packages -is what the user is modifying directly, and those groupings are likely -unpredictable. Thus it is opportune to not group top-level packages in the same -layer. - -This raises a new question: Can we make better decisions about where to split -the top-level? - -## (Even closer to) ideal layering using (even) more data - -So far when deciding layer layouts, only information immediately available in -the build graph of the image has been considered. We do however have much more -information available, as we have both the entire nixpkgs-tree and potentially -other information (such as download statistics). - -We can calculate the total number of references to any derivation in nixpkgs and -use that to rank the popularity of each package. Packages within some percentile -can then be singled out as good candidates for a separate layer. - -When faced with a splitting decision such as in the last section, this data can -aid the decision. Assume for example that package B in the above is actually -`openssl`, which is a very popular package. Taking this into account would -instead yield the following layers: - -``` -L1: E, -L2: D, F -L3: B, -L4: A, C -``` - -## Layer budgets and download size considerations - -As described in the introduction, there is a finite amount of layers available -for each image (the “layer budget”). When calculating the layer distribution, we -might end up with the “ideal” list of layers that we would like to create. Using -our previous example: - -``` -L1: E, -L2: D, F -L3: A -L4: B -L5: C -``` - -If we only have a layer budget of 4 available, something needs to be merged into -the same layer. To make a decision here we could consider only the package -popularity, but there is in fact another piece of information that has not come -up yet: The actual size of the package. - -Presumably a user would not mind downloading a library that is a few kilobytes -in size repeatedly, but they would if it was a 200 megabyte binary instead. - -Conversely if a large binary was successfully cached, but an extremely popular -small library is not, the total download size might also grow to irritating -levels. - -To avoid this we can calculate a merge rating: - - merge_rating(pkg) = popularity_percentile(pkg) × size(pkg.subtree) - -Packages with a low merge rating would be merged together before packages with -higher merge ratings. - -## Implementation - -There are two primary components of the implementation: - -1. The layering component which, given an image specification, decides the image - layers. - -2. The popularity component which, given the entire nixpkgs-tree, calculates the - popularity of packages. - -## Layering component - -It turns out that graph theory’s concept of [dominator trees][] maps reasonably -well onto the proposed idea of separating direct and indirect dependencies. This -becomes visible when creating the dominator tree of a simple example: - -![Example without extra edges](/static/img/nixery/example_plain.webp) - -Before calculating the dominator tree, we inspect each node and insert extra -edges from the root for packages that match a certain popularity or size -threshold. In this example, G is popular and an extra edge is inserted: - -![Example with extra edges](/static/img/nixery/example_extra.webp) - -Calculating the dominator tree of this graph now yields our ideal layer -distribution: - -![Dominator tree of example](/static/img/nixery/dominator.webp) - -The nodes immediately dominated by the root node can now be “harvested” as image -layers, and merging can be performed as described above until the result fits -into the layer budget. - -To implement this, the layering component uses the [gonum/graph][] library which -supports calculating dominator trees. The program is fed with Nix’s -`exportReferencesGraph` (which contains the runtime dependency graph and runtime -closure size) as well as the popularity data and layer budget. It returns a list -of layers, each specifying the paths it should contain. - -Nix invokes this program and uses the output to create a derivation for each -layer, which is then built and returned to Nixery as usual. - -TIP: This is implemented in [`layers.go`][layers.go] in Nixery. The file starts -with an explanatory comment that talks through the process in detail. - -## Popularity component - -The primary issue in calculating the popularity of each package in the tree is -that we are interested in the runtime dependencies of a derivation, not its -build dependencies. - -To access information about the runtime dependency, the derivation actually -needs to be built by Nix - it can not be inferred because Nix does not know -which store paths will still be referenced by the build output. - -However for packages that are cached in the NixOS cache, we can simply inspect -the `narinfo`-files and use those to determine popularity. - -Not every package in nixpkgs is cached, but we can expect all *popular* packages -to be cached. Relying on the cache should therefore be reasonable and avoids us -having to rebuild/download all packages. - -The implementation will read the `narinfo` for each store path in the cache at a -given commit and create a JSON-file containing the total reference count per -package. - -For the public Nixery instance, these popularity files will be distributed via a -GCS bucket. - -TIP: This is implemented in [popcount][] in Nixery. - --------- - -Hopefully this detailed design review was useful to you. You can also watch [my -NixCon talk][talk] about Nixery for a review of some of this, and some demos. - -[Nixery]: https://code.tvl.fyi/tree/tools/nixery -[grhmc]: https://grahamc.com/blog/nix-and-layered-docker-images -[Nix]: https://nixos.org/nix -[registry protocols]: https://github.com/opencontainers/distribution-spec/blob/master/spec.md -[nixery.dev]: https://nixery.dev -[dominator trees]: https://en.wikipedia.org/wiki/Dominator_(graph_theory) -[gonum/graph]: https://godoc.org/gonum.org/v1/gonum/graph -[layers.go]: https://code.tvl.fyi/tree/tools/nixery/layers/layers.go -[popcount]: https://code.tvl.fyi/tree/tools/nixery/popcount -[talk]: https://www.youtube.com/watch?v=pOI9H4oeXqA diff --git a/users/tazjin/blog/posts/nsa-zettabytes.md b/users/tazjin/blog/posts/nsa-zettabytes.md deleted file mode 100644 index f8b326f2f..000000000 --- a/users/tazjin/blog/posts/nsa-zettabytes.md +++ /dev/null @@ -1,93 +0,0 @@ -I've been reading a few discussions on Reddit about the new NSA data -centre that is being built and stumbled upon [this -post](http://www.reddit.com/r/restorethefourth/comments/1jf6cx/the_guardian_releases_another_leaked_document_nsa/cbe5hnc), -putting its alleged storage capacity at *5 zettabytes*. - -That seems to be a bit much which I tried to explain to that guy, but I -was quickly blocked by the common conspiracy argument that government -technology is somehow far beyond the wildest dreams of us mere mortals - -thus I wrote a very long reply that will most likely never be seen by -anybody. Therefore I've decided to repost it here. - ------------------------------------------------------------------------- - -I feel like I've entered /r/conspiracy. Please have some facts (and do -read them!) - -A one terabyte SSD (I assume that\'s what you meant by flash-drive) -would require 5000000000 of those. That is *five billion* of those flash -drives. Can you visualise how much five billion flash-drives are? - -A single SSD is roughly 2cm\*13cm\*13cm with an approximate weight of -80g. That would make 400 000 metric tons of SSDs, a weight equivalent to -*over one thousand Boeing 747 airplanes*. Even if we assume that they -solder the flash chips directly onto some kind of controller (which also -weighs something), the raw material for that would be completely insane. - -Another visualization: If you stacked 5 billion SSDs on top of each -other you would get an SSD tower that is a hundred thousand kilometres -high, that is equivalent to 2,5 x the equatorial circumference of -*Earth* or 62000 miles. - -The volume of those SSDs would be clocking in at 1690000000 cubic -metres, more than the Empire State building. Are you still with me? - -Lets speak cost. The Samsung SSD that I assume you are referring to will -clock in at \$600, lets assume that the NSA gets a discount when buying -*five billion* of those and gets them at the cheap price of \$250. That -makes 1.25 trillion dollars. That would be a significant chunk of the -current US national debt. - -And all of this is just SSDs to stick into servers and storage units, -which need a whole bunch of other equipment as well to support them - -the cost would probably shoot up to something like 8 trillion dollars if -they were to build this. It would with very high certainty be more than -the annual production of SSDs (I can\'t find numbers on that -unfortunately) and take up *slightly* more space than they have in the -Utah data centre (assuming you\'re not going to tell me that it is in -fact attached to an underground base that goes down to the core of the -Earth). - -Lets look at the \"But the government has better technologies!\" idea. - -Putting aside the fact that the military *most likely* does not have a -secret base on Mars that deals with advanced science that the rest of us -can only dream of, and doing this under the assumption that they do have -this base, lets assume that they build a storage chip that stores 100TB. -This reduces the amount of needed chips to \"just\" 50 million, lets say -they get 10 of those into a server / some kind of specialized storage -unit and we only need 5 million of those specially engineered servers, -with custom connectors, software, chips, storage, most likely also power -sources and whatever - 10 million completely custom units built with -technology that is not available to the market. Google is estimated to -have about a million servers in total, I don\'t know exactly in how many -data centres those are placed but numbers I heard recently said that -it\'s about 40. When Apple assembles a new iPhone model they need -massive factories with thousands of workers and supplies from many -different countries, over several months, to assemble just a few million -units for their launch month. - -You are seriously proposing that the NSA is better than Google and Apple -and the rest of the tech industry, world-wide, combined at designing -*everything* in tech, manufacturing *everything* in tech, without *any* -information about that leaking and without *any* of the science behind -it being known? That\'s not just insane, that\'s outright impossible. - -And we haven\'t even touched upon how they would route the necessary -amounts of bandwidth (crazy insane) to save *the entire internet* into -that data center. - ------------------------------------------------------------------------- - -I\'m not saying that the NSA is not building a data center to store -surveillance information, to have more capacity to spy on people and all -that - I\'m merely making the point that the extent in which conspiracy -sites say they do this vastly overestimates their actual abilities. They -don\'t have magic available to them! Instead of making up insane figures -like that you should focus on what we actually know about their -operations, because using those figures in a debate with somebody who is -responsible for this (and knows what they\'re talking about) will end -with you being destroyed - nobody will listen to the rest of what -you\'re saying when that happens. - -\"Stick to the facts\" is valid for our side as well. diff --git a/users/tazjin/blog/posts/reliably-switch-buffers.md b/users/tazjin/blog/posts/reliably-switch-buffers.md deleted file mode 100644 index ec56c4b2d..000000000 --- a/users/tazjin/blog/posts/reliably-switch-buffers.md +++ /dev/null @@ -1,18 +0,0 @@ -Вчера вечером написал некоторые патчи для моего emacs-конфига. Их на самом деле давно уже хотел написать, они решают маленькие проблемы которые мне постоянно мешали. Об одной из проблем я хочу рассказать, потому что она привела к тому, что "порог раздражения" был переступлен. - -Emacs у меня основная часть своей рабочей среды. Он у меня является, конечно, текстовым редактором, но и еще менеджером окон, мэйл-клиентом, чат-клиентом и много другого. - -Внутри emacs есть концепция "буферов", один буфер может быть один открытый файл в текстовом редакторе, один чат на Телеграме, или одно десктопное окно (например, браузер). Навигация между ними осуществляется с помощью команды `switch-to-buffer` (или кое-каких альтернатив, например `ivy-switch-buffer`, `helm-switch-buffer` и так далее). Буфер - на стороне emacs-lisp является объектом с некоторыми полями. Одно из них: `buffer-name`. - -У всех buffer-switch команд есть одинаковая проблема: Они берут список буферов из emacs, показывают *имена* буферов пользователю, и в результате получают выбранное *имя*. Затем они просят emacs открыть буфер с этим именем. - -Кто-то наверно уже понял какая тут проблема. Имени буферов могут меняться, и да, не только могут, но и делают! Например, Телеграм-клиент может показать каличество непрочитанных сообщений в названии, окно с Яндекс Музыкой меняет названия по треку, и так далее. Получается довольно часто такая ситуация, что название меняется при выборе буфера, и `switch-to-buffer` больше не найдет выбранный буфер и просто открывает новый, пустой буфер с старым названием! Когда разработывали эти команды в emacs (да, это совершенно давно, где-то в 70х/80х, большинства нас пока не было тогда!), они никогда не сталкивались с такими ситуациями, и это решение, которое тогда хорошо работало теперь больше просто не адекватно. - -Фикс был не очень сложным. Вместо списка имен буферов создаю alist с названием и *с самим объектом*, и после выбора буфера с списка передаю именно этот объект, а не только его название, в функтцию, которая открывает буфер. - -Коммит с этой новой функцией здесь: cl/9147 -Советую её особенно всем пользователям EXWM! - -Для меня это настоящее улучшение жизни. Конечно, это странно звучит, но даже если бы у меня была такая проблема всего раз в день, это каким-то образом привело бы к ухудшению моего настроения. Как маленький камешек в твоем ботинке. - -Выньте камни из своих ботинок! diff --git a/users/tazjin/blog/posts/reversing-watchguard-vpn.md b/users/tazjin/blog/posts/reversing-watchguard-vpn.md deleted file mode 100644 index e000d7a76..000000000 --- a/users/tazjin/blog/posts/reversing-watchguard-vpn.md +++ /dev/null @@ -1,158 +0,0 @@ -TIP: WatchGuard has -[responded](https://web.archive.org/web/20230326041952/https://www.reddit.com/r/netsec/comments/5tg0f9/reverseengineering_watchguard_mobile_vpn/dds6knx/) -to this post on Reddit. If you haven\'t read the post yet I\'d recommend -doing that first before reading the response to have the proper context. - ------------------------------------------------------------------------- - -One of my current clients makes use of -[WatchGuard](http://www.watchguard.com/help/docs/fireware/11/en-US/Content/en-US/mvpn/ssl/mvpn_ssl_client-install_c.html) -Mobile VPN software to provide access to the internal network. - -Currently WatchGuard only provides clients for OS X and Windows, neither -of which I am very fond of. In addition an OpenVPN configuration file is -provided, but it quickly turned out that this was only a piece of the -puzzle. - -The problem is that this VPN setup is secured using 2-factor -authentication (good!), but it does not use OpenVPN's default -[challenge/response](https://openvpn.net/index.php/open-source/documentation/miscellaneous/79-management-interface.html) -functionality to negotiate the credentials. - -Connecting with the OpenVPN config that the website supplied caused the -VPN server to send me a token to my phone, but I simply couldn't figure -out how to supply it back to the server. In a normal challenge/response -setting the token would be supplied as the password on the second -authentication round, but the VPN server kept rejecting that. - -Other possibilities were various combinations of username&password -(I've seen a lot of those around) so I tried a whole bunch, for example -`$password:$token` or even a `sha1(password, token)` - to no avail. - -At this point it was time to crank out -[Hopper](https://www.hopperapp.com/) and see what's actually going on -in the official OS X client - which uses OpenVPN under the hood! - -Diving into the client ----------------------- - -The first surprise came up right after opening the executable: It had -debug symbols in it - and was written in Objective-C! - -![Debug symbols](/static/img/watchblob_1.webp) - -A good first step when looking at an application binary is going through -the strings that are included in it, and the WatchGuard client had a lot -to offer. Among the most interesting were a bunch of URIs that looked -important: - -![Some URIs](/static/img/watchblob_2.webp) - -I started with the first one - - %@?action=sslvpn_download&filename=%@&fw_password=%@&fw_username=%@ - -and just curled it on the VPN host, replacing the username and -password fields with bogus data and the filename field with -`client.wgssl` - another string in the executable that looked like a -filename. - -To my surprise this endpoint immediately responded with a GZIPed file -containing the OpenVPN config, CA certificate, and the client -*certificate and key*, which I previously thought was only accessible -after logging in to the web UI - oh well. - -The next endpoint I tried ended up being a bit more interesting still: - - /?action=sslvpn_logon&fw_username=%@&fw_password=%@&style=fw_logon_progress.xsl&fw_logon_type=logon&fw_domain=Firebox-DB - -Inserting the correct username and password into the query parameters -actually triggered the process that sent a token to my phone. The -response was a simple XML blob: - -```xml -<?xml version="1.0" encoding="UTF-8"?> -<resp> - <action>sslvpn_logon</action> - <logon_status>4</logon_status> - <auth-domain-list> - <auth-domain> - <name>RADIUS</name> - </auth-domain> - </auth-domain-list> - <logon_id>441</logon_id> - <chaStr>Enter Your 6 Digit Passcode </chaStr> -</resp> -``` - -Somewhat unsurprisingly that `chaStr` field is actually the challenge -string displayed in the client when logging in. - -This was obviously going in the right direction so I proceeded to the -procedures making use of this string. The first step was a relatively -uninteresting function called `-[VPNController sslvpnLogon]` which -formatted the URL, opened it and checked whether the `logon_status` was -`4` before proceeding with the `logon_id` and `chaStr` contained in the -response. - -*(Code snippets from here on are Hopper's pseudo-Objective-C)* - -![sslvpnLogon](/static/img/watchblob_3.webp) - -It proceeded to the function `-[VPNController processTokenPrompt]` which -showed the dialog window into which the user enters the token, sent it -off to the next URL and checked the `logon_status` again: - -(`r12` is the reference to the `VPNController` instance, i.e. `self`). - -![processTokenPrompt](/static/img/watchblob_4.webp) - -If the `logon_status` was `1` (apparently \"success\" here) it proceeded -to do something quite interesting: - -![processTokenPrompt2](/static/img/watchblob_5.webp) - -The user's password was overwritten with the (verified) OTP token - -before OpenVPN had even been started! - -Reading a bit more of the code in the subsequent -`-[VPNController doLogin]` method revealed that it shelled out to -`openvpn` and enabled the management socket, which makes it possible to -remotely control an `openvpn` process by sending it commands over TCP. - -It then simply sent the username and the OTP token as the credentials -after configuring OpenVPN with the correct config file: - -![doLogin](/static/img/watchblob_6.webp) - -... and the OpenVPN connection then succeeds. - -TL;DR ------ - -Rather than using OpenVPN's built-in challenge/response mechanism, the -WatchGuard client validates user credentials *outside* of the VPN -connection protocol and then passes on the OTP token, which seems to be -temporarily in a 'blessed' state after verification, as the user's -password. - -I didn't check to see how much verification of this token is performed -(does it check the source IP against the IP that performed the challenge -validation?), but this certainly seems like a bit of a security issue - -considering that an attacker on the same network would, if they time the -attack right, only need your username and 6-digit OTP token to -authenticate. - -Don't roll your own security, folks! - -Bonus ------ - -The whole reason why I set out to do this is so I could connect to this -VPN from Linux, so this blog post wouldn't be complete without a -solution for that. - -To make this process really easy I've written a [little -tool](https://github.com/tazjin/watchblob) that performs the steps -mentioned above from the CLI and lets users know when they can -authenticate using their OTP token. diff --git a/users/tazjin/blog/posts/sick-in-sweden.md b/users/tazjin/blog/posts/sick-in-sweden.md deleted file mode 100644 index 0c43c5832..000000000 --- a/users/tazjin/blog/posts/sick-in-sweden.md +++ /dev/null @@ -1,26 +0,0 @@ -I\'ve been sick more in the two years in Sweden than in the ten years -before that. - -Why? I have a theory about it and after briefly discussing it with one -of my roommates (who is experiencing the same thing) I\'d like to share -it with you: - -Normally when people get sick, are coughing, have a fever and so on they -take a few days off from work and stay at home. The reasons are twofold: -You want to rest a bit in order to get rid of the disease and you want -to *avoid infecting your co-workers*. - -In Sweden people will drag themselves into work anyways, because of a -concept called the -[karensdag](https://www.forsakringskassan.se/wps/portal/sjukvard/sjukskrivning_och_sjukpenning/karensdag_och_forstadagsintyg). -The TL;DR of this is \'if you take days off sick you won\'t get paid for -the first day, and only 80% of your salary on the remaining days\'. - -Many people are not willing to take that financial hit. In combination -with Sweden\'s rather mediocre healthcare system you end up constantly -being surrounded by sick people, not just in your own office but also on -public transport and basically all other public places. - -Oh and the best thing about this? Swedish politicians [often ignore -this](https://www.aftonbladet.se/nyheter/article10506886.ab) rule and -just don\'t report their sick days. Nice. diff --git a/users/tazjin/blog/posts/the-smu-problem.md b/users/tazjin/blog/posts/the-smu-problem.md deleted file mode 100644 index f411e3116..000000000 --- a/users/tazjin/blog/posts/the-smu-problem.md +++ /dev/null @@ -1,151 +0,0 @@ -After having tested countless messaging apps over the years, being -unsatisfied with most of them and finally getting stuck with -[Telegram](https://telegram.org/) I have developed a little theory about -messaging apps. - -SMU stands for *Security*, *Multi-Device* and *Usability*. Quite like -the [CAP-theorem](https://en.wikipedia.org/wiki/CAP_theorem) I believe -that you can - using current models - only solve two out of three things -on this list. Let me elaborate what I mean by the individual points: - -**Security**: This is mainly about encryption of messages, not so much -about hiding identities to third-parties. Commonly some kind of -asymmetric encryption scheme. Verification of keys used must be possible -for the user. - -**Multi-Device**: Messaging-app clients for multiple devices, with -devices being linked to the same identifier, receiving the same messages -and being independent of each other. A nice bonus is also an open -protocol (like Telegram\'s) that would let people write new clients. - -**Usability**: Usability is a bit of a broad term, but what I mean by it -here is handling contacts and identities. It should be easy to create -accounts, give contact information to people and have everything just -work in a somewhat automated fashion. - -Some categorisation of popular messaging apps: - -**SU**: Threema - -**MU**: Telegram, Google Hangouts, iMessage, Facebook Messenger - -**SM**: -[Signal](https://gist.github.com/TheBlueMatt/d2fcfb78d29faca117f5) - -*Side note: The most popular messaging app - WhatsApp - only scores a -single letter (U). This makes it completely uninteresting to me.* - -Let\'s talk about **SM** - which might contain the key to solving SMU. -Two approaches are interesting here. - -The single key model --------------------- - -In Signal there is a single identity key which can be used to register a -device on the server. There exists a process for sharing this identity -key from a primary device to a secondary one, so that the secondary -device can register itself (see the link above for a description). - -This *almost* breaks M because there is still a dependence on a primary -device and newly onboarded devices can not be used to onboard further -devices. However, for lack of a better SM example I\'ll give it a pass. - -The other thing it obviously breaks is U as the process for setting it -up is annoying and having to rely on the primary device is a SPOF (there -might be a way to recover from a lost primary device, but I didn\'t find -any information so far). - -The multiple key model ----------------------- - -In iMessage every device that a user logs into creates a new key pair -and submits its public key to a per-account key pool. Senders fetch all -available public keys for a recipient and encrypt to all of the keys. - -Devices that join can catch up on history by receiving it from other -devices that use its public key. - -This *almost* solves all of SMU, but its compliance with S breaks due to -the fact that the key pool is not auditable, and controlled by a -third-party (Apple). How can you verify that they don\'t go and add -another key to your pool? - -A possible solution -------------------- - -Out of these two approaches I believe the multiple key one looks more -promising. If there was a third-party handling the key pool but in a way -that is verifiable, transparent and auditable that model could be used -to solve SMU. - -The technology I have been thinking about for this is some kind of -blockchain model and here\'s how I think it could work: - -1. Bob installs the app and begins onboarding. The first device - generates its keypair, submits the public key and an account - creation request. - -2. Bob\'s account is created on the messaging apps\' servers and a - unique identifier plus the fingerprint of the first device\'s public - key is written to the chain. - -3. Alice sends a message to Bob, her device asks the messaging service - for Bob\'s account\'s identity and public keys. Her device verifies - the public key fingerprint against the one in the blockchain before - encrypting to it and sending the message. - -4. Bob receives Alice\'s message on his first device. - -5. Bob logs in to his account on a second device. The device generates - a key pair and sends the public key to the service, the service - writes it to the blockchain using its identifier. - -6. The messaging service requests that Bob\'s first device signs the - second device\'s key and triggers a simple confirmation popup. - -7. Bob confirms the second device on his first device. It signs the key - and writes the signature to the chain. - -8. Alice sends another message, her device requests Bob\'s current keys - and receives the new key. It verifies that both the messaging - service and one of Bob\'s older devices have confirmed this key in - the chain. It encrypts the message to both keys and sends it on. - -9. Bob receives Alice\'s message on both devices. - -After this the second device can request conversation history from the -first one to synchronise old messages. - -Further devices added to an account can be confirmed by any of the -devices already in the account. - -The messaging service could not add new keys for an account on its own -because it does not control any of the private keys confirmed by the -chain. - -In case all devices were lost, the messaging service could associate the -account with a fresh identity in the block chain. Message history -synchronisation would of course be impossible. - -Feedback welcome ----------------- - -I would love to hear some input on this idea, especially if anyone knows -of an attempt to implement a similar model already. Possible attack -vectors would also be really interesting. - -Until something like this comes to fruition, I\'ll continue using -Telegram with GPG as the security layer when needed. - -**Update:** WhatsApp has launched an integration with the Signal guys -and added their protocol to the official WhatsApp app. This means -WhatsApp now firmly sits in the SU-category, but it still does not solve -this problem. - -**Update 2:** Facebook Messenger has also integrated with Signal, but -their secret chats do not support multi-device well (it is Signal -afterall). This means it scores either SU or MU depending on which mode -you use it in. - -An interesting service I have not yet evaluated properly is -[Matrix](http://matrix.org/). diff --git a/users/tazjin/blog/posts/thoughts.md b/users/tazjin/blog/posts/thoughts.md deleted file mode 100644 index 7ce23f9c8..000000000 --- a/users/tazjin/blog/posts/thoughts.md +++ /dev/null @@ -1,142 +0,0 @@ -<!-- - - This file contains a bunch of random thoughts I don't want to lose, - often resulting from conversation with other people, but that are - too far removed from what most people can relate to for me to just - publish them. Sometimes it's convenient to be able to share them, - though. - - For that reason, if you stumble upon this file without me having - linked it to you intentionally, feel free to read it but keep the - sharing to a minimum (though do feel free to share the thoughts - themselves, of course). - ---> -WARNING: This is not intended for a large audience. If you stumble -upon this page by chance, please keep the sharing to a minimum. - -TIP: It's always work-in-progress. Things come and go. Or change. Who -knows? - ---------- - -### Three things - -*[mid/late 2020]* - -All things in the universe take the shape of one of approximately -three things. If you had Hoogle for the entire universe, you'd -probably find that one of them is `fmap`. - -There might be a few more, or a few less (or some may have been -deprecated), but you get the idea. I guess [five][] would be a good -number. - -[five]: https://principiadiscordia.com/book/23.php - ----------------------- - -### Free energy principle - -*[mid/late 2020]* - -Karl Friston wrote: - -> The free-energy principle says that any self-organizing system that -> is at equilibrium with its environment must minimize its free -> energy. - -Or, somewhat paraphrased: - -> Any Markov blanket capable of modeling its environment aims to -> reduce its level of surprise by either adapting its model, or -> through other action. - -Seems reasonable to me. - -### More bizarre universe - -*[many years ago]* - -Douglas Adams wrote: - -> There is a theory which states that if ever anyone discovers exactly -> what the Universe is for and why it is here, it will instantly -> disappear and be replaced by something even more bizarre and -> inexplicable. There is another theory which states that this has -> already happened. - -### Alpha decay - -*[late 2022]* - -Finance people say: - -> Alpha Decay is commonly referred to as the loss of prediction power -> of a trading strategy over time. As a consequence, the profitability -> of a strategy tends to gradually decrease. Given enough time, the -> strategy converges to having no superior predictive power and -> returns when compared to a suitable benchmark. - -A market is a big optimiser. Any successful trading strategy adds -friction in a place that the optimiser wants to remove. - -Alpha decay is unavoidable without changing and adapting the strategy. - -### Optimising universe - -*[late 2022]* - -*(thanks edef for helping me think through this one!)* - -Assume that the universe acts as a giant optimiser, and consider that -the three things above are related and specialisations of more generic -ideas: - -1. Every delineable entity in the universe (i.e. every *Markov - blanket*) attempts to reduce its level of surprise (the free energy - principle). - -2. The universe needs replacement (a more bizarre universe) if global - surprise drops to a minimum[^heat]. - -3. Without improvement that outpaces the optimiser of the universe, - any strategy leading to (2) will get eroded by alpha decay long - before. - -4. We don't know if it is possible to outpace the optimiser from - within. - -On a personal note, it seems to me that achieving (2) is likely -undesirable. It probably takes god[^god] a lot of resources to create -an ever more complex universe and this process might be much less -enjoyable than "running" (for lack of a better word) a universe. Under -this assumption, a universe that achieves (2) faster than others might -be a failure, and on a higher level conditions leading to its creation -might be subject to another optimiser. - -Or it could be the other way around, but this seems more likely to me -personally. - -### Superintelligence - -*[late 2022]* - -Under the previous assumption, achieving superintelligence is likely a -bad idea for anyone feeling some kind of attachment to *this* -universe. - -Or it might be the exact opposite, but I don't think so. - -------------------------------- - -[^heat]: Note that this is consistent with the heat death of the - universe. - -[^god]: I'm using the word "god" as the best English approximation of - a concept that different religions and philosophies all attempt to - approach. I think that for many cognitive purposes, an - anthropomorphised idea (as in the abrahamic religions) is useful, - but ideas from some Eastern religions or modern philosophers like - Bach or Watts are likely more aligned with the "nature of things" - as such. diff --git a/users/tazjin/blog/posts/tvix-eval-talk-2023.md b/users/tazjin/blog/posts/tvix-eval-talk-2023.md deleted file mode 100644 index 4a0ec5688..000000000 --- a/users/tazjin/blog/posts/tvix-eval-talk-2023.md +++ /dev/null @@ -1,19 +0,0 @@ -7 сентября я выступил с докладом про реализацию языка Nix на Rust, на -[Московском Rust-митапе][rustmsk] / [Московском клубе -программистов][progmsk]. - -<iframe width="800" height="500" src="https://www.youtube.com/embed/7zS2_ZhwPfY?start=4013" title="RUST - современный язык программирования" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> - -Вот все связанные с ним ссылки, которые могут быть интересны: - -* [Tvix](https://tvix.dev), главный сайт проекта -* [TVL](https://tvl.fyi), наше онлайн-сообщество -* [Tvixbolt](https://bolt.tvix.dev/), наш "godbolt" для tvix -* [MMTk](https://www.mmtk.io/), Rust-библиотека с компонентами для garbage-collection -* [Интервью / доклад](https://www.youtube.com/live/0Lhahzs-Wos?si=BlFDVBUPsIpHg0p5), Nix -- не только пакетный менеджер -* [NixCon 2023](https://2023.nixcon.org/) -* [Yew](https://yew.rs/), WASM-фреймворк для Rust -* [tazlog](https://t.me/tazlog), мой канал на Телеге - -[rustmsk]: https://t.me/ruRust_msk -[progmsk]: https://prog.msk.ru/ diff --git a/users/tazjin/chase-geese/default.nix b/users/tazjin/chase-geese/default.nix deleted file mode 100644 index 595ca9289..000000000 --- a/users/tazjin/chase-geese/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -# Helpers for mounting GeeseFS into the right place. -{ depot, pkgs, ... }: - -pkgs.writeShellScriptBin "chase-geese" '' - set -ueo pipefail - - echo "Fetching credentials ..." - eval $(pass show keys/tazjin-geesefs) - - echo "Mounting the cloud ..." - mkdir -p ~/cloud - ${pkgs.geesefs}/bin/geesefs tazjins-files ~/cloud -'' diff --git a/users/tazjin/cursed/default.nix b/users/tazjin/cursed/default.nix deleted file mode 100644 index 336a746db..000000000 --- a/users/tazjin/cursed/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.web) bubblegum; -in -(bubblegum.writeCGI - { - name = "cursed"; - } ./responder.nix) // { meta.ci.skip = true; } diff --git a/users/tazjin/cursed/responder.nix b/users/tazjin/cursed/responder.nix deleted file mode 100644 index 9c1e29a20..000000000 --- a/users/tazjin/cursed/responder.nix +++ /dev/null @@ -1,75 +0,0 @@ -{ depot, ... }: - -let - inherit (depot.users.sterni.nix.html) - __findFile - esc - ; - - # CGI envvars: https://www.instanet.com/cgi/env.html - method = builtins.getEnv "REQUEST_METHOD"; - path = builtins.getEnv "PATH_INFO"; - - rawQuery = builtins.getEnv "QUERY_STRING"; - query = with builtins; let - pairs = (filter (s: isString s && s != "") (split "&" rawQuery)); - tuples = filter (l: length l > 0) (map (p: filter (s: isString s) (split "=" p)) pairs); - mkAttr = t: { - name = elemAt t 0; - value = elemAt t 1; - }; - in - listToAttrs (map mkAttr tuples); - - default = let { - hasQuery = if builtins.length (builtins.attrNames query) > 0 then "?" else ""; - body = <html> { lang = "en"; } [ - (<head> { } [ - (<title> { } "some cursed nix") - ]) - (<body> { } [ - (<p> { } "hello volgasprint") - (<p> { } [ method " " path hasQuery rawQuery ]) - (<p> { } (builtins.toJSON query)) - ]) - ]; - }; - - greeter = withDoctype (<html> { lang = "en"; } [ - (<head> { } [ - (<title> { } "hello there") - ]) - (<body> { } [ - (<p> { } "hello ${query.name or "unknown"}") - ]) - ]); - - weather = let { - town = query.town or "Kazan"; - w = builtins.fetchurl "https://wttr.in/${town}?"; - rendered = with depot.third_party.nixpkgs; runCommand "weather-${town}" { } '' - cat ${w} | ${ansi2html}/bin/ansi2html > $out - ''; - - body = builtins.readFile "${rendered}"; - }; - - routes = { - "/other" = (withDoctype (<html> { lang = "en"; } [ - (<head> { } [ - (<title> { } "other endpoint") - ]) - (<body> { } [ - (<p> { } "this is another route") - ]) - ])); - "/greeter" = greeter; - "/weather" = weather; - }."${path}" or default; - -in -depot.web.bubblegum.respond "OK" -{ - "Content-Type" = "text/html"; -} - routes diff --git a/users/tazjin/default.nix b/users/tazjin/default.nix deleted file mode 100644 index 1b68b7127..000000000 --- a/users/tazjin/default.nix +++ /dev/null @@ -1,30 +0,0 @@ -# //users/tazjin-specific CI configuration. -{ depot, pkgs, ... }: - -let - rustfmt = pkgs.writeShellScript "rustfmt-tazjin" '' - ${pkgs.fd}/bin/fd -e rs | \ - ${pkgs.ripgrep}/bin/rg 'users/tazjin' | \ - xargs ${pkgs.rustfmt}/bin/rustfmt --check --config-path users/tazjin - ''; - -in -depot.nix.readTree.drvTargets { - rustfmt = rustfmt.overrideAttrs (_: { - # rustfmt not respecting config atm, disable - meta.ci.skip = true; - - meta.ci.extraSteps.rustfmt = { - command = rustfmt; - }; - }); - - # Use a screen lock command that resets the keyboard layout - # before locking, to avoid locking me out when the layout is - # in Russian. - screenLock = pkgs.writeShellScriptBin "tazjin-screen-lock" '' - ${pkgs.xorg.setxkbmap}/bin/setxkbmap us - ${pkgs.xorg.setxkbmap}/bin/setxkbmap -option caps:super - exec ${pkgs.xsecurelock}/bin/xsecurelock - ''; -} diff --git a/users/tazjin/dns/default.nix b/users/tazjin/dns/default.nix deleted file mode 100644 index 6ff6cc06e..000000000 --- a/users/tazjin/dns/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -# Performs simple (local-only) validity checks on DNS zones. -{ depot, pkgs, ... }: - -let - checkZone = zone: file: pkgs.runCommand "${zone}-check" { } '' - ${pkgs.bind}/bin/named-checkzone -i local ${zone} ${file} | tee $out - ''; - -in -depot.nix.readTree.drvTargets { - kontemplate-works = checkZone "kontemplate.works" ./kontemplate.works.zone; - tazj-in = checkZone "tazj.in" ./tazj.in.zone; -} diff --git a/users/tazjin/dns/import b/users/tazjin/dns/import deleted file mode 100755 index 8ea1d694c..000000000 --- a/users/tazjin/dns/import +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -set -ue - -# Imports a zone file into Google Cloud DNS -readonly ZONE="${1}" -readonly FILE="${2}" - -gcloud dns record-sets import "${FILE}" \ - --project composite-watch-759 \ - --zone-file-format \ - --delete-all-existing \ - --zone "${ZONE}" diff --git a/users/tazjin/dns/kontemplate.works.zone b/users/tazjin/dns/kontemplate.works.zone deleted file mode 100644 index 326a129d2..000000000 --- a/users/tazjin/dns/kontemplate.works.zone +++ /dev/null @@ -1,15 +0,0 @@ -;; -*- mode: zone; -*- -;; Do not delete these -kontemplate.works. 21600 IN NS ns-cloud-d1.googledomains.com. -kontemplate.works. 21600 IN NS ns-cloud-d2.googledomains.com. -kontemplate.works. 21600 IN NS ns-cloud-d3.googledomains.com. -kontemplate.works. 21600 IN NS ns-cloud-d4.googledomains.com. -kontemplate.works. 21600 IN SOA ns-cloud-d1.googledomains.com. cloud-dns-hostmaster.google.com. 4 21600 3600 259200 300 - -;; Github site setup -kontemplate.works. 60 IN A 185.199.108.153 -kontemplate.works. 60 IN A 185.199.109.153 -kontemplate.works. 60 IN A 185.199.110.153 -kontemplate.works. 60 IN A 185.199.111.153 - -www.kontemplate.works. 60 IN CNAME tazjin.github.io. diff --git a/users/tazjin/dns/tazj.in.zone b/users/tazjin/dns/tazj.in.zone deleted file mode 100644 index 43db5834a..000000000 --- a/users/tazjin/dns/tazj.in.zone +++ /dev/null @@ -1,33 +0,0 @@ -;; -*- mode: zone; -*- -;; Do not delete these -tazj.in. 21600 IN NS ns-cloud-a1.googledomains.com. -tazj.in. 21600 IN NS ns-cloud-a2.googledomains.com. -tazj.in. 21600 IN NS ns-cloud-a3.googledomains.com. -tazj.in. 21600 IN NS ns-cloud-a4.googledomains.com. -tazj.in. 21600 IN SOA ns-cloud-a1.googledomains.com. cloud-dns-hostmaster.google.com. 123 21600 3600 1209600 300 - -;; Email setup -tazj.in. 300 IN MX 1 aspmx.l.google.com. -tazj.in. 300 IN MX 5 alt1.aspmx.l.google.com. -tazj.in. 300 IN MX 5 alt2.aspmx.l.google.com. -tazj.in. 300 IN MX 10 alt3.aspmx.l.google.com. -tazj.in. 300 IN MX 10 alt4.aspmx.l.google.com. -tazj.in. 300 IN TXT "v=spf1 include:_spf.google.com ~all" -google._domainkey.tazj.in. 21600 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9AphX/WJf8zVXQB5Jk0Ry1MI6ARa6vEyAoJtpjpt9Nbm7XU4qVWFRJm+L0VFd5EZ5YDPJTIZ90lJE3/B8vae2ipnoGbJbj8LaVSzzIPMbWmhPhX3fkLJFdkv7xRDMDn730iYXRlfkgv6GsqbS8vZt7mzxx4mpnePTI323yjRVkwRW8nGVbsmB25ZoG1/0985" "kg4mSYxzWeJ2ozCPFhT4sfMtZMXe/4QEkJz/zkod29KZfFJmLgEaf73WLdBX8kdwbhuh2PYXt/PwzUrRzF5ujVCsSaTZwdRVPErcf+yo4NvedelTjjs8rFVfoJiaDD1q2bQ3w0gDEBWPdC2VP7k9zwIDAQAB" - -;; Site verifications -tazj.in. 3600 IN TXT "keybase-site-verification=gC4kzEmnLzY7F669PjN-pw2Cf__xHqcxQ08Gb-W9dhE" -tazj.in. 300 IN TXT "google-site-verification=d3_MI1OwD6q2OT42Vvh0I9w2u3Q5KFBu-PieNUE1Fig" -www.tazj.in. 3600 IN TXT "keybase-site-verification=ER8m_byyqAhzeIy9TyzkAU1H2p2yHtpvImuB_XrRF2U" - -;; Blog "storage engine" -blog.tazj.in. 21600 IN NS ns-cloud-c1.googledomains.com. -blog.tazj.in. 21600 IN NS ns-cloud-c2.googledomains.com. -blog.tazj.in. 21600 IN NS ns-cloud-c3.googledomains.com. -blog.tazj.in. 21600 IN NS ns-cloud-c4.googledomains.com. - -;; Webpage records setup -tazj.in. 300 IN A 34.98.120.189 -www.tazj.in. 300 IN A 34.98.120.189 -git.tazj.in. 300 IN A 34.98.120.189 -files.tazj.in. 300 IN CNAME c.storage.googleapis.com. diff --git a/users/tazjin/docs/install-zfs.md b/users/tazjin/docs/install-zfs.md deleted file mode 100644 index 415af30fd..000000000 --- a/users/tazjin/docs/install-zfs.md +++ /dev/null @@ -1,116 +0,0 @@ -Current steps for my NixOS-on-ZFS installs with impermanence. - -## Target layout (example from tverskoy): - -Partitioning: - -``` -nvme0n1 259:0 0 238.5G 0 disk -├─nvme0n1p1 259:1 0 128M 0 part /boot (type: EFI system) -└─nvme0n1p2 259:2 0 238.3G 0 part (type: Solaris root) -``` - -ZFS layout: - -``` -NAME USED AVAIL REFER MOUNTPOINT -zpool 212G 19.0G 248K /zpool -zpool/ephemeral 668M 19.0G 192K /zpool/ephemeral -zpool/ephemeral/home 667M 19.0G 667M legacy -zpool/local 71.3G 19.0G 192K /zpool/local -zpool/local/nix 71.3G 19.0G 71.3G legacy -zpool/safe 140G 19.0G 192K /zpool/safe -zpool/safe/depot 414M 19.0G 414M legacy -zpool/safe/persist 139G 19.0G 139G legacy -``` - -With reset-snapshots: - -``` -NAME USED AVAIL REFER MOUNTPOINT -zpool/ephemeral/home@blank 144K - 192K - -zpool/ephemeral/home@tazjin-clean 144K - 200K - -``` - -Legacy mountpoints are used because the NixOS wiki advises that using -ZFS own mountpoints might lead to issues with the mount order during -boot. - -## Install steps - -1. First, get internet. - -2. Use `fdisk` to set up the partition layout above (fwiw, EFI type - should be `1`, Solaris root should be `66`). - -3. Format the first partition for EFI: `mkfs.fat -F32 -n EFI $part1` - -4. Init ZFS stuff: - - ``` - zpool create \ - # 2 SSD only settings - -o ashift=12 \ - -o autotrim=on \ - -R /mnt \ - -O canmount=off \ - -O mountpoint=none \ - -O acltype=posixacl \ - -O compression=lz4 \ - -O atime=off \ - -O xattr=sa \ - -O encryption=aes-256-gcm \ - -O keylocation=prompt \ - -O keyformat=passphrase \ - zpool $part2 - ``` - - Reserve some space for deletions: - - ``` - zfs create -o refreservation=1G -o mountpoint=none zpool/reserved - ``` - - Create the datasets as per the target layout: - - ``` - # Throwaway datasets - zfs create -o canmount=off -o mountpoint=none zpool/ephemeral - zfs create -o mountpoint=legacy zpool/ephemeral/root - zfs create -o mountpoint=legacy zpool/ephemeral/home - - # Persistent datasets - zfs create -o canmount=off -o mountpoint=none zpool/persistent - zfs create -o mountpoint=legacy zpool/persistent/nix - zfs create -o mountpoint=legacy zpool/persistent/depot - zfs create -o mountpoint=legacy zpool/persistent/data - ``` - - Create completely blank snapshots of the ephemeral datasets: - - ``` - zfs snapshot zpool/ephemeral/root@blank - zfs snapshot zpool/ephemeral/home@blank - ``` - - The ephemeral home volume needs the user folder already set up with - permissions. Mount it and create the folder there: - - ``` - mount -t zfs zpool/ephemeral/root /mnt - mkdir /mnt/home - mount -t zfs zpool/ephemeral/home /mnt/home - mkdir /mnt/home/tazjin - chmod 1000:100 /mnt/home/tazjin - zfs snapshot zpool/ephemeral/home@tazjin-clean - ``` - - Now the persistent Nix store volume can be mounted and installation - can begin. - - ``` - mkdir /mnt/nix - mount -t zfs zpool/persistent/nix /mnt/nix - ``` - -4. Configure & install NixOS as usual. diff --git a/users/tazjin/dotfiles/.skip-subtree b/users/tazjin/dotfiles/.skip-subtree deleted file mode 100644 index 954981f43..000000000 --- a/users/tazjin/dotfiles/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -Stuff below here is managed manually, without readTree. diff --git a/users/tazjin/dotfiles/config.fish b/users/tazjin/dotfiles/config.fish deleted file mode 100644 index de2c99ae6..000000000 --- a/users/tazjin/dotfiles/config.fish +++ /dev/null @@ -1,40 +0,0 @@ -# Configure classic prompt -set fish_color_user --bold blue -set fish_color_cwd --bold white - -# Enable colour hints in VCS prompt: -set __fish_git_prompt_showcolorhints yes -set __fish_git_prompt_color_prefix purple -set __fish_git_prompt_color_suffix purple - -# Fish configuration -set fish_greeting "" -set PATH $HOME/.local/bin $HOME/.cargo/bin $PATH - -# Editor configuration -set -gx EDITOR "emacsclient" -set -gx ALTERNATE_EDITOR "emacs -q -nw" -set -gx VISUAL "emacsclient" - -# Miscellaneous -eval (direnv hook fish) - -# Useful command aliases -alias gpr 'git pull --rebase' -alias gco 'git checkout' -alias gf 'git fetch' -alias gap 'git add -p' -alias pbcopy 'xclip -selection clipboard' -alias edit 'emacsclient -n' -alias servedir 'nix-shell -p haskellPackages.wai-app-static --run warp' - -# Old habits die hard (also ls is just easier to type): -alias ls 'exa' - -# Fix up nix-env & friends for Nix 2.0 -export NIX_REMOTE=daemon - -# Fix display of fish in emacs' term-mode: -function fish_title - true -end diff --git a/users/tazjin/dotfiles/default.nix b/users/tazjin/dotfiles/default.nix deleted file mode 100644 index 6291a1030..000000000 --- a/users/tazjin/dotfiles/default.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ depot, pkgs, ... }@args: - -rec { - dunstrc = ./dunstrc; - niri = ./niri.config.kdl; - fuzzel = ./fuzzel.ini; - waybar = { - config = import ./waybar/config.nix args; - style = pkgs.runCommandNoCC "waybar-style.css" - { - CHICAGO95 = depot.third_party.chicago95; - } '' - cat ${./waybar/style.css} | ${pkgs.envsubst}/bin/envsubst > $out - ''; - }; - - # Helper derivation for iterating on waybar config. - waybarTest = pkgs.runCommandNoCC "waybar-conf" { } '' - mkdir -p $out - cat ${pkgs.writeText "waybar-conf.json" (builtins.toJSON(builtins.attrValues waybar.config))} > $out/config - cp ${waybar.style} $out/style.css - ''; -} diff --git a/users/tazjin/dotfiles/dunstrc b/users/tazjin/dotfiles/dunstrc deleted file mode 100644 index d984ff94e..000000000 --- a/users/tazjin/dotfiles/dunstrc +++ /dev/null @@ -1,15 +0,0 @@ -[global] -origin = bottom-right -offset = 5x5 # takes into account menu bar! -corner_radius = 5 -frame_width = 1 -frame_color = "#000000" -foreground = "#000000" -background = "#ffffe1" -font = Arial 12 -follow = keyboard -vertical_alignment = top -format = "<b>%s</b>\n<i>from %a</i>\n\n%b" -icon_theme = "Chicago95-tux" -enable_recursive_icon_lookup = true -icon_position = left diff --git a/users/tazjin/dotfiles/fuzzel.ini b/users/tazjin/dotfiles/fuzzel.ini deleted file mode 100644 index 92d46c0b6..000000000 --- a/users/tazjin/dotfiles/fuzzel.ini +++ /dev/null @@ -1,17 +0,0 @@ -[main] -font=Arial - -[colors] -background=c0c0c0ff -text=000000ff -input=000000ff -prompt=000000ff -match=808080ff -selection=000080ff -selection-match=ffffffff -selection-text=ffffffff -border=080808ff - -[border] -width=2 -radius=5 diff --git a/users/tazjin/dotfiles/msmtprc b/users/tazjin/dotfiles/msmtprc deleted file mode 100644 index 2af3b9433..000000000 --- a/users/tazjin/dotfiles/msmtprc +++ /dev/null @@ -1,15 +0,0 @@ -defaults -port 587 -tls on -tls_trust_file /etc/ssl/certs/ca-certificates.crt - -# GSuite for tazj.in -account tazjin -host smtp.gmail.com -port 587 -from mail@tazj.in -auth oauthbearer -user mail@tazj.in -passwordeval "cat ~/mail/account.tazjin/.credentials.gmailieer.json | jq -r '.access_token'" - -account default : tazjin diff --git a/users/tazjin/dotfiles/niri.config.kdl b/users/tazjin/dotfiles/niri.config.kdl deleted file mode 100644 index bfb810f10..000000000 --- a/users/tazjin/dotfiles/niri.config.kdl +++ /dev/null @@ -1,141 +0,0 @@ -// https://github.com/YaLTeR/niri/wiki/Configuration:-Overview - -input { - keyboard { - xkb { - layout "us,ru" - options "grp:win_space_toggle,compose:ralt,caps:super" - } - } - - touchpad { - tap - } - - trackball { - left-handed - } -} - -layout { - gaps 12 - center-focused-column "never" - - preset-column-widths { - proportion 0.33333 - proportion 0.5 - proportion 0.66667 - } - - default-column-width {} - - focus-ring { - off - } - - border { - off - } -} - -spawn-at-startup "xwayland-satellite" -spawn-at-startup "xrandr --output eDP-1 --primary" -spawn-at-startup "wpaperd" "-d" -spawn-at-startup "systemctl --user start xss-lock" - -environment { - QT_QPA_PLATFORM "wayland" - DISPLAY ":0" - EDITOR "emacsclient" -} - -hotkey-overlay { - skip-at-startup -} - -screenshot-path "~/screenshots/screenshot-%Y-%m-%d_%H-%M-%S.png" - -animations { - slowdown 0.3 -} - -binds { - Mod+Shift+Slash { show-hotkey-overlay; } - - Mod+T { spawn "emacsclient" "--no-wait" "--create-frame" "--eval" "(vterm)"; } - Mod+Shift+T { spawn "alacritty"; } // fallback terminal - Mod+D { spawn "xfce4-appfinder" "--disable-server"; } - Super+Alt+L { spawn "swaylock" "-fFkl" "-c" "#008080"; } - Super+B { spawn "emacsclient" "-e" "(niri-go-anywhere-external)"; } - - // Volume control - XF86AudioRaiseVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1+"; } - XF86AudioLowerVolume allow-when-locked=true { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.1-"; } - XF86AudioMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; } - XF86AudioMicMute allow-when-locked=true { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SOURCE@" "toggle"; } - - // Brightness control - XF86MonBrightnessUp allow-when-locked=true { spawn "light" "-A" "5"; } - Shift+XF86MonBrightnessUp allow-when-locked=true { spawn "light" "-A" "1"; } - XF86MonBrightnessDown allow-when-locked=true { spawn "light" "-U" "5"; } - Shift+XF86MonBrightnessDown allow-when-locked=true { spawn "light" "-U" "1"; } - - Mod+Q { close-window; } - - Mod+Left { focus-column-or-monitor-left; } - Mod+Right { focus-column-or-monitor-right; } - Mod+Down { focus-column-or-monitor-right; } - Mod+Up { focus-column-or-monitor-left; } - Mod+J { focus-column-or-monitor-left; } - Mod+K { focus-column-or-monitor-right; } - Mod+L { focus-window-up; } - Mod+Semicolon { focus-window-down; } - - Mod+Ctrl+Left { move-column-left-or-to-monitor-left; } - Mod+Ctrl+Right { move-column-right-or-to-monitor-right; } - Mod+Ctrl+J { move-column-left-or-to-monitor-left; } - Mod+Ctrl+K { move-column-right-or-to-monitor-right; } - - Mod+Home { focus-column-first; } - Mod+End { focus-column-last; } - - Mod+Ctrl+Home { move-column-to-first; } - Mod+Ctrl+End { move-column-to-last; } - - // Scroll (or move windows) between columns when holding the modifier down. - Mod+WheelScrollDown cooldown-ms=150 { focus-column-or-monitor-right; } - Mod+WheelScrollUp cooldown-ms=150 { focus-column-or-monitor-left; } - Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-right-or-to-monitor-right; } - Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-left-or-to-monitor-left; } - - Mod+Comma { consume-window-into-column; } - Mod+Period { expel-window-from-column; } - - // There are also commands that consume or expel a single window to the side. - // Mod+BracketLeft { consume-or-expel-window-left; } - // Mod+BracketRight { consume-or-expel-window-right; } - - Mod+R { switch-preset-column-width; } - Mod+Shift+R { reset-window-height; } - Mod+F { maximize-column; } - Mod+Shift+F { fullscreen-window; } - Mod+C { center-column; } - - Mod+Minus { set-column-width "-10%"; } - Mod+Equal { set-column-width "+10%"; } - - // Finer height adjustments when in column with other windows. - Mod+Shift+Minus { set-window-height "-2%"; } - Mod+Shift+Equal { set-window-height "+2%"; } - - Print { screenshot; } - Ctrl+Print { screenshot-screen; } - Alt+Print { screenshot-window; } - - Mod+Shift+E { quit; } -} - -// tverskoy screen fix -output "AU Optronics 0x5A2D Unknown" { - scale 1.0 -} diff --git a/users/tazjin/dotfiles/notmuch-config b/users/tazjin/dotfiles/notmuch-config deleted file mode 100644 index a490774e6..000000000 --- a/users/tazjin/dotfiles/notmuch-config +++ /dev/null @@ -1,21 +0,0 @@ -# .notmuch-config - Configuration file for the notmuch mail system -# -# For more information about notmuch, see https://notmuchmail.org - -[database] -path=/home/vincent/mail - -[user] -name=Vincent Ambo -primary_email=mail@tazj.in -other_email=tazjin@gmail.com; - -[new] -tags=unread;inbox; -ignore= - -[search] -exclude_tags=deleted;spam;draft; - -[maildir] -synchronize_flags=true diff --git a/users/tazjin/dotfiles/waybar/config.nix b/users/tazjin/dotfiles/waybar/config.nix deleted file mode 100644 index ba5281f02..000000000 --- a/users/tazjin/dotfiles/waybar/config.nix +++ /dev/null @@ -1,64 +0,0 @@ -{ depot, pkgs, ... }: - -let - launcher = "${pkgs.xfce4-appfinder}/bin/xfce4-appfinder --disable-server"; -in -{ - mainBar = { - layer = "top"; - position = "bottom"; - modules-left = [ "custom/start" "wlr/taskbar" ]; - - "custom/start" = { - format = " Start"; - on-click = "xfce4-appfinder --disable-server"; - }; - - modules-right = [ "tray" "backlight" "battery" "pulseaudio" "clock" ]; - - pulseaudio = { - on-click = "pavucontrol"; - format = " "; #styling only - states = { - low = 1; - medium = 40; - high = 75; - }; - }; - - battery = { - format = " "; # styling only - interval = 10; - states = { - full = 100; - good = 85; - medium = 60; - low = 40; - warning = 20; - critical = 10; - }; - }; - - backlight = { - format = "{percent}%"; # styling only - on-scroll-up = "light -A 1"; - on-scroll-down = "light -U 1"; - }; - - clock.format-alt = "{:%a, %d. %b %H:%M}"; - - tray = { - icon-size = 20; - spacing = 10; - }; - - "wlr/taskbar" = { - format = "{icon} {title}"; - on-click = "activate"; - rewrite = { - # Truncate any format over 16 characters. - "^(.{16}).+$" = "$1…"; - }; - }; - }; -} diff --git a/users/tazjin/dotfiles/waybar/style.css b/users/tazjin/dotfiles/waybar/style.css deleted file mode 100644 index 52f5759cc..000000000 --- a/users/tazjin/dotfiles/waybar/style.css +++ /dev/null @@ -1,254 +0,0 @@ -* { - /* `otf-font-awesome` is required to be installed for icons */ - font-family: FontAwesome, MS Sans Serif; - font-size: 14px; -} - -window#waybar { - background-color: #c0c0c0; - border-top: 0.1875em solid #dfdfdf; - color: #000000; - transition-property: background-color; - transition-duration: .5s; -} - -window#waybar.hidden { - opacity: 0.2; -} - -window#waybar.termite { - background-color: #3F3F3F; -} - -window#waybar.chromium { - background-color: #000000; - border: none; -} - -button { - /* Use box-shadow instead of border so the text isn't offset */ - box-shadow: inset 0 -0.1875em transparent; - /* Avoid rounded borders under each button name */ - border: none; - border-radius: 0; -} - -/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ -button:hover { - background: inherit; - box-shadow: inset 0 -0.1875em #ffffff; -} - -#mode { - background-color: #64727D; - box-shadow: inset 0 -0.1875em #ffffff; -} - -#clock, -#battery, -#cpu, -#memory, -#disk, -#temperature, -#backlight, -#network, -#pulseaudio, -#wireplumber, -#custom-media, -#tray, -#mode, -#idle_inhibitor, -#scratchpad, -#power-profiles-daemon, -#mpd { - padding: 0 0.3125em; - padding-top: 0em; - padding-bottom: 0em; - /* color: #ffffff; */ -} - -#window, -#workspaces { - margin: 0 0.25em; -} - -/* faithful-ish recreation of the old Windows start button ... */ -#custom-start { - /* general positioning to keep the spacing approximately correct */ - color: @button_text_color; - font-weight: bold; - margin: 0.2em; - margin-top: 0.35em; - padding: 0.2em; - padding-left: 1.25em; - - /* raised button look, as per the Chicago95 GTK button style */ - border: 0.1em solid; - border-radius: 0em; - color: @button_text_color; - outline-color: @outline_color; - border-top-color: @border_bright; - border-right-color: @border_dark; - border-left-color: @border_bright; - border-bottom-color: @border_dark; - background-color: @button_bg_color; - box-shadow: inset -0.1em -0.1em @border_shade, inset 0.1em 0.1em @border_light; - - /* the actual image! */ - background-image: url("${CHICAGO95}/share/icons/Chicago95/categories/scalable/xfdesktop-menu.svg"); - background-position: 0.15em center; - background-repeat: no-repeat; - background-size: 1.4em; -} - -.modules-right { - margin: 0.2em; - margin-top: 0.35em; -} - -#clock { - border-top: 0.1em solid gray; - border-left: 0.1em solid gray; - border-right: 0.1em solid white; - border-bottom: 0.1em solid white; -} - -/* base setup for classes that have a Chicago95 icon as the display */ -#battery, #pulseaudio, #backlight { - background-position: center; - background-repeat: no-repeat; - background-size: 24px; - min-width: 24px; - color: transparent; /* because the tooltips are still desirable */ -} - -#backlight { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/32/xfpm-brightness-lcd.png"); - font-size: 0px; -} - -/* battery levels matching Chicago95 icons */ - -#battery.charging.critical { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-000-charging.png"); -} - -#battery.charging.warning { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-020-charging.png"); -} - -#battery.charging.low { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-040-charging.png"); -} - -#battery.charging.medium { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-060-charging.png"); -} - -#battery.charging.good { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-080-charging.png"); -} - -#battery.charging.full { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-100-charging.png"); -} - -#battery.critical { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-000.png"); -} - -#battery.warning { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-020.png"); -} - -#battery.low { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-040.png"); -} - -#battery.medium { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-060.png"); -} - -#battery.good { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-080.png"); -} - -#battery.full { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/48/battery-100.png"); -} - -/* volume levels matching Chicago95 icons */ - -#pulseaudio.muted { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/32/audio-volume-muted.png"); -} - -#pulseaudio.low { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/32/audio-volume-low.png"); -} - -#pulseaudio.medium { - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/32/audio-volume-medium.png"); -} - -#pulseaudio { /* default, if no lower volume state is set */ - background-image: url("${CHICAGO95}/share/icons/Chicago95/status/32/audio-volume-high.png"); -} - -@keyframes blink { - to { - background-color: #ffffff; - color: #000000; - } -} - -label:focus { - background-color: #000000; -} - -#tray > .passive { - -gtk-icon-effect: dim; -} - -#tray > .needs-attention { - -gtk-icon-effect: highlight; - background-color: #e35f5f; -} - -#idle_inhibitor { - background-color: #2d3436; -} - -#idle_inhibitor.activated { - background-color: #ecf0f1; - color: #2d3436; -} - -#taskbar { - color: @button_text_color; - margin: 0.2em; - margin-top: 0.35em; -} - -#taskbar button { - padding: 0.2em; - margin-right: 0.3em; - border: 0.1em solid; - border-radius: 0em; - color: @button_text_color; - outline-color: @outline_color; - border-top-color: @border_bright; - border-right-color: @border_dark; - border-left-color: @border_bright; - border-bottom-color: @border_dark; - background-color: @button_bg_color; - box-shadow: inset -0.1em -0.1em @border_shade, inset 0.1em 0.1em @border_light; -} - -#taskbar button.active { - border-top-color: @border_dark; - border-right-color: @border_bright; - border-left-color: @border_dark; - border-bottom-color: @border_bright; - box-shadow: inset 1px 1px @border_shade; -} diff --git a/users/tazjin/eaglemode/default.nix b/users/tazjin/eaglemode/default.nix deleted file mode 100644 index 9f59695a4..000000000 --- a/users/tazjin/eaglemode/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -# Derivation for my fully configured Eagle Mode. -{ depot, ... }: - -with depot.tools.eaglemode; - -withConfig { - config = etcDir { - extraPaths = [ - commands.emacsclient - plugins.example - plugins.yatracker - plugins.qoi - plugins.avif - ]; - }; -} diff --git a/users/tazjin/elisp-deps/deps.el b/users/tazjin/elisp-deps/deps.el deleted file mode 100644 index 954d71cfb..000000000 --- a/users/tazjin/elisp-deps/deps.el +++ /dev/null @@ -1,83 +0,0 @@ -;; Visualise the internal structure of an Emacs Lisp file using -;; Graphviz. -;; -;; Entry point is the function `edeps-analyse-file'. - -(require 'map) - -(defun edeps-read-defs (file-name) - "Stupidly read all definitions from an Emacs Lisp file. This only -considers top-level forms, where the first element of the form is -a symbol whose name contains the string `def', and where the -second element is a symbol. - -Returns a hashmap of all these symbols with the remaining forms -in their bodies." - - (with-temp-buffer - (insert-file-contents file-name) - (goto-char (point-min)) - - (let ((symbols (make-hash-table))) - (condition-case _err - (while t - (let ((form (read (current-buffer)))) - (when (and (listp form) - (symbolp (car form)) - (string-match "def" (symbol-name (car form))) - (symbolp (cadr form))) - (when (and (map-contains-key symbols (cadr form)) - ;; generic methods have multiple definitions - (not (eq (car form) 'cl-defmethod))) - (error "Duplicate symbol: %s" (symbol-name (cadr form)))) - - (map-put! symbols (cadr form) - (cons (car form) (cddr form)))))) - (end-of-file symbols))))) - -(defun edeps-analyse-structure (symbols) - "Analyse the internal structure of the symbols found by -edeps-read-defs, and return a hashmap with the results of the -analysis. The hashmap uses the symbols as keys, " - (let ((deps (make-hash-table))) - (map-do - (lambda (sym val) - (dolist (expr (flatten-list (cdr val))) - (when (map-contains-key symbols expr) - (map-put! deps expr (cons sym (ht-get deps expr)))))) - symbols) - deps)) - -(defun edeps-graph-deps (symbols deps) - (with-temp-buffer - (insert "digraph edeps {\n") - - ;; List all symbols first - (insert " subgraph {\n") - (map-do - (lambda (sym val) - (insert " " (format "\"%s\" [label=\"%s\\n(%s)\"];\n" sym sym (car val)))) - symbols) - (insert " }\n\n") - - ;; Then drop all the edges in there .. - (insert " subgraph {\n") - (map-do - (lambda (sym deps) - (dolist (dep deps) - (insert " " (format "\"%s\" -> \"%s\";\n" dep sym)))) - deps) - (insert " }\n") - - (insert "}\n") - (buffer-string))) - -(defun edeps-analyse-file (infile outfile) - "Produces a dot-graph in OUTFILE from an internal structural -analysis of INFILE. This can be graphed using the graphviz -package." - (let* ((symbols (edeps-read-defs infile)) - (deps (edeps-analyse-structure symbols))) - (with-temp-buffer - (insert (edeps-graph-deps symbols deps)) - (write-file outfile)))) diff --git a/users/tazjin/emacs/.gitignore b/users/tazjin/emacs/.gitignore deleted file mode 100644 index 7b666905f..000000000 --- a/users/tazjin/emacs/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -.smex-items -*token* -auto-save-list/ -clones/ -elpa/ -irc.el -local.el -other/ -scripts/ -themes/ -*.elc diff --git a/users/tazjin/emacs/README.md b/users/tazjin/emacs/README.md deleted file mode 100644 index 5c6673339..000000000 --- a/users/tazjin/emacs/README.md +++ /dev/null @@ -1,7 +0,0 @@ -tools/emacs -=========== - -This sub-folder builds my Emacs configuration, supplying packages from -Nix and configuration from this folder. - -I use Emacs for many things (including as my desktop environment). diff --git a/users/tazjin/emacs/config/bindings.el b/users/tazjin/emacs/config/bindings.el deleted file mode 100644 index d8b63e33e..000000000 --- a/users/tazjin/emacs/config/bindings.el +++ /dev/null @@ -1,104 +0,0 @@ -;; Switch buffers reliably in the face of spurious renames. -(global-set-key (kbd "C-x b") #'reliably-switch-buffer) - -;; Font size -(define-key global-map (kbd "C-=") 'increase-default-text-scale) ;; '=' because there lies '+' -(define-key global-map (kbd "C--") 'decrease-default-text-scale) -(define-key global-map (kbd "C-x C-0") 'set-default-text-scale) - -;; imenu instead of insert-file -(global-set-key (kbd "C-x i") 'imenu) - -;; Window switching. (C-x o goes to the next window) -(windmove-default-keybindings) ;; Shift+direction - -;; Start eshell or switch to it if it's active. -(global-set-key (kbd "C-x m") 'eshell) - -(global-set-key (kbd "M-g M-g") 'goto-line-with-feedback) - -;; Miscellaneous editing commands -(global-set-key (kbd "C-c w") 'whitespace-cleanup) -(global-set-key (kbd "C-c a") 'align-regexp) -(global-set-key (kbd "C-c m") 'mc/mark-dwim) - -;; Browse URLs (very useful for Gerrit's push output, etc!) -(global-set-key (kbd "C-c b p") 'browse-url-at-point) -(global-set-key (kbd "C-c b b") 'browse-url) - -;; C-x REALLY QUIT (idea by @magnars) -(global-set-key (kbd "C-x r q") 'save-buffers-kill-terminal) -(global-set-key (kbd "C-x C-c") 'ignore) - -;; Open a file in project: -(global-set-key (kbd "C-c f") 'project-find-file) - -;; Open a file via magit: -(global-set-key (kbd "C-c C-f") #'magit-find-file-worktree) - -;; Insert TODO comments -(global-set-key (kbd "C-c t") 'insert-todo-comment) - -;; Open the depot -(global-set-key (kbd "s-s d") #'tvl-depot-status) - -;; Open any project through zoxide -(global-set-key (kbd "s-s r") #'zoxide-open-project) - -;; Add subthread collapsing to notmuch-show. -;; -;; C-, closes a thread, C-. opens a thread. This mirrors stepping -;; in/out of definitions. -(define-key notmuch-show-mode-map (kbd "C-,") 'notmuch-show-open-or-close-subthread) -(define-key notmuch-show-mode-map (kbd "C-.") - (lambda () - (interactive) - (notmuch-show-open-or-close-subthread t))) ;; open - -;; Get rid of the annoying `save-some-buffers' shortcut which I -;; *NEVER* use intentionally. -(unbind-key (kbd "C-x s") 'global-map) - -;; German keyboard layout with Y and Z in the correct place. - -(quail-define-package - "german-qwerty" "German" "DE@" t - "German (Deutsch) input method with QWERTY keys" - nil t t t t nil nil nil nil nil t) - -;; 1! 2" 3§ 4$ 5% 6& 7/ 8( 9) 0= ß? [{ ]} -;; qQ wW eE rR tT yY uU iI oO pP üÜ +* -;; aA sS dD fF gG hH jJ kK lL öÖ äÄ #^ -;; zZ xX cC vV bB nN mM ,; .: -_ - -(quail-define-rules - ("-" ?ß) - ("=" ?\[) - ("`" ?\]) - ("[" ?ü) - ("]" ?+) - (";" ?ö) - ("'" ?ä) - ("\\" ?#) - ("/" ?-) - - ("@" ?\") - ("#" ?§) - ("^" ?&) - ("&" ?/) - ("*" ?\() - ("(" ?\)) - (")" ?=) - ("_" ??) - ("+" ?{) - ("~" ?}) - ("{" ?Ü) - ("}" ?*) - (":" ?Ö) - ("\"" ?Ä) - ("|" ?^) - ("<" ?\;) - (">" ?:) - ("?" ?_)) - -(provide 'bindings) diff --git a/users/tazjin/emacs/config/custom.el b/users/tazjin/emacs/config/custom.el deleted file mode 100644 index 3e9a9dcd0..000000000 --- a/users/tazjin/emacs/config/custom.el +++ /dev/null @@ -1,25 +0,0 @@ -(custom-set-variables - ;; custom-set-variables was added by Custom. - ;; If you edit it by hand, you could mess it up, so be careful. - ;; Your init file should contain only one such instance. - ;; If there is more than one, they won't work right. - '(ac-auto-show-menu 0.8) - '(ac-delay 0.2) - '(avy-background t) - '(cargo-process--enable-rust-backtrace 1) - '(custom-safe-themes - (quote - ("d61fc0e6409f0c2a22e97162d7d151dee9e192a90fa623f8d6a071dbf49229c6" "3c83b3676d796422704082049fc38b6966bcad960f896669dfc21a7a37a748fa" "89336ca71dae5068c165d932418a368a394848c3b8881b2f96807405d8c6b5b6" default))) - '(display-time-default-load-average nil) - '(display-time-interval 30) - '(elnode-send-file-program "/run/current-system/sw/bin/cat") - '(frame-brackground-mode (quote dark)) - '(global-auto-complete-mode t) - '(kubernetes-commands-display-buffer-function (quote display-buffer)) - '(lsp-gopls-server-path "/home/tazjin/go/bin/gopls") - '(magit-log-show-gpg-status t) - '(ns-alternate-modifier (quote none)) - '(ns-command-modifier (quote control)) - '(ns-right-command-modifier (quote meta)) - '(require-final-newline (quote visit-save)) - '(tls-program (quote ("gnutls-cli --x509cafile %t -p %p %h")))) diff --git a/users/tazjin/emacs/config/desktop.el b/users/tazjin/emacs/config/desktop.el deleted file mode 100644 index aa232fec2..000000000 --- a/users/tazjin/emacs/config/desktop.el +++ /dev/null @@ -1,333 +0,0 @@ -;; -*- lexical-binding: t; -*- -;; -;; Configure desktop environment settings, including both -;; window-management (EXWM) as well as additional system-wide -;; commands. - -(require 'exwm) -(require 'exwm-config) -(require 'exwm-randr) -(require 'exwm-systemtray) -(require 'exwm-xim ) -(require 'f) -(require 'ring) -(require 's) -(require 'seq) - -(defcustom tazjin--screen-lock-command "tazjin-screen-lock" - "Command to execute for locking the screen." - :group 'tazjin) - -(defcustom tazjin--backlight-increase-command "light -A 4" - "Command to increase screen brightness." - :group 'tazjin) - -(defcustom tazjin--backlight-decrease-command "light -U 4" - "Command to decrease screen brightness." - :group 'tazjin) - -(defun pactl (cmd) - (shell-command (concat "pactl " cmd)) - (message "Volume command: %s" cmd)) - -(defun volume-mute () (interactive) (pactl "set-sink-mute @DEFAULT_SINK@ toggle")) -(defun volume-up () (interactive) (pactl "set-sink-volume @DEFAULT_SINK@ +5%")) -(defun volume-down () (interactive) (pactl "set-sink-volume @DEFAULT_SINK@ -5%")) - -(defun brightness-up () - (interactive) - (shell-command tazjin--backlight-increase-command) - (message "Brightness increased")) - -(defun brightness-down () - (interactive) - (shell-command tazjin--backlight-decrease-command) - (message "Brightness decreased")) - -(defun set-xkb-layout (layout) - "Set the current X keyboard layout." - - (shell-command (format "setxkbmap %s" layout)) - (shell-command "setxkbmap -option caps:super") - (message "Set X11 keyboard layout to '%s'" layout)) - -(defun lock-screen () - (interactive) - (set-xkb-layout "us") - (deactivate-input-method) - (shell-command tazjin--screen-lock-command)) - -(defun create-window-name () - "Construct window names to be used for EXWM buffers by - inspecting the window's X11 class and title. - - A lot of commonly used applications either create titles that - are too long by default, or in the case of web - applications (such as Cider) end up being constructed in - awkward ways. - - To avoid this issue, some rewrite rules are applied for more - human-accessible titles." - - (pcase (list (or exwm-class-name "unknown") (or exwm-title "unknown")) - ;; Yandex.Music -> `Я.Music<... stuff ...>' - (`("Chromium-browser" ,(and (pred (lambda (title) (s-starts-with? "Yandex.Music - " title))) title)) - (format "Я.Music<%s>" (s-chop-prefix "Yandex.Music - " title))) - - ;; For other Chromium windows, make the title shorter. - (`("Chromium-browser" ,title) - (format "Chromium<%s>" (s-truncate 42 (s-chop-suffix " - Chromium" title)))) - - ;; similarly for Firefox - (`("firefox" ,title) - (format "FF<%s>" title)) - - ;; Quassel buffers - ;; - ;; These have a title format that looks like: - ;; "Quassel IRC - #tvl (hackint) — Quassel IRC" - (`("quassel" ,title) - (progn - (if (string-match - (rx "Quassel IRC - " - (group (one-or-more (any alnum "[" "]" "&" "-" "#"))) ;; <-- channel name - " (" (group (one-or-more (any ascii space))) ")" ;; <-- network name - " — Quassel IRC") - title) - (format "Quassel<%s>" (match-string 2 title)) - title))) - - ;; For any other application, a name is constructed from the - ;; window's class and name. - (`(,class ,title) (format "%s<%s>" class (s-truncate 12 title))))) - -;; EXWM launch configuration - -(let ((titlef (lambda () - (exwm-workspace-rename-buffer (create-window-name))))) - (add-hook 'exwm-update-class-hook titlef) - (add-hook 'exwm-update-title-hook titlef)) - -(fringe-mode 3) - -;; tab-bar related config -(setq tab-bar-show 1) -(setq tab-bar-tab-hints t) - -(setq tab-bar-format - '(tab-bar-format-history - tab-bar-format-tabs tab-bar-separator - tab-bar-format-align-right tab-bar-format-global)) - -(setq tab-bar-new-tab-choice - (lambda () (get-buffer-create "*scratch*"))) - -(tab-bar-mode 1) - -(setq x-no-window-manager t) ;; TODO(tazjin): figure out when to remove this -(exwm-enable) -(exwm-randr-enable) - -;; Tab-management shortcuts - -(defun tab-bar-select-or-return () - "This function behaves like `tab-bar-select-tab', except it calls -`tab-recent' if asked to jump to the current tab. This simulates -the back&forth behaviour of i3." - (interactive) - (let* ((key (event-basic-type last-command-event)) - (tab (if (and (characterp key) (>= key ?1) (<= key ?9)) - (- key ?0) - 0)) - (current (1+ (tab-bar--current-tab-index)))) - (if (eq tab current) - (tab-recent) - (tab-bar-select-tab tab)))) - -(dotimes (i 8) - (exwm-input-set-key (kbd (format "s-%d" (+ 1 i))) #'tab-bar-select-or-return)) - -(exwm-input-set-key (kbd "s-9") #'tab-last) -(exwm-input-set-key (kbd "s-f") #'tab-next) -(exwm-input-set-key (kbd "s-b") #'tab-recent) -(exwm-input-set-key (kbd "s-w") #'tab-close) -(exwm-input-set-key (kbd "s-n") #'tab-new) - -;; Launch applications / any command with completion (dmenu style!) -(exwm-input-set-key (kbd "s-d") #'run-xdg-app) -(exwm-input-set-key (kbd "s-x") #'run-external-command) -(exwm-input-set-key (kbd "s-p") #'password-store-lookup) - -;; Add vterm selector to a key -(exwm-input-set-key (kbd "s-v") #'ts/switch-to-terminal) - -;; Toggle between line-mode / char-mode -(exwm-input-set-key (kbd "C-c C-t C-t") #'exwm-input-toggle-keyboard) - -;; Volume keys -(exwm-input-set-key (kbd "<XF86AudioMute>") #'volume-mute) -(exwm-input-set-key (kbd "<XF86AudioRaiseVolume>") #'volume-up) -(exwm-input-set-key (kbd "<XF86AudioLowerVolume>") #'volume-down) - -;; Brightness keys -(exwm-input-set-key (kbd "<XF86MonBrightnessDown>") #'brightness-down) -(exwm-input-set-key (kbd "<XF86MonBrightnessUp>") #'brightness-up) -(exwm-input-set-key (kbd "<XF86Display>") #'lock-screen) - -;; Shortcuts for switching between keyboard layouts -(defmacro bind-xkb (lang key) - `(exwm-input-set-key (kbd (format "s-%s" ,key)) - (lambda () - (interactive) - (set-xkb-layout ,lang)))) - -(bind-xkb "us" "k u") -(bind-xkb "de" "k d") -(bind-xkb "no" "k n") -(bind-xkb "ru" "k r") -(bind-xkb "se" "k s") -(bind-xkb "us" "л г") -(bind-xkb "de" "л в") -(bind-xkb "no" "л т") -(bind-xkb "ru" "л к") - -;; Configuration of EXWM input method handling for X applications -(exwm-xim-enable) -(setq default-input-method "russian-computer") -(push ?\C-\\ exwm-input-prefix-keys) - -;; Line-editing shortcuts -(exwm-input-set-simulation-key (kbd "C-d") (kbd "DEL")) -(exwm-input-set-simulation-key (kbd "C-w") (kbd "C-c")) - -;; Show time & battery status in the mode line -(display-time-mode) -(display-battery-mode) - -;; enable display of X11 system tray within Emacs -(exwm-systemtray-enable) - -;; Multi-monitor configuration. -;; -;; With tab-bar-mode, each monitor only displays at most one -;; workspace. Workspaces are only created, never deleted, meaning that -;; the number of workspaces will be equivalent to the maximum number -;; of displays that were connected during a session. -;; -;; The first workspace is special: It is kept on the primary monitor. - -(defun exwm-assign-workspaces () - "Assigns workspaces to the currently existing monitors, putting -the first one on the primary display and allocating the others -dynamically if needed in no particular order." - (interactive) - (let* ((randr-monitors (exwm-randr--get-monitors)) - (primary (car randr-monitors)) - (all-monitors (seq-map #'car (cadr randr-monitors))) - (sorted-primary-first (seq-sort (lambda (a b) - (or (equal a primary) - (< a b))) - all-monitors)) - ;; assign workspace numbers to each monitor ... - (workspace-assignments - (flatten-list (seq-map-indexed (lambda (monitor idx) - (list idx monitor)) - sorted-primary-first)))) - ;; ensure that the required workspaces exist - (exwm-workspace-switch-create (- (seq-length all-monitors) 1)) - - ;; update randr config - (setq exwm-randr-workspace-monitor-plist workspace-assignments) - (exwm-randr-refresh) - - ;; leave focus on primary workspace - (exwm-workspace-switch 0))) - -(defun list-available-monitors () - "List connected, but unused monitors." - (let* ((all-connected - (seq-map (lambda (line) (car (s-split " " line))) - (s-lines (s-trim (shell-command-to-string "xrandr | grep connected | grep -v disconnected"))))) - (all-active (seq-map #'car (cadr (exwm-randr--get-monitors))))) - (seq-filter (lambda (s) (not (seq-contains-p all-active s))) - all-connected))) - -(defun exwm-enable-monitor () - "Interactively construct an EXWM invocation that enable the -given monitor and assigns a workspace to it." - (interactive) - - (let* ((monitors (list-available-monitors)) - (primary (car (exwm-randr--get-monitors))) - (monitor (pcase (seq-length monitors) - (0 (error "No available monitors.")) - (1 (car monitors)) - (_ - (completing-read "Which monitor? " (list-available-monitors) nil t)))) - - (configurations `(("secondary (left)" . ,(format "--left-of %s" primary)) - ("secondary (right)" . ,(format "--right-of %s" primary)) - ("primary (left)" . ,(format "--left-of %s --primary" primary)) - ("primary (right)" . ,(format "--right-of %s --primary" primary)) - ("mirror" . ,(format "--same-as %s" primary)))) - - (where (completing-read (format "%s should be " monitor) - (seq-map #'car configurations) - nil t)) - (xrandr-pos (cdr (assoc where configurations))) - (xrandr-cmd (format "xrandr --output %s --auto %s" monitor xrandr-pos))) - (message "Invoking '%s'" xrandr-cmd) - (shell-command xrandr-cmd) - (exwm-assign-workspaces))) - -(defun exwm-disable-monitor () - "Interactively choose a monitor to disable." - (interactive) - - (let* ((all (exwm-randr--get-monitors)) - (active (seq-map #'car (cadr all))) - (monitor (if (> (seq-length active) 1) - (completing-read "Disable which monitor? " active nil t) - (error "Only one monitor is active!"))) - - ;; If this monitor was primary, pick another active one instead. - (remaining (seq-filter (lambda (s) (not (equal s monitor))) active)) - (new-primary - (when (equal monitor (car all)) - (pcase (seq-length remaining) - (1 (car remaining)) - (_ (completing-read "New primary? " remaining nil t)))))) - - (when new-primary - (shell-command (format "xrandr --output %s --primary" new-primary))) - - (shell-command (format "xrandr --output %s --off" monitor)) - (exwm-assign-workspaces))) - -(defun exwm-switch-monitor () - "Switch focus to another monitor by name." - (interactive) - - ;; TODO: Filter out currently active? How to determine it? - (let* ((target (completing-read "Switch to monitor: " - (seq-map #'car (cadr (exwm-randr--get-monitors))) - nil t)) - (target-workspace - (cl-loop for (workspace screen) on exwm-randr-workspace-monitor-plist by #'cddr - when (equal screen target) return workspace))) - (exwm-workspace-switch target-workspace))) - -(exwm-input-set-key (kbd "s-m e") #'exwm-enable-monitor) -(exwm-input-set-key (kbd "s-m d") #'exwm-disable-monitor) -(exwm-input-set-key (kbd "s-m o") #'exwm-switch-monitor) - -;; Notmuch shortcuts as EXWM globals -;; (g m => gmail) -(exwm-input-set-key (kbd "s-g m") #'notmuch) - -;; Let buffers move seamlessly between workspaces by making them -;; accessible in selectors on all frames. -(setq exwm-workspace-show-all-buffers t) -(setq exwm-layout-show-all-buffers t) - -(provide 'desktop) diff --git a/users/tazjin/emacs/config/eshell-setup.el b/users/tazjin/emacs/config/eshell-setup.el deleted file mode 100644 index 0b23c5a2d..000000000 --- a/users/tazjin/emacs/config/eshell-setup.el +++ /dev/null @@ -1,68 +0,0 @@ -;; EShell configuration - -(require 'eshell) - -;; Generic settings -;; Hide banner message ... -(setq eshell-banner-message "") - -;; Prompt configuration -(defun clean-pwd (path) - "Turns a path of the form /foo/bar/baz into /f/b/baz - (inspired by fish shell)" - (let* ((hpath (replace-regexp-in-string home-dir - "~" - path)) - (current-dir (split-string hpath "/")) - (cdir (last current-dir)) - (head (butlast current-dir))) - (concat (mapconcat (lambda (s) - (if (string= "" s) nil - (substring s 0 1))) - head - "/") - (if head "/" nil) - (car cdir)))) - -(defun vcprompt (&optional args) - "Call the external vcprompt command with optional arguments. - VCPrompt" - (replace-regexp-in-string - "\n" "" - (shell-command-to-string (concat "vcprompt" args)))) - -(defmacro with-face (str &rest properties) - `(propertize ,str 'face (list ,@properties))) - -(defun prompt-f () - "EShell prompt displaying VC info and such" - (concat - (with-face (concat (clean-pwd (eshell/pwd)) " ") :foreground "#96a6c8") - (if (= 0 (user-uid)) - (with-face "#" :foreground "#f43841") - (with-face "$" :foreground "#73c936")) - (with-face " " :foreground "#95a99f"))) - - -(setq eshell-prompt-function 'prompt-f) -(setq eshell-highlight-prompt nil) -(setq eshell-prompt-regexp "^.+? \\((\\(git\\|svn\\|hg\\|darcs\\|cvs\\|bzr\\):.+?) \\)?[$#] ") - -;; Ignore version control folders in autocompletion -(setq eshell-cmpl-cycle-completions nil - eshell-save-history-on-exit t - eshell-cmpl-dir-ignore "\\`\\(\\.\\.?\\|CVS\\|\\.svn\\|\\.git\\)/\\'") - -;; Load some EShell extensions -(eval-after-load 'esh-opt - '(progn - (require 'em-term) - (require 'em-cmpl) - ;; More visual commands! - (add-to-list 'eshell-visual-commands "ssh") - (add-to-list 'eshell-visual-commands "tail") - (add-to-list 'eshell-visual-commands "sl"))) - -(setq eshell-directory-name "~/.config/eshell/") - -(provide 'eshell-setup) diff --git a/users/tazjin/emacs/config/functions.el b/users/tazjin/emacs/config/functions.el deleted file mode 100644 index 68a384d20..000000000 --- a/users/tazjin/emacs/config/functions.el +++ /dev/null @@ -1,352 +0,0 @@ -(require 'chart) -(require 'dash) -(require 'map) - -(require 'gio-list-apps) ;; native module! - -(defun goto-line-with-feedback () - "Show line numbers temporarily, while prompting for the line number input" - (interactive) - (unwind-protect - (progn - (setq-local display-line-numbers t) - (let ((target (read-number "Goto line: "))) - (avy-push-mark) - (goto-line target))) - (setq-local display-line-numbers nil))) - -(defun esk-add-watchwords () - (font-lock-add-keywords - nil '(("\\<\\(FIX\\(ME\\)?\\|TODO\\|DEBUG\\|HACK\\|REFACTOR\\|NOCOMMIT\\)" - 1 font-lock-warning-face t)))) - -(add-hook 'prog-mode-hook 'esk-add-watchwords) - -(defun esk-sudo-edit (&optional arg) - (interactive "p") - (if (or arg (not buffer-file-name)) - (find-file (concat "/sudo:root@localhost:" (read-file-name "File: "))) - (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name)))) - -;; Get the nix store path for a given derivation. -;; If the derivation has not been built before, this will trigger a build. -(defun nix-store-path (derivation) - (let ((expr (concat "with import <nixos> {}; " derivation))) - (s-chomp (shell-command-to-string (concat "nix-build -E '" expr "'"))))) - -(defun insert-nix-store-path () - (interactive) - (let ((derivation (read-string "Derivation name (in <nixos>): "))) - (insert (nix-store-path derivation)))) - -(defun toggle-force-newline () - "Buffer-local toggle for enforcing final newline on save." - (interactive) - (setq-local require-final-newline (not require-final-newline)) - (message "require-final-newline in buffer %s is now %s" - (buffer-name) - require-final-newline)) - -(defun list-external-commands () - "Creates a list of all external commands available on $PATH - while filtering NixOS wrappers." - (cl-loop - for dir in (split-string (getenv "PATH") path-separator) - when (and (file-exists-p dir) (file-accessible-directory-p dir)) - for lsdir = (cl-loop for i in (directory-files dir t) - for bn = (file-name-nondirectory i) - when (and (not (s-contains? "-wrapped" i)) - (not (member bn completions)) - (not (file-directory-p i)) - (file-executable-p i)) - collect bn) - append lsdir into completions - finally return (sort completions 'string-lessp))) - -(defvar external-command-flag-overrides - '(("google-chrome" . "--force-device-scale-factor=1.4")) - - "This setting lets me add additional flags to specific commands - that are run interactively via `run-external-command'.") - -(defun run-external-command--handler (cmd) - "Execute the specified command and notify the user when it - finishes." - (let* ((extra-flags (cdr (assoc cmd external-command-flag-overrides))) - (cmd (if extra-flags (s-join " " (list cmd extra-flags)) cmd))) - (message "Starting %s..." cmd) - (set-process-sentinel - (start-process-shell-command cmd nil cmd) - (lambda (process event) - (when (string= event "finished\n") - (message "%s process finished." process)))))) - -(defun run-external-command () - "Prompts the user with a list of all installed applications and - lets them select one to launch." - - (interactive) - (let ((external-commands-list (list-external-commands))) - (run-external-command--handler - (completing-read "Command: " external-commands-list - nil ;; predicate - t ;; require-match - nil ;; initial-input - ;; hist - 'external-commands-history)))) - -(defun password-store-lookup (&optional password-store-dir) - "Interactive password-store lookup function that actually uses -the GPG agent correctly." - - (interactive) - - (let* ((entry (completing-read "Copy password of entry: " - (password-store-list (or password-store-dir - (password-store-dir))) - nil ;; predicate - t ;; require-match - )) - (password (or (let ((epa-suppress-error-buffer t)) - (auth-source-pass-get 'secret entry)) - (error "failed to decrypt '%s', wrong password?" entry)))) - (password-store-clear) - (kill-new password) - (setq password-store-kill-ring-pointer kill-ring-yank-pointer) - (message "Copied %s to the kill ring. Will clear in %s seconds." - entry (password-store-timeout)) - (setq password-store-timeout-timer - (run-at-time (password-store-timeout) - nil 'password-store-clear)))) - -(defhydra mc/mark-more-hydra (:color pink) - ("<up>" mc/mmlte--up "Mark previous like this") - ("<down>" mc/mmlte--down "Mark next like this") - ("<left>" mc/mmlte--left (if (eq mc/mark-more-like-this-extended-direction 'up) - "Skip past the cursor furthest up" - "Remove the cursor furthest down")) - ("<right>" mc/mmlte--right (if (eq mc/mark-more-like-this-extended-direction 'up) - "Remove the cursor furthest up" - "Skip past the cursor furthest down")) - ("f" nil "Finish selecting")) - -;; Mute the message that mc/mmlte wants to print on its own -(advice-add 'mc/mmlte--message :around (lambda (&rest args) (ignore))) - -(defun mc/mark-dwim (arg) - "Select multiple things, but do what I mean." - - (interactive "p") - (if (not (region-active-p)) (mc/mark-next-lines arg) - (if (< 1 (count-lines (region-beginning) - (region-end))) - (mc/edit-lines arg) - ;; The following is almost identical to `mc/mark-more-like-this-extended', - ;; but uses a hydra (`mc/mark-more-hydra') instead of a transient key map. - (mc/mmlte--down) - (mc/mark-more-hydra/body)))) - -(setq mc/cmds-to-run-for-all '(kill-region paredit-newline)) - -(setq mc/cmds-to-run-once '(mc/mark-dwim - mc/mark-more-hydra/mc/mmlte--down - mc/mark-more-hydra/mc/mmlte--left - mc/mark-more-hydra/mc/mmlte--right - mc/mark-more-hydra/mc/mmlte--up - mc/mark-more-hydra/mmlte--up - mc/mark-more-hydra/nil)) - -(defun insert-todo-comment (prefix todo) - "Insert a comment at point with something for me to do." - - (interactive "P\nsWhat needs doing? ") - (save-excursion - (move-end-of-line nil) - (insert (format " %s TODO(%s): %s" - (s-trim-right comment-start) - (if prefix (read-string "Who needs to do this? ") - (getenv "USER")) - todo)))) - -;; Custom text scale adjustment functions that operate on the entire instance -(defun modify-text-scale (factor) - (set-face-attribute 'default nil - :height (+ (* factor 5) (face-attribute 'default :height)))) - -(defun increase-default-text-scale (prefix) - "Increase default text scale in all Emacs frames, or just the - current frame if PREFIX is set." - - (interactive "P") - (if prefix (text-scale-increase 1) - (modify-text-scale 1))) - -(defun decrease-default-text-scale (prefix) - "Increase default text scale in all Emacs frames, or just the - current frame if PREFIX is set." - - (interactive "P") - (if prefix (text-scale-decrease 1) - (modify-text-scale -1))) - -(defun set-default-text-scale (prefix &optional to) - "Set the default text scale to the specified value, or the - default. Restores current frame's text scale only, if PREFIX is - set." - - (interactive "P") - (if prefix (text-scale-adjust 0) - (set-face-attribute 'default nil :height (or to 120)))) - -(defun screenshot-select (filename) - "Take a screenshot based on a mouse-selection and save it to - ~/screenshots." - (interactive "sScreenshot filename: ") - (let* ((path (f-join "~/screenshots" - (format "%s-%d.png" - (if (string-empty-p filename) "shot" filename) - (time-convert nil 'integer))))) - (shell-command (format "maim --select %s" path)) - (message "Wrote screenshot to %s" path))) - -(defun graph-unread-mails () - "Create a bar chart of unread mails based on notmuch tags. - Certain tags are excluded from the overview." - - (interactive) - (let ((tag-counts - (-keep (-lambda ((name . search)) - (let ((count - (string-to-number - (s-trim - (notmuch-command-to-string "count" search "and" "tag:unread"))))) - (when (>= count 1) (cons name count)))) - (notmuch-hello-generate-tag-alist '("unread" "signed" "attachment" "important"))))) - - (chart-bar-quickie - (if (< (length tag-counts) 6) - 'vertical 'horizontal) - "Unread emails" - (-map #'car tag-counts) "Tag:" - (-map #'cdr tag-counts) "Count:"))) - -(defun notmuch-show-open-or-close-subthread (&optional prefix) - "Open or close the subthread from (and including) the message at point." - (interactive "P") - (save-excursion - (let ((current-depth (map-elt (notmuch-show-get-message-properties) :depth 0))) - (loop do (notmuch-show-message-visible (notmuch-show-get-message-properties) prefix) - until (or (not (notmuch-show-goto-message-next)) - (= (map-elt (notmuch-show-get-message-properties) :depth) current-depth))))) - (force-window-update)) - -(defun vterm-send-ctrl-x () - "Sends `C-x' to the libvterm." - (interactive) - (vterm-send-key "x" nil nil t)) - -(defun find-depot-project (dir) - "Function used in the `project-find-functions' hook list to - determine the current project root of a depot project." - (when (s-starts-with? "/depot" dir) - (if (f-exists-p (f-join dir "default.nix")) - (cons 'transient dir) - (find-depot-project (f-parent dir))))) - -(add-to-list 'project-find-functions #'find-depot-project) - -(defun find-cargo-project (dir) - "Attempt to find the current project in `project-find-functions' -by looking for a `Cargo.toml' file." - (when dir - (unless (equal "/" dir) - (if (f-exists-p (f-join dir "Cargo.toml")) - (cons 'transient dir) - (find-cargo-project (f-parent dir)))))) - -(add-to-list 'project-find-functions #'find-cargo-project) - -(defun magit-find-file-worktree () - (interactive) - "Find a file in the current (ma)git worktree." - (magit-find-file--internal "{worktree}" - (magit-read-file-from-rev "HEAD" "Find file") - #'pop-to-buffer-same-window)) - -(defun zoxide-open-project () - "Query Zoxide for paths, and open the result as appropriate (magit or dired)." - (interactive) - (zoxide-open-with - nil - (lambda (path) - (condition-case err (magit-status-setup-buffer path) - (magit-outside-git-repo (dired path)))))) - -(defun toggle-nix-test-and-exp () - "Switch between the .nix and .exp file in a Tvix/Nix test." - (interactive) - (let* ((file (buffer-file-name)) - (other (if (s-suffix? ".nix" file) - (s-replace-regexp ".nix$" ".exp" file) - (if (s-suffix? ".exp" file) - (s-replace-regexp ".exp$" ".nix" file) - (error "Not a .nix/.exp file!"))))) - (find-file other))) - -(defun reliably-switch-buffer () - "Reliably and interactively switch buffers, without ending up in a -situation where the buffer was renamed during selection and an -empty new buffer is created. - -This is done by, in contrast to most buffer-switching functions, -retaining a list of the buffer *objects* and their associated -names, instead of only their names (which might change)." - - (interactive) - (let* ((buffers (seq-map (lambda (b) (cons (buffer-name b) b)) - (seq-filter (lambda (b) (not (string-prefix-p " " (buffer-name b)))) - (buffer-list)))) - - ;; Annotate buffers that display remote files. I frequently - ;; want to see it, because I might have identically named - ;; files open locally and remotely at the same time, and it - ;; helps with differentiating them. - (completion-extra-properties - '(:annotation-function - (lambda (name) - (if-let* ((file (buffer-file-name (cdr (assoc name buffers)))) - (remote (file-remote-p file))) - (format " [%s]" remote))))) - - (name (completing-read "Switch to buffer: " (seq-map #'car buffers))) - (selected (or (cdr (assoc name buffers)) - ;; Allow users to manually select invisible buffers ... - (get-buffer name)))) - (switch-to-buffer (or selected name) nil 't))) - -(defun run-xdg-app () - "Use `//users/tazjin/gio-list-apps' to retrieve a list of -installed (and visible) XDG apps, and let users launch them." - (interactive) - (let* ((apps (taz-list-xdg-apps)) - - ;; Display the command that will be run as an annotation - (completion-extra-properties - '(:annotation-function (lambda (app) (format " [%s]" (cdr (assoc app apps))))))) - - (run-external-command--handler (cdr (assoc (completing-read "App: " apps nil t) apps))))) - -(defun advice-remove-all (sym) - "Remove all advices from symbol SYM." - (interactive "aFunction symbol: ") - (advice-mapc (lambda (advice _props) (advice-remove sym advice)) sym)) - -(defun M-x-always-same-window () - "Run `execute-extended-command', but ensure that whatever it does -always opens in the same window in which the command was invoked." - (interactive) - (let ((display-buffer-overriding-action - '((display-buffer-same-window) . ((inhibit-same-window . nil))))) - (call-interactively #'execute-extended-command))) - -(provide 'functions) diff --git a/users/tazjin/emacs/config/init.el b/users/tazjin/emacs/config/init.el deleted file mode 100644 index d11409f3e..000000000 --- a/users/tazjin/emacs/config/init.el +++ /dev/null @@ -1,273 +0,0 @@ -;;; init.el --- Package bootstrapping. -*- lexical-binding: t; -*- - -;; Disable annoying warnings from native compilation. -(setq native-comp-async-report-warnings-errors nil - warning-suppress-log-types '((comp))) - -;; Packages are installed via Nix configuration, this file only -;; initialises the newly loaded packages. - -(require 'use-package) -(require 'seq) - -(package-initialize) - -;; Initialise all packages installed via Nix. - -(use-package ace-window - :bind (("C-x o" . ace-window)) - :config - (setq aw-keys '(?f ?j ?d ?k ?s ?l ?a) - aw-scope 'frame)) - -(use-package auth-source-pass :config (auth-source-pass-enable)) - -(use-package avy - :bind (("M-j" . avy-goto-char) - ("M-p" . avy-pop-mark) - ("M-g g" . avy-goto-line))) - -(use-package browse-kill-ring) - -(use-package company - :config - (global-company-mode)) - -(use-package consult - :bind - ("C-c r g" . consult-ripgrep) - ("C-s" . consult-line)) - -(use-package dash) -(use-package gruber-darker-theme) - -(use-package eglot - :custom - (eglot-autoshutdown t) - (eglot-send-changes-idle-time 0.3)) - -(use-package ht) - -(use-package hydra) -(use-package idle-highlight-mode :hook ((prog-mode . idle-highlight-mode))) - -(use-package multiple-cursors) - -(use-package notmuch - :custom - (notmuch-search-oldest-first nil) - (notmuch-show-all-tags-list t) - (notmuch-hello-tag-list-make-query "tag:unread")) - -(use-package paredit :hook ((lisp-mode . paredit-mode) - (emacs-lisp-mode . paredit-mode))) - -(use-package pinentry - :config - (setq epa-pinentry-mode 'loopback) - (pinentry-start)) - -(use-package prescient - :config - (prescient-persist-mode) - (setq completion-styles '(basic prescient))) - -(use-package vertico-prescient - :config - (vertico-prescient-mode)) - -(use-package company-prescient - :config - (company-prescient-mode)) - -(use-package rainbow-delimiters :hook (prog-mode . rainbow-delimiters-mode)) -(use-package rainbow-mode) -(use-package s) -(use-package string-edit-at-point) -(use-package term-switcher - :bind (:map global-map ("C-c v" . #'ts/switch-to-terminal))) - -(use-package undo-tree - :config (global-undo-tree-mode) - :custom (undo-tree-auto-save-history nil)) - -(use-package uuidgen) -(use-package which-key :config (which-key-mode t)) - -;; -;; Applications in emacs -;; - -(use-package magit - :bind ("C-c g" . magit-status) - :config (setq magit-repository-directories '(("/home/tazjin/projects" . 2) - ("/home/tazjin" . 1)))) - -(use-package password-store) -(use-package restclient) - -(use-package vterm - :custom - (vterm-shell "fish") - (vterm-kill-buffer-on-exit t)) - -;; vterm removed the ability to set a custom title generator function -;; via the public API, so this overrides its private title generation -;; function instead -(defun vterm--set-title (title) - (rename-buffer - (generate-new-buffer-name - (format "vterm<%s>" - (s-trim-left - (s-chop-prefix "fish" title)))))) - -;; -;; Packages providing language-specific functionality -;; - -(use-package cargo - :hook ((rust-mode . cargo-minor-mode) - (cargo-process-mode . visual-line-mode)) - :bind (:map cargo-mode-map ("C-c C-c C-l" . ignore))) - -(use-package dockerfile-ts-mode) - -(use-package erlang - :hook ((erlang-mode . (lambda () - ;; Don't indent after '>' while I'm writing - (local-set-key ">" 'self-insert-command))))) - -(use-package f) - -(use-package go-ts-mode - :custom - (go-ts-mode-indent-offset 4)) - -(use-package haskell-mode) - -(use-package ielm - :hook ((inferior-emacs-lisp-mode . (lambda () - (rainbow-delimiters-mode-enable))))) - -(use-package jq-mode - :config (add-to-list 'auto-mode-alist '("\\.jq\\'" . jq-mode))) - -(use-package kotlin-mode - :hook ((kotlin-mode . (lambda () - (setq indent-line-function #'indent-relative))))) - -(use-package markdown-mode - :config - (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode)) - (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode))) - -(use-package markdown-toc) -(use-package niri) - -(use-package nix-mode - :hook ((nix-mode . (lambda () - (setq indent-line-function #'nix-indent-line))))) - -(use-package nix-util) -(use-package nginx-mode) -(use-package rust-mode) - -(use-package sly - :hook ((sly-mrepl-mode . (lambda () - (paredit-mode) - (rainbow-delimiters-mode-enable)))) - :config - (setq common-lisp-hyperspec-root "file:///home/tazjin/docs/lisp/")) - -(use-package telega - :bind (:map global-map ("C-x c" . (lambda (p) (interactive "P") - (if p (call-interactively #'telega-chat-with) - (telega)))) - :map telega-chat-button-map ("a" . ignore)) - :config (telega-mode-line-mode 1) - :custom - (telega-emoji-use-images nil) - (telega-completing-read-function #'completing-read) - (telega-video-player-command "vlc")) - -(use-package terraform-mode) -(use-package toml-ts-mode) - -(use-package treecrumbs - :hook ((yaml-ts-mode . treecrumbs-mode))) - -(use-package tvl) - -(use-package vertico - :config - (vertico-mode)) - -(use-package web-mode) -(use-package yaml-ts-mode) -(use-package zoxide) - -(use-package passively - :custom - (passively-store-state "/persist/tazjin/known-russian-words.el")) - -;; Note taking configuration for deft. -(use-package deft - :custom - (deft-directory "/persist/tazjin/deft/") - (deft-extensions '("md" "org" "txt")) - (deft-default-extension "md")) - -(use-package zetteldeft - :custom - ;; Configure for Markdown - (zetteldeft-link-indicator "[[") - (zetteldeft-link-suffix "]]") - (zetteldeft-title-prefix "# ") - (zetteldeft-list-prefix "* ")) - -;; Initialise midnight.el, which by default automatically cleans up -;; unused buffers at midnight. -(require 'midnight) - -(defgroup tazjin nil - "Settings related to my configuration") - -(defcustom depot-path "/depot" - "Local path to the depot checkout" - :group 'tazjin) - -;; Configuration changes in `customize` can not actually be persisted -;; to the customise file that Emacs is currently using (since it comes -;; from the Nix store). -;; -;; The way this will work for now is that Emacs will *write* -;; configuration to the file tracked in my repository, while not -;; actually *reading* it from there (unless Emacs is rebuilt). -(setq custom-file (f-join depot-path "users" "tazjin" "emacs" "config" "custom.el")) -(load-library "custom") - -(defvar home-dir (expand-file-name "~")) - -;; Seed RNG -(random t) - -;; Load all other Emacs configuration. These configurations are -;; added to `load-path' by Nix. -(mapc 'require '(mail-setup - look-and-feel - functions - settings - bindings - eshell-setup)) -(ace-window-display-mode) - -;; If a local configuration library exists, it should be loaded. -;; -;; This can be provided by calling my Emacs derivation with -;; `withLocalConfig'. -(if-let (local-file (locate-library "local")) - (load local-file)) - -(require 'dottime) - -(provide 'init) diff --git a/users/tazjin/emacs/config/look-and-feel.el b/users/tazjin/emacs/config/look-and-feel.el deleted file mode 100644 index b771b4cd0..000000000 --- a/users/tazjin/emacs/config/look-and-feel.el +++ /dev/null @@ -1,98 +0,0 @@ -;;; -*- lexical-binding: t; -*- - -;; Hide those ugly tool bars: -(tool-bar-mode 0) -(scroll-bar-mode 0) -(menu-bar-mode 0) -(add-hook 'after-make-frame-functions - (lambda (frame) (scroll-bar-mode 0))) - -;; Don't do any annoying things: -(setq ring-bell-function 'ignore) -(setq initial-scratch-message "") - -;; Usually emacs will run as a proper GUI application, in which case a few -;; extra settings are nice-to-have: -(when window-system - (setq frame-title-format '(buffer-file-name "%f" ("%b"))) - (mouse-wheel-mode t) - (blink-cursor-mode -1)) - -;; Configure Emacs fonts. -(let ((font (format "JetBrains Mono-%d" 12))) - (setq default-frame-alist `((font . ,font))) - (set-frame-font font t t)) - -;; Configure the modeline - -;; Implements a mode-line warning if there are any logged in TTY -;; sessions apart from the graphical one. -;; -;; The status is only updated once every 30 seconds, as it requires -;; shelling out to some commands (for now). -(defun list-tty-sessions () - "List all logged in tty sessions, except tty7 (graphical)" - (let ((command "who | awk '{print $2}' | grep -v tty7")) - (-filter (lambda (s) (not (string-empty-p s))) - (s-lines - (s-trim (let ((default-directory "/")) - (shell-command-to-string command))))))) - -(defvar cached-tty-sessions (cons (time-convert nil 'integer) (list-tty-sessions)) - "Cached TTY session value to avoid running the command too often.") - -;; TODO(tazjin): add this to the modeline - -(defun get-cached-tty-sessions () - (let ((time )) - (when (< 30 - (- (time-convert nil 'integer) - (car cached-tty-sessions))) - (setq cached-tty-sessions - (cons (time-convert nil 'integer) (list-tty-sessions))))) - - (cdr cached-tty-sessions)) - -;; Auto refresh buffers -(global-auto-revert-mode 1) - -;; Use clipboard properly -(setq select-enable-clipboard t) - -;; Show in-progress chords in minibuffer -(setq echo-keystrokes 0.1) - -;; Show column numbers in all buffers -(column-number-mode t) - -(defalias 'yes-or-no-p 'y-or-n-p) -(defalias 'auto-tail-revert-mode 'tail-mode) - -;; Style line numbers (shown with M-g g) -(setq linum-format - (lambda (line) - (propertize - (format (concat " %" - (number-to-string - (length (number-to-string - (line-number-at-pos (point-max))))) - "d ") - line) - 'face 'linum))) - -;; Display tabs as 2 spaces -(setq tab-width 2) - -;; Don't wrap around when moving between buffers -(setq windmove-wrap-around nil) - -;; Don't show me all emacs warnings immediately. Unfortunately this is -;; not very granular, as emacs displays most of its warnings in the -;; `emacs' "category", but without it every time I -;; fullscreen/unfullscreen the warning buffer destroys my layout. -;; -;; Warnings suppressed by this are still logged to the warnings -;; buffer. -(setq warning-suppress-types '((emacs))) - -(provide 'look-and-feel) diff --git a/users/tazjin/emacs/config/mail-setup.el b/users/tazjin/emacs/config/mail-setup.el deleted file mode 100644 index 7352c8ba1..000000000 --- a/users/tazjin/emacs/config/mail-setup.el +++ /dev/null @@ -1,79 +0,0 @@ -(require 'notmuch) - -;; (global-set-key (kbd "C-c m") 'notmuch-hello) -;; (global-set-key (kbd "C-c C-e n") 'notmuch-mua-new-mail) - -(setq notmuch-cache-dir (format "%s/.cache/notmuch" (getenv "HOME"))) -(make-directory notmuch-cache-dir t) - -;; Cache addresses for completion: -(setq notmuch-address-save-filename (concat notmuch-cache-dir "/addresses")) - -;; Don't spam my home folder with drafts: -(setq notmuch-draft-folder "drafts") ;; relative to notmuch database - -;; Mark things as read when archiving them: -(setq notmuch-archive-tags '("-inbox" "-unread" "+archive")) - -;; Show me saved searches that I care about: -(setq notmuch-saved-searches - '((:name "inbox" :query "tag:inbox" :count-query "tag:inbox AND tag:unread" :key "i") - (:name "sent" :query "tag:sent" :key "t") - (:name "drafts" :query "tag:draft"))) -(setq notmuch-show-empty-saved-searches t) - -;; Mail sending configuration -(setq sendmail-program "gmi") ;; lieer binary supports sendmail emulation -(setq message-sendmail-extra-arguments - '("send" "--quiet" "-t" "-C" "~/mail/account.tazjin")) -(setq send-mail-function 'sendmail-send-it) -(setq notmuch-mua-user-agent-function - (lambda () (format "Emacs %s; notmuch.el %s" emacs-version notmuch-emacs-version))) -(setq mail-host-address (system-name)) -(setq notmuch-mua-cite-function #'message-cite-original-without-signature) -(setq notmuch-fcc-dirs nil) ;; Gmail does this server-side -(setq message-signature nil) ;; Insert message signature manually with C-c C-w - -;; Close mail buffers after sending mail -(setq message-kill-buffer-on-exit t) - -;; Ensure sender is correctly passed to msmtp -(setq mail-specify-envelope-from t - message-sendmail-envelope-from 'header - mail-envelope-from 'header) - -;; Store sent mail in the correct folder per account -(setq notmuch-maildir-use-notmuch-insert nil) - -;; I don't use drafts but I instinctively hit C-x C-s constantly, lets -;; handle that gracefully. -(define-key notmuch-message-mode-map (kbd "C-x C-s") #'ignore) - -;; Define a mode-line segment for displaying the count of unread, -;; important mails in the last window's mode-line: -(defvar *last-notmuch-count-redraw* 0) -(defvar *current-notmuch-count* nil) - -(defun update-display-notmuch-counts () - "Update and render the current state of the notmuch unread - count for display in the mode-line. - - The offlineimap-timer runs every 2 minutes, so it does not make - sense to refresh this much more often than that." - - (when (> (- (float-time) *last-notmuch-count-redraw*) 30) - (setq *last-notmuch-count-redraw* (float-time)) - (let* ((inbox-unread (notmuch-saved-search-count "tag:inbox and tag:unread")) - (notmuch-count (format "I: %s; D: %s" inbox-unread))) - (setq *current-notmuch-count* notmuch-count))) - - (when (and (bottom-right-window-p) - ;; Only render if the initial update is done and there - ;; are unread mails: - *current-notmuch-count* - (not (equal *current-notmuch-count* "I: 0; D: 0"))) - *current-notmuch-count*)) - -;; TODO(tazjin): re-add this segment to the modeline - -(provide 'mail-setup) diff --git a/users/tazjin/emacs/config/settings.el b/users/tazjin/emacs/config/settings.el deleted file mode 100644 index afe181b70..000000000 --- a/users/tazjin/emacs/config/settings.el +++ /dev/null @@ -1,92 +0,0 @@ -(require 'uniquify) - -;; We don't live in the 80s, but we're also not a shitty web app. -(setq gc-cons-threshold 20000000) - -(setq uniquify-buffer-name-style 'forward) - -; Fix some defaults -(setq visible-bell nil - inhibit-startup-message t - color-theme-is-global t - sentence-end-double-space nil - shift-select-mode nil - uniquify-buffer-name-style 'forward - whitespace-style '(face trailing lines-tail tabs) - whitespace-line-column 80 - default-directory "~" - fill-column 80 - ediff-split-window-function 'split-window-horizontally - initial-major-mode 'emacs-lisp-mode) - -(setq-default tab-width 4) -(setq-default fill-column 80) - -(add-to-list 'safe-local-variable-values '(lexical-binding . t)) -(add-to-list 'safe-local-variable-values '(whitespace-line-column . 80)) - -(set-default 'indent-tabs-mode nil) - -;; UTF-8 please -(setq locale-coding-system 'utf-8) ; pretty -(set-terminal-coding-system 'utf-8) ; pretty -(set-keyboard-coding-system 'utf-8) ; pretty -(set-selection-coding-system 'utf-8) ; please -(prefer-coding-system 'utf-8) ; with sugar on top - -;; Make emacs behave sanely (overwrite selected text) -(delete-selection-mode 1) - -;; Keep your temporary files in tmp, emacs! -(setq auto-save-file-name-transforms - `((".*" ,temporary-file-directory t))) -(setq backup-directory-alist - `((".*" . ,temporary-file-directory))) - -(remove-hook 'kill-buffer-query-functions 'server-kill-buffer-query-function) - -;; Show time in 24h format -(setq display-time-24hr-format t) - -;; Use python-mode for Starlark files. -(add-to-list 'auto-mode-alist '("\\.star\\'" . python-mode)) - -;; Use cmake-mode for relevant files. -(add-to-list 'auto-mode-alist '("ya\\.make\\'" . cmake-ts-mode)) - -;; Use tree-sitter modes for various languages. -(setq major-mode-remap-alist - '((bash-mode . bash-ts-mode) - (c++-mode . c++-ts-mode) - (c-mode . c-ts-mode) - (c-or-c++-mode . c-or-c++-ts-mode) - (json-mode . json-ts-mode) - (python-mode . python-ts-mode) - (rust-mode . rust-ts-mode) - (toml-mode . toml-ts-mode) - (yaml-mode . yaml-ts-mode) - (go-mode . go-ts-mode) - (cmake-mode . cmake-ts-mode))) - -;; Visually highlight current line in programming buffers -(add-hook 'prog-mode-hook 'hl-line-mode) - -;; Enable rainbow-delimiters for all things programming -(add-hook 'prog-mode-hook 'rainbow-delimiters-mode) - -;; Always highlight matching brackets -(show-paren-mode 1) - -;; Always auto-close parantheses and other pairs -(electric-pair-mode) - -;; Keep track of recent files -(recentf-mode) - -;; Easily navigate sillycased words -(global-subword-mode 1) - -;; Transparently open compressed files -(auto-compression-mode t) - -(provide 'settings) diff --git a/users/tazjin/emacs/default.nix b/users/tazjin/emacs/default.nix deleted file mode 100644 index dac9e10b0..000000000 --- a/users/tazjin/emacs/default.nix +++ /dev/null @@ -1,154 +0,0 @@ -# This file builds an Emacs pre-configured with the packages I need -# and my personal Emacs configuration. -{ depot, lib, pkgs, ... }: - -pkgs.makeOverridable - ({ emacs ? pkgs.emacs-pgtk }: - let - emacsPackages = (pkgs.emacsPackagesFor emacs); - emacsWithPackages = emacsPackages.emacsWithPackages; - - # $PATH for binaries that need to be available to Emacs - emacsBinPath = lib.makeBinPath [ - emacsPackages.checkedTelega - pkgs.libwebp # for dwebp, required by telega - ]; - - identity = x: x; - - # tree-sitter grammars for various ts-modes - customTreesitGrammars = emacs.pkgs.treesit-grammars.with-grammars (g: with g; [ - tree-sitter-bash - tree-sitter-c - tree-sitter-cmake - tree-sitter-cpp - tree-sitter-css - tree-sitter-dockerfile - tree-sitter-go - tree-sitter-gomod - tree-sitter-hcl - tree-sitter-html - tree-sitter-java - tree-sitter-json - tree-sitter-latex - tree-sitter-make - tree-sitter-nix - tree-sitter-python - tree-sitter-rust - tree-sitter-sql - tree-sitter-toml - tree-sitter-typescript - tree-sitter-yaml - ]); - - tazjinsEmacs = pkgfun: (emacsWithPackages (epkgs: pkgfun (with epkgs; [ - ace-link - ace-window - avy - bazel - browse-kill-ring - cargo - clojure-mode - company - company-prescient - consult - deft - direnv - elixir-mode - elm-mode - erlang - go-mode - google-c-style - gruber-darker-theme - haskell-mode - ht - hydra - idle-highlight-mode - inspector - jq-mode - kotlin-mode - kubernetes - magit - markdown-toc - multiple-cursors - nginx-mode - nix-mode - notmuch - paredit - password-store - pinentry - prescient - protobuf-mode - rainbow-delimiters - rainbow-mode - request - restclient - rust-mode - sly - string-edit-at-point - terraform-mode - undo-tree - uuidgen - vertico - vertico-prescient - vterm - web-mode - websocket - which-key - xelb - yasnippet - zetteldeft - zoxide - - # Wonky stuff - checkedTelega - customTreesitGrammars # TODO(tazjin): how is this *supposed* to work?! - - # Custom depot packages (either ours, or overridden ones) - tvlPackages.dottime - tvlPackages.niri - tvlPackages.nix-util - tvlPackages.passively - tvlPackages.rcirc - tvlPackages.term-switcher - tvlPackages.treecrumbs - tvlPackages.tvl - - # Dynamic/native modules - depot.users.tazjin.gio-list-apps - ]))); - in - lib.fix - (self: l: f: (pkgs.writeShellScriptBin "tazjins-emacs" '' - export PATH="${emacsBinPath}:$PATH" - exec ${tazjinsEmacs f}/bin/emacs \ - --debug-init \ - --no-site-file \ - --no-site-lisp \ - --no-init-file \ - --directory ${./config} ${if l != null then "--directory ${l}" else ""} \ - --eval "(add-to-list 'treesit-extra-load-path \"${customTreesitGrammars}/lib\")" \ - --eval "(require 'init)" $@ - '').overrideAttrs - (_: { - passthru = { - # Expose original Emacs used for my configuration. - inherit emacs; - - # Expose the pure emacs with all packages. - inherit emacsPackages; - emacsWithPackages = tazjinsEmacs f; - - # Call overrideEmacs with a function (pkgs -> pkgs) to modify the - # packages that should be included in this Emacs distribution. - overrideEmacs = f': self l f'; - - # Call withLocalConfig with the path to a *folder* containing a - # `local.el` which provides local system configuration. - withLocalConfig = confDir: self confDir f; - }; - })) - null - identity - ) -{ } diff --git a/users/tazjin/finito/.gitignore b/users/tazjin/finito/.gitignore deleted file mode 100644 index 548206b0b..000000000 --- a/users/tazjin/finito/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.envrc -/target/ -**/*.rs.bk diff --git a/users/tazjin/finito/Cargo.lock b/users/tazjin/finito/Cargo.lock deleted file mode 100644 index 7427a6b11..000000000 --- a/users/tazjin/finito/Cargo.lock +++ /dev/null @@ -1,773 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "addr2line" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602d785912f476e480434627e8732e6766b760c045bbf897d9dfaa9f4fbd399c" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler32" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "autocfg" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" - -[[package]] -name = "backtrace" -version = "0.3.49" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05100821de9e028f12ae3d189176b41ee198341eb8f369956407fea2f5cc666c" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" -dependencies = [ - "byteorder", - "safemem", -] - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "block-buffer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" -dependencies = [ - "arrayref", - "byte-tools", -] - -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" - -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -dependencies = [ - "byteorder", - "iovec", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "chrono" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" -dependencies = [ - "num-integer", - "num-traits", - "time", -] - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crypto-mac" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0999b4ff4d3446d4ddb19a63e9e00c1876e75cd7000d20e57a693b4b3f08d958" -dependencies = [ - "constant_time_eq", - "generic-array", -] - -[[package]] -name = "digest" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" -dependencies = [ - "generic-array", -] - -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2 1.0.18", - "quote 1.0.7", - "syn 1.0.33", - "synstructure", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "fallible-iterator" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7217124812dc5672b7476d0c2d20cfe9f7c0f1ba0904b674a9762a0212f72e" - -[[package]] -name = "finito" -version = "0.1.0" -dependencies = [ - "serde", -] - -[[package]] -name = "finito-door" -version = "0.1.0" -dependencies = [ - "failure", - "finito", - "serde", - "serde_derive", -] - -[[package]] -name = "finito-postgres" -version = "0.1.0" -dependencies = [ - "chrono", - "finito", - "finito-door", - "postgres", - "postgres-derive", - "r2d2_postgres", - "serde", - "serde_json", - "uuid", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" - -[[package]] -name = "generic-array" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -dependencies = [ - "typenum", -] - -[[package]] -name = "gimli" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc8e0c9bce37868955864dbecd2b1ab2bdf967e6f28066d65aaac620444b65c" - -[[package]] -name = "hex" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" - -[[package]] -name = "hmac" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f3bdb08579d99d7dc761c0e266f13b5f2ab8c8c703b9fc9ef333cd8f48f55e" -dependencies = [ - "crypto-mac", - "digest", -] - -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - -[[package]] -name = "itoa" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" - -[[package]] -name = "libc" -version = "0.2.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" - -[[package]] -name = "lock_api" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - -[[package]] -name = "md5" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c56d6a0b07f9e19282511c83fc5b086364cbae4ba8c7d5f190c3d9b0425a48" - -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" -dependencies = [ - "libc", -] - -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - -[[package]] -name = "num-integer" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" -dependencies = [ - "autocfg", -] - -[[package]] -name = "object" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" - -[[package]] -name = "parking_lot" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" -dependencies = [ - "cfg-if", - "cloudabi", - "libc", - "redox_syscall", - "smallvec", - "winapi", -] - -[[package]] -name = "phf" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" -dependencies = [ - "siphasher", -] - -[[package]] -name = "postgres" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115dde90ef51af573580c035857badbece2aa5cde3de1dfb3c932969ca92a6c5" -dependencies = [ - "bytes", - "fallible-iterator", - "log", - "postgres-protocol", - "postgres-shared", - "socket2", -] - -[[package]] -name = "postgres-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44ef42ae50f1547dde36aa78d5e44189cbf21f4e77ce6ddc2bbaa068337fc221" -dependencies = [ - "quote 0.5.2", - "syn 0.13.11", -] - -[[package]] -name = "postgres-protocol" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2487e66455bf88a1b247bf08a3ce7fe5197ac6d67228d920b0ee6a0e97fd7312" -dependencies = [ - "base64", - "byteorder", - "bytes", - "fallible-iterator", - "generic-array", - "hmac", - "md5", - "memchr", - "rand 0.3.23", - "sha2", - "stringprep", -] - -[[package]] -name = "postgres-shared" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffac35b3e0029b404c24a3b82149b4e904f293e8ca4a327eefa24d3ca50df36f" -dependencies = [ - "chrono", - "fallible-iterator", - "hex", - "phf", - "postgres-protocol", - "serde_json", - "uuid", -] - -[[package]] -name = "proc-macro2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" -dependencies = [ - "unicode-xid 0.2.1", -] - -[[package]] -name = "quote" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" -dependencies = [ - "proc-macro2 0.3.8", -] - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2 1.0.18", -] - -[[package]] -name = "r2d2" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1497e40855348e4a8a40767d8e55174bce1e445a3ac9254ad44ad468ee0485af" -dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", -] - -[[package]] -name = "r2d2_postgres" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c7fe9c0c3d2c298cf262bc3ce4b89cdf0eab620fd9fe759f65b34a1a00fb93" -dependencies = [ - "postgres", - "postgres-shared", - "r2d2", -] - -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -dependencies = [ - "libc", - "rand 0.4.6", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -dependencies = [ - "fuchsia-cprng", - "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -dependencies = [ - "rand_core 0.4.2", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" - -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "safemem" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" - -[[package]] -name = "scheduled-thread-pool" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0988d7fdf88d5e5fcf5923a0f1e8ab345f3e98ab4bc6bc45a2d5ff7f7458fbf6" -dependencies = [ - "parking_lot", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "serde" -version = "1.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" - -[[package]] -name = "serde_derive" -version = "1.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" -dependencies = [ - "proc-macro2 1.0.18", - "quote 1.0.7", - "syn 1.0.33", -] - -[[package]] -name = "serde_json" -version = "1.0.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" -dependencies = [ - "block-buffer", - "byte-tools", - "digest", - "fake-simd", -] - -[[package]] -name = "siphasher" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" - -[[package]] -name = "smallvec" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" - -[[package]] -name = "socket2" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "winapi", -] - -[[package]] -name = "stringprep" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "syn" -version = "0.13.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" -dependencies = [ - "proc-macro2 0.3.8", - "quote 0.5.2", - "unicode-xid 0.1.0", -] - -[[package]] -name = "syn" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" -dependencies = [ - "proc-macro2 1.0.18", - "quote 1.0.7", - "unicode-xid 0.2.1", -] - -[[package]] -name = "synstructure" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" -dependencies = [ - "proc-macro2 1.0.18", - "quote 1.0.7", - "syn 1.0.33", - "unicode-xid 0.2.1", -] - -[[package]] -name = "time" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "tinyvec" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" - -[[package]] -name = "typenum" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "uuid" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22" -dependencies = [ - "rand 0.3.23", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/users/tazjin/finito/Cargo.toml b/users/tazjin/finito/Cargo.toml deleted file mode 100644 index 310133abe..000000000 --- a/users/tazjin/finito/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[workspace] -members = [ - "finito-core", - "finito-door", - "finito-postgres" -] diff --git a/users/tazjin/finito/README.md b/users/tazjin/finito/README.md deleted file mode 100644 index 5acd67d3b..000000000 --- a/users/tazjin/finito/README.md +++ /dev/null @@ -1,27 +0,0 @@ -Finito -====== - -This is a Rust port of the Haskell state-machine library Finito. It is -slightly less featureful because it loses the ability to ensure that -side-effects are contained and because of a slight reduction in -expressivity, which makes it a bit more restrictive. - -However, it still implements the FSM model well enough. - -# Components - -Finito is split up into multiple independent components (note: not all -of these exist yet), separating functionality related to FSM -persistence from other things. - -* `finito`: Core abstraction implemented by Finito -* `finito-door`: Example implementation of a simple, lockable door -* `finito-postgres`: Persistent state-machines using Postgres - -**Note**: The `finito` core library does not contain any tests. Its -coverage is instead provided by the `finito-door` library, which -actually implements an example FSM. - -These are split out because the documentation for `finito-door` is -interesting regardless and because other Finito packages also need an -example implementation. diff --git a/users/tazjin/finito/default.nix b/users/tazjin/finito/default.nix deleted file mode 100644 index 9a39591ea..000000000 --- a/users/tazjin/finito/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ depot, ... }: - -depot.third_party.naersk.buildPackage { - src = ./.; - - # Got broken by a rustc update (?) - # https://buildkite.com/tvl/depot/builds/17910#01841493-dc42-44f8-b904-32bf3d835485 - meta.ci.skip = true; -} diff --git a/users/tazjin/finito/finito-core/Cargo.toml b/users/tazjin/finito/finito-core/Cargo.toml deleted file mode 100644 index 1d7bdb8b0..000000000 --- a/users/tazjin/finito/finito-core/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "finito" -version = "0.1.0" -authors = ["Vincent Ambo <mail@tazj.in>"] - -[dependencies] -serde = "1.0" diff --git a/users/tazjin/finito/finito-core/src/lib.rs b/users/tazjin/finito/finito-core/src/lib.rs deleted file mode 100644 index aaec03a77..000000000 --- a/users/tazjin/finito/finito-core/src/lib.rs +++ /dev/null @@ -1,248 +0,0 @@ -//! Finito's core finite-state machine abstraction. -//! -//! # What & why? -//! -//! Most processes that occur in software applications can be modeled -//! as finite-state machines (FSMs), however the actual states, the -//! transitions between them and the model's interaction with the -//! external world is often implicit. -//! -//! Making the states of a process explicit using a simple language -//! that works for both software developers and other people who may -//! have opinions on processes makes it easier to synchronise thoughts, -//! extend software and keep a good level of control over what is going -//! on. -//! -//! This library aims to provide functionality for implementing -//! finite-state machines in a way that balances expressivity and -//! safety. -//! -//! Finito does not aim to prevent every possible incorrect -//! transition, but aims for somewhere "safe-enough" (please don't -//! lynch me) that is still easily understood. -//! -//! # Conceptual overview -//! -//! The core idea behind Finito can be expressed in a single line and -//! will potentially look familiar if you have used Erlang in a -//! previous life. The syntax used here is the type-signature notation -//! of Haskell. -//! -//! ```text -//! advance :: state -> event -> (state, [action]) -//! ``` -//! -//! In short, every FSM is made up of three distinct types: -//! -//! * a state type representing all possible states of the machine -//! -//! * an event type representing all possible events in the machine -//! -//! * an action type representing a description of all possible side-effects -//! of the machine -//! -//! Using the definition above we can now say that a transition in a -//! state-machine, involving these three types, takes an initial state -//! and an event to apply it to and returns a new state and a list of -//! actions to execute. -//! -//! With this definition most processes can already be modeled quite -//! well. Two additional functions are required to make it all work: -//! -//! ```text -//! -- | The ability to cause additional side-effects after entering -//! -- a new state. -//! > enter :: state -> [action] -//! ``` -//! -//! as well as -//! -//! ```text -//! -- | An interpreter for side-effects -//! act :: action -> m [event] -//! ``` -//! -//! **Note**: This library is based on an original Haskell library. In -//! Haskell, side-effects can be controlled via the type system which -//! is impossible in Rust. -//! -//! Some parts of Finito make assumptions about the programmer not -//! making certain kinds of mistakes, which are pointed out in the -//! documentation. Unfortunately those assumptions are not -//! automatically verifiable in Rust. -//! -//! ## Example -//! -//! Please consult `finito-door` for an example representing a simple, -//! lockable door as a finite-state machine. This gives an overview -//! over Finito's primary features. -//! -//! If you happen to be the kind of person who likes to learn about -//! libraries by reading code, you should familiarise yourself with the -//! door as it shows up as the example in other finito-related -//! libraries, too. -//! -//! # Persistence, side-effects and mud -//! -//! These three things are inescapable in the fateful realm of -//! computers, but Finito separates them out into separate libraries -//! that you can drag in as you need them. -//! -//! Currently, those libraries include: -//! -//! * `finito`: Core components and classes of Finito -//! -//! * `finito-in-mem`: In-memory implementation of state machines that do not -//! need to live longer than an application using standard library -//! concurrency primitives. -//! -//! * `finito-postgres`: Postgres-backed, persistent implementation of state -//! machines that, well, do need to live longer. Uses Postgres for -//! concurrency synchronisation, so keep that in mind. -//! -//! Which should cover most use-cases. Okay, enough prose, lets dive -//! in. -//! -//! # Does Finito make you want to scream? -//! -//! Please reach out! I want to know why! - -extern crate serde; - -use serde::de::DeserializeOwned; -use serde::Serialize; -use std::fmt::Debug; -use std::mem; - -/// Primary trait that needs to be implemented for every state type -/// representing the states of an FSM. -/// -/// This trait is used to implement transition logic and to "tie the -/// room together", with the room being our triplet of types. -pub trait FSM -where - Self: Sized, -{ - /// A human-readable string uniquely describing what this FSM - /// models. This is used in log messages, database tables and - /// various other things throughout Finito. - const FSM_NAME: &'static str; - - /// The associated event type of an FSM represents all possible - /// events that can occur in the state-machine. - type Event; - - /// The associated action type of an FSM represents all possible - /// actions that can occur in the state-machine. - type Action; - - /// The associated error type of an FSM represents failures that - /// can occur during action processing. - type Error: Debug; - - /// The associated state type of an FSM describes the state that - /// is made available to the implementation of action - /// interpretations. - type State; - - /// `handle` deals with any incoming events to cause state - /// transitions and emit actions. This function is the core logic - /// of any state machine. - /// - /// Implementations of this function **must not** cause any - /// side-effects to avoid breaking the guarantees of Finitos - /// conceptual model. - fn handle(self, event: Self::Event) -> (Self, Vec<Self::Action>); - - /// `enter` is called when a new state is entered, allowing a - /// state to produce additional side-effects. - /// - /// This is useful for side-effects that event handlers do not - /// need to know about and for resting assured that a certain - /// action has been caused when a state is entered. - /// - /// FSM state types are expected to be enum (i.e. sum) types. A - /// state is considered "new" and enter calls are run if is of a - /// different enum variant. - fn enter(&self) -> Vec<Self::Action>; - - /// `act` interprets and executes FSM actions. This is the only - /// part of an FSM in which side-effects are allowed. - fn act(action: Self::Action, state: &Self::State) -> Result<Vec<Self::Event>, Self::Error>; -} - -/// This function is the primary function used to advance a state -/// machine. It takes care of both running the event handler as well -/// as possible state-enter calls and returning the result. -/// -/// Users of Finito should basically always use this function when -/// advancing state-machines manually, and never call FSM-trait -/// methods directly. -pub fn advance<S: FSM>(state: S, event: S::Event) -> (S, Vec<S::Action>) { - // Determine the enum variant of the initial state (used to - // trigger enter calls). - let old_discriminant = mem::discriminant(&state); - - let (new_state, mut actions) = state.handle(event); - - // Compare the enum variant of the resulting state to the old one - // and run `enter` if they differ. - let new_discriminant = mem::discriminant(&new_state); - let mut enter_actions = if old_discriminant != new_discriminant { - new_state.enter() - } else { - vec![] - }; - - actions.append(&mut enter_actions); - - (new_state, actions) -} - -/// This trait is implemented by Finito backends. Backends are -/// expected to be able to keep track of the current state of an FSM -/// and retrieve it / apply updates transactionally. -/// -/// See the `finito-postgres` and `finito-in-mem` crates for example -/// implementations of this trait. -/// -/// Backends must be parameterised over an additional (user-supplied) -/// state type which can be used to track application state that must -/// be made available to action handlers, for example to pass along -/// database connections. -pub trait FSMBackend<S: 'static> { - /// Key type used to identify individual state machines in this - /// backend. - /// - /// TODO: Should be parameterised over FSM type after rustc - /// #44265. - type Key; - - /// Error type for all potential failures that can occur when - /// interacting with this backend. - type Error: Debug; - - /// Insert a new state-machine into the backend's storage and - /// return its newly allocated key. - fn insert_machine<F>(&self, initial: F) -> Result<Self::Key, Self::Error> - where - F: FSM + Serialize + DeserializeOwned; - - /// Retrieve the current state of an FSM by its key. - fn get_machine<F: FSM>(&self, key: Self::Key) -> Result<F, Self::Error> - where - F: FSM + Serialize + DeserializeOwned; - - /// Advance a state machine by applying an event and persisting it - /// as well as any resulting actions. - /// - /// **Note**: Whether actions are automatically executed depends - /// on the backend used. Please consult the backend's - /// documentation for details. - fn advance<'a, F: FSM>(&'a self, key: Self::Key, event: F::Event) -> Result<F, Self::Error> - where - F: FSM + Serialize + DeserializeOwned, - F::State: From<&'a S>, - F::Event: Serialize + DeserializeOwned, - F::Action: Serialize + DeserializeOwned; -} diff --git a/users/tazjin/finito/finito-door/Cargo.toml b/users/tazjin/finito/finito-door/Cargo.toml deleted file mode 100644 index 32c0a5a7c..000000000 --- a/users/tazjin/finito/finito-door/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "finito-door" -version = "0.1.0" -authors = ["Vincent Ambo <mail@tazj.in>"] - -[dependencies] -failure = "0.1" -serde = "1.0" -serde_derive = "1.0" - -[dependencies.finito] -path = "../finito-core" diff --git a/users/tazjin/finito/finito-door/src/lib.rs b/users/tazjin/finito/finito-door/src/lib.rs deleted file mode 100644 index 441ab0e3d..000000000 --- a/users/tazjin/finito/finito-door/src/lib.rs +++ /dev/null @@ -1,333 +0,0 @@ -//! Example implementation of a lockable door in Finito -//! -//! # What & why? -//! -//! This module serves as a (hopefully simple) example of how to -//! implement finite-state machines using Finito. Note that the -//! concepts of Finito itself won't be explained in detail here, -//! consult its library documentation for that. -//! -//! Reading through this module should give you a rough idea of how to -//! work with Finito and get you up and running modeling things -//! *quickly*. -//! -//! Note: The generated documentation for this module will display the -//! various components of the door, but it will not inform you about -//! the actual transition logic and all that stuff. Read the source, -//! too! -//! -//! # The Door -//! -//! My favourite example when explaining these state-machines -//! conceptually has been to use a simple, lockable door. Our door has -//! a keypad next to it which can be used to lock the door by entering -//! a code, after which the same code must be entered to unlock it -//! again. -//! -//! The door can only be locked if it is closed. Oh, and it has a few -//! extra features: -//! -//! * whenever the door's state changes, an IRC channel receives a message about -//! that -//! -//! * the door calls the police if the code is intered incorrectly more than a -//! specified number of times (mhm, lets say, three) -//! -//! * if the police is called the door can not be interacted with anymore (and -//! honestly, for the sake of this example, we don't care how its -//! functionality is restored) -//! -//! ## The Door - Visualized -//! -//! Here's a rough attempt at drawing a state diagram in ASCII. The -//! bracketed words denote states, the arrows denote events: -//! -//! ```text -//! <--Open--- <--Unlock-- correct code? --Unlock--> -//! [Opened] [Closed] [Locked] [Disabled] -//! --Close--> ----Lock--> -//! ``` -//! -//! I'm so sorry for that drawing. -//! -//! ## The Door - Usage example -//! -//! An interaction session with our final door could look like this: -//! -//! ```rust,ignore -//! use finito_postgres::{insert_machine, advance}; -//! -//! let door = insert_machine(&conn, &DoorState::Opened)?; -//! -//! advance(&conn, &door, DoorEvent::Close)?; -//! advance(&conn, &door, DoorEvent::Lock(1337))?; -//! -//! format!("Door is now: {}", get_machine(&conn, &door)?); -//! ``` -//! -//! Here we have created, closed and then locked a door and inspected -//! its state. We will see that it is locked, has the locking code we -//! gave it and three remaining attempts to open it. -//! -//! Alright, enough foreplay, lets dive in! - -#[macro_use] -extern crate serde_derive; - -extern crate failure; -extern crate finito; - -use finito::FSM; - -/// Type synonym to represent the code with which the door is locked. This -/// exists only for clarity in the signatures below and please do not email me -/// about the fact that an integer is not actually a good representation of -/// numerical digits. Thanks! -type Code = usize; - -/// Type synonym to represent the remaining number of unlock attempts. -type Attempts = usize; - -/// This type represents the possible door states and the data that they carry. -/// We can infer this from the "diagram" in the documentation above. -/// -/// This type is the one for which `finito::FSM` will be implemented, making it -/// the wooden (?) heart of our door. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub enum DoorState { - /// In `Opened` state, the door is wide open and anyone who fits through can - /// go through. - Opened, - - /// In `Closed` state, the door is shut but does not prevent anyone from - /// opening it. - Closed, - - /// In `Locked` state, the door is locked and waiting for someone to enter - /// its locking code on the keypad. - /// - /// This state contains the code that the door is locked with, as well as - /// the remaining number of attempts before the door calls the police and - /// becomes unusable. - Locked { code: Code, attempts: Attempts }, - - /// This state represents a disabled door after the police has been called. - /// The police will need to unlock it manually! - Disabled, -} - -/// This type represents the events that can occur in our door, i.e. the input -/// and interactions it receives. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub enum DoorEvent { - /// `Open` means someone is opening the door! - Open, - - /// `Close` means, you guessed it, the exact opposite. - Close, - - /// `Lock` means somebody has entered a locking code on the - /// keypad. - Lock(Code), - - /// `Unlock` means someone has attempted to unlock the door. - Unlock(Code), -} - -/// This type represents the possible actions, a.k.a. everything our door "does" -/// that does not just impact itself, a.k.a. side-effects. -/// -/// **Note**: This type by itself *is not* a collection of side-effects, it -/// merely describes the side-effects we want to occur (which are then -/// interpreted by the machinery later). -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub enum DoorAction { - /// `NotifyIRC` is used to display some kind of message on the - /// aforementioned IRC channel that is, for some reason, very interested in - /// the state of the door. - NotifyIRC(String), - - /// `CallThePolice` does what you think it does. - /// - /// **Note**: For safety reasons, causing this action is not recommended for - /// users inside the US! - CallThePolice, -} - -/// This trait implementation turns our 'DoorState' into a type actually -/// representing a finite-state machine. To implement it, we need to do three -/// main things: -/// -/// * Define what our associated `Event` and `Action` type should be -/// -/// * Define the event-handling and state-entering logic (i.e. the meat of the -/// ... door) -/// -/// * Implement the interpretation of our actions, i.e. implement actual -/// side-effects -impl FSM for DoorState { - const FSM_NAME: &'static str = "door"; - - // As you might expect, our `Event` type is 'DoorEvent' and our `Action` - // type is 'DoorAction'. - type Event = DoorEvent; - type Action = DoorAction; - type State = (); - - // For error handling, the door simply uses `failure` which provides a - // generic, chainable error type. In real-world implementations you may want - // to use a custom error type or similar. - type Error = failure::Error; - - // The implementation of `handle` provides us with the actual transition - // logic of the door. - // - // The door is conceptually not that complicated so it is relatively short. - fn handle(self, event: DoorEvent) -> (Self, Vec<DoorAction>) { - match (self, event) { - // An opened door can be closed: - (DoorState::Opened, DoorEvent::Close) => return (DoorState::Closed, vec![]), - - // A closed door can be opened: - (DoorState::Closed, DoorEvent::Open) => return (DoorState::Opened, vec![]), - - // A closed door can also be locked, in which case the locking code - // is stored with the next state and the unlock attempts default to - // three: - (DoorState::Closed, DoorEvent::Lock(code)) => { - return (DoorState::Locked { code, attempts: 3 }, vec![]) - } - - // A locked door receiving an `Unlock`-event can do several - // different things ... - (DoorState::Locked { code, attempts }, DoorEvent::Unlock(unlock_code)) => { - // In the happy case, entry of a correct code leads to the door - // becoming unlocked (i.e. transitioning back to `Closed`). - if code == unlock_code { - return (DoorState::Closed, vec![]); - } - - // If the code wasn't correct and the fraudulent unlocker ran - // out of attempts (i.e. there was only one attempt remaining), - // it's time for some consequences. - if attempts == 1 { - return (DoorState::Disabled, vec![DoorAction::CallThePolice]); - } - - // If the code wasn't correct, but there are still some - // remaining attempts, the user doesn't have to face the police - // quite yet but IRC gets to laugh about it. - return ( - DoorState::Locked { - code, - attempts: attempts - 1, - }, - vec![DoorAction::NotifyIRC("invalid code entered".into())], - ); - } - - // This actually already concludes our event-handling logic. Our - // uncaring door does absolutely nothing if you attempt to do - // something with it that it doesn't support, so the last handler is - // a simple fallback. - // - // In a real-world state machine, especially one that receives - // events from external sources, you may want fallback handlers to - // actually do something. One example could be creating an action - // that logs information about unexpected events, alerts a - // monitoring service, or whatever else. - (current, _) => (current, vec![]), - } - } - - // The implementation of `enter` lets door states cause additional actions - // they are transitioned to. In the door example we use this only to notify - // IRC about what is going on. - fn enter(&self) -> Vec<DoorAction> { - let msg = match self { - DoorState::Opened => "door was opened", - DoorState::Closed => "door was closed", - DoorState::Locked { .. } => "door was locked", - DoorState::Disabled => "door was disabled", - }; - - vec![DoorAction::NotifyIRC(msg.into())] - } - - // The implementation of `act` lets us perform actual side-effects. - // - // Again, for the sake of educational simplicity, this does not deal with - // all potential (or in fact any) error cases that can occur during this toy - // implementation of actions. - // - // Additionally the `act` function can return new events. This is useful for - // a sort of "callback-like" pattern (cause an action to fetch some data, - // receive it as an event) but is not used in this example. - fn act(action: DoorAction, _state: &()) -> Result<Vec<DoorEvent>, failure::Error> { - match action { - DoorAction::NotifyIRC(msg) => { - use std::fs::OpenOptions; - use std::io::Write; - - let mut file = OpenOptions::new() - .append(true) - .create(true) - .open("/tmp/door-irc.log")?; - - write!(file, "<doorbot> {}\n", msg)?; - Ok(vec![]) - } - - DoorAction::CallThePolice => { - // TODO: call the police - println!("The police was called! For real!"); - Ok(vec![]) - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use finito::advance; - - fn test_fsm<S: FSM>(initial: S, events: Vec<S::Event>) -> (S, Vec<S::Action>) { - events - .into_iter() - .fold((initial, vec![]), |(state, mut actions), event| { - let (new_state, mut new_actions) = advance(state, event); - actions.append(&mut new_actions); - (new_state, actions) - }) - } - - #[test] - fn test_door() { - let initial = DoorState::Opened; - let events = vec![ - DoorEvent::Close, - DoorEvent::Open, - DoorEvent::Close, - DoorEvent::Lock(1234), - DoorEvent::Unlock(1234), - DoorEvent::Lock(4567), - DoorEvent::Unlock(1234), - ]; - let (final_state, actions) = test_fsm(initial, events); - - assert_eq!(final_state, DoorState::Locked { - code: 4567, - attempts: 2 - }); - assert_eq!(actions, vec![ - DoorAction::NotifyIRC("door was closed".into()), - DoorAction::NotifyIRC("door was opened".into()), - DoorAction::NotifyIRC("door was closed".into()), - DoorAction::NotifyIRC("door was locked".into()), - DoorAction::NotifyIRC("door was closed".into()), - DoorAction::NotifyIRC("door was locked".into()), - DoorAction::NotifyIRC("invalid code entered".into()), - ]); - } -} diff --git a/users/tazjin/finito/finito-postgres/Cargo.toml b/users/tazjin/finito/finito-postgres/Cargo.toml deleted file mode 100644 index dd8d1d000..000000000 --- a/users/tazjin/finito/finito-postgres/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "finito-postgres" -version = "0.1.0" -authors = ["Vincent Ambo <mail@tazj.in>"] - -[dependencies] -chrono = "0.4" -postgres-derive = "0.3" -serde = "1.0" -serde_json = "1.0" -r2d2_postgres = "0.14" - -[dependencies.postgres] -version = "0.15" -features = [ "with-uuid", "with-chrono", "with-serde_json" ] - -[dependencies.uuid] -version = "0.5" -features = [ "v4" ] - -[dependencies.finito] -path = "../finito-core" - -[dev-dependencies.finito-door] -path = "../finito-door" diff --git a/users/tazjin/finito/finito-postgres/migrations/2018-09-26-160621_bootstrap_finito_schema/down.sql b/users/tazjin/finito/finito-postgres/migrations/2018-09-26-160621_bootstrap_finito_schema/down.sql deleted file mode 100644 index 9b56f9d35..000000000 --- a/users/tazjin/finito/finito-postgres/migrations/2018-09-26-160621_bootstrap_finito_schema/down.sql +++ /dev/null @@ -1,4 +0,0 @@ -DROP TABLE actions; -DROP TYPE ActionStatus; -DROP TABLE events; -DROP TABLE machines; diff --git a/users/tazjin/finito/finito-postgres/migrations/2018-09-26-160621_bootstrap_finito_schema/up.sql b/users/tazjin/finito/finito-postgres/migrations/2018-09-26-160621_bootstrap_finito_schema/up.sql deleted file mode 100644 index 18ace393b..000000000 --- a/users/tazjin/finito/finito-postgres/migrations/2018-09-26-160621_bootstrap_finito_schema/up.sql +++ /dev/null @@ -1,37 +0,0 @@ --- Creates the initial schema required by finito-postgres. - -CREATE TABLE machines ( - id UUID PRIMARY KEY, - created TIMESTAMPTZ NOT NULL DEFAULT NOW(), - fsm TEXT NOT NULL, - state JSONB NOT NULL -); - -CREATE TABLE events ( - id UUID PRIMARY KEY, - created TIMESTAMPTZ NOT NULL DEFAULT NOW(), - fsm TEXT NOT NULL, - fsm_id UUID NOT NULL REFERENCES machines(id), - event JSONB NOT NULL -); -CREATE INDEX idx_events_machines ON events(fsm_id); - -CREATE TYPE ActionStatus AS ENUM ( - 'Pending', - 'Completed', - 'Failed' -); - -CREATE TABLE actions ( - id UUID PRIMARY KEY, - created TIMESTAMPTZ NOT NULL DEFAULT NOW(), - fsm TEXT NOT NULL, - fsm_id UUID NOT NULL REFERENCES machines(id), - event_id UUID NOT NULL REFERENCES events(id), - content JSONB NOT NULL, - status ActionStatus NOT NULL, - error TEXT -); - -CREATE INDEX idx_actions_machines ON actions(fsm_id); -CREATE INDEX idx_actions_events ON actions(event_id); diff --git a/users/tazjin/finito/finito-postgres/src/error.rs b/users/tazjin/finito/finito-postgres/src/error.rs deleted file mode 100644 index ed33775cd..000000000 --- a/users/tazjin/finito/finito-postgres/src/error.rs +++ /dev/null @@ -1,103 +0,0 @@ -//! This module defines error types and conversions for issue that can -//! occur while dealing with persisted state machines. - -use std::error::Error as StdError; -use std::{fmt, result}; -use uuid::Uuid; - -// errors to chain: -use postgres::Error as PgError; -use r2d2_postgres::r2d2::Error as PoolError; -use serde_json::Error as JsonError; - -pub type Result<T> = result::Result<T, Error>; - -#[derive(Debug)] -pub struct Error { - pub kind: ErrorKind, - pub context: Option<String>, -} - -#[derive(Debug)] -pub enum ErrorKind { - /// Errors occuring during JSON serialization of FSM types. - Serialization(String), - - /// Errors occuring during communication with the database. - Database(String), - - /// Errors with the database connection pool. - DBPool(String), - - /// State machine could not be found. - FSMNotFound(Uuid), - - /// Action could not be found. - ActionNotFound(Uuid), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use ErrorKind::*; - let msg = match &self.kind { - Serialization(err) => format!("JSON serialization error: {}", err), - - Database(err) => format!("PostgreSQL error: {}", err), - - DBPool(err) => format!("Database connection pool error: {}", err), - - FSMNotFound(id) => format!("FSM with ID {} not found", id), - - ActionNotFound(id) => format!("Action with ID {} not found", id), - }; - - match &self.context { - None => write!(f, "{}", msg), - Some(ctx) => write!(f, "{}: {}", ctx, msg), - } - } -} - -impl StdError for Error {} - -impl<E: Into<ErrorKind>> From<E> for Error { - fn from(err: E) -> Error { - Error { - kind: err.into(), - context: None, - } - } -} - -impl From<JsonError> for ErrorKind { - fn from(err: JsonError) -> ErrorKind { - ErrorKind::Serialization(err.to_string()) - } -} - -impl From<PgError> for ErrorKind { - fn from(err: PgError) -> ErrorKind { - ErrorKind::Database(err.to_string()) - } -} - -impl From<PoolError> for ErrorKind { - fn from(err: PoolError) -> ErrorKind { - ErrorKind::DBPool(err.to_string()) - } -} - -/// Helper trait that makes it possible to supply contextual -/// information with an error. -pub trait ResultExt<T> { - fn context<C: fmt::Display>(self, ctx: C) -> Result<T>; -} - -impl<T, E: Into<Error>> ResultExt<T> for result::Result<T, E> { - fn context<C: fmt::Display>(self, ctx: C) -> Result<T> { - self.map_err(|err| Error { - context: Some(format!("{}", ctx)), - ..err.into() - }) - } -} diff --git a/users/tazjin/finito/finito-postgres/src/lib.rs b/users/tazjin/finito/finito-postgres/src/lib.rs deleted file mode 100644 index ea63cc9df..000000000 --- a/users/tazjin/finito/finito-postgres/src/lib.rs +++ /dev/null @@ -1,456 +0,0 @@ -//! PostgreSQL-backed persistence for Finito state machines -//! -//! This module implements ... TODO when I can write again. -//! -//! TODO: events & actions should have `SERIAL` keys - -#[macro_use] -extern crate postgres; -#[macro_use] -extern crate postgres_derive; - -extern crate chrono; -extern crate finito; -extern crate r2d2_postgres; -extern crate serde; -extern crate serde_json; -extern crate uuid; - -#[cfg(test)] -mod tests; -#[cfg(test)] -extern crate finito_door; - -mod error; -pub use error::{Error, ErrorKind, Result}; - -use chrono::prelude::{DateTime, Utc}; -use error::ResultExt; -use finito::{FSMBackend, FSM}; -use postgres::transaction::Transaction; -use postgres::GenericConnection; -use r2d2_postgres::{r2d2, PostgresConnectionManager}; -use serde::de::DeserializeOwned; -use serde::Serialize; -use serde_json::Value; -use std::marker::PhantomData; -use uuid::Uuid; - -type DBPool = r2d2::Pool<PostgresConnectionManager>; -type DBConn = r2d2::PooledConnection<PostgresConnectionManager>; - -/// This struct represents rows in the database table in which events -/// are persisted. -#[derive(Debug, ToSql, FromSql)] -struct EventT { - /// ID of the persisted event. - id: Uuid, - - /// Timestamp at which the event was stored. - created: DateTime<Utc>, - - /// Name of the type of FSM that this state belongs to. - fsm: String, - - /// ID of the state machine belonging to this event. - fsm_id: Uuid, - - /// Serialised content of the event. - event: Value, -} - -/// This enum represents the possible statuses an action can be in. -#[derive(Debug, PartialEq, ToSql, FromSql)] -#[postgres(name = "actionstatus")] -enum ActionStatus { - /// The action was requested but has not run yet. - Pending, - - /// The action completed successfully. - Completed, - - /// The action failed to run. Information about the error will - /// have been persisted in Postgres. - Failed, -} - -/// This struct represents rows in the database table in which actions -/// are persisted. -#[derive(Debug, ToSql, FromSql)] -struct ActionT { - /// ID of the persisted event. - id: Uuid, - - /// Timestamp at which the event was stored. - created: DateTime<Utc>, - - /// Name of the type of FSM that this state belongs to. - fsm: String, - - /// ID of the state machine belonging to this event. - fsm_id: Uuid, - - /// ID of the event that resulted in this action. - event_id: Uuid, - - /// Serialised content of the action. - #[postgres(name = "content")] // renamed because 'action' is a keyword in PG - action: Value, - - /// Current status of the action. - status: ActionStatus, - - /// Detailed (i.e. Debug-trait formatted) error message, if an - /// error occured during action processing. - error: Option<String>, -} - -// The following functions implement the public interface of -// `finito-postgres`. - -/// TODO: Write docs for this type, brain does not want to do it right -/// now. -pub struct FinitoPostgres<S> { - state: S, - - db_pool: DBPool, -} - -impl<S> FinitoPostgres<S> { - pub fn new(state: S, db_pool: DBPool, _pool_size: usize) -> Self { - FinitoPostgres { state, db_pool } - } -} - -impl<State: 'static> FSMBackend<State> for FinitoPostgres<State> { - type Key = Uuid; - type Error = Error; - - fn insert_machine<S: FSM + Serialize>(&self, initial: S) -> Result<Uuid> { - let query = r#" - INSERT INTO machines (id, fsm, state) - VALUES ($1, $2, $3) - "#; - - let id = Uuid::new_v4(); - let fsm = S::FSM_NAME.to_string(); - let state = serde_json::to_value(initial).context("failed to serialise FSM")?; - - self.conn()? - .execute(query, &[&id, &fsm, &state]) - .context("failed to insert FSM")?; - - return Ok(id); - } - - fn get_machine<S: FSM + DeserializeOwned>(&self, key: Uuid) -> Result<S> { - get_machine_internal(&*self.conn()?, key, false) - } - - /// Advance a persisted state machine by applying an event, and - /// storing the event as well as all resulting actions. - /// - /// This function holds a database-lock on the state's row while - /// advancing the machine. - /// - /// **Note**: This function returns the new state of the machine - /// immediately after applying the event, however this does not - /// necessarily equate to the state of the machine after all related - /// processing is finished as running actions may result in additional - /// transitions. - fn advance<'a, S>(&'a self, key: Uuid, event: S::Event) -> Result<S> - where - S: FSM + Serialize + DeserializeOwned, - S::State: From<&'a State>, - S::Event: Serialize + DeserializeOwned, - S::Action: Serialize + DeserializeOwned, - { - let conn = self.conn()?; - let tx = conn.transaction().context("could not begin transaction")?; - let state = get_machine_internal(&tx, key, true)?; - - // Advancing the FSM consumes the event, so it is persisted first: - let event_id = insert_event::<_, S>(&tx, key, &event)?; - - // Core advancing logic is run: - let (new_state, actions) = finito::advance(state, event); - - // Resulting actions are persisted (TODO: and interpreted) - let mut action_ids = vec![]; - for action in actions { - let action_id = insert_action::<_, S>(&tx, key, event_id, &action)?; - action_ids.push(action_id); - } - - // And finally the state is updated: - update_state(&tx, key, &new_state)?; - tx.commit().context("could not commit transaction")?; - - self.run_actions::<S>(key, action_ids); - - Ok(new_state) - } -} - -impl<State: 'static> FinitoPostgres<State> { - /// Execute several actions at the same time, each in a separate - /// thread. Note that actions returning further events, causing - /// further transitions, returning further actions and so on will - /// potentially cause multiple threads to get created. - fn run_actions<'a, S>(&'a self, fsm_id: Uuid, action_ids: Vec<Uuid>) - where - S: FSM + Serialize + DeserializeOwned, - S::Event: Serialize + DeserializeOwned, - S::Action: Serialize + DeserializeOwned, - S::State: From<&'a State>, - { - let state: S::State = (&self.state).into(); - let conn = self.conn().expect("TODO"); - - for action_id in action_ids { - let tx = conn.transaction().expect("TODO"); - - // TODO: Determine which concurrency setup we actually want. - if let Ok(events) = run_action(tx, action_id, &state, PhantomData::<S>) { - for event in events { - self.advance::<S>(fsm_id, event).expect("TODO"); - } - } - } - } - - /// Retrieve a single connection from the database connection pool. - fn conn(&self) -> Result<DBConn> { - self.db_pool - .get() - .context("failed to retrieve connection from pool") - } -} - -/// Insert a single state-machine into the database and return its -/// newly allocated, random UUID. -pub fn insert_machine<C, S>(conn: &C, initial: S) -> Result<Uuid> -where - C: GenericConnection, - S: FSM + Serialize, -{ - let query = r#" - INSERT INTO machines (id, fsm, state) - VALUES ($1, $2, $3) - "#; - - let id = Uuid::new_v4(); - let fsm = S::FSM_NAME.to_string(); - let state = serde_json::to_value(initial).context("failed to serialize FSM")?; - - conn.execute(query, &[&id, &fsm, &state])?; - - return Ok(id); -} - -/// Insert a single event into the database and return its UUID. -fn insert_event<C, S>(conn: &C, fsm_id: Uuid, event: &S::Event) -> Result<Uuid> -where - C: GenericConnection, - S: FSM, - S::Event: Serialize, -{ - let query = r#" - INSERT INTO events (id, fsm, fsm_id, event) - VALUES ($1, $2, $3, $4) - "#; - - let id = Uuid::new_v4(); - let fsm = S::FSM_NAME.to_string(); - let event_value = serde_json::to_value(event).context("failed to serialize event")?; - - conn.execute(query, &[&id, &fsm, &fsm_id, &event_value])?; - return Ok(id); -} - -/// Insert a single action into the database and return its UUID. -fn insert_action<C, S>(conn: &C, fsm_id: Uuid, event_id: Uuid, action: &S::Action) -> Result<Uuid> -where - C: GenericConnection, - S: FSM, - S::Action: Serialize, -{ - let query = r#" - INSERT INTO actions (id, fsm, fsm_id, event_id, content, status) - VALUES ($1, $2, $3, $4, $5, $6) - "#; - - let id = Uuid::new_v4(); - let fsm = S::FSM_NAME.to_string(); - let action_value = serde_json::to_value(action).context("failed to serialize action")?; - - conn.execute(query, &[ - &id, - &fsm, - &fsm_id, - &event_id, - &action_value, - &ActionStatus::Pending, - ])?; - - return Ok(id); -} - -/// Update the state of a specified machine. -fn update_state<C, S>(conn: &C, fsm_id: Uuid, state: &S) -> Result<()> -where - C: GenericConnection, - S: FSM + Serialize, -{ - let query = r#" - UPDATE machines SET state = $1 WHERE id = $2 - "#; - - let state_value = serde_json::to_value(state).context("failed to serialize FSM")?; - let res_count = conn.execute(query, &[&state_value, &fsm_id])?; - - if res_count != 1 { - Err(ErrorKind::FSMNotFound(fsm_id).into()) - } else { - Ok(()) - } -} - -/// Conditionally alter SQL statement to append locking clause inside -/// of a transaction. -fn alter_for_update(alter: bool, query: &str) -> String { - match alter { - false => query.to_string(), - true => format!("{} FOR UPDATE", query), - } -} - -/// Retrieve the current state of a state machine from the database, -/// optionally locking the machine state for the duration of some -/// enclosing transaction. -fn get_machine_internal<C, S>(conn: &C, id: Uuid, for_update: bool) -> Result<S> -where - C: GenericConnection, - S: FSM + DeserializeOwned, -{ - let query = alter_for_update( - for_update, - r#" - SELECT state FROM machines WHERE id = $1 - "#, - ); - - let rows = conn - .query(&query, &[&id]) - .context("failed to retrieve FSM")?; - - if let Some(row) = rows.into_iter().next() { - Ok(serde_json::from_value(row.get(0)).context("failed to deserialize FSM")?) - } else { - Err(ErrorKind::FSMNotFound(id).into()) - } -} - -/// Retrieve an action from the database, optionally locking it for -/// the duration of some enclosing transaction. -fn get_action<C, S>(conn: &C, id: Uuid) -> Result<(ActionStatus, S::Action)> -where - C: GenericConnection, - S: FSM, - S::Action: DeserializeOwned, -{ - let query = alter_for_update( - true, - r#" - SELECT status, content FROM actions - WHERE id = $1 AND fsm = $2 - "#, - ); - - let rows = conn.query(&query, &[&id, &S::FSM_NAME])?; - - if let Some(row) = rows.into_iter().next() { - let action = - serde_json::from_value(row.get(1)).context("failed to deserialize FSM action")?; - Ok((row.get(0), action)) - } else { - Err(ErrorKind::ActionNotFound(id).into()) - } -} - -/// Update the status of an action after an attempt to run it. -fn update_action_status<C, S>( - conn: &C, - id: Uuid, - status: ActionStatus, - error: Option<String>, - _fsm: PhantomData<S>, -) -> Result<()> -where - C: GenericConnection, - S: FSM, -{ - let query = r#" - UPDATE actions SET status = $1, error = $2 - WHERE id = $3 AND fsm = $4 - "#; - - let result = conn.execute(&query, &[&status, &error, &id, &S::FSM_NAME])?; - - if result != 1 { - Err(ErrorKind::ActionNotFound(id).into()) - } else { - Ok(()) - } -} - -/// Execute a single action in case it is pending or retryable. Holds -/// a lock on the action's database row while performing the action -/// and writes back the status afterwards. -/// -/// Should the execution of an action fail cleanly (i.e. without a -/// panic), the error will be persisted. Should it fail by panicking -/// (which developers should never do explicitly in action -/// interpreters) its status will not be changed. -fn run_action<S>( - tx: Transaction, - id: Uuid, - state: &S::State, - _fsm: PhantomData<S>, -) -> Result<Vec<S::Event>> -where - S: FSM, - S::Action: DeserializeOwned, -{ - let (status, action) = get_action::<Transaction, S>(&tx, id)?; - - let result = match status { - ActionStatus::Pending => { - match S::act(action, state) { - // If the action succeeded, update its status to - // completed and return the created events. - Ok(events) => { - update_action_status(&tx, id, ActionStatus::Completed, None, PhantomData::<S>)?; - events - } - - // If the action failed, persist the debug message and - // return nothing. - Err(err) => { - let msg = Some(format!("{:?}", err)); - update_action_status(&tx, id, ActionStatus::Failed, msg, PhantomData::<S>)?; - vec![] - } - } - } - - _ => { - // TODO: Currently only pending actions are run because - // retryable actions are not yet implemented. - vec![] - } - }; - - tx.commit().context("failed to commit transaction")?; - Ok(result) -} diff --git a/users/tazjin/finito/finito-postgres/src/tests.rs b/users/tazjin/finito/finito-postgres/src/tests.rs deleted file mode 100644 index dd270c387..000000000 --- a/users/tazjin/finito/finito-postgres/src/tests.rs +++ /dev/null @@ -1,54 +0,0 @@ -use super::*; - -use finito_door::*; -use postgres::{Connection, TlsMode}; - -// TODO: read config from environment -fn open_test_connection() -> Connection { - Connection::connect("postgres://finito:finito@localhost/finito", TlsMode::None) - .expect("Failed to connect to test database") -} - -#[test] -fn test_insert_machine() { - let conn = open_test_connection(); - let initial = DoorState::Opened; - let door = insert_machine(&conn, initial).expect("Failed to insert door"); - let result = get_machine(&conn, &door, false).expect("Failed to fetch door"); - - assert_eq!( - result, - DoorState::Opened, - "Inserted door state should match" - ); -} - -#[test] -fn test_advance() { - let conn = open_test_connection(); - - let initial = DoorState::Opened; - let events = vec![ - DoorEvent::Close, - DoorEvent::Open, - DoorEvent::Close, - DoorEvent::Lock(1234), - DoorEvent::Unlock(1234), - DoorEvent::Lock(4567), - DoorEvent::Unlock(1234), - ]; - - let door = insert_machine(&conn, initial).expect("Failed to insert door"); - - for event in events { - advance(&conn, &door, event).expect("Failed to advance door FSM"); - } - - let result = get_machine(&conn, &door, false).expect("Failed to fetch door"); - let expected = DoorState::Locked { - code: 4567, - attempts: 2, - }; - - assert_eq!(result, expected, "Advanced door state should match"); -} diff --git a/users/tazjin/generator-example/.gitignore b/users/tazjin/generator-example/.gitignore deleted file mode 100644 index ea8c4bf7f..000000000 --- a/users/tazjin/generator-example/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/users/tazjin/generator-example/Cargo.lock b/users/tazjin/generator-example/Cargo.lock deleted file mode 100644 index a6f25ee39..000000000 --- a/users/tazjin/generator-example/Cargo.lock +++ /dev/null @@ -1,124 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "genawaiter" -version = "0.99.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86bd0361bcbde39b13475e6e36cb24c329964aa2611be285289d1e4b751c1a0" -dependencies = [ - "genawaiter-macro", - "genawaiter-proc-macro", - "proc-macro-hack", -] - -[[package]] -name = "genawaiter-macro" -version = "0.99.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b32dfe1fdfc0bbde1f22a5da25355514b5e450c33a6af6770884c8750aedfbc" - -[[package]] -name = "genawaiter-proc-macro" -version = "0.99.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784f84eebc366e15251c4a8c3acee82a6a6f427949776ecb88377362a9621738" -dependencies = [ - "proc-macro-error", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "generator-example" -version = "0.1.0" -dependencies = [ - "genawaiter", -] - -[[package]] -name = "proc-macro-error" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "syn-mid", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn-mid" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa8e7560a164edb1621a55d18a0c59abf49d360f47aa7b821061dd7eea7fac9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" diff --git a/users/tazjin/generator-example/Cargo.toml b/users/tazjin/generator-example/Cargo.toml deleted file mode 100644 index faf313973..000000000 --- a/users/tazjin/generator-example/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "generator-example" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -genawaiter = "0.99.1" diff --git a/users/tazjin/generator-example/README.md b/users/tazjin/generator-example/README.md deleted file mode 100644 index 0bec13ee9..000000000 --- a/users/tazjin/generator-example/README.md +++ /dev/null @@ -1,11 +0,0 @@ -generator-example -================= - -This is an experiment with the [`genawaiter`][] crate, to see if it -could be suitable for dealing with the execution flattening problem in -Tvix. - -It constructs a dummy example that is similar to some of the problems -we have in Tvix that require generator-like thunk forcing. - -[`genawaiter`]: https://docs.rs/genawaiter/latest/genawaiter/index.html diff --git a/users/tazjin/generator-example/src/main.rs b/users/tazjin/generator-example/src/main.rs deleted file mode 100644 index 4aa931caf..000000000 --- a/users/tazjin/generator-example/src/main.rs +++ /dev/null @@ -1,115 +0,0 @@ -use genawaiter::rc::{Co, Gen}; -use std::cell::RefCell; -use std::future::Future; -use std::pin::Pin; -use std::rc::Rc; - -#[derive(Debug)] -enum ValueRepr { - Int(i64), - Thunk((i64, i64)), -} - -#[derive(Clone, Debug)] -struct Value(Rc<RefCell<ValueRepr>>); - -impl Value { - fn force(&self) { - let mut inner = self.0.borrow_mut(); - match *inner { - ValueRepr::Int(_) => return, - ValueRepr::Thunk((a, b)) => { - *inner = ValueRepr::Int(a + b); - } - } - } - - fn is_forced(&self) -> bool { - matches!(*self.0.borrow(), ValueRepr::Int(_)) - } - - fn int(&self) -> i64 { - match *self.0.borrow() { - ValueRepr::Int(i) => i, - ValueRepr::Thunk(_) => panic!("unforced thunk!"), - } - } -} - -impl From<i64> for Value { - fn from(value: i64) -> Self { - Value(Rc::new(RefCell::new(ValueRepr::Int(value)))) - } -} - -impl From<(i64, i64)> for Value { - fn from(value: (i64, i64)) -> Self { - Value(Rc::new(RefCell::new(ValueRepr::Thunk(value)))) - } -} - -async fn list_maker(values: Vec<Value>, co: Co<Value>) -> Vec<i64> { - let mut output: Vec<i64> = vec![]; - - for value in values { - if !value.is_forced() { - co.yield_(value.clone()).await; - } - - output.push(value.int()); - } - - output -} - -async fn list_reverser(values: Vec<Value>, co: Co<Value>) -> Vec<i64> { - let mut output = list_maker(values, co).await; - output.reverse(); - output -} - -struct Frame { - gen: Gen<Value, (), Pin<Box<dyn Future<Output = Vec<i64>>>>>, -} - -fn pin_future( - f: impl Future<Output = Vec<i64>> + 'static, -) -> Pin<Box<dyn Future<Output = Vec<i64>>>> { - Box::pin(f) -} - -fn main() { - let mut frames: Vec<Frame> = vec![]; - - let values: Vec<Value> = vec![ - 42.into(), - (12, 54).into(), - 4.into(), - (40, 2).into(), - 2.into(), - ]; - let second = values.clone(); - - frames.push(Frame { - gen: Gen::new(|co| pin_future(list_maker(values, co))), - }); - - frames.push(Frame { - gen: Gen::new(|co| pin_future(list_reverser(second, co))), - }); - - for (idx, mut frame) in frames.into_iter().enumerate() { - loop { - match frame.gen.resume() { - genawaiter::GeneratorState::Yielded(val) => { - println!("yielded {:?} in frame {}", val, idx); - val.force(); - } - genawaiter::GeneratorState::Complete(list) => { - println!("result {}: {:?}", idx, list); - break; - } - } - } - } -} diff --git a/users/tazjin/german-string/.gitignore b/users/tazjin/german-string/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/users/tazjin/german-string/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/users/tazjin/german-string/Cargo.lock b/users/tazjin/german-string/Cargo.lock deleted file mode 100644 index ffd73ea32..000000000 --- a/users/tazjin/german-string/Cargo.lock +++ /dev/null @@ -1,399 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "german-string" -version = "0.1.0" -dependencies = [ - "proptest", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.156" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5f43f184355eefb8d17fc948dbecf6c13be3c141f20d834ae842193a448c72a" - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proptest" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" -dependencies = [ - "bit-set", - "bit-vec", - "bitflags", - "lazy_static", - "num-traits", - "rand", - "rand_chacha", - "rand_xorshift", - "regex-syntax", - "rusty-fork", - "tempfile", - "unarray", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rusty-fork" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" -dependencies = [ - "fnv", - "quick-error", - "tempfile", - "wait-timeout", -] - -[[package]] -name = "syn" -version = "2.0.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" -dependencies = [ - "cfg-if", - "fastrand", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "unarray" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "wait-timeout" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -dependencies = [ - "libc", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/users/tazjin/german-string/Cargo.toml b/users/tazjin/german-string/Cargo.toml deleted file mode 100644 index 8eec963f0..000000000 --- a/users/tazjin/german-string/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "german-string" -version = "0.1.0" -edition = "2021" - -[dev-dependencies] -proptest = "1.5.0" diff --git a/users/tazjin/german-string/default.nix b/users/tazjin/german-string/default.nix deleted file mode 100644 index c6cbc8c3c..000000000 --- a/users/tazjin/german-string/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ depot, pkgs, ... }: - -depot.third_party.naersk.buildPackage { - src = ./.; -} diff --git a/users/tazjin/german-string/src/lib.rs b/users/tazjin/german-string/src/lib.rs deleted file mode 100644 index 328eca309..000000000 --- a/users/tazjin/german-string/src/lib.rs +++ /dev/null @@ -1,435 +0,0 @@ -use std::alloc::Layout; -use std::cmp::Ordering; -use std::fmt::{Debug, Formatter}; - -#[derive(Clone, Copy)] -#[repr(C)] -struct GSSmall { - len: u32, - data: [u8; 12], -} - -#[derive(Clone, Copy)] -#[repr(transparent)] -struct StorageClassPtr(usize); - -impl StorageClassPtr { - fn transient(ptr: *const u8) -> Self { - debug_assert!( - (ptr as usize & 0b1) == 0, - "pointer must be at least 2-byte aligned" - ); - Self(ptr as usize) - } - - fn persistent(ptr: *const u8) -> Self { - debug_assert!( - (ptr as usize & 0b1) == 0, - "pointer must be at least 2-byte aligned" - ); - Self((ptr as usize) | 0b1) - } - - fn as_ptr(&self) -> *const u8 { - (self.0 & !0b1) as *const u8 - } - - unsafe fn as_mut_ptr(&self) -> *mut u8 { - (self.0 & !0b1) as *mut u8 - } - - fn is_transient(&self) -> bool { - (self.0 & 0b1) == 0 - } -} - -#[derive(Clone, Copy)] -#[repr(C)] -struct GSLarge { - len: u32, - prefix: [u8; 4], - data: StorageClassPtr, -} - -const _ASSERT_VARIANTS_SIZE: () = assert!( - std::mem::size_of::<GSSmall>() == std::mem::size_of::<GSLarge>(), - "German String variants must have the same size" -); - -union GSRepr { - small: GSSmall, - large: GSLarge, -} - -#[repr(transparent)] -pub struct GermanString(GSRepr); - -const _ASSERT_GSTRING_SIZE: () = assert!( - std::mem::size_of::<GermanString>() == 16, - "German String should be 16 bytes in size", -); - -impl GermanString { - /// Creates a new transient German String from the given slice, copying the - /// data in the process. - pub fn transient(bytes: &[u8]) -> GermanString { - if bytes.len() > u32::MAX as usize { - panic!("GermanString maximum length is {} bytes", u32::MAX); - } - - if bytes.len() <= 12 { - let mut s = GSSmall { - len: bytes.len() as u32, - data: [0u8; 12], - }; - s.data[..bytes.len()].copy_from_slice(bytes); - GermanString(GSRepr { small: s }) - } else { - let layout = Layout::array::<u8>(bytes.len()).unwrap(); - let mut large = GSLarge { - len: bytes.len() as u32, - prefix: [0u8; 4], - data: unsafe { - let ptr = std::alloc::alloc(layout); - if ptr.is_null() { - std::alloc::handle_alloc_error(layout); - } - std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, bytes.len()); - StorageClassPtr::transient(ptr) - }, - }; - - large.prefix.copy_from_slice(&bytes[..4]); - - GermanString(GSRepr { large }) - } - } - - /// Creates a new transient German String from the given owned bytes. Short - /// strings will be copied into the string representation, long strings will - /// be moved out of the given vector without additional allocations. - pub fn transient_from_owned(bytes: Vec<u8>) -> GermanString { - if bytes.len() > u32::MAX as usize { - panic!("GermanString maximum length is {} bytes", u32::MAX); - } - - if bytes.len() <= 12 { - let mut s = GSSmall { - len: bytes.len() as u32, - data: [0u8; 12], - }; - - s.data[..bytes.len()].copy_from_slice(&bytes); - GermanString(GSRepr { small: s }) - } else { - let md = std::mem::ManuallyDrop::new(bytes); - let mut large = GSLarge { - len: md.len() as u32, - prefix: [0u8; 4], - data: StorageClassPtr::transient(md.as_ptr()), - }; - - large.prefix.copy_from_slice(&md[..4]); - GermanString(GSRepr { large }) - } - } - - /// Creates a persistent German String from a static data buffer. - pub fn persistent(bytes: &'static [u8]) -> GermanString { - if bytes.len() > u32::MAX as usize { - panic!("GermanString maximum length is {} bytes", u32::MAX); - } - - if bytes.len() <= 12 { - let mut s = GSSmall { - len: bytes.len() as u32, - data: [0u8; 12], - }; - - s.data[..bytes.len()].copy_from_slice(&bytes); - GermanString(GSRepr { small: s }) - } else { - let mut large = GSLarge { - len: bytes.len() as u32, - prefix: [0u8; 4], - data: StorageClassPtr::persistent(bytes.as_ptr()), - }; - - large.prefix.copy_from_slice(&bytes[..4]); - GermanString(GSRepr { large }) - } - } - - /// Creates a persistent German String by leaking the provided data. - pub fn persistent_leak(bytes: Vec<u8>) -> GermanString { - if bytes.len() > u32::MAX as usize { - panic!("GermanString maximum length is {} bytes", u32::MAX); - } - - if bytes.len() <= 12 { - let mut s = GSSmall { - len: bytes.len() as u32, - data: [0u8; 12], - }; - - s.data[..bytes.len()].copy_from_slice(&bytes); - GermanString(GSRepr { small: s }) - } else { - let md = std::mem::ManuallyDrop::new(bytes); - let mut large = GSLarge { - len: md.len() as u32, - prefix: [0u8; 4], - data: StorageClassPtr::persistent(md.as_ptr()), - }; - - large.prefix.copy_from_slice(&md[..4]); - GermanString(GSRepr { large }) - } - } - - /// Creates a persistent German String from a static data buffer. - pub fn persistent_from_str(s: &'static str) -> GermanString { - GermanString::persistent(s.as_bytes()) - } - - pub fn len(&self) -> usize { - // SAFETY: The length field is located in the same location for both - // variants, reading it from either is safe. - unsafe { self.0.small.len as usize } - } - - pub fn as_bytes(&self) -> &[u8] { - if self.len() > 12 { - unsafe { std::slice::from_raw_parts(self.0.large.data.as_ptr(), self.len()) } - } else { - unsafe { &self.0.small.data.as_ref()[..self.len()] } - } - } - - pub fn as_str(&self) -> Result<&str, std::str::Utf8Error> { - std::str::from_utf8(self.as_bytes()) - } -} - -impl Drop for GermanString { - fn drop(&mut self) { - unsafe { - if self.len() > 12 && self.0.large.data.is_transient() { - let layout = Layout::array::<u8>(self.len()).unwrap(); - std::alloc::dealloc(self.0.large.data.as_mut_ptr(), layout); - } - } - } -} - -impl PartialEq for GermanString { - fn eq(&self, other: &GermanString) -> bool { - if self.len() != other.len() { - return false; - } - - unsafe { - if self.len() <= 12 { - return self.0.small.data[..self.len()] == other.0.small.data[..other.len()]; - } - return self.0.large.data.as_ptr() == other.0.large.data.as_ptr() - || (self.0.large.prefix == other.0.large.prefix - && self.as_bytes() == other.as_bytes()); - } - } -} - -impl Eq for GermanString {} - -impl Ord for GermanString { - fn cmp(&self, other: &GermanString) -> Ordering { - match (self.len().cmp(&12), other.len().cmp(&12)) { - // two small strings - (Ordering::Less | Ordering::Equal, Ordering::Less | Ordering::Equal) => unsafe { - self.0.small.data[..self.len()].cmp(&other.0.small.data[..other.len()]) - }, - // two large strings - (Ordering::Greater, Ordering::Greater) => unsafe { - match self.0.large.prefix.cmp(&other.0.large.prefix) { - Ordering::Equal => self.as_bytes().cmp(other.as_bytes()), - ordering => ordering, - } - }, - - // LHS large, RHS small - (Ordering::Greater, _) => { - let prefix_ordering = - unsafe { self.0.large.prefix.as_slice().cmp(&other.0.small.data[..4]) }; - - if prefix_ordering != Ordering::Equal { - return prefix_ordering; - } - - self.as_bytes().cmp(other.as_bytes()) - } - - // LHS small, RHS large - (_, Ordering::Greater) => { - let prefix_ordering = - unsafe { self.0.small.data[..4].cmp(other.0.large.prefix.as_slice()) }; - - if prefix_ordering != Ordering::Equal { - return prefix_ordering; - } - - self.as_bytes().cmp(other.as_bytes()) - } - } - } -} - -impl PartialOrd for GermanString { - fn partial_cmp(&self, other: &GermanString) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Debug for GermanString { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { - String::from_utf8_lossy(self.as_bytes()).fmt(f) - } -} - -impl Clone for GermanString { - fn clone(&self) -> Self { - unsafe { - if self.len() <= 12 { - return GermanString(GSRepr { - small: self.0.small.clone(), - }); - } - - if self.0.large.data.is_transient() { - return GermanString::transient(self.as_bytes()); - } - - return GermanString(GSRepr { - large: self.0.large.clone(), - }); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use proptest::prelude::*; - - impl Arbitrary for GermanString { - type Parameters = <String as Arbitrary>::Parameters; - type Strategy = BoxedStrategy<Self>; - - fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { - any_with::<String>(args) - .prop_map(|s| GermanString::transient(s.as_bytes())) - .boxed() - } - } - - #[test] - fn test_empty_string() { - let empty = GermanString::transient(b""); - - assert_eq!(empty.len(), 0, "empty string should be empty"); - assert_eq!(empty.as_bytes(), b"", "empty string should contain nothing"); - assert_eq!( - empty.as_str().expect("empty string is valid UTF-8"), - "", - "empty string should contain empty string" - ); - } - - #[test] - fn test_short_string() { - let short = GermanString::transient(b"meow"); - - assert_eq!(short.len(), 4, "'meow' is four characters"); - assert_eq!( - short.as_bytes(), - b"meow", - "short string returns correct bytes" - ); - assert_eq!( - short.as_str().expect("'meow' is valid UTF-8"), - "meow", - "short string returns correct string" - ); - } - - #[test] - fn test_long_string() { - let input: &str = "This code was written at https://signal.live"; - let long = GermanString::transient(input.as_bytes()); - - assert_eq!(long.len(), 44, "long string has correct length"); - assert_eq!( - long.as_bytes(), - input.as_bytes(), - "long string returns correct bytes" - ); - - assert_eq!( - long.as_str().expect("input is valid UTF-8"), - input, - "long string returns correct string" - ); - } - - proptest! { - #[test] - fn test_roundtrip_vec(input: Vec<u8>) { - let gs = GermanString::transient_from_owned(input.clone()); - assert_eq!(input.len(), gs.len(), "length should match"); - - let out = gs.as_bytes().to_owned(); - assert_eq!(input, out, "roundtrip should yield same bytes"); - } - - #[test] - fn test_roundtrip_string(input: String) { - let gs = GermanString::transient_from_owned(input.clone().into_bytes()); - assert_eq!(input.len(), gs.len(), "length should match"); - - let out = String::from_utf8(gs.as_bytes().to_owned()) - .expect("string should be valid after roundtrip"); - - assert_eq!(input, out, "roundtrip should yield same string"); - } - - // Test [`Eq`] implementation. - #[test] - fn test_eq(lhs: Vec<u8>, rhs: Vec<u8>) { - let lhs_gs = GermanString::transient(lhs.as_slice()); - let rhs_gs = GermanString::transient(rhs.as_slice()); - - assert_eq!( - (lhs == rhs), - (lhs_gs == rhs_gs), - "Eq should match between std::String and GermanString ({:?} == {:?})", - lhs, rhs, - ); - } - - #[test] - fn test_reflexivity(x: GermanString) { - prop_assert!(x == x); - } - - #[test] - fn test_symmetry(x: GermanString, y: GermanString) { - prop_assert_eq!(x == y, y == x); - } - - #[test] - fn test_transitivity(x: GermanString, y: GermanString, z: GermanString) { - if x == y && y == z { - assert!(x == z); - } - } - } -} diff --git a/users/tazjin/gio-list-apps/.gitignore b/users/tazjin/gio-list-apps/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/users/tazjin/gio-list-apps/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/users/tazjin/gio-list-apps/Cargo.lock b/users/tazjin/gio-list-apps/Cargo.lock deleted file mode 100644 index b475b35a6..000000000 --- a/users/tazjin/gio-list-apps/Cargo.lock +++ /dev/null @@ -1,616 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" - -[[package]] -name = "cfg-expr" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b40ccee03b5175c18cde8f37e7d2a33bcef6f8ec8f7cc0d81090d1bb380949c9" -dependencies = [ - "smallvec", - "target-lexicon", -] - -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "darling" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "emacs" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6797a940189d353de79bec32abe717aeeecd79a08236e84404c888354e040665" -dependencies = [ - "anyhow", - "ctor", - "emacs-macros", - "emacs_module", - "once_cell", - "rustc_version", - "thiserror", -] - -[[package]] -name = "emacs-macros" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69656fdfe7c2608b87164964db848b5c3795de7302e3130cce7131552c6be161" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "emacs_module" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3067bc974045ed2c6db333bd4fc30d3bdaafa6421a9a889fa7b2826b6f7f2fa" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-core", - "futures-macro", - "futures-task", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "gio" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7884cba6b1c5db1607d970cadf44b14a43913d42bc68766eea6a5e2fe0891524" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror", -] - -[[package]] -name = "gio-list-apps" -version = "0.1.0" -dependencies = [ - "emacs", - "gio", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "glib" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331156127e8166dd815cf8d2db3a5beb492610c716c03ee6db4f2d07092af0a7" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror", -] - -[[package]] -name = "glib-macros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "179643c50bf28d20d2f6eacd2531a88f2f5d9747dd0b86b8af1e8bb5dd0de3c0" -dependencies = [ - "heck", - "proc-macro-crate", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "hashbrown" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indexmap" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "serde_spanned" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" -dependencies = [ - "serde", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" - -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "system-deps" -version = "6.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" -dependencies = [ - "cfg-expr", - "heck", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "target-lexicon" -version = "0.12.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0e916b1148c8e263850e1ebcbd046f333e0683c724876bb0da63ea4373dc8a" - -[[package]] -name = "thiserror" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "toml" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - -[[package]] -name = "unicode-ident" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" - -[[package]] -name = "version-compare" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "winnow" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" -dependencies = [ - "memchr", -] diff --git a/users/tazjin/gio-list-apps/Cargo.toml b/users/tazjin/gio-list-apps/Cargo.toml deleted file mode 100644 index eb62d1fca..000000000 --- a/users/tazjin/gio-list-apps/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "gio-list-apps" -version = "0.1.0" -edition = "2021" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -emacs = "0.18.0" -gio = "0.18.1" diff --git a/users/tazjin/gio-list-apps/default.nix b/users/tazjin/gio-list-apps/default.nix deleted file mode 100644 index c63f4dd48..000000000 --- a/users/tazjin/gio-list-apps/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ depot, pkgs, lib, ... }: - -pkgs.rustPlatform.buildRustPackage { - name = "gio-list-apps"; - src = lib.cleanSource ./.; - cargoLock.lockFile = ./Cargo.lock; - nativeBuildInputs = [ pkgs.pkg-config ]; - buildInputs = [ pkgs.gtk3 depot.users.tazjin.emacs.emacs ]; - - postInstall = '' - mkdir -p $out/share/emacs/site-lisp - ln -s $out/lib/libgio_list_apps.so $out/share/emacs/site-lisp/gio-list-apps.so - ''; -} diff --git a/users/tazjin/gio-list-apps/src/lib.rs b/users/tazjin/gio-list-apps/src/lib.rs deleted file mode 100644 index 55eb8dc0b..000000000 --- a/users/tazjin/gio-list-apps/src/lib.rs +++ /dev/null @@ -1,31 +0,0 @@ -use emacs::{defun, Env, IntoLisp, Result, Value}; -use gio::traits::AppInfoExt; -use gio::AppInfo; - -emacs::plugin_is_GPL_compatible!(); - -#[emacs::module(defun_prefix = "taz", mod_in_name = false)] -fn init(_: &Env) -> Result<()> { - Ok(()) -} - -/// Returns an alist of the currently available XDG applications (through their -/// `.desktop' shortcuts), and the command line parameters needed to start them. -/// -/// Hidden applications or applications without specified command-line -/// parameters are not included. -#[defun] -fn list_xdg_apps(env: &Env) -> Result<Value> { - let mut visible_apps: Vec<Value> = vec![]; - - for app in AppInfo::all().into_iter().filter(AppInfo::should_show) { - if let Some(cmd) = app - .commandline() - .and_then(|p| Some(p.to_str()?.to_string())) - { - visible_apps.push(env.cons(app.name().as_str().into_lisp(env)?, cmd.into_lisp(env)?)?); - } - } - - env.list(&visible_apps) -} diff --git a/users/tazjin/gruber-darker.qss b/users/tazjin/gruber-darker.qss deleted file mode 100644 index 16f4c2f32..000000000 --- a/users/tazjin/gruber-darker.qss +++ /dev/null @@ -1,508 +0,0 @@ -/** -** Gruber Darker theme for Quassel. -** -** This theme derives from multiple different things: -** -** - Quassel DarkSolarized (https://gist.github.com/Zren/e91ad5197f9d6b6d410f) -** - Quassel Dracula (https://github.com/dracula/quassel) -** - gruber-darker for Emacs (https://github.com/rexim/gruber-darker-theme) -** - Original Gruber theme for BBEdit (https://daringfireball.net/projects/bbcolors/schemes/) -** -** This is a work-in-progress as I haven't figured out the point of -** all of the colours yet, and what I want them to be instead. -** -**/ - -/** -** Helpful Links: -** - QT: -** http://qt-project.org/doc/qt-4.8/stylesheet-syntax.html -** http://doc.qt.nokia.com/4.7-snapshot/stylesheet-reference.html -** http://doc.qt.nokia.com/4.7-snapshot/stylesheet-examples.html -** - Plastique Client Style: -** https://qt.gitorious.org/qt/qt/source/src/gui/styles/qplastiquestyle.cpp -** https://github.com/mirror/qt/blob/4.8/src/gui/styles/qplastiquestyle.cpp -** - Quassel Stylesheet Gallery: -** http://bugs.quassel-irc.org/projects/1/wiki/Stylesheet_Gallery -** http://bugs.quassel-irc.org/projects/1/wiki/Stylesheet_Gallery#DarkMonokaiqss -*/ - -/** -** - QSS Notes: -** Quassel stylesheets also support Palette { role: color; } for setting the system -** palette. See the QPalette docs for available roles, and convert them into qss-style -** attributes, so ButtonText would become button-text or see qssparser.cpp In fact, -** qssparser.cpp is the authorative source for Quassel's qss syntax that contains all -** the extensions over standard Qt qss syntax. -** See: -** http://qt-project.org/doc/qt-4.8/qpalette.html#ColorRole-enum -** https://github.com/quassel/quassel/blob/master/src/uisupport/qssparser.cpp -** -*/ - -Palette { - /* Window colors */ - window: #282828; - background: #181818; - foreground: #f4f4f4; - - base: #181818; - alternate-base: #282828; - - /* Just setting palette(tooltip-base) doesn't work as intended so we set it in - ** a QTooltip{} rule as well. - */ - tooltip-base: #282a36; // palette(base) TODO - tooltip-text: white; // palette(text) TODO - - /* The following attributes should be done in a scale */ - light: #444444; // Tab Borders, Scrollbar handle grips, Titled Panel border (Settings) - midlight: #333333; // ? - button: #292929; // Menu BG, Scrollbar and Button base. - mid: #252525; // Titled Panel border (Settings) - dark: #202020; // TreeView [-] and ... color (Also various borders in Windows Client Style) - shadow: #1d1d1d; // ? - - - /* Text colors */ - text: white; - button-text: #f8f8f2; - - highlight: #44475a; - - /* Link colors */ - link: #ff79c6; - link-visited: #bd93f9; - - /* Color of the marker line in the chat view. BG Node that is overlayed on the first new ChatLine. */ - // 0 -> 0.1 (sharp line) - marker-line: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #586e75, stop: 0.1 #586e75, stop: 0.1 transparent); -} - -/* -** Base Object Colors -*/ - -/* Tables */ -// QTreeView#settingsTree -> Tree in the Settings popup. - -QTreeView, QTableView { - alternate-background-color: #282a36; - // background-color: palette(shadow); - border: 0px; -} - -QTreeView { - selection-background-color: transparent; -} - -QTreeView::item { - border-left: 2px solid palette(base); -} - -QTreeView::item:focus { - border-width: 0 0 0 2px; - outline: none; -} - -QTreeView::item:selected { - border-width: 0 0 0 2px; - color: palette(button-text); -} - -QTreeView::item:hover { - background: palette(dark); -} - - -QTreeView::item:selected:active{ - color: palette(button-text); - background: palette(dark); - border-color: palette(highlight); -} - -QTreeView::item:selected:!active { - color: palette(button-text); - background: palette(dark); - border-color: palette(highlight); -} - -/* Scrollbar */ -/* From Quassel Wiki: http://sprunge.us/iZGB */ -QScrollBar { - //background: transparent; - background: palette(base); - margin: 0; -} -QScrollBar:hover { - /* Optional: Subtle accent of scrolling area on hover */ - background: #161616; /* base +2 */ -} -QScrollBar:vertical { - width: 8px; -} -QScrollBar:horizontal { - height: 8px; -} - -QScrollBar::handle { - padding: 0; - margin: 2px; - border-radius: 2px; - border: 2px solid palette(midlight); - background: palette(midlight); -} - -QScrollBar::handle:vertical { - min-height: 20px; - min-width: 0px; -} - -QScrollBar::handle:horizontal { - min-width: 20px; - min-height: 0px; -} -QScrollBar::handle:hover { - border-color: palette(light); - background: palette(light); -} -QScrollBar::handle:pressed { - background: palette(highlight); - border-color: palette(highlight); -} - -QScrollBar::add-line , QScrollBar::sub-line { - height: 0px; - border: 0px; -} -QScrollBar::up-arrow, QScrollBar::down-arrow { - border: 0px; - width: 0px; - height: 0px; -} - -QScrollBar::add-page, QScrollBar::sub-page { - background: none; -} - -/* Input Box */ -MultiLineEdit { - //background: palette(base); - //color: palette(foreground); -} - -/* Widgets */ -/* http://doc.qt.nokia.com/4.7-snapshot/qdockwidget.html */ -//QMainWindow, -QMainWindow QAbstractScrollArea { - //border: 0; // Remove borders. - border: 1px solid palette(shadow); -} - -QMainWindow { - //background: palette(mid); // Main window trim -} - -/* Splitter */ -/* The splits between QDockWidgets and QMainWindow is a different element. */ -QSplitter::handle, -QMainWindow::separator { - background: palette(dark); -} -QSplitter::handle:horizontal:hover, -QMainWindow::separator:vertical:hover { - background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop: 0 palette(window), stop: 0.5 palette(light), stop: 1 palette(window)); -} - -QSplitter::handle:vertical:hover, -QMainWindow::separator:horizontal:hover { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(window), stop: 0.5 palette(light), stop: 1 palette(window)); -} - -/* Menu Bar / Context Menues */ -QMenu { - margin: 5px; // A bit of nice padding around menu items. -} - -/* ToolTip */ -/* Note: You cannot create transparent sections in the popup box without a mask set. Thus the black edges outside the rounded borders. */ -QToolTip { - border: 2px solid #202020; // palette(dark) - border-radius: 2px; - background: #282a36; // palette(base) - color: white; // palette(text) -} - -/* Tabs */ -/* - The palette is designed for the selected one to be darker. So we need to change it. Decided to do a simple line. - tab:bottom and tab:top reverse y1 and y2 on the linear gradients. - - Tab Shadow: #444444 (light) - Tab Hover: #666 - Tab Selected: palette(highlight) -*/ - -QTabWidget::tab-bar { - alignment: center; -} - -QTabBar::tab { - min-width: 30px; - height: 20px; -} - -QTabBar::tab:bottom:selected { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(highlight), stop: 0.2 palette(highlight), stop: 0.2 transparent); -} - -QTabBar::tab:top:selected { - background: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0, stop: 0 palette(highlight), stop: 0.2 palette(highlight), stop: 0.2 transparent); -} - -QTabBar::tab:!selected { - color: #888; -} - -QTabBar::tab:bottom:!selected { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 palette(light), stop: 0.2 palette(light), stop: 0.2 transparent); -} - -QTabBar::tab:top:!selected { - background: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0, stop: 0 palette(light), stop: 0.2 palette(light), stop: 0.2 transparent); -} - -QTabBar::tab:!selected:hover { - color: #aaa; -} - -QTabBar::tab:bottom:!selected:hover { - background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #666, stop: 0.2 #666, stop: 0.2 transparent); -} - -QTabBar::tab:top:!selected:hover { - background: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0, stop: 0 #666, stop: 0.2 #666, stop: 0.2 transparent); -} - -/* -** Quassel CSS -*/ - -/* Main Chat Background Override */ -ChatView { - background: #181818; -} -ChatView QScrollBar { - background: #282a36; -} -ChatView QScrollBar:hover { - background: #282a36; -} - -ChatView QScrollBar::handle { - border-color: #44475a; - background: #44475a; -} - -ChatView QScrollBar::handle:hover { - border-color: #44475a; - background: #44475a; -} - -/**/ -QStatusBar {} -QStatusBar::item { - border: none; -} -QStatusBar QLabel { - color: #888; -} - -/* https://github.com/quassel/quassel/blob/master/src/qtui/ui/msgprocessorstatuswidget.ui */ -QStatusBar MsgProcessorStatusWidget {} -QStatusBar MsgProcessorStatusWidget QLabel#label {} -QStatusBar MsgProcessorStatusWidget QProgressBar#progressBar {} - -/* https://github.com/quassel/quassel/blob/master/src/qtui/ui/coreconnectionstatuswidget.ui */ -QStatusBar CoreConnectionStatusWidget {} -QStatusBar CoreConnectionStatusWidget QLabel#messageLabel {} -QStatusBar CoreConnectionStatusWidget QProgressBar#progressBar {} -QStatusBar CoreConnectionStatusWidget QLabel#lagLabel {} -QStatusBar CoreConnectionStatusWidget QLabel#sslLabel { - qproperty-pixmap: none; /* Hide the SSL status icon */ -} - - -/* Font */ -// Will not override if selectors are doubled up eg: "ChatLine, MultiLineEdit {}" -// These will override anything set in Quassel's Settings. -/** - * Don't bold or style MultiLineEdit text in any way otherwise you will be - * prone to get weird behaviour in submitting from the Input box. - * It will randomly bold your input if you do. - */ -ChatLine { - //font-family: "MingLiU_HKSCS-ExtB", "Courier New", Courier, Monotype; - - //font-size: 13pt; - //font-weight: bold; - } -MultiLineEdit { - //font-family: "MingLiU_HKSCS-ExtB", "Courier New", Courier, Monotype; - - //font-size: 20px; - //font-weight: normal; - } -ChatLine#plain { - //font-weight: bold; - } - -/* Font: UI Global Font */ -QWidget { - //font-family: consolas; - } -ChatListItem { - font-family: consolas; - } -NickListItem { - font-family: consolas; - } -StyledLabel#topicLabel { - font-family: consolas; - font-size: 14px; - } - - -/* Topic Box */ -StyledLabel#topicLabel { background: palette(base); font-family: consolas; } - -/* Buffer / Channel List */ -/** - state: inactive, channel-event, unread-message, highlighted - type: query, channel, network -**/ -ChatListItem { foreground: #f8f8f2; } -ChatListItem[state="inactive"] { foreground: #44475a; } -ChatListItem[state="channel-event"] { foreground: #6272a4; } /* palette(button-text) */ -ChatListItem[state="unread-message"] { foreground: #f8f8f2; } -ChatListItem[state="highlighted"] { foreground: #44475a; } - -ChatListItem[type="network", state="unread-message"] { foreground: #44475a; } -ChatListItem[type="network", state="highlighted"] { foreground: #44475a; } -ChatListItem[type="query", state="unread-message"] { foreground: #44475a; } - - -/* Nick List */ -/** - state: away - type: user, category -**/ -NickListItem[type="category"] { foreground: #6272a4; } -NickListItem[type="user"] { foreground: #f8f8f2 } -NickListItem[type="user", state="away"] { foreground: #44475a; } - - - -/* Chatbox Line Formatting */ -ChatLine[label="highlight"] { - foreground: #f5f5f5; - background: #282828; -} - -/* -** Option: Bold highlighted text, but not the timestamp. -*/ -/* -ChatLine[label="highlight"] { font-weight: bold; } -ChatLine::timestamp[label="highlight"]{ font-weight: normal; } -*/ - -ChatLine::timestamp[label="highlight"] { foreground: #44475a; } - -ChatLine::timestamp { } - -/* ::contents == Message */ -ChatLine::contents { - /* Can only set background */ -} - -ChatLine#plain { foreground: #f8f8f2; } -ChatLine#notice { foreground: #44475a; } -ChatLine#action { foreground: #565f73; font-style: italic; font-weight: bold; } -ChatLine#nick { foreground: #6272a4; } -ChatLine#mode { foreground: #6272a4; } -ChatLine#join { foreground: #6272a4; } -ChatLine#part { foreground: #6272a4; } -ChatLine#quit { foreground: #6272a4; } -ChatLine#kick { foreground: #6272a4; } -ChatLine#kill { foreground: #6272a4; } -ChatLine#server { foreground: #44475a; } -ChatLine#info { foreground: #44475a; } -ChatLine#error { foreground: #ff5555; } -ChatLine#daychange { foreground: #44475a; } -ChatLine#topic { foreground: #f1fa8c; } -ChatLine#netsplit-join { foreground: #44475a; } -ChatLine#netsplit-quit { foreground: #44475a; } - -ChatLine::timestamp { - foreground: #586e75; - // Resets the timestemp font during #action and other possible formatting. - font-style: normal; - font-weight: normal; -} - -ChatLine::url { - foreground: palette(link); - //font-style: underline; // Uncomment if you always want an underline on links. -} - -/* Sender Colors */ -ChatLine::sender#plain[sender="self"] { foreground: #586e75; } - -/** - * The following are the sixteen colours used for the senders. - * The names are calculated by taking the hash of the nickname. - * Then take the modulo (the remainder) when divided by 16. - * Preview: http://i.imgur.com/xeRKI4H.png - */ -ChatLine::sender#plain[sender="0"] { foreground: #96a6c8; } -ChatLine::sender#plain[sender="1"] { foreground: #73c936; } -ChatLine::sender#plain[sender="2"] { foreground: #ffdd33; } -ChatLine::sender#plain[sender="3"] { foreground: #cc8c3c; } -ChatLine::sender#plain[sender="4"] { foreground: #ff4f58; } -ChatLine::sender#plain[sender="5"] { foreground: #9e95c7; } -ChatLine::sender#plain[sender="6"] { foreground: #95a99f; } -ChatLine::sender#plain[sender="7"] { foreground: #8be9fd; } - -/* +32 */ -ChatLine::sender#plain[sender="8"] { foreground: #96a6c8; } -ChatLine::sender#plain[sender="9"] { foreground: #73c936; } -ChatLine::sender#plain[sender="a"] { foreground: #ffdd33; } -ChatLine::sender#plain[sender="b"] { foreground: #cc8c3c; } -ChatLine::sender#plain[sender="c"] { foreground: #ff4f58; } -ChatLine::sender#plain[sender="d"] { foreground: #9e95c7; } -ChatLine::sender#plain[sender="e"] { foreground: #95a99f; } -ChatLine::sender#plain[sender="f"] { foreground: #8be9fd; } - -/* -** mIRC formats -*/ -ChatLine[format="bold"] { font-weight: bold;} -ChatLine[format="italic"] { font-style: italic; } -ChatLine[format="underline"] { font-style: underline; } - -/* Blues are hard to read. */ -ChatLine[fg-color="2"] { foreground: #15a; } -ChatLine[bg-color="2"] { background: #15a; } -ChatLine[fg-color="c"] { foreground: #15f; } -ChatLine[bg-color="c"] { background: #15f; } - -/* -** Experimental -*/ -BufferViewDock[active=true] { - /* The circle is hardcoded into the title. */ - /* Color only changes on a refresh (F5) (so it's pointless). */ - /* Also colors the border in Breeze. */ - //color: palette(highlight); -} diff --git a/users/tazjin/hanebuschtag.txt b/users/tazjin/hanebuschtag.txt deleted file mode 100644 index daeb41c9a..000000000 --- a/users/tazjin/hanebuschtag.txt +++ /dev/null @@ -1,66 +0,0 @@ -bazurschnaburkini -buchweizengrütze -burkischnurkischnurzelwutz -burwurgurken -burwurka -gaschnurzel -gezwurkel -grunzelgewunzel -gurzelschnurzelgurke -hanemazurka -hanemazurkelgurkel -haneschlawitzka -haneschnaburkeln -haneschnawurkagurka -haneschnawurkel -haneschnuren -haneschnurkissima -hanewurka -hanewurkini -hanewurzeln -ronzelschlawonzel -ronzelwonzel -schabernackel -schabernackensteak -schlagurkelwini -schlaraffenwurburzel -schlawiburschnurschlakini -schlawonzel -schlawurkinischnagurka -schlawurzelgegurkel -schlawurzeltrollurzel -schlunzelgarfunzel -schmonzelgafonzel -schmotzrotzel -schnaburka -schnaburkel -schnaburkini -schnackel -schnarkelbarkel -schnarwurzelka -schnawurkeln -schnawurzelgackschnurschnacksschnicks -schnawurzini -schniepel -schnirkelschini -schnöckel -schnockelgockel -schnorchel -schnörk -schnorkelbusch -schnörkelknörkel -schnorkelorgel -schnörks -schnotzelgekrotzel -schnudelwurkini -schnurburka -schnurkini -schnurkinihanfini -schnurzelgawurzel -schnurzelwurzelwutz -schnurzelwutz -strazurkeln -wazurka -wurkelgurkel -wurkelschnurrini -wurzelchakramahurka diff --git a/users/tazjin/home/arbat.nix b/users/tazjin/home/arbat.nix deleted file mode 100644 index 83daf2012..000000000 --- a/users/tazjin/home/arbat.nix +++ /dev/null @@ -1,11 +0,0 @@ -# Home manage configuration for arbat. - -{ depot, pkgs, ... }: # readTree -{ config, lib, ... }: # home-manager - -{ - imports = [ - depot.users.tazjin.home.shared - depot.users.tazjin.home.persistence - ]; -} diff --git a/users/tazjin/home/khamovnik.nix b/users/tazjin/home/khamovnik.nix deleted file mode 100644 index 6bac67eb1..000000000 --- a/users/tazjin/home/khamovnik.nix +++ /dev/null @@ -1,10 +0,0 @@ -# Home manage configuration for zamalek. - -{ depot, pkgs, ... }: # readTree -{ config, lib, ... }: # home-manager - -{ - imports = [ - depot.users.tazjin.home.shared - ]; -} diff --git a/users/tazjin/home/persistence.nix b/users/tazjin/home/persistence.nix deleted file mode 100644 index 9ea5ca8eb..000000000 --- a/users/tazjin/home/persistence.nix +++ /dev/null @@ -1,42 +0,0 @@ -# Persistence configuration for machines with throw-away setups. - -{ depot, pkgs, ... }: # readTree -{ config, lib, ... }: # home-manager - -{ - imports = [ (depot.third_party.sources.impermanence + "/home-manager.nix") ]; - - home.persistence."/persist/tazjin/home" = { - allowOther = true; - - directories = [ - ".cargo" - ".config/audacity" - ".config/chromium" - ".config/google-chrome" - ".config/quassel-irc.org" - ".config/syncthing" - ".config/unity3d" - ".electrum" - ".gnupg" - ".local/share/audacity" - ".local/share/direnv" - ".local/share/fish" - ".local/share/keyrings" - ".local/share/zoxide" - ".mozilla/firefox" - ".password-store" - ".rustup" - ".ssh" - ".steam" - ".telega" - ".thunderbird" - "go" - "mail" - ]; - - files = [ - ".notmuch-config" - ]; - }; -} diff --git a/users/tazjin/home/shared.nix b/users/tazjin/home/shared.nix deleted file mode 100644 index 531fc6991..000000000 --- a/users/tazjin/home/shared.nix +++ /dev/null @@ -1,131 +0,0 @@ -# Shared home configuration for all machines. - -{ depot, pkgs, ... }: # readTree -{ config, lib, ... }: # home-manager - - -let - inherit (depot.third_party) chicago95; - - # URL handler to open `tg://` URLs in telega.el - telega-launcher = pkgs.writeShellScriptBin "telega-launcher" '' - echo "Opening ''${1} in telega.el ..." - ${depot.users.tazjin.emacs.emacs}/bin/emacsclient -e "(telega-browse-url \"''${1}\")" - ''; -in -{ - home.activation.screenshots = lib.hm.dag.entryAnywhere '' - $DRY_RUN_CMD mkdir -p $HOME/screenshots - ''; - - programs.git = { - enable = true; - userName = "Vincent Ambo"; - userEmail = "mail@tazj.in"; - extraConfig = { - pull.rebase = true; - init.defaultBranch = "canon"; - safe.directory = [ "/depot" ]; - }; - }; - - programs.fish = { - enable = true; - interactiveShellInit = '' - # emacs vterm integration - source (find '${pkgs.emacsPackages.vterm}' -name 'emacs-vterm.fish') - - # z - ${pkgs.zoxide}/bin/zoxide init fish | source - ''; - }; - - home.packages = [ telega-launcher ]; - - xdg.desktopEntries.telega-launcher = { - name = "Telega Launcher"; - exec = "${telega-launcher}/bin/telega-launcher"; - terminal = false; - mimeType = [ "x-scheme-handler/tg" ]; - }; - - xdg.mimeApps = { - enable = true; - defaultApplications = { - "x-scheme-handler/tg" = [ "telega-launcher.desktop" ]; - "text/html" = [ "firefox.desktop" ]; - "x-scheme-handler/http" = [ "firefox.desktop" ]; - "x-scheme-handler/https" = [ "firefox.desktop" ]; - "x-scheme-handler/about" = [ "firefox.desktop" ]; - "x-scheme-handler/unknown" = [ "firefox.desktop" ]; - }; - }; - - # workaround for https://github.com/nix-community/home-manager/issues/4199 - home.activation.backupWorkaround = lib.hm.dag.entryBefore [ "linkGeneration" ] '' - run rm -f ~/.config/mimeapps.list.backup - ''; - - # put Niri (& related tools) configuration in place - xdg.configFile."niri/config.kdl".source = depot.users.tazjin.dotfiles.niri; - xdg.configFile."fuzzel/fuzzel.ini".source = depot.users.tazjin.dotfiles.fuzzel; - - programs.wpaperd = { - enable = true; - settings = { - default = { - duration = "1d"; - mode = "center"; - sorting = "random"; - }; - - any.path = ../wallpapers; - }; - }; - - programs.waybar = { - enable = true; - settings = depot.users.tazjin.dotfiles.waybar.config; - style = depot.users.tazjin.dotfiles.waybar.style; - systemd.enable = true; - }; - systemd.user.services.waybar.Unit.After = lib.mkForce [ "niri.service" ]; - - - services.swayidle = let cmd = "${pkgs.swaylock}/bin/swaylock -fFkl -c 008080"; in { - enable = true; - events = [ - { event = "before-sleep"; command = cmd; } - { event = "lock"; command = cmd; } - ]; - }; - systemd.user.services.swayidle.Unit.After = lib.mkForce [ "niri.service" ]; - - # Enable the dunst notification daemon, but force the - # configuration file separately instead of going via the strange - # Nix->dunstrc encoding route. - services.dunst.enable = true; - xdg.configFile."dunst/dunstrc" = { - source = depot.users.tazjin.dotfiles.dunstrc; - onChange = '' - ${pkgs.procps}/bin/pkill -u "$USER" ''${VERBOSE+-e} dunst || true - ''; - }; - - gtk = { - enable = true; - theme.name = "Chicago95"; - theme.package = chicago95; - - iconTheme.name = "Chicago95-tux"; - iconTheme.package = chicago95; - - cursorTheme.name = lib.mkDefault "Chicago95_Animated_Hourglass_Cursors"; - cursorTheme.package = chicago95; - }; - - systemd.user.startServices = true; - - # Previous default version, see https://github.com/nix-community/home-manager/blob/master/docs/release-notes/rl-2211.adoc - home.stateVersion = "18.09"; -} diff --git a/users/tazjin/home/tverskoy.nix b/users/tazjin/home/tverskoy.nix deleted file mode 100644 index 6f1116340..000000000 --- a/users/tazjin/home/tverskoy.nix +++ /dev/null @@ -1,18 +0,0 @@ -# Home manage configuration for tverskoy. - -{ depot, pkgs, ... }: # readTree -{ config, lib, ... }: # home-manager - -{ - imports = [ - depot.users.tazjin.home.shared - depot.users.tazjin.home.persistence - ]; - - home.persistence."/persist/tazjin/home" = { - directories = [ - ".config/spotify" - ".local/share/Steam" - ]; - }; -} diff --git a/users/tazjin/home/zamalek.nix b/users/tazjin/home/zamalek.nix deleted file mode 100644 index 98da5e6b2..000000000 --- a/users/tazjin/home/zamalek.nix +++ /dev/null @@ -1,13 +0,0 @@ -# Home manage configuration for zamalek. - -{ depot, pkgs, ... }: # readTree -{ config, lib, ... }: # home-manager - -{ - imports = [ - depot.users.tazjin.home.shared - depot.users.tazjin.home.persistence - ]; - - gtk.cursorTheme.name = lib.mkForce "Chicago95_Animated_Hourglass_Cursors_HiDPI"; -} diff --git a/users/tazjin/homepage/default.nix b/users/tazjin/homepage/default.nix deleted file mode 100644 index b46f9d491..000000000 --- a/users/tazjin/homepage/default.nix +++ /dev/null @@ -1,97 +0,0 @@ -# Assembles the website index and configures an nginx instance to -# serve it. -# -# The website is made up of a simple header&footer and content -# elements for things such as blog posts and projects. -# -# Content for the blog is in //users/tazjin/blog instead of here. -{ depot, lib, pkgs, ... }@args: - -with depot; -with nix.yants; - -let - inherit (builtins) readFile replaceStrings sort; - inherit (pkgs) writeFile runCommand; - - # The different types of entries on the homepage. - entryClass = enum "entryClass" [ - "blog" - "project" - "note" - "misc" - ]; - - # The definition of a single entry. - entry = struct "entry" { - class = entryClass; - title = option string; - url = option string; - date = int; # epoch - description = option string; - }; - - escape = replaceStrings [ "<" ">" "&" "'" ] [ "<" ">" "&" "'" ]; - - postToEntry = defun [ web.blog.post entry ] (post: { - class = "blog"; - title = post.title; - url = "/blog/${post.key}"; - date = post.date; - description = post.description or "Blog post from ${formatDate post.date}"; - }); - - formatDate = defun [ int string ] (date: readFile (runCommand "date" { } '' - date --date='@${toString date}' '+%Y-%m-%d' | tr -d '\n' > $out - '')); - - entryUrl = defun [ entry string ] (entry: - if entry.class == "note" - then "#${toString entry.date}" - else entry.url - ); - - hasDescription = defun [ entry bool ] (entry: - ((entry ? description) && (entry.description != null)) - ); - - entryTitle = defun [ entry string ] (entry: - let - optionalColon = lib.optionalString (hasDescription entry) ":"; - titleText = - if (!(entry ? title) && (entry.class == "note")) - then "[${formatDate entry.date}]" - else lib.optionalString (entry ? title) ((escape entry.title) + optionalColon); - in - lib.optionalString (titleText != "") - ''<span class="entry-title ${entry.class}">${titleText}</span>'' - ); - - entryToDiv = defun [ entry string ] (entry: '' - <a href="${entryUrl entry}" id="${toString entry.date}" class="entry"> - ${entryTitle entry} - ${ - lib.optionalString (hasDescription entry) - "<span class=\"entry-description\">${escape entry.description}</span>" - } - </a> - ''); - - index = entries: pkgs.writeText "index.html" (lib.concatStrings ( - [ (builtins.readFile ./header.html) ] - ++ (map entryToDiv (sort (a: b: a.date > b.date) entries)) - ++ [ (builtins.readFile ./footer.html) ] - )); - - pageEntries = import ./entries.nix; - homepage = index ((map postToEntry users.tazjin.blog.posts) ++ pageEntries); - atomFeed = import ./feed.nix (args // { inherit entry pageEntries; }); -in -runCommand "website" { } '' - mkdir $out - cp ${homepage} $out/index.html - cp ${atomFeed} $out/feed.atom - mkdir $out/static - cp -r ${depot.web.static}/* $out/static - cp -rf ${./static}/* $out/static -'' diff --git a/users/tazjin/homepage/entries.nix b/users/tazjin/homepage/entries.nix deleted file mode 100644 index 0e98c073e..000000000 --- a/users/tazjin/homepage/entries.nix +++ /dev/null @@ -1,159 +0,0 @@ -let - note = date: description: { - class = "note"; - inherit description date; - }; -in -[ - { - class = "project"; - title = "VolgaSprint - Nix hacking in Kazan"; - url = "https://volgasprint.org/"; - date = 1712307024; - description = '' - Hacking on Nix projects for a week in Kazan, Russia, in August - 2024. Come join us! - ''; - } - { - class = "misc"; - title = "@tazlog on Telegram"; - url = "https://t.me/tazlog"; - date = 1643321164; - description = '' - My Telegram channel with occasional random life updates and musings. - ''; - } - { - class = "project"; - title = "Ship It! #37"; - url = "https://changelog.com/shipit/37"; - date = 1641819600; - description = '' - Podcast episode about TVL, Nix, monorepos and all sorts of related things. - ''; - } - { - class = "project"; - title = "Tvix"; - url = "https://tvl.fyi/blog/rewriting-nix"; - date = 1638381387; - description = "TVL is rewriting Nix with funding from NLNet."; - } - { - class = "misc"; - title = "Interview with Joscha Bach"; - url = "https://www.youtube.com/watch?v=P-2P3MSZrBM"; - date = 1594594800; - description = '' - Mind-bending discussion with philosopher Joscha Bach. - ''; - } - { - class = "misc"; - title = "The Virus Lounge"; - url = "https://tvl.fyi"; - date = 1587435629; - description = "A community around Nix, monorepos, build tooling and more!"; - } - { - class = "project"; - title = "depot"; - url = "https://code.tvl.fyi/about"; - date = 1576800000; - description = "Merging all of my projects into a single, Nix-based monorepo"; - } - { - class = "project"; - title = "Nixery"; - url = "https://github.com/google/nixery"; - date = 1565132400; - description = "A Nix-backed container registry that builds container images on demand"; - } - { - class = "project"; - title = "kontemplate"; - url = "https://code.tvl.fyi/about/ops/kontemplate"; - date = 1486550940; - description = "Simple file templating tool built for Kubernetes resources"; - } - { - class = "misc"; - title = "dottime"; - url = "https://dotti.me/"; - date = 1560898800; - description = "A universal convention for conveying time"; - } - { - class = "project"; - title = "journaldriver"; - url = "https://code.tvl.fyi/about/ops/journaldriver"; - date = 1527375600; - description = "Small daemon to forward logs from journald to Stackdriver Logging"; - } - { - class = "misc"; - title = "Principia Discordia"; - url = "https://principiadiscordia.com/book/1.php"; - date = 1495494000; - description = '' - A short book about everything that everyone should read. - ''; - } - { - class = "misc"; - title = "Nix — не только пакетный менеджер"; - date = 1663923600; - url = "https://www.youtube.com/watch?v=0Lhahzs-Wos"; - description = "Двухчасовой (!) разговор с введением в Nix, NixOS и так далее"; - } - { - class = "project"; - title = "yandex-cloud-rs"; - date = 1650877200; - url = "https://docs.rs/yandex-cloud"; - description = "Простой SDK на Rust для работы с API Yandex Cloud."; - } - { - class = "project"; - title = "nix-1p"; - date = 1564650000; - url = "https://code.tvl.fyi/about/nix/nix-1p"; - description = "A (more or less) one-page introduction to the Nix language."; - } - { - class = "misc"; - title = "Ставим NixOS!"; - date = 1678784400; - url = "https://progmsk.timepad.ru/event/2358560/"; - description = "Встреча в undef.space для помощи в начале работы с Nix/NixOS"; - } - { - class = "misc"; - title = "Tvix - September '22"; - date = 1662973200; - url = "https://tvl.fyi/blog/tvix-status-september-22"; - description = "Tvix update blog post over on TVL"; - } - { - class = "project"; - title = "Tvixbolt"; - date = 1667293200; - url = "https://bolt.tvix.dev/"; - description = "In-browser language evaluator for Nix, based on Tvix"; - } - { - class = "project"; - title = "ООО ТВЛ"; - date = 1609491600; - url = "https://tvl.su/ru/"; - description = "Официальный сайт моей компании по IT-консалтингу."; - } - - # Notes. - (note 1676106000 "If you have a Huawei device that sometimes struggles on public Wi-Fi networks, try enabling MAC-address randomisation. Huawei devices often get pushed onto management networks!") - (note 1686868637 "I moved some of my pages (including this one) to a machine in my flat in Moscow. If you end up having access trouble because your ISP blocks Russian resources, please let me know.") - (note 1686868636 "Protip: Use the Reddit blackout to click the 'Logout' button, and never come back.") - (note 1486550941 "↓ I no longer recommend people to use this. Generate your configuration from a language like Nix instead.") - (note 1576800001 "↓ No longer just my projects, it's all of TVL! Go check it out.") -] diff --git a/users/tazjin/homepage/feed.nix b/users/tazjin/homepage/feed.nix deleted file mode 100644 index 8043d7ff3..000000000 --- a/users/tazjin/homepage/feed.nix +++ /dev/null @@ -1,43 +0,0 @@ -# Creates the Atom feed for my homepage. -{ depot, lib, pkgs, entry, pageEntries, ... }: - -with depot.nix.yants; - -let - inherit (builtins) filter map readFile; - inherit (lib) max singleton; - inherit (pkgs) writeText; - inherit (depot.web) blog atom-feed; - - pageEntryToEntry = defun [ entry atom-feed.entry ] (e: { - id = "tazjin:${e.class}:${toString e.date}"; - updated = e.date; - published = e.date; - title = e.title; - summary = e.description; - - links = singleton { - rel = "alternate"; - href = e.url; - }; - }); - - allEntries = (with depot.users.tazjin.blog; map (blog.toFeedEntry config) posts) - ++ (map pageEntryToEntry (filter (e: e.class != "note") pageEntries)); - - feed = { - id = "https://tazj.in/"; - title = "tazjin's interblag"; - subtitle = "my posts, projects and other interesting things"; - rights = "© 2020 tazjin"; - authors = [ "tazjin" ]; - - links = singleton { - rel = "self"; - href = "https://tazjin/feed.atom"; - }; - - entries = allEntries; - }; -in -writeText "feed.atom" (atom-feed.renderFeed feed) diff --git a/users/tazjin/homepage/footer.html b/users/tazjin/homepage/footer.html deleted file mode 100644 index 2f1713506..000000000 --- a/users/tazjin/homepage/footer.html +++ /dev/null @@ -1,2 +0,0 @@ - </div> -</body> diff --git a/users/tazjin/homepage/header.html b/users/tazjin/homepage/header.html deleted file mode 100644 index 320b5ded8..000000000 --- a/users/tazjin/homepage/header.html +++ /dev/null @@ -1,29 +0,0 @@ -<!DOCTYPE html> -<head><meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta name="description" content="tazjin's blog"> - <link rel="stylesheet" type="text/css" href="static/tvl.css" media="all"> - <link rel="stylesheet" type="text/css" href="static/tazjin.css" media="all"> - <link rel="icon" type="image/webp" href="/static/favicon.webp"> - <link rel="alternate" type="application/atom+xml" href="/feed.atom"> - <title>tazjin's interblag - - -
    -

    - tazjin's interblag -

    -
    -
    -
    -

    - Below are some of - my projects, blog - posts, notes and some - other random things. If you'd like to - get in touch, email me at mail@[this domain] or ping me - on TVL IRC. -

    -
    -
    -
    diff --git a/users/tazjin/homepage/static/favicon.webp b/users/tazjin/homepage/static/favicon.webp deleted file mode 100644 index f99c90853..000000000 Binary files a/users/tazjin/homepage/static/favicon.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/nixery/dominator.webp b/users/tazjin/homepage/static/img/nixery/dominator.webp deleted file mode 100644 index 2d8569a6c..000000000 Binary files a/users/tazjin/homepage/static/img/nixery/dominator.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/nixery/example_extra.webp b/users/tazjin/homepage/static/img/nixery/example_extra.webp deleted file mode 100644 index 101f0f633..000000000 Binary files a/users/tazjin/homepage/static/img/nixery/example_extra.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/nixery/example_plain.webp b/users/tazjin/homepage/static/img/nixery/example_plain.webp deleted file mode 100644 index a2b90b3e2..000000000 Binary files a/users/tazjin/homepage/static/img/nixery/example_plain.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/nixery/ideal_layout.webp b/users/tazjin/homepage/static/img/nixery/ideal_layout.webp deleted file mode 100644 index 0e9f74556..000000000 Binary files a/users/tazjin/homepage/static/img/nixery/ideal_layout.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/watchblob_1.webp b/users/tazjin/homepage/static/img/watchblob_1.webp deleted file mode 100644 index 27e588e1a..000000000 Binary files a/users/tazjin/homepage/static/img/watchblob_1.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/watchblob_2.webp b/users/tazjin/homepage/static/img/watchblob_2.webp deleted file mode 100644 index b2dea98b4..000000000 Binary files a/users/tazjin/homepage/static/img/watchblob_2.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/watchblob_3.webp b/users/tazjin/homepage/static/img/watchblob_3.webp deleted file mode 100644 index 99b49373b..000000000 Binary files a/users/tazjin/homepage/static/img/watchblob_3.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/watchblob_4.webp b/users/tazjin/homepage/static/img/watchblob_4.webp deleted file mode 100644 index 41dbdb6be..000000000 Binary files a/users/tazjin/homepage/static/img/watchblob_4.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/watchblob_5.webp b/users/tazjin/homepage/static/img/watchblob_5.webp deleted file mode 100644 index c42a4ce1b..000000000 Binary files a/users/tazjin/homepage/static/img/watchblob_5.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/img/watchblob_6.webp b/users/tazjin/homepage/static/img/watchblob_6.webp deleted file mode 100644 index 144076185..000000000 Binary files a/users/tazjin/homepage/static/img/watchblob_6.webp and /dev/null differ diff --git a/users/tazjin/homepage/static/tazjin.css b/users/tazjin/homepage/static/tazjin.css deleted file mode 100644 index f921b562e..000000000 --- a/users/tazjin/homepage/static/tazjin.css +++ /dev/null @@ -1,57 +0,0 @@ -/* Homepage styling */ - -.dark { - background-color: #181818; - color: #e4e4ef; -} - -.dark-link, .interblag-title { - color: #96a6c8; -} - - -.interblag-title { - text-decoration: none; -} - -.entry-container { - display: flex; - flex-direction: column; - flex-wrap: nowrap; - justify-content: flex-start; -} - -.entry { - margin-top: 5px; - margin-bottom: 5px; - padding-left: 5px; - text-decoration: none; -} - -.entry:nth-child(odd) { - background: #282828; -} - -.entry-description { - color: #e4e4ef; -} - -.misc { - color: #73c936; - border-color: #73c936; -} - -.blog { - color: #268bd2; - border-color: #268bd2; -} - -.project { - color: #ff4f58; - border-color: #ff4f58; -} - -.note { - color: #ffdd33; - border-color: #ffdd33; -} diff --git a/users/tazjin/keys/default.nix b/users/tazjin/keys/default.nix deleted file mode 100644 index 300cd49e8..000000000 --- a/users/tazjin/keys/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -# My SSH public keys -{ ... }: - -let withAll = keys: keys // { all = builtins.attrValues keys; }; -in withAll { - tverskoy = "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBAWvA3RpXpMAqruUbB+eVgvvHCzhs5R9khFRza3YSLeFiIqOxVVgyhzW/BnCSD9t/5JrqRdJIGQLnkQU9m4REhUAAAAEc3NoOg== tazjin@tverskoy"; - tverskoy_ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM1fGWz/gsq+ZeZXjvUrV+pBlanw1c3zJ9kLTax9FWQy tazjin@tverskoy"; - zamalek_sk = "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIOAw3OaPAjnC6hArGYEmBoXhPf7aZdRGlDZcSqm6gbB8AAAABHNzaDo= tazjin@zamalek"; - zamalek_ed25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDBRXeb8EuecLHP0bW4zuebXp4KRnXgJTZfeVWXQ1n1R tazjin@zamalek"; - khamovnik_yk = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPgOyR4rRM8IaVGgN2ZxGlKtd7GLYbxdRTRa3u9EhRNSkHAvRTN9sgw7mm0iPLnHChPy10anKV43vTaIm906Gm8="; - khamovnik_agenix = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG4YSl5+DHQR3rOoBJLQfQ840U0CrYkByMKdzu/LDxoT tazjin@khamovnik"; - arbat = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ1Eai0p7eF7XML5wokqF4GlVZM+YXEORfs/GPGwEky7 tazjin@arbat"; -} diff --git a/users/tazjin/kinesis/README.md b/users/tazjin/kinesis/README.md deleted file mode 100644 index 7cd95a5e5..000000000 --- a/users/tazjin/kinesis/README.md +++ /dev/null @@ -1,10 +0,0 @@ -Kinesis configuration -===================== - -This folder backs up the configuration for my Kinesis keyboards. -Configuration is not mutually compatible between the Advantage 2 and -the Advantage 360, so they are stored in different folders and -(mostly) programmed on-board. - -I keep these around in case I get a new keyboard and want to bootstrap -it to behave the same way as the previous one. diff --git a/users/tazjin/kinesis/advantage2/qwerty.txt b/users/tazjin/kinesis/advantage2/qwerty.txt deleted file mode 100755 index 624e809c2..000000000 --- a/users/tazjin/kinesis/advantage2/qwerty.txt +++ /dev/null @@ -1,6 +0,0 @@ -[caps]>[rwin] -[lctrl]>[lalt] -[delete]>[lctrl] -[rctrl]>[rwin] -{pup}>{-rwin}{b}{+rwin} -{pdown}>{-rwin}{f}{+rwin} diff --git a/users/tazjin/niri-reap/.gitignore b/users/tazjin/niri-reap/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/users/tazjin/niri-reap/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/users/tazjin/niri-reap/Cargo.lock b/users/tazjin/niri-reap/Cargo.lock deleted file mode 100644 index e7916c5b3..000000000 --- a/users/tazjin/niri-reap/Cargo.lock +++ /dev/null @@ -1,104 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "niri-ipc" -version = "0.1.9" -source = "git+https://github.com/YaLTeR/niri.git#6a48728ffb1e638839b07f9ab2f06b2adb41dc61" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "niri-reap" -version = "0.1.0" -dependencies = [ - "niri-ipc", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "serde" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "syn" -version = "2.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" diff --git a/users/tazjin/niri-reap/Cargo.toml b/users/tazjin/niri-reap/Cargo.toml deleted file mode 100644 index 5f6677196..000000000 --- a/users/tazjin/niri-reap/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "niri-reap" -version = "0.1.0" -edition = "2021" - -[dependencies] -niri-ipc = { git = "https://github.com/YaLTeR/niri.git", version = "0.1.9" } diff --git a/users/tazjin/niri-reap/README.md b/users/tazjin/niri-reap/README.md deleted file mode 100644 index 207a08765..000000000 --- a/users/tazjin/niri-reap/README.md +++ /dev/null @@ -1,20 +0,0 @@ -niri-reap -========= - -Tiny, MIT-licensed companion program for [niri](https://github.com/YaLTeR/niri). - -I don't use workspaces in my workflow, but when disconnecting an external -screen, the workspaces that it was displaying are moved to the remaining screen. - -This program "reaps" all windows on workspaces except the currently active one, -and moves them all to the current workspace. - -## Usage - -If you have the full TVL monorepo, just `mg run //users/tazjin/niri-reap`. There -is no configuration, and there are no flags. - -If you don't have the TVL monorepo and just want `niri-reap`, do this: - -1. Get the code: `git clone https://code.tvl.fyi/depot.git:/users/tazjin/niri-reap.git` -2. Run the code: `cargo run` diff --git a/users/tazjin/niri-reap/default.nix b/users/tazjin/niri-reap/default.nix deleted file mode 100644 index 80c82f475..000000000 --- a/users/tazjin/niri-reap/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ depot, pkgs, ... }: - -pkgs.rustPlatform.buildRustPackage { - name = "niri-reap"; - src = depot.third_party.gitignoreSource ./.; - - cargoLock = { - lockFile = ./Cargo.lock; - outputHashes = { - "niri-ipc-0.1.9" = "sha256:1s294bw62mmckq9xyfzgw4p2nvkzday4k276j60m668prhlfp071"; - }; - }; -} diff --git a/users/tazjin/niri-reap/src/main.rs b/users/tazjin/niri-reap/src/main.rs deleted file mode 100644 index 315a5015d..000000000 --- a/users/tazjin/niri-reap/src/main.rs +++ /dev/null @@ -1,93 +0,0 @@ -use niri_ipc::socket::Socket; -use niri_ipc::{Action, Reply, Request, Response, Window, Workspace}; - -fn sock() -> Socket { - Socket::connect().expect("could not connect to Niri socket") -} - -fn list_workspaces() -> Vec { - let (reply, _) = sock() - .send(Request::Workspaces) - .expect("failed to send workspace request"); - - match reply { - Reply::Err(err) => panic!("failed to list workspaces: {}", err), - Reply::Ok(Response::Workspaces(w)) => w, - Reply::Ok(other) => panic!("unexpected reply from Niri: {:#?}", other), - } -} - -fn list_windows() -> Vec { - let (reply, _) = sock() - .send(Request::Windows) - .expect("failed to send window request"); - - match reply { - Reply::Err(err) => panic!("failed to list windows: {}", err), - Reply::Ok(Response::Windows(w)) => w, - Reply::Ok(other) => panic!("unexpected reply from Niri: {:#?}", other), - } -} - -fn reap_window(window: u64, workspace: u64) { - let (reply, _) = sock() - .send(Request::Action(Action::MoveWindowToWorkspace { - window_id: Some(window), - reference: niri_ipc::WorkspaceReferenceArg::Id(workspace), - })) - .expect("failed to send window move request"); - - reply.expect("failed to move window to workspace"); -} - -fn get_active_workspace(workspaces: &[Workspace]) -> &Workspace { - workspaces - .iter() - .filter(|w| w.is_focused) - .next() - .expect("expected an active workspace") -} - -fn move_workspace_up() { - let (result, _) = sock() - .send(Request::Action(Action::MoveWorkspaceUp {})) - .expect("failed to send workspace move command"); - - result.expect("failed to move workspace up"); -} - -fn main() { - let mut workspaces = list_workspaces(); - let mut active_workspace = get_active_workspace(&workspaces); - - // Ensure that the current workspace is the first one, to avoid issues with - // indices changing during the window moves. - while active_workspace.idx > 1 { - move_workspace_up(); - workspaces = list_workspaces(); - active_workspace = get_active_workspace(&workspaces); - } - - let orphan_workspaces = workspaces - .iter() - .filter(|w| w.output == active_workspace.output) - .filter(|w| w.idx > 1) - .map(|w| w.id) - .collect::>(); - - if orphan_workspaces.is_empty() { - return; - } - - let reapable = list_windows() - .into_iter() - .filter(|w| match w.workspace_id { - Some(id) => orphan_workspaces.contains(&id), - None => true, - }) - .collect::>(); - - for window in reapable.iter().rev() { - reap_window(window.id, active_workspace.id); - } -} diff --git a/users/tazjin/nisp/transform.el b/users/tazjin/nisp/transform.el deleted file mode 100644 index 89b2bb104..000000000 --- a/users/tazjin/nisp/transform.el +++ /dev/null @@ -1,137 +0,0 @@ -;; Nix as a Lisp - -(require 'cl-lib) -(require 'json) -(require 's) -(require 'dash) - -(defun nisp/expr (form) - "Entrypoint for Nisp->Nix transformation. Will translate FORM -into Nix code, if it is a valid Nisp expression. - -To make code generation slightly easier, each -expression (including literals) is wrapped in an extra pair of -parens." - (concat - "(" - (pcase form - ;; Special keywords - ('() "null") - (`(let . ,rest) (nisp/let form)) - (`(fn . ,rest) (nisp/fn form)) - (`(if ,cond ,then ,else) (nisp/if cond then else)) - - ;; Nix operators & builtins that need special handling - (`(or ,lhs ,rhs) (nisp/infix "||" lhs rhs)) - (`(and ,lhs ,rhs) (nisp/infix "&&" lhs rhs)) - (`(> ,lhs ,rhs) (nisp/infix ">" lhs rhs)) - (`(< ,lhs ,rhs) (nisp/infix "<" lhs rhs)) - (`(>= ,lhs ,rhs) (nisp/infix ">=" lhs rhs)) - (`(<= ,lhs ,rhs) (nisp/infix "<=" lhs rhs)) - (`(+ ,lhs ,rhs) (nisp/infix "+" lhs rhs)) - (`(- ,lhs ,rhs) (nisp/infix "-" lhs rhs)) - (`(* ,lhs ,rhs) (nisp/infix "*" lhs rhs)) - (`(/ ,lhs ,rhs) (nisp/infix "/" lhs rhs)) - (`(-> ,lhs ,rhs) (nisp/infix "->" lhs rhs)) - (`(? ,lhs ,rhs) (nisp/infix "?" lhs rhs)) - (`(// ,lhs ,rhs) (nisp/infix "//" lhs rhs)) - (`(++ ,lhs ,rhs) (nisp/infix "++" lhs rhs)) - (`(== ,lhs ,rhs) (nisp/infix "==" lhs rhs)) - (`(!= ,lhs ,rhs) (nisp/infix "!=" lhs rhs)) - (`(! ,term) (concat "!" (nisp/expr term))) - (`(- ,term) (concat "-" (nisp/expr term))) - - ;; Attribute sets - (`(attrs . ,rest) (nisp/attribute-set form)) - - ;; Function calls - ((and `(,func . ,args) - (guard (symbolp func))) - (nisp/funcall func args)) - - ;; Primitives - ((pred stringp) (json-encode-string form)) - ((pred numberp) (json-encode-number form)) - ((pred keywordp) (substring (symbol-name form) 1)) - ((pred symbolp) (symbol-name form)) - - ;; Lists - ((pred arrayp) (nisp/list form)) - - (other (error "Encountered unhandled form: %s" other))) - ")")) - -(defun nisp/infix (op lhs rhs) - (concat (nisp/expr lhs) " " op " " (nisp/expr rhs))) - -(defun nisp/funcall (func args) - (concat (symbol-name func) " " (s-join " " (-map #'nisp/expr args)))) - -(defun nisp/let (form) - (pcase form - (`(let . (,bindings . (,body . ()))) (concat "let " - (nisp/let bindings) - (nisp/expr body))) - (`((:inherit . ,inherits) . ,rest) (concat (nisp/inherit (car form)) - " " - (nisp/let rest))) - (`((,name . (,value . ())) .,rest) (concat (symbol-name name) " = " - (nisp/expr value) "; " - (nisp/let rest))) - ('() "in ") - (other (error "malformed form '%s' in let expression" other)))) - -(defun nisp/inherit (form) - (pcase form - (`(:inherit . ,rest) (concat "inherit " (nisp/inherit rest))) - (`((,source) . ,rest) (concat "(" (symbol-name source) ") " (nisp/inherit rest))) - (`(,item . ,rest) (concat (symbol-name item) " " (nisp/inherit rest))) - ('() ";"))) - -(defun nisp/if (cond then else) - (concat "if " (nisp/expr cond) - " then " (nisp/expr then) - " else " (nisp/expr else))) - -(defun nisp/list (form) - (cl-check-type form array) - (concat "[ " - (mapconcat #'nisp/expr form " ") - "]")) - - -(defun nisp/attribute-set (form) - "Attribute sets have spooky special handling because they are -not supported by the reader." - (pcase form - (`(attrs . ,rest) (concat "{ " (nisp/attribute-set rest))) - ((and `(,name . (,value . ,rest)) - (guard (keywordp name))) - (concat (substring (symbol-name name) 1) " = " - (nisp/expr value) "; " - (nisp/attribute-set rest))) - ('() "}"))) - -(defun nisp/fn (form) - (pcase form - (`(fn ,args ,body) (concat - (cl-loop for arg in args - concat (format "%s: " arg)) - (nisp/expr body))))) - -;; The following functions are not part of the transform. - -(defun nisp/eval (form) - (interactive "sExpression: ") - (when (stringp form) - (setq form (read form))) - - (message - ;; TODO(tazjin): Construct argv manually to avoid quoting issues. - (s-chomp - (shell-command-to-string - (concat "nix-instantiate --eval -E '" (nisp/expr form) "'"))))) - -(defun nisp/eval-last-sexp () - (interactive) - (nisp/eval (edebug-last-sexp))) diff --git a/users/tazjin/nix.svg b/users/tazjin/nix.svg deleted file mode 100644 index d2ef7c81a..000000000 --- a/users/tazjin/nix.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - diff --git a/users/tazjin/nixos/.gitignore b/users/tazjin/nixos/.gitignore deleted file mode 100644 index 212d3ad27..000000000 --- a/users/tazjin/nixos/.gitignore +++ /dev/null @@ -1 +0,0 @@ -local-config.nix diff --git a/users/tazjin/nixos/README.md b/users/tazjin/nixos/README.md deleted file mode 100644 index 662f2a36a..000000000 --- a/users/tazjin/nixos/README.md +++ /dev/null @@ -1,17 +0,0 @@ -NixOS configuration -=================== - -My NixOS configurations! It configures most of the packages I require -on my systems, sets up Emacs the way I need and does a bunch of other -interesting things. - -System configuration lives in folders, and some of the modules stem -from `//ops/modules`. - -Machines are deployed with the script at `ops.nixos.rebuild-system`. - -## Configured hosts: - -* `tverskoy` - X13 AMD that's travelling around with me -* `frog` - weapon of mass computation (in storage in London) -* `camden` - NUC formerly serving tazj.in (in storage in London) diff --git a/users/tazjin/nixos/arbat/default.nix b/users/tazjin/nixos/arbat/default.nix deleted file mode 100644 index 6a15b9b0e..000000000 --- a/users/tazjin/nixos/arbat/default.nix +++ /dev/null @@ -1,72 +0,0 @@ -# arbat is my Unchartevice 6640MA, with a Zhaoxin CPU. -{ depot, lib, pkgs, ... }: - -config: -let - mod = name: depot.path.origSrc + ("/ops/modules/" + name); - usermod = name: depot.path.origSrc + ("/users/tazjin/nixos/modules/" + name); - - zdevice = device: { - inherit device; - fsType = "zfs"; - }; -in -{ - imports = [ - (usermod "chromium.nix") - (usermod "desktop.nix") - (usermod "fonts.nix") - (usermod "home-config.nix") - (usermod "laptop.nix") - (usermod "persistence.nix") - (usermod "physical.nix") - ((pkgs.srcOnly pkgs.home-manager) + "/nixos") - ]; - - tvl.cache.enable = true; - - boot = { - loader.systemd-boot.enable = true; - supportedFilesystems = [ "zfs" ]; - zfs.devNodes = "/dev/"; - # TODO: double-check this list - initrd.availableKernelModules = [ "ahci" "uhci_hcd" "ehci_pci" "xhci_pci" "usb_storage" "sd_mod" "rtsx_usb_sdmmc" ]; - kernelModules = [ "kvm-intel" ]; # interesting - }; - - networking = { - hostName = "arbat"; - hostId = "864f050b"; - networkmanager.enable = true; - }; - - fileSystems = { - "/" = zdevice "zpool/ephemeral/root"; - "/home" = zdevice "zpool/ephemeral/home"; - "/persist" = zdevice "zpool/persistent/data" // { neededForBoot = true; }; - "/nix" = zdevice "zpool/persistent/nix"; - "/depot" = zdevice "zpool/persistent/depot"; - - "/boot" = { - device = "/dev/disk/by-uuid/B3B5-92F7"; - fsType = "vfat"; - }; - }; - - hardware = { - enableRedistributableFirmware = true; - graphics.enable = true; - bluetooth.enable = true; - }; - - # TODO(tazjin): decide on this - services.libinput = { - enable = true; - # libinput thinks the touchpad is a mouse - mouse.naturalScrolling = false; - mouse.disableWhileTyping = true; - }; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - system.stateVersion = "24.11"; -} diff --git a/users/tazjin/nixos/camden/default.nix b/users/tazjin/nixos/camden/default.nix deleted file mode 100644 index 4af29fc7c..000000000 --- a/users/tazjin/nixos/camden/default.nix +++ /dev/null @@ -1,345 +0,0 @@ -# This file configures camden.tazj.in, my homeserver. -{ depot, pkgs, lib, ... }: - -config: -let - nginxRedirect = { from, to, acmeHost }: { - serverName = from; - useACMEHost = acmeHost; - forceSSL = true; - - extraConfig = "return 301 https://${to}$request_uri;"; - }; - mod = name: depot.path.origSrc + ("/ops/modules/" + name); -in -lib.fix (self: { - imports = [ - (mod "quassel.nix") - (mod "smtprelay.nix") - ]; - - # camden is intended to boot unattended, despite having an encrypted - # root partition. - # - # The below configuration uses an externally connected USB drive - # that contains a LUKS key file to unlock the disk automatically at - # boot. - # - # TODO(tazjin): Configure LUKS unlocking via SSH instead. - boot = { - initrd = { - availableKernelModules = [ - "ahci" - "xhci_pci" - "usbhid" - "usb_storage" - "sd_mod" - "sdhci_pci" - "rtsx_usb_sdmmc" - "r8169" - ]; - - kernelModules = [ "dm-snapshot" ]; - - luks.devices.camden-crypt = { - fallbackToPassword = true; - device = "/dev/disk/by-label/camden-crypt"; - keyFile = "/dev/sdb"; - keyFileSize = 4096; - }; - }; - - loader = { - systemd-boot.enable = true; - efi.canTouchEfiVariables = true; - }; - - tmp.cleanOnBoot = true; - }; - - fileSystems = { - "/" = { - device = "/dev/disk/by-label/camden-root"; - fsType = "ext4"; - }; - - "/home" = { - device = "/dev/disk/by-label/camden-home"; - fsType = "ext4"; - }; - - "/boot" = { - device = "/dev/disk/by-label/BOOT"; - fsType = "vfat"; - }; - }; - - nix.settings = { - max-jobs = lib.mkDefault 4; - trusted-users = [ "root" "tazjin" ]; - substituters = [ - "https://tazjin.cachix.org" - ]; - - trusted-public-keys = [ - "tazjin.cachix.org-1:IZkgLeqfOr1kAZjypItHMg1NoBjm4zX9Zzep8oRSh7U=" - ]; - }; - - powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; - - networking = { - hostName = "camden"; - interfaces.enp1s0.useDHCP = true; - interfaces.enp1s0.ipv6.addresses = [ - { - address = "2a01:4b00:821a:ce02::5"; - prefixLength = 64; - } - ]; - - firewall.enable = false; - }; - - time.timeZone = "UTC"; - - # System-wide application setup - programs.fish.enable = true; - programs.mosh.enable = true; - - fonts = { - packages = [ pkgs.jetbrains-mono ]; - fontconfig.defaultFonts.monospace = [ "JetBrains Mono" ]; - }; - - environment.systemPackages = - # programs from the depot - (with depot; [ - fun.idual.script - fun.idual.setAlarm - ]) ++ - - # programs from nixpkgs - (with pkgs; [ - bat - curl - direnv - emacs-nox - fswebcam - git - gnupg - google-cloud-sdk - htop - jq - pass - pciutils - restic - ripgrep - screen - ]); - - users = { - # Set up my own user for logging in and doing things ... - users.tazjin = { - isNormalUser = true; - uid = 1000; - extraGroups = [ "git" "wheel" "quassel" "video" ]; - shell = pkgs.fish; - }; - - # Set up a user & group for general git shenanigans - groups.git = { }; - users.git = { - group = "git"; - isSystemUser = true; - }; - }; - - # Services setup - services.openssh.enable = true; - services.haveged.enable = true; - - # Join Tailscale into home network - services.tailscale.enable = true; - - # Allow sudo-ing via the forwarded SSH agent. - security.pam.sshAgentAuth.enable = true; - - # NixOS 20.03 broke nginx and I can't be bothered to debug it - # anymore, all solution attempts have failed, so here's a - # brute-force fix. - systemd.services.fix-nginx = { - script = "${pkgs.coreutils}/bin/chown -R nginx: /var/spool/nginx /var/cache/nginx"; - - serviceConfig = { - User = "root"; - Type = "oneshot"; - }; - }; - - systemd.timers.fix-nginx = { - wantedBy = [ "multi-user.target" ]; - timerConfig = { - OnCalendar = "minutely"; - }; - }; - - # Provision a TLS certificate outside of nginx to avoid - # nixpkgs#38144 - security.acme = { - acceptTerms = true; - - certs."tazj.in" = { - email = "mail@tazj.in"; - group = "nginx"; - webroot = "/var/lib/acme/acme-challenge"; - postRun = "systemctl reload nginx"; - - extraDomainNames = [ - "cs.tazj.in" - "git.tazj.in" - "www.tazj.in" - - # Local domains (for this machine only) - "camden.tazj.in" - ]; - }; - - certs."quassel.tazj.in" = { - email = "mail@tazj.in"; - webroot = "/var/lib/acme/challenge-quassel"; - group = "quassel"; - }; - }; - - # Forward logs to Google Cloud Platform - services.journaldriver = { - enable = true; - logStream = "home"; - googleCloudProject = "tazjins-infrastructure"; - applicationCredentials = "/etc/gcp/key.json"; - }; - - services.depot.quassel = { - enable = true; - acmeHost = "quassel.tazj.in"; - bindAddresses = [ - "0.0.0.0" - ]; - }; - - services.bitlbee = { - enable = false; - portNumber = 2337; # bees - }; - - # serve my website(s) - services.nginx = { - enable = true; - enableReload = true; - package = with pkgs; nginx.override { - modules = [ nginxModules.rtmp ]; - }; - - recommendedTlsSettings = true; - recommendedGzipSettings = true; - recommendedProxySettings = true; - - appendConfig = '' - rtmp_auto_push on; - rtmp { - server { - listen 1935; - chunk_size 4000; - - application tvl { - live on; - - allow publish 88.98.195.213; - allow publish 10.0.1.0/24; - deny publish all; - - allow play all; - } - } - } - ''; - - commonHttpConfig = '' - log_format json_combined escape=json - '{' - '"remote_addr":"$remote_addr",' - '"method":"$request_method",' - '"uri":"$request_uri",' - '"status":$status,' - '"request_size":$request_length,' - '"response_size":$body_bytes_sent,' - '"response_time":$request_time,' - '"referrer":"$http_referer",' - '"user_agent":"$http_user_agent"' - '}'; - - access_log syslog:server=unix:/dev/log,nohostname json_combined; - ''; - - virtualHosts.homepage = { - serverName = "tazj.in"; - serverAliases = [ "camden.tazj.in" ]; - default = true; - useACMEHost = "tazj.in"; - root = depot.users.tazjin.homepage; - forceSSL = true; - - extraConfig = '' - ${depot.users.tazjin.blog.oldRedirects} - - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - location ~* \.(webp|woff2)$ { - add_header Cache-Control "public, max-age=31536000"; - } - - location /blog/ { - alias ${depot.users.tazjin.blog.rendered}/; - - if ($request_uri ~ ^/(.*)\.html$) { - return 302 /$1; - } - - try_files $uri $uri.html $uri/ =404; - } - - location = /tazjin { - return 200 "tazjin"; - } - - location /blobs/ { - alias /var/www/blobs/; - } - ''; - }; - - virtualHosts.cgit-old = nginxRedirect { - from = "git.tazj.in"; - to = "code.tvl.fyi"; - acmeHost = "tazj.in"; - }; - - virtualHosts.cs-old = nginxRedirect { - from = "cs.tazj.in"; - to = "cs.tvl.fyi"; - acmeHost = "tazj.in"; - }; - }; - - # Timer units that can be started with systemd-run to set my alarm. - systemd.user.services.light-alarm = { - script = "${depot.fun.idual.script}/bin/idualctl wakey"; - postStart = "${pkgs.systemd}/bin/systemctl --user stop light-alarm.timer"; - serviceConfig = { - Type = "oneshot"; - }; - }; - - system.stateVersion = "19.09"; -}) diff --git a/users/tazjin/nixos/default.nix b/users/tazjin/nixos/default.nix deleted file mode 100644 index 6bca09d8f..000000000 --- a/users/tazjin/nixos/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ depot, lib, ... }: - -let systemFor = sys: (depot.ops.nixos.nixosFor sys).system; -in depot.nix.readTree.drvTargets { - arbatSystem = systemFor depot.users.tazjin.nixos.arbat; - camdenSystem = systemFor depot.users.tazjin.nixos.camden; - tverskoySystem = systemFor depot.users.tazjin.nixos.tverskoy; - zamalekSystem = systemFor depot.users.tazjin.nixos.zamalek; - koptevoRaw = depot.ops.nixos.nixosFor depot.users.tazjin.nixos.koptevo; - koptevoSystem = systemFor depot.users.tazjin.nixos.koptevo; - khamovnikSystem = systemFor depot.users.tazjin.nixos.khamovnik; - - # no need to build this while the machine is in storage - # frogSystem = systemFor depot.users.tazjin.nixos.frog; -} diff --git a/users/tazjin/nixos/frog/default.nix b/users/tazjin/nixos/frog/default.nix deleted file mode 100644 index 5c5080dbe..000000000 --- a/users/tazjin/nixos/frog/default.nix +++ /dev/null @@ -1,279 +0,0 @@ -{ depot, lib, pkgs, ... }: - -config: -let - inherit (pkgs) lieer; - - quasselClient = pkgs.quassel.override { - client = true; - enableDaemon = false; - monolithic = false; - }; -in -lib.fix (self: { - boot = { - tmp.useTmpfs = true; - kernelModules = [ "kvm-amd" ]; - - loader = { - systemd-boot.enable = true; - efi.canTouchEfiVariables = true; - }; - - initrd = { - luks.devices.frog-crypt.device = "/dev/disk/by-label/frog-crypt"; - availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "usbhid" "sd_mod" ]; - kernelModules = [ "dm-snapshot" ]; - }; - - kernelPackages = pkgs.linuxPackages_latest; - kernel.sysctl = { - "kernel.perf_event_paranoid" = -1; - }; - - # Enable this again if frog is put back into use ... - # - # kernelPatches = [ - # depot.third_party.kernelPatches.trx40_usb_audio - # ]; - }; - - hardware = { - cpu.amd.updateMicrocode = true; - enableRedistributableFirmware = true; - graphics = { - enable = true; - enable32Bit = true; - }; - - bluetooth = { - enable = true; - }; - }; - - services.pulseaudio = { - enable = true; - package = pkgs.pulseaudioFull; - }; - - nix.settings = { - max-jobs = 48; - substituters = [ "ssh://nix-ssh@whitby.tvl.fyi" ]; - }; - - networking = { - hostName = "frog"; - useDHCP = true; - - # Don't use ISP's DNS servers: - nameservers = [ - "8.8.8.8" - "8.8.4.4" - ]; - - firewall.enable = false; - }; - - # Generate an immutable /etc/resolv.conf from the nameserver settings - # above (otherwise DHCP overwrites it): - environment.etc."resolv.conf" = with lib; { - source = pkgs.writeText "resolv.conf" '' - ${concatStringsSep "\n" (map (ns: "nameserver ${ns}") self.networking.nameservers)} - options edns0 - ''; - }; - - time.timeZone = "Europe/London"; - - fileSystems = { - "/".device = "/dev/disk/by-label/frog-root"; - "/boot".device = "/dev/disk/by-label/BOOT"; - "/home".device = "/dev/disk/by-label/frog-home"; - }; - - # Configure user account - users.extraUsers.tazjin = { - extraGroups = [ "wheel" "audio" "docker" ]; - isNormalUser = true; - uid = 1000; - shell = pkgs.fish; - }; - - security.sudo = { - enable = true; - extraConfig = "wheel ALL=(ALL:ALL) SETENV: ALL"; - }; - - fonts = { - packages = with pkgs; [ - corefonts - dejavu_fonts - jetbrains-mono - noto-fonts-cjk-sans - noto-fonts-emoji - ]; - - fontconfig = { - hinting.enable = true; - subpixel.lcdfilter = "light"; - - defaultFonts = { - monospace = [ "JetBrains Mono" ]; - }; - }; - }; - - # Configure location (Vauxhall, London) for services that need it. - location = { - latitude = 51.4819109; - longitude = -0.1252998; - }; - - programs.fish.enable = true; - programs.ssh.startAgent = true; - - services.redshift.enable = true; - services.openssh.enable = true; - services.fstrim.enable = true; - services.blueman.enable = true; - - # Required for Yubikey usage as smartcard - services.pcscd.enable = true; - services.udev.packages = [ - pkgs.yubikey-personalization - ]; - - # Enable Docker for Nixery testing - virtualisation.docker = { - enable = true; - autoPrune.enable = true; - }; - - services.xserver = { - enable = true; - xkb.layout = "us"; - xkb.options = "caps:super"; - exportConfiguration = true; - videoDrivers = [ "amdgpu" ]; - displayManager = { - # Give EXWM permission to control the session. - sessionCommands = "${pkgs.xorg.xhost}/bin/xhost +SI:localuser:$USER"; - - lightdm.enable = true; - lightdm.greeters.gtk.clock-format = "%H·%M"; # TODO(tazjin): TZ? - }; - - windowManager.session = lib.singleton { - name = "exwm"; - start = "${depot.users.tazjin.emacs}/bin/tazjins-emacs"; - }; - }; - - # Do not restart the display manager automatically - systemd.services.display-manager.restartIfChanged = lib.mkForce false; - - # clangd needs more than ~2GB in the runtime directory to start up - services.logind.extraConfig = '' - RuntimeDirectorySize=16G - ''; - - # Configure email setup - systemd.user.services.lieer-tazjin = { - description = "Synchronise mail@tazj.in via lieer"; - script = "${lieer}/bin/gmi sync"; - - serviceConfig = { - WorkingDirectory = "%h/mail/account.tazjin"; - Type = "oneshot"; - }; - }; - - systemd.user.timers.lieer-tazjin = { - wantedBy = [ "timers.target" ]; - - timerConfig = { - OnActiveSec = "1"; - OnUnitActiveSec = "180"; - }; - }; - - environment.systemPackages = - # programs from the depot - (with depot; [ - fun.idual.script - fun.uggc - lieer - ops.kontemplate - quasselClient - third_party.git - tools.nsfv-setup - users.tazjin.emacs - ]) ++ - - # programs from nixpkgs - (with pkgs; [ - age - bat - chromium - clang-manpages - clang-tools - clang - curl - direnv - dnsutils - emacs # mostly for emacsclient - fd - file - gdb - gnupg - go - google-chrome - google-cloud-sdk - htop - hyperfine - i3lock - iftop - imagemagick - jq - kubectl - linuxPackages.perf - man-pages - miller - msmtp - nix-prefetch-github - notmuch - obs-studio - openssh - openssl - pass - pavucontrol - pciutils - pinentry - pinentry-emacs - pmutils - pwgen - ripgrep - rustup - screen - spotify - tokei - transmission - tree - unzip - usbutils - v4l-utils - vlc - xclip - xsecurelock - yubico-piv-tool - yubikey-personalization - zoxide - - # Commented out because of interim breakage: - # steam - # lutris - ]); - - # ... and other nonsense. - system.stateVersion = "20.03"; -}) diff --git a/users/tazjin/nixos/khamovnik/default.nix b/users/tazjin/nixos/khamovnik/default.nix deleted file mode 100644 index feccc420e..000000000 --- a/users/tazjin/nixos/khamovnik/default.nix +++ /dev/null @@ -1,158 +0,0 @@ -# Yandex work laptop -# -# Some of the configuration for this machine is not public. -{ depot, lib, pkgs, ... }: - -config: -let - mod = name: depot.path.origSrc + ("/ops/modules/" + name); - usermod = name: depot.path.origSrc + ("/users/tazjin/nixos/modules/" + name); - - zdevice = device: { - inherit device; - fsType = "zfs"; - }; - - # Determine whether private Yandex-specific configuration should be loaded, - # and fail if it is unexpectedly not available. - yandexConfigIncludes = - let - hostname = if builtins.pathExists "/etc/hostname" then builtins.readFile "/etc/hostname" else ""; - isKhamovnik = hostname == "khamovnik\n"; - private = /arc/junk/tazjin; - hasPrivate = builtins.pathExists private; - in - assert isKhamovnik -> hasPrivate; - if !isKhamovnik then [ ] else [ - (private + "/nixos/yandex.nix") - (private + "/emacs/module.nix") - ]; - -in -{ - imports = [ - (usermod "chromium.nix") - (usermod "desktop.nix") - (usermod "fonts.nix") - (usermod "home-config.nix") - (usermod "laptop.nix") - (usermod "physical.nix") - (usermod "systemd-unfreeze.nix") - - ((pkgs.srcOnly pkgs.home-manager) + "/nixos") - ] ++ yandexConfigIncludes; - - # from hardware-configuration.nix - boot = { - initrd.luks.devices."luks-9c3cd590-a648-450d-ae42-ed3859d4c717".device = - "/dev/disk/by-uuid/9c3cd590-a648-450d-ae42-ed3859d4c717"; - - initrd.availableKernelModules = [ - "xhci_pci" - "thunderbolt" - "ahci" - "nvme" - "usb_storage" - "sd_mod" - "rtsx_pci_sdmmc" - ]; - kernelModules = [ "kvm-intel" ]; - - tmp.cleanOnBoot = true; - }; - - fileSystems = { - "/" = { - device = "/dev/disk/by-uuid/1f783029-c4f9-4192-b893-84f4f0c2a493"; - fsType = "ext4"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/DD01-2B3E"; - fsType = "vfat"; - }; - }; - - swapDevices = [{ - device = "/dev/disk/by-uuid/9b9049c5-5975-441d-9ac6-2f9150775fd6"; - }]; - - tvl.cache.enable = true; - - networking.hostName = "khamovnik"; - networking.networkmanager.enable = true; - - nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; - powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; - hardware.cpu.intel.updateMicrocode = true; - hardware.enableRedistributableFirmware = true; - hardware.graphics.extraPackages = with pkgs; [ - intel-compute-runtime - intel-media-driver - intel-vaapi-driver - ]; - - # from generated configuration.nix - # Bootloader. - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = true; - - # Setup keyfile - boot.initrd.secrets = { - "/crypto_keyfile.bin" = null; - }; - - # Enable swap on luks - boot.initrd.luks.devices."luks-e9a4b4dc-ade2-45bf-8ed0-0ed5c4c392c9".device = "/dev/disk/by-uuid/e9a4b4dc-ade2-45bf-8ed0-0ed5c4c392c9"; - boot.initrd.luks.devices."luks-e9a4b4dc-ade2-45bf-8ed0-0ed5c4c392c9".keyFile = "/crypto_keyfile.bin"; - - # Select internationalisation properties. - i18n.defaultLocale = "en_US.UTF-8"; - i18n.extraLocaleSettings = { - LC_ADDRESS = "ru_RU.UTF-8"; - LC_IDENTIFICATION = "ru_RU.UTF-8"; - LC_MEASUREMENT = "ru_RU.UTF-8"; - LC_MONETARY = "ru_RU.UTF-8"; - LC_NAME = "ru_RU.UTF-8"; - LC_NUMERIC = "ru_RU.UTF-8"; - LC_PAPER = "ru_RU.UTF-8"; - LC_TELEPHONE = "ru_RU.UTF-8"; - LC_TIME = "ru_RU.UTF-8"; - }; - - # Enable sound with pipewire. - services.pulseaudio.enable = false; - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - }; - - # Try to work around Intel CPU throttling bugs - services.throttled.enable = true; - - # Try to get suspend to work more reliably - services.logind = { - lidSwitch = "suspend"; - lidSwitchDocked = "suspend"; - lidSwitchExternalPower = "suspend"; - }; - - virtualisation.docker.enable = true; - - hardware.bluetooth.enable = true; - users.users.tazjin.extraGroups = [ "tss" ]; - - environment.systemPackages = with pkgs; [ - tdesktop - linuxPackages.perf - hotspot - protobuf - ]; - - programs.adb.enable = true; - - system.stateVersion = "23.05"; # Did you read the comment? -} diff --git a/users/tazjin/nixos/koptevo/default.nix b/users/tazjin/nixos/koptevo/default.nix deleted file mode 100644 index 187f7b92f..000000000 --- a/users/tazjin/nixos/koptevo/default.nix +++ /dev/null @@ -1,309 +0,0 @@ -# NUC in my closet. -_: # ignore readTree options - -{ config, depot, lib, pkgs, ... }: - -let - mod = name: depot.path.origSrc + ("/ops/modules/" + name); - usermod = name: depot.path.origSrc + ("/users/tazjin/nixos/modules/" + name); -in -{ - imports = [ - (mod "quassel.nix") - (mod "www/base.nix") - (usermod "airsonic.nix") - (usermod "geesefs.nix") - (usermod "homepage.nix") - (usermod "miniflux.nix") - (usermod "predlozhnik.nix") - (usermod "tgsa.nix") - (depot.third_party.agenix.src + "/modules/age.nix") - ]; - - boot = { - loader.systemd-boot.enable = true; - loader.efi.canTouchEfiVariables = true; - initrd.availableKernelModules = [ "ahci" "xhci_pci" "usb_storage" "sd_mod" "sdhci_pci" ]; - kernelModules = [ "kvm-intel" ]; - kernelParams = [ "nomodeset" ]; - }; - - nix.settings.trusted-users = [ "tazjin" ]; - - fileSystems = { - "/" = { - device = "rpool/root"; - fsType = "zfs"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/E214-E6B3"; - fsType = "vfat"; - }; - - "/var" = { - device = "rpool/var"; - fsType = "zfs"; - }; - - "/home" = { - device = "rpool/home"; - fsType = "zfs"; - }; - }; - - hardware.cpu.intel.updateMicrocode = true; - hardware.enableRedistributableFirmware = true; - services.fwupd.enable = true; - - networking = { - hostName = "koptevo"; - hostId = "07bbbf4f"; - domain = "tazj.in"; - useDHCP = true; - firewall.enable = true; - firewall.allowedTCPPorts = [ 22 80 443 8776 9443 ]; - - wireless.enable = true; - wireless.networks."How do I computer fast?" = { - psk = "washyourface"; - }; - }; - - time.timeZone = "UTC"; - - security.acme = { - acceptTerms = true; - defaults.email = lib.mkForce "acme@tazj.in"; - - # wildcard cert for usage with Yggdrasil services - certs."y.tazj.in" = { - dnsProvider = "yandexcloud"; - credentialFiles.YANDEX_CLOUD_IAM_TOKEN_FILE = "/run/agenix/lego-yandex"; - extraDomainNames = [ "*.y.tazj.in" ]; - - # folder tvl/tazjin-private/default - environmentFile = builtins.toFile "lego-yandex-env" '' - YANDEX_CLOUD_FOLDER_ID=b1gq41rsbggeum4qafnh - ''; - }; - }; - - programs.fish.enable = true; - - users.users.tazjin = { - isNormalUser = true; - extraGroups = [ "wheel" "docker" "systemd-journal" ]; - shell = pkgs.fish; - openssh.authorizedKeys.keys = depot.users.tazjin.keys.all; - }; - - users.users.nginx.extraGroups = [ "acme" ]; - - age.secrets = - let - secretFile = name: depot.users.tazjin.secrets."${name}.age"; - in - { - lego-yandex.file = secretFile "lego-yandex"; - tgsa-yandex.file = secretFile "tgsa-yandex"; - }; - - security.sudo.wheelNeedsPassword = false; - - services.openssh.enable = true; - - services.depot.quassel = { - enable = true; - acmeHost = "koptevo.tazj.in"; - bindAddresses = [ - "0.0.0.0" - "::" - ]; - }; - - services.tailscale = { - enable = true; - useRoutingFeatures = "server"; # for exit-node usage - }; - - # Automatically collect garbage from the Nix store. - services.depot.automatic-gc = { - enable = true; - interval = "daily"; - diskThreshold = 15; # GiB - maxFreed = 10; # GiB - preserveGenerations = "14d"; - }; - - services.nginx.virtualHosts."koptevo.tazj.in" = { - addSSL = true; - enableACME = true; - - extraConfig = '' - location = / { - return 302 https://at.tvl.fyi/?q=%2F%2Fusers%2Ftazjin%2Fnixos%2Fkoptevo%2Fdefault.nix; - } - ''; - }; - - # I don't use the podcast nor playlist feature, - # but I *have to* supply podcasts to gonic ... - systemd.tmpfiles.rules = [ - "d /tmp/fake-podcasts 0555 nobody nobody -" - "d /tmp/fake-playlists 0555 nobody nobody -" - ]; - - services.gonic = { - enable = true; - settings = { - listen-addr = "0.0.0.0:4747"; - scan-interval = 5; - scan-at-start-enabled = true; - podcast-path = [ "/tmp/fake-podcasts" ]; - playlists-path = [ "/tmp/fake-playlists" ]; - music-path = [ "/var/lib/geesefs/tazjins-files/music" ]; - }; - }; - - # hack to work around the strict sandboxing of the gonic module - # breaking DNS resolution - systemd.services.gonic.serviceConfig.BindReadOnlyPaths = [ - "-/etc/resolv.conf" - ]; - - # add a hard dependency on the FUSE mount - systemd.services.gonic.requires = [ "geesefs.service" ]; - - services.nginx.virtualHosts."music.tazj.in" = { - addSSL = true; - enableACME = true; - - locations."/" = { - proxyPass = "http://127.0.0.1:4747"; - }; - }; - - # List packages installed in system profile. To search, run: - # $ nix search wget - environment.systemPackages = with pkgs; [ - bat - curl - emacs-nox - htop - jq - nano - nmap - radicle-node - wget - ]; - - # configure Yggdrasil network - services.yggdrasil = { - enable = true; - persistentKeys = true; - openMulticastPort = true; - - settings = { - Listen = [ "tls://[::]:9443" ]; # yggd - IfName = "ygg0"; - Peers = [ - "quic://ygg-msk-1.averyan.ru:8364" - "tls://ekb.itrus.su:7992" - "tls://s-mow-1.sergeysedoy97.ru:65534" - ]; - - MulticastInterfaces = [{ - Regex = "enp.*"; - Beacon = true; - Listen = true; - Port = 0; - }]; - - AllowedPublicKeys = [ - "573fd89392e2741ead4edd85034c91c88f1e560d991bbdbf1fccb6233db4d325" # khamovnik - "a56300c3af1ad54840f4b38b9438e3c108a0aa0fd72793dc7d6bd57325c6d691" # zamalek - "301e98e68522f55b3d9fb7a37817eb0e1aeb6478ef1ac124b9915080e9be205f" # tverskoy - "152b658f8a3e0cd6d1486c3cb984795ec7c9a02274c9f096bd2045cabf8bfa92" # A9 - "550f4920592d2831d013fd1c83ba9ad174ec352273260fd5d7c2627dbe60d097" # matepad - ]; - }; - }; - - # TODO(tazjin): move this to a module for radicle stuff - services.radicle = { - enable = true; - publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILHs6jSvMdtu9oJCt48etEs8ExjfGY5PmWQsRzFleogS"; - privateKeyFile = "/etc/secrets/radicle"; # TODO: to manage, or not to manage ... - - settings = { - web.pinned.repositories = [ - "rad:z3r5zMi9U3az3i4cPKxMcA3K7xx9L" # depot - "rad:z2mdnBK1tX6pibdBfRct3ThCgheHu" # tvix-go - ]; - - node = { - alias = "rad.tazj.in"; - seedingPolicy.default = "block"; - }; - }; - - node = { - openFirewall = true; - listenAddress = "[::]"; - }; - - httpd = { - enable = true; - listenAddress = "127.0.0.1"; - listenPort = 7235; # radl - }; - }; - - services.nginx.virtualHosts."rad.tazj.in" = { - enableACME = true; - forceSSL = true; - locations."/".proxyPass = "http://127.0.0.1:7235"; - }; - - services.nginx.virtualHosts."rad.y.tazj.in" = { - enableSSL = true; - useACMEHost = "y.tazj.in"; - locations = config.services.nginx.virtualHosts."rad.tazj.in".locations; - }; - - services.nginx.virtualHosts."src.tazj.in" = { - enableACME = true; - forceSSL = true; - root = depot.third_party.radicle-explorer.withPreferredSeeds [{ - hostname = "rad.tazj.in"; - port = 443; - scheme = "https"; - }]; - - locations."/" = { - index = "index.html"; - extraConfig = '' - try_files $uri $uri/ /index.html; - ''; - }; - }; - - services.nginx.virtualHosts."src.y.tazj.in" = { - enableSSL = true; - useACMEHost = "y.tazj.in"; - root = depot.third_party.radicle-explorer.withPreferredSeeds [{ - hostname = "rad.y.tazj.in"; - port = 443; - scheme = "https"; - }]; - - locations = config.services.nginx.virtualHosts."src.tazj.in".locations; - }; - - programs.mtr.enable = true; - programs.mosh.enable = true; - zramSwap.enable = true; - - system.stateVersion = "23.05"; -} diff --git a/users/tazjin/nixos/modules/airsonic.nix b/users/tazjin/nixos/modules/airsonic.nix deleted file mode 100644 index 815f18377..000000000 --- a/users/tazjin/nixos/modules/airsonic.nix +++ /dev/null @@ -1,32 +0,0 @@ -# airsonic is a decent, web-based player UI for subsonic -{ pkgs, ... }: - -let - env = builtins.toFile "env.js" '' - window.env = { - SERVER_URL: "https://music.tazj.in", - } - ''; - - airsonicDist = pkgs.fetchzip { - name = "airsonic-refix"; - - # from master CI @ f894d5eacebec2f47486f340c8610f446d4f64b3 - # https://github.com/tamland/airsonic-refix/actions/runs/6150155527 - url = "https://storage.yandexcloud.net/tazjin-public/airsonic-refix-f894d5ea.zip"; - sha256 = "02rnh9h7rh22wkghays389yddwbwg7sawmczdxdmjrcnkc7mq2jz"; - - stripRoot = false; - postFetch = "cp ${env} $out/env.js"; - }; -in -{ - services.nginx.virtualHosts."player.tazj.in" = { - enableACME = true; - forceSSL = true; - root = "${airsonicDist}"; - - # deal with SPA routing requirements - locations."/".extraConfig = "try_files $uri /index.html;"; - }; -} diff --git a/users/tazjin/nixos/modules/chromium.nix b/users/tazjin/nixos/modules/chromium.nix deleted file mode 100644 index 22f1c8d36..000000000 --- a/users/tazjin/nixos/modules/chromium.nix +++ /dev/null @@ -1,30 +0,0 @@ -# Configure the Chromium browser with various useful things. -{ pkgs, ... }: - -{ - environment.systemPackages = [ - (pkgs.chromium.override { - enableWideVine = true; # DRM support (for Кинопоиск) - }) - ]; - - programs.chromium = { - enable = true; - homepageLocation = "about:blank"; - - extensions = [ - "dbepggeogbaibhgnhhndojpepiihcmeb" # Vimium - "cjpalhdlnbpafiamejdnhcphjbkeiagm" # uBlock Origin - "mohaicophfnifehkkkdbcejkflmgfkof" # nitter redirect - "lhdifindchogekmjooeiolmjdlheilae" # Huruf - ]; - - extraOpts = { - SpellcheckEnabled = true; - SpellcheckLanguage = [ - "ru" - "en-GB" - ]; - }; - }; -} diff --git a/users/tazjin/nixos/modules/default.nix b/users/tazjin/nixos/modules/default.nix deleted file mode 100644 index d747e8e13..000000000 --- a/users/tazjin/nixos/modules/default.nix +++ /dev/null @@ -1,2 +0,0 @@ -# Make readTree happy at this level. -_: { } diff --git a/users/tazjin/nixos/modules/desktop.nix b/users/tazjin/nixos/modules/desktop.nix deleted file mode 100644 index d2cdb3764..000000000 --- a/users/tazjin/nixos/modules/desktop.nix +++ /dev/null @@ -1,79 +0,0 @@ -# EXWM and other desktop configuration. -{ config, depot, lib, pkgs, ... }: - -{ - services = { - pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - }; - - blueman.enable = true; - libinput.enable = true; - - xserver = { - enable = true; # wayland doesn't work otherwise ...?! - displayManager.gdm = { - enable = true; - wayland = true; - }; - }; - }; - - services.displayManager.sessionPackages = [ pkgs.niri ]; - - programs.xwayland.enable = true; - - environment.systemPackages = with pkgs; [ - # core packages - niri - xwayland-satellite - swaylock - - # support tooling - alacritty - fuzzel - kanshi - qt5.qtwayland - swayidle - waybar - wdisplays - wl-clipboard - wl-mirror - wlr-randr - xfce.xfce4-appfinder - depot.users.tazjin.niri-reap - ]; - - # Do not restart the display manager automatically - systemd.services.display-manager.restartIfChanged = lib.mkForce false; - - # pipewire MUST start before niri, otherwise screen sharing doesn't work - systemd.user.services.pipewire.wantedBy = [ "niri.service" ]; - systemd.user.services.pipewire.before = [ "niri.service" ]; - - # enable "desktop portals", which are important somehow - xdg.portal = { - enable = true; - extraPortals = with pkgs; [ - xdg-desktop-portal-gtk - xdg-desktop-portal-gnome - ]; - config.common.default = "*"; - }; - - # swaylock needs an empty PAM configuration, otherwise it locks the user out - security.pam.services.swaylock = { }; - - # enable theming support for Qt that is compatible with Chicago95 theme - qt.enable = true; - qt.platformTheme = "qt5ct"; - - # If something needs more than 10s to stop it should probably be - # killed. - systemd.extraConfig = '' - DefaultTimeoutStopSec=10s - ''; -} diff --git a/users/tazjin/nixos/modules/fonts.nix b/users/tazjin/nixos/modules/fonts.nix deleted file mode 100644 index 01ec11842..000000000 --- a/users/tazjin/nixos/modules/fonts.nix +++ /dev/null @@ -1,26 +0,0 @@ -# Attempt at configuring reasonable font-rendering. - -{ depot, pkgs, ... }: - -{ - fonts = { - packages = with pkgs; [ - corefonts - dejavu_fonts - font-awesome - jetbrains-mono - noto-fonts-cjk-sans - noto-fonts-color-emoji - noto-fonts-monochrome-emoji - ]; - - fontconfig = { - hinting.enable = true; - subpixel.lcdfilter = "light"; - - defaultFonts = { - monospace = [ "JetBrains Mono" ]; - }; - }; - }; -} diff --git a/users/tazjin/nixos/modules/geesefs.nix b/users/tazjin/nixos/modules/geesefs.nix deleted file mode 100644 index 60ee821e2..000000000 --- a/users/tazjin/nixos/modules/geesefs.nix +++ /dev/null @@ -1,38 +0,0 @@ -{ depot, pkgs, ... }: - -{ - imports = [ - (depot.third_party.agenix.src + "/modules/age.nix") - ]; - - age.secrets.geesefs-tazjins-files.file = depot.users.tazjin.secrets."geesefs-tazjins-files.age"; - programs.fuse.userAllowOther = true; - - systemd.services.geesefs = { - description = "geesefs @ tazjins-files"; - wantedBy = [ "multi-user.target" ]; - path = [ pkgs.fuse ]; - - serviceConfig = { - # TODO: can't get fusermount to work for non-root users (e.g. DynamicUser) here, why? - - Restart = "always"; - LoadCredential = "geesefs-tazjins-files:/run/agenix/geesefs-tazjins-files"; - StateDirectory = "geesefs"; - ExecStartPre = "/run/wrappers/bin/umount -a -t fuse.geesefs"; - }; - - script = '' - set -u # bail out if systemd is misconfigured ... - set -x - - mkdir -p $STATE_DIRECTORY/tazjins-files $STATE_DIRECTORY/cache - - ${pkgs.geesefs}/bin/geesefs \ - -f -o allow_other \ - --cache $STATE_DIRECTORY/cache \ - --shared-config $CREDENTIALS_DIRECTORY/geesefs-tazjins-files \ - tazjins-files $STATE_DIRECTORY/tazjins-files - ''; - }; -} diff --git a/users/tazjin/nixos/modules/hidpi.nix b/users/tazjin/nixos/modules/hidpi.nix deleted file mode 100644 index 2ff61d499..000000000 --- a/users/tazjin/nixos/modules/hidpi.nix +++ /dev/null @@ -1,19 +0,0 @@ -# Configuration for machines with HiDPI displays, which are a total -# mess, of course. -{ ... }: - -{ - # Expose a variable to all programs that might be interested in the - # screen settings to do conditional initialisation (mostly for Emacs). - environment.variables.HIDPI_SCREEN = "true"; - - # TODO(tazjin): this option has been removed and needs to be replaced - # by manual configuration: https://github.com/NixOS/nixpkgs/issues/222805 - # Ensure a larger font size in early boot stage. - # hardware.video.hidpi.enable = true; - - # Bump DPI across the board. - # TODO(tazjin): This should actually be set per monitor, but I - # haven't yet figured out the right interface for doing that. - services.xserver.dpi = 161; -} diff --git a/users/tazjin/nixos/modules/home-config.nix b/users/tazjin/nixos/modules/home-config.nix deleted file mode 100644 index 9aa1cab46..000000000 --- a/users/tazjin/nixos/modules/home-config.nix +++ /dev/null @@ -1,21 +0,0 @@ -# Inject the right home-manager config for the machine. - -{ config, depot, pkgs, ... }: - -{ - users.users.tazjin = { - isNormalUser = true; - createHome = true; - extraGroups = [ "wheel" "networkmanager" "video" "adbusers" "yggdrasil" ]; - uid = 1000; - shell = pkgs.fish; - initialHashedPassword = "$2b$05$1eBPdoIgan/C/L8JFqIHBuVscQyTKw1L/4VBlzlLvLBEf6CXS3EW6"; - }; - - nix.settings.trusted-users = [ "tazjin" ]; - - home-manager.backupFileExtension = "backup"; - home-manager.useGlobalPkgs = true; - home-manager.users.tazjin = with depot.users.tazjin; - home."${config.networking.hostName}" or home.shared; -} diff --git a/users/tazjin/nixos/modules/homepage.nix b/users/tazjin/nixos/modules/homepage.nix deleted file mode 100644 index 65191d6e7..000000000 --- a/users/tazjin/nixos/modules/homepage.nix +++ /dev/null @@ -1,59 +0,0 @@ -# serve tazjin's website & blog -{ depot, config, lib, pkgs, ... }: - -let - extraConfig = '' - location = /en/rss.xml { - return 301 https://tazj.in/feed.atom; - } - - ${depot.users.tazjin.blog.oldRedirects} - location /blog/ { - alias ${depot.users.tazjin.blog.rendered}/; - - if ($request_uri ~ ^/(.*)\.html$) { - return 302 /$1; - } - - try_files $uri $uri.html $uri/ =404; - } - - location = /predlozhnik { - return 302 https://predlozhnik.ru; - } - - # redirect for easier entry on a TV - location = /tv { - return 302 https://tazj.in/blobs/play.html; - } - - # Temporary place for serving static files. - location /blobs/ { - alias /var/lib/tazjins-blobs/; - } - ''; -in -{ - config = { - services.nginx.virtualHosts."tazj.in" = { - enableACME = true; - forceSSL = true; - root = depot.users.tazjin.homepage; - serverAliases = [ "www.tazj.in" ]; - inherit extraConfig; - }; - - services.nginx.virtualHosts."y.tazj.in" = { - enableSSL = true; - useACMEHost = "y.tazj.in"; - root = depot.users.tazjin.homepage; - inherit extraConfig; - }; - - services.nginx.virtualHosts."git.tazj.in" = { - enableACME = true; - forceSSL = true; - extraConfig = "return 301 https://code.tvl.fyi$request_uri;"; - }; - }; -} diff --git a/users/tazjin/nixos/modules/laptop.nix b/users/tazjin/nixos/modules/laptop.nix deleted file mode 100644 index e0d67dc25..000000000 --- a/users/tazjin/nixos/modules/laptop.nix +++ /dev/null @@ -1,15 +0,0 @@ -# Configuration specifically for laptops that move around. -{ ... }: - -{ - time.timeZone = "Europe/Moscow"; - - # Automatically detect location for redshift & so on ... - services.geoclue2.enable = true; - location.provider = "geoclue2"; - - # Enable power-saving features. - services.tlp.enable = true; - - programs.light.enable = true; -} diff --git a/users/tazjin/nixos/modules/miniflux.nix b/users/tazjin/nixos/modules/miniflux.nix deleted file mode 100644 index 72089bfb3..000000000 --- a/users/tazjin/nixos/modules/miniflux.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ config, depot, lib, pkgs, ... }: - -{ - age.secrets.miniflux.file = depot.users.tazjin.secrets."miniflux.age"; - - services.miniflux = { - enable = true; - adminCredentialsFile = "/run/agenix/miniflux"; - config.LISTEN_ADDR = "127.0.0.1:6359"; - config.BASE_URL = "https://feeds.tazj.in"; - }; - - services.nginx.virtualHosts."feeds" = { - serverName = "feeds.tazj.in"; - enableACME = true; - forceSSL = true; - - locations."/" = { - proxyPass = "http://127.0.0.1:6359"; - }; - }; -} diff --git a/users/tazjin/nixos/modules/persistence.nix b/users/tazjin/nixos/modules/persistence.nix deleted file mode 100644 index d3a918025..000000000 --- a/users/tazjin/nixos/modules/persistence.nix +++ /dev/null @@ -1,27 +0,0 @@ -# Configuration for persistent (non-home) data. -{ config, depot, pkgs, lib, ... }: - -{ - imports = [ - (depot.third_party.sources.impermanence + "/nixos.nix") - ]; - - environment.persistence."/persist" = { - directories = [ - "/etc/NetworkManager/system-connections" - "/etc/mullvad-vpn" - "/var/cache/mullvad-vpn" - "/var/lib/bluetooth" - "/var/lib/systemd/coredump" - "/var/lib/tailscale" - "/var/lib/private/yggdrasil" - "/var/log" - ]; - - files = lib.optional (builtins.isNull config.networking.hostId) [ - "/etc/machine-id" - ]; - }; - - programs.fuse.userAllowOther = true; -} diff --git a/users/tazjin/nixos/modules/physical.nix b/users/tazjin/nixos/modules/physical.nix deleted file mode 100644 index ef33ae403..000000000 --- a/users/tazjin/nixos/modules/physical.nix +++ /dev/null @@ -1,128 +0,0 @@ -# Default configuration settings for physical machines that I use. -{ lib, pkgs, config, depot, ... }: - -let - pass-otp = pkgs.pass.withExtensions (e: [ e.pass-otp ]); -in -{ - options = with lib; { - tazjin.emacs = mkOption { - type = types.package; - default = depot.users.tazjin.emacs; - description = '' - Derivation with my Emacs package, with configuration included. - ''; - }; - }; - - config = { - # Install all the default software. - environment.systemPackages = - # programs from the depot - (with depot; [ - config.tazjin.emacs - third_party.agenix.cli - tools.when - users.tazjin.chase-geese - users.tazjin.eaglemode - users.tazjin.screenLock - ]) ++ - - # programs from nixpkgs - (with pkgs; [ - (aspellWithDicts (d: [ d.ru ])) - amber - bat - curl - ddcutil - direnv - dnsutils - electrum - firefox - config.tazjin.emacs.emacs # emacsclient - expect - fd - file - gdb - git - gnupg - go - gopls - gotools - gtk3 # for gtk-launch - htop - hyperfine - iftop - imagemagick - josh - jq - lieer - maim - man-pages - moreutils - mosh - msmtp - networkmanagerapplet - nix-prefetch-github - nmap - notmuch - openssh - openssl - pass-otp - pavucontrol - pinentry - pinentry-emacs - pulseaudio # for pactl - pwgen - quasselClient - radicle-node - rink - ripgrep - rustup - screen - tig - tokei - tree - unzip - vlc - volumeicon - watchexec - whois - xclip - xsecurelock - zoxide - ]); - - # Run services & configure programs for all machines. - services.fwupd.enable = true; - - # Disable the broken NetworkManager-wait-online.service - systemd.services.NetworkManager-wait-online.enable = lib.mkForce false; - - # Disable the thing that prints annoying warnings when trying to - # run manually patchelfed binaries - environment.stub-ld.enable = false; - - # Enable yggdrasil network. - services.yggdrasil = { - enable = true; - persistentKeys = true; - settings.IfName = "ygg0"; - }; - - programs = { - fish.enable = true; - mosh.enable = true; - ssh.startAgent = true; - }; - - # Automatically collect garbage from the Nix store. - services.depot.automatic-gc = { - enable = true; - interval = "1 hour"; - diskThreshold = 16; # GiB - maxFreed = 50; # GiB - preserveGenerations = "14d"; - }; - }; -} diff --git a/users/tazjin/nixos/modules/predlozhnik.nix b/users/tazjin/nixos/modules/predlozhnik.nix deleted file mode 100644 index db20963df..000000000 --- a/users/tazjin/nixos/modules/predlozhnik.nix +++ /dev/null @@ -1,10 +0,0 @@ -# Host predlozhnik.ru, serving //users/tazjin/predlozhnik -{ depot, ... }: - -{ - services.nginx.virtualHosts."predlozhnik.ru" = { - root = depot.corp.russian.predlozhnik; - enableACME = true; - forceSSL = true; - }; -} diff --git a/users/tazjin/nixos/modules/systemd-unfreeze.nix b/users/tazjin/nixos/modules/systemd-unfreeze.nix deleted file mode 100644 index 650d233fb..000000000 --- a/users/tazjin/nixos/modules/systemd-unfreeze.nix +++ /dev/null @@ -1,15 +0,0 @@ -# Workaround for disabling semi-broken systemd user slice freezing (whatever -# that is). This can cause machines to become unusable after resume. - -let - override.environment.SYSTEMD_SLEEP_FREEZE_USER_SESSIONS = "false"; -in -{ - systemd.services = { - systemd-suspend = override; - systemd-hibernate = override; - systemd-hybrid-sleep = override; - systemd-suspend-then-hibernate = override; - }; -} - diff --git a/users/tazjin/nixos/modules/tgsa.nix b/users/tazjin/nixos/modules/tgsa.nix deleted file mode 100644 index e162e0d82..000000000 --- a/users/tazjin/nixos/modules/tgsa.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ config, depot, lib, pkgs, ... }: - -{ - systemd.services.tgsa = { - description = "telegram -> SA bbcode thing"; - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - DynamicUser = true; - Restart = "always"; - LoadCredential = "tgsa-yandex.json:/run/agenix/tgsa-yandex"; - }; - - script = '' - export YANDEX_KEY_FILE="''${CREDENTIALS_DIRECTORY}/tgsa-yandex.json" - ${depot.users.tazjin.tgsa}/bin/tgsa - ''; - }; - - services.nginx.virtualHosts."tgsa" = { - serverName = "tgsa.tazj.in"; - enableACME = true; - forceSSL = true; - - locations."/" = { - proxyPass = "http://127.0.0.1:8472"; - }; - }; -} diff --git a/users/tazjin/nixos/tverskoy/default.nix b/users/tazjin/nixos/tverskoy/default.nix deleted file mode 100644 index 856763db4..000000000 --- a/users/tazjin/nixos/tverskoy/default.nix +++ /dev/null @@ -1,159 +0,0 @@ -# tverskoy is my Thinkpad X13 AMD 1st gen -{ depot, lib, pkgs, ... }: - -config: -let - quasselClient = pkgs.quassel.override { - client = true; - enableDaemon = false; - monolithic = false; - }; - - mod = name: depot.path.origSrc + ("/ops/modules/" + name); - usermod = name: depot.path.origSrc + ("/users/tazjin/nixos/modules/" + name); -in -lib.fix (self: { - imports = [ - (mod "open_eid.nix") - (usermod "chromium.nix") - (usermod "desktop.nix") - (usermod "fonts.nix") - (usermod "home-config.nix") - (usermod "laptop.nix") - (usermod "persistence.nix") - (usermod "physical.nix") - (usermod "systemd-unfreeze.nix") - - ((pkgs.srcOnly pkgs.home-manager) + "/nixos") - ] ++ lib.optional (builtins.pathExists ./local-config.nix) ./local-config.nix; - - tvl.cache.enable = true; - tvl.cache.builderball = true; - - boot = { - initrd.availableKernelModules = [ "nvme" "ehci_pci" "xhci_pci" "usb_storage" "sd_mod" "rtsx_pci_sdmmc" ]; - initrd.kernelModules = [ ]; - - # Restore /home to the blank snapshot, erasing all ephemeral data. - initrd.postDeviceCommands = lib.mkAfter '' - zfs rollback -r zpool/ephemeral/home@tazjin-clean - ''; - - # Install thinkpad modules for TLP - extraModulePackages = [ pkgs.linuxPackages.acpi_call ]; - - kernelModules = [ "acpi_call" "kvm-amd" "i2c_dev" ]; - loader.systemd-boot.enable = true; - loader.efi.canTouchEfiVariables = true; - }; - - users.users.tazjin.extraGroups = [ "docker" "vboxusers" "adbusers" ]; - - fileSystems = { - "/" = { - device = "zpool/ephemeral/root"; - fsType = "zfs"; - }; - - "/home" = { - device = "zpool/ephemeral/home"; - fsType = "zfs"; - }; - - "/nix" = { - device = "zpool/local/nix"; - fsType = "zfs"; - }; - - "/depot" = { - device = "zpool/safe/depot"; - fsType = "zfs"; - }; - - "/persist" = { - device = "zpool/safe/persist"; - fsType = "zfs"; - neededForBoot = true; - }; - - # SD card - "/mnt" = { - device = "/dev/disk/by-uuid/c602d703-f1b9-4a44-9e45-94dfe24bdaa8"; - fsType = "ext4"; - }; - - "/boot" = { - device = "/dev/disk/by-uuid/BF4F-388B"; - fsType = "vfat"; - }; - }; - - hardware = { - cpu.amd.updateMicrocode = true; - enableRedistributableFirmware = true; - bluetooth.enable = true; - - graphics = { - enable = true; - enable32Bit = true; - - extraPackages = with pkgs; [ - vaapiVdpau - libvdpau-va-gl - ]; - }; - }; - - networking = { - hostName = "tverskoy"; - hostId = "3c91827f"; - domain = "tvl.su"; - useDHCP = false; - networkmanager.enable = true; - firewall.enable = false; - - nameservers = [ - "8.8.8.8" - "8.8.4.4" - ]; - }; - - security.rtkit.enable = true; - - services = { - tailscale.enable = true; - printing.enable = true; - - # expose i2c device as /dev/i2c-amdgpu-dm and make it user-accessible - # this is required for sending control commands to the Dasung screen. - udev.extraRules = '' - SUBSYSTEM=="i2c-dev", ACTION=="add", DEVPATH=="/devices/pci0000:00/0000:00:08.1/0000:06:00.0/i2c-5/i2c-dev/i2c-5", SYMLINK+="i2c-amdgpu-dm", TAG+="uaccess" - ''; - - xserver.videoDrivers = [ "amdgpu" ]; - }; - - systemd.user.services.lieer-tazjin = { - description = "Synchronise mail@tazj.in via lieer"; - script = "${pkgs.lieer}/bin/gmi sync"; - - serviceConfig = { - WorkingDirectory = "%h/mail/account.tazjin"; - Type = "oneshot"; - }; - }; - - systemd.user.timers.lieer-tazjin = { - wantedBy = [ "timers.target" ]; - - timerConfig = { - OnActiveSec = "1"; - OnUnitActiveSec = "180"; - }; - }; - - # android stuff for hacking on Awful.apk - programs.adb.enable = true; - - system.stateVersion = "20.09"; -}) diff --git a/users/tazjin/nixos/zamalek/default.nix b/users/tazjin/nixos/zamalek/default.nix deleted file mode 100644 index 2be79c1bd..000000000 --- a/users/tazjin/nixos/zamalek/default.nix +++ /dev/null @@ -1,83 +0,0 @@ -# zamalek is my Huawei MateBook X (unknown year) -{ depot, lib, pkgs, ... }: - -config: -let - mod = name: depot.path.origSrc + ("/ops/modules/" + name); - usermod = name: depot.path.origSrc + ("/users/tazjin/nixos/modules/" + name); - - zdevice = device: { - inherit device; - fsType = "zfs"; - }; -in -{ - imports = [ - (usermod "chromium.nix") - (usermod "desktop.nix") - (usermod "fonts.nix") - (usermod "hidpi.nix") - (usermod "home-config.nix") - (usermod "laptop.nix") - (usermod "persistence.nix") - (usermod "physical.nix") - - ((pkgs.srcOnly pkgs.home-manager) + "/nixos") - ] ++ lib.optional (builtins.pathExists ./local-config.nix) ./local-config.nix; - - tvl.cache.enable = true; - - boot = { - initrd.availableKernelModules = [ "nvme" "xhci_pci" ]; - loader.systemd-boot.enable = true; - loader.efi.canTouchEfiVariables = true; - supportedFilesystems = [ "zfs" ]; - zfs.devNodes = "/dev/"; - - extraModprobeConfig = '' - options snd_hda_intel power_save=1 - options iwlwifi power_save=1 - options iwldvm force_cam=0 - options i915 enable_guc=3 enable_fbc=1 - ''; - }; - - fileSystems = { - "/" = zdevice "zpool/ephemeral/root"; - "/home" = zdevice "zpool/ephemeral/home"; - "/persist" = zdevice "zpool/persistent/data" // { neededForBoot = true; }; - "/nix" = zdevice "zpool/persistent/nix"; - "/depot" = zdevice "zpool/persistent/depot"; - - "/boot" = { - device = "/dev/disk/by-uuid/2487-3908"; - fsType = "vfat"; - }; - }; - - networking = { - hostName = "zamalek"; - domain = "tvl.su"; - hostId = "ee399356"; - networkmanager.enable = true; - - nameservers = [ - "8.8.8.8" - "8.8.4.4" - ]; - }; - - hardware = { - cpu.intel.updateMicrocode = true; - bluetooth.enable = true; - enableRedistributableFirmware = true; - graphics.enable = true; - }; - - services.libinput.touchpad.clickMethod = "clickfinger"; - services.libinput.touchpad.tapping = false; - services.avahi.enable = true; - services.tailscale.enable = true; - - system.stateVersion = "21.11"; -} diff --git a/users/tazjin/presentations/bootstrapping-2018/README.md b/users/tazjin/presentations/bootstrapping-2018/README.md deleted file mode 100644 index e9573ae3f..000000000 --- a/users/tazjin/presentations/bootstrapping-2018/README.md +++ /dev/null @@ -1,5 +0,0 @@ -These are the slides for a talk I gave at the Norwegian Unix User Group on -2018-03-13. - -There is more information and a recording on the [event -page](https://www.nuug.no/aktiviteter/20180313-reproduible-compiler/). diff --git a/users/tazjin/presentations/bootstrapping-2018/default.nix b/users/tazjin/presentations/bootstrapping-2018/default.nix deleted file mode 100644 index 726e7064f..000000000 --- a/users/tazjin/presentations/bootstrapping-2018/default.nix +++ /dev/null @@ -1,55 +0,0 @@ -# This derivation builds the LaTeX presentation. - -{ pkgs, ... }: - -with pkgs; - -let - tex = texlive.combine { - inherit (texlive) - beamer - beamertheme-metropolis - etoolbox - euenc - extsizes - fontspec - lualibs - luaotfload - luatex - minted - count1to - multitoc - prelim2e - ragged2e - pgfopts - scheme-basic - translator; - }; -in -stdenv.mkDerivation { - name = "nuug-bootstrapping-slides"; - src = ./.; - - FONTCONFIG_FILE = makeFontsConf { - fontDirectories = [ fira fira-code fira-mono ]; - }; - - buildInputs = [ tex fira fira-code fira-mono ]; - buildPhase = '' - # LaTeX needs a cache folder in /home/ ... - mkdir home - export HOME=$PWD/home - # ${tex}/bin/luaotfload-tool -ufv - - # As usual, TeX needs to be run twice ... - function run() { - ${tex}/bin/lualatex presentation.tex - } - run && run - ''; - - installPhase = '' - mkdir -p $out - cp presentation.pdf $out/ - ''; -} diff --git a/users/tazjin/presentations/bootstrapping-2018/drake-meme.png b/users/tazjin/presentations/bootstrapping-2018/drake-meme.png deleted file mode 100644 index 4b0367543..000000000 Binary files a/users/tazjin/presentations/bootstrapping-2018/drake-meme.png and /dev/null differ diff --git a/users/tazjin/presentations/bootstrapping-2018/nixos-logo.png b/users/tazjin/presentations/bootstrapping-2018/nixos-logo.png deleted file mode 100644 index ce0c98c2c..000000000 Binary files a/users/tazjin/presentations/bootstrapping-2018/nixos-logo.png and /dev/null differ diff --git a/users/tazjin/presentations/bootstrapping-2018/notes.org b/users/tazjin/presentations/bootstrapping-2018/notes.org deleted file mode 100644 index 363d75352..000000000 --- a/users/tazjin/presentations/bootstrapping-2018/notes.org +++ /dev/null @@ -1,89 +0,0 @@ -#+TITLE: Bootstrapping, reproducibility, etc. -#+AUTHOR: Vincent Ambo -#+DATE: <2018-03-10 Sat> - -* Compiler bootstrapping - This section contains notes about compiler bootstrapping, the - history thereof, which compilers need it - and so on: - -** C - -** Haskell - - self-hosted compiler (GHC) - -** Common Lisp - CL is fairly interesting in this space because it is a language - that is defined via an ANSI standard that compiler implementations - normally actually follow! - - CL has several ecosystem components that focus on making - abstracting away implementation-specific calls and if a self-hosted - compiler is written in CL using those components it can be - cross-bootstrapped. - -** Python - -* A note on runtimes - Sometimes the compiler just isn't enough ... - -** LLVM -** JVM - -* References - https://github.com/mame/quine-relay - https://manishearth.github.io/blog/2016/12/02/reflections-on-rusting-trust/ - https://tests.reproducible-builds.org/debian/reproducible.html - -* Slide thoughts: - 1. Hardware trust has been discussed here a bunch, most recently - during the puri.sm talk. Hardware trust is important, as we see - with IME, but it's striking that people often take a leap to "I'm - now on my trusted Debian with free software". - - Unless you built it yourself from scratch (Spoiler: you haven't) - you're placing trust in what is basically foreign binary blobs. - - Agenda: Implications/attack vectors of this, state of the chicken - & egg, the topic of reproducibility, what can you do? (Nix!) - - 2. Chicken-and-egg issue - - It's an important milestone for a language to become self-hosted: - You begin doing a kind of dogfeeding, you begin to enforce - reliability & consistency guarantees to avoid having to redo your - own codebase constantly and so on. - - However, the implication is now that you need your own compiler - to compile itself. - - Common examples: - - C/C++ compilers needed to build C/C++ compilers: - - GCC 4.7 was the last version of GCC that could be built with a - standard C-compiler, nowadays it is mostly written in C++. - - Certain versions of GCC can be built with LLVM/Clang. - - Clang/LLVM can be compiled by itself and also GCC. - - - Rust was originally written in OCAML but moved to being - self-hosted in 2011. Currently rustc-releases are always built - with a copy of the previous release. - - It's relatively new so we can build the chain all the way. - - Notable exceptions: Some popular languages are not self-hosted, - for example Clojure. Languages also have runtimes, which may be - written in something else (e.g. Haskell -> C runtime) -* How to help: - Most of this advice is about reproducible builds, not bootstrapping, - as that is a much harder project. - - - fix reproducibility issues listed in Debian's issue tracker (focus - on non-Debian specific ones though) - - experiment with NixOS / GuixSD to get a better grasp on the - problem space of reproducibility - - If you want to contribute to bootstrapping, look at - bootstrappable.org and their wiki. Several initiatives such as MES - could need help! diff --git a/users/tazjin/presentations/bootstrapping-2018/presentation.pdf b/users/tazjin/presentations/bootstrapping-2018/presentation.pdf deleted file mode 100644 index 7f435fe5b..000000000 Binary files a/users/tazjin/presentations/bootstrapping-2018/presentation.pdf and /dev/null differ diff --git a/users/tazjin/presentations/bootstrapping-2018/presentation.tex b/users/tazjin/presentations/bootstrapping-2018/presentation.tex deleted file mode 100644 index d3aa61337..000000000 --- a/users/tazjin/presentations/bootstrapping-2018/presentation.tex +++ /dev/null @@ -1,251 +0,0 @@ -\documentclass[12pt]{beamer} -\usetheme{metropolis} -\newenvironment{code}{\ttfamily}{\par} -\title{Where does \textit{your} compiler come from?} -\date{2018-03-13} -\author{Vincent Ambo} -\institute{Norwegian Unix User Group} -\begin{document} - \maketitle - - %% Slide 1: - \section{Introduction} - - %% Slide 2: - \begin{frame}{Chicken and egg} - Self-hosted compilers are often built using themselves, for example: - - \begin{itemize} - \item C-family compilers bootstrap themselves \& each other - \item (Some!) Common Lisp compilers can bootstrap each other - \item \texttt{rustc} bootstraps itself with a previous version - \item ... same for many other languages! - \end{itemize} - \end{frame} - - \begin{frame}{Chicken, egg and ... lizard?} - It's not just compilers: Languages have runtimes, too. - - \begin{itemize} - \item JVM is implemented in C++ - \item Erlang-VM is C - \item Haskell runtime is C - \end{itemize} - - ... we can't ever get away from C, can we? - \end{frame} - - %% Slide 3: - \begin{frame}{Trusting Trust} - \begin{center} - \huge{Could this be exploited?} - \end{center} - \end{frame} - - %% Slide 4: - \begin{frame}{Short interlude: A quine} - \begin{center} - \begin{code} - ((lambda (x) (list x (list 'quote x))) - \newline\vspace*{6mm} '(lambda (x) (list x (list 'quote x)))) - \end{code} - \end{center} - \end{frame} - - %% Slide 5: - \begin{frame}{Short interlude: Quine Relay} - \begin{center} - \includegraphics[ - keepaspectratio=true, - height=\textheight - ]{quine-relay.png} - \end{center} - \end{frame} - - %% Slide 6: - \begin{frame}{Trusting Trust} - An attack described by Ken Thompson in 1983: - - \begin{enumerate} - \item Modify a compiler to detect when it's compiling itself. - \item Let the modification insert \textit{itself} into the new compiler. - \item Add arbitrary attack code to the modification. - \item \textit{Optional!} Remove the attack from the source after compilation. - \end{enumerate} - \end{frame} - - %% Slide 7: - \begin{frame}{Damage potential?} - \begin{center} - \large{Let your imagination run wild!} - \end{center} - \end{frame} - - %% Slide 8: - \section{Countermeasures} - - %% Slide 9: - \begin{frame}{Diverse Double-Compiling} - Assume we have: - - \begin{itemize} - \item Target language compilers $A$ and $T$ - \item The source code of $A$: $ S_{A} $ - \end{itemize} - \end{frame} - - %% Slide 10: - \begin{frame}{Diverse Double-Compiling} - Apply the first stage (functional equivalence): - - \begin{itemize} - \item $ X = A(S_{A})$ - \item $ Y = T(S_{A})$ - \end{itemize} - - Apply the second stage (bit-for-bit equivalence): - - \begin{itemize} - \item $ V = X(S_{A})$ - \item $ W = Y(S_{A})$ - \end{itemize} - - Now we have a new problem: Reproducibility! - \end{frame} - - %% Slide 11: - \begin{frame}{Reproducibility} - Bit-for-bit equivalent output is hard, for example: - - \begin{itemize} - \item Timestamps in output artifacts - \item Non-deterministic linking order in concurrent builds - \item Non-deterministic VM \& memory states in outputs - \item Randomness in builds (sic!) - \end{itemize} - \end{frame} - - \begin{frame}{Reproducibility} - \begin{center} - Without reproducibility, we can never trust that any shipped - binary matches the source code! - \end{center} - \end{frame} - - %% Slide 12: - \section{(Partial) State of the Union} - - \begin{frame}{The Desired State} - \begin{center} - \begin{enumerate} - \item Full-source bootstrap! - \item All packages reproducible! - \end{enumerate} - \end{center} - \end{frame} - - %% Slide 13: - \begin{frame}{Bootstrapping Debian} - \begin{itemize} - \item Sparse information on the Debian-wiki - \item Bootstrapping discussions mostly resolve around new architectures - \item GCC is compiled by depending on previous versions of GCC - \end{itemize} - \end{frame} - - \begin{frame}{Reproducing Debian} - Debian has a very active effort for reproducible builds: - - \begin{itemize} - \item Organised information about reproducibility status - \item Over 90\% reproducibility in Debian package base! - \end{itemize} - \end{frame} - - \begin{frame}{Short interlude: Nix} - \begin{center} - \includegraphics[ - keepaspectratio=true, - height=0.7\textheight - ]{nixos-logo.png} - \end{center} - \end{frame} - - \begin{frame}{Short interlude: Nix} - \begin{center} - \includegraphics[ - keepaspectratio=true, - height=0.90\textheight - ]{drake-meme.png} - \end{center} - \end{frame} - - \begin{frame}{Short interlude: Nix} - \begin{center} - \includegraphics[ - keepaspectratio=true, - height=0.7\textheight - ]{nixos-logo.png} - \end{center} - \end{frame} - - \begin{frame}{Bootstrapping NixOS} - Nix evaluation can not recurse forever: The bootstrap can not - simply depend on a previous GCC. - - Workaround: \texttt{bootstrap-tools} tarball from a previous - binary cache is fetched and used. - - An unfortunate magic binary blob ... - \end{frame} - - \begin{frame}{Reproducing NixOS} - Not all reproducibility patches have been ported from Debian. - - However: Builds are fully repeatable via the Nix fundamentals! - \end{frame} - - \section{Future Developments} - - \begin{frame}{Bootstrappable: stage0} - Hand-rolled ``Cthulhu's Path to Madness'' hex-programs: - - \begin{itemize} - \item No non-auditable binary blobs - \item Aims for understandability by 70\% of programmers - \item End goal is a full-source bootstrap of GCC - \end{itemize} - \end{frame} - - - \begin{frame}{Bootstrappable: MES} - Bootstrapping the ``Maxwell Equations of Software'': - - \begin{itemize} - \item Minimal C-compiler written in Scheme - \item Minimal Scheme-interpreter (currently in C, but intended to - be rewritten in stage0 macros) - \item End goal is full-source bootstrap of the entire GuixSD - \end{itemize} - \end{frame} - - \begin{frame}{Other platforms} - \begin{itemize} - \item Nix for Darwin is actively maintained - \item F-Droid Android repository works towards fully reproducible - builds of (open) Android software - \item Mobile devices (phones, tablets, etc.) are a lost cause at - the moment - \end{itemize} - \end{frame} - - \begin{frame}{Thanks!} - Resources: - \begin{itemize} - \item bootstrappable.org - \item reproducible-builds.org - \end{itemize} - - @tazjin | mail@tazj.in - \end{frame} -\end{document} diff --git a/users/tazjin/presentations/bootstrapping-2018/quine-relay.png b/users/tazjin/presentations/bootstrapping-2018/quine-relay.png deleted file mode 100644 index 5644dc390..000000000 Binary files a/users/tazjin/presentations/bootstrapping-2018/quine-relay.png and /dev/null differ diff --git a/users/tazjin/presentations/bootstrapping-2018/result.pdfpc b/users/tazjin/presentations/bootstrapping-2018/result.pdfpc deleted file mode 100644 index b0fa6c9a0..000000000 --- a/users/tazjin/presentations/bootstrapping-2018/result.pdfpc +++ /dev/null @@ -1,142 +0,0 @@ -[file] -result -[last_saved_slide] -10 -[font_size] -20000 -[notes] -### 1 -- previous discussions of hardware trust (e.g. purism presentation) -- people leap to "now I'm on my trusted Debian!" -- unless you built it from scratch (spoiler: you haven't) you're *trusting* someone - -Agenda: Implications of trust with focus on bootstrap paths and reproducibility, plus how you can help.### 2 -self-hosting: -- C-family: GCC pre/post 4.7, Clang -- Common Lisp: Sunshine land! (with SBCL) -- rustc: Bootstrap based on previous versions (C++ transpiler underway!) -- many other languages also work this way! - -(Noteable counterexample: Clojure is written in Java!)### 3 - -- compilers are just one bit, the various runtimes exist, too!### 4 - -Could this be exploited? - -People don't think about where their compiler comes from. - -Even if they do, they may only go so far as to say "I'll just recompile it using ". - -Unfortunately, spoiler alert, life isn't that easy in the computer world and yes, exploitation is possible.### 5 - -- describe what a quine is -- classic Lisp quine -- explain demo quine -- demo demo quine - -- this is interesting, but not useful - can quines do more than that?### 6 - -- quine-relay: "art project" with 128-language circular quine - -- show source of quine-relay - -- (demo quine relay?) - -- side-note: this program is very, very trustworthy!### 7 - -Ken Thompson (designer of UNIX and a couple other things!) received Turing award in 1983, and described attack in speech. - -- figure out how to detect self-compilation -- make that modification a quine -- insert modification into new compiler -- add attack code to modification -- remove attack from source, distributed binary will still be compromised! it's like evolution :)### 8 - -damage potential is basically infinite: - -- classic "login" attack -=> also applicable to other credentials - -- attack (weaken) crypto algorithms - -- you can probably think of more!### 10 - -idea being: potential vulnerability would have to work across compilers: - -the more compilers we can introduce (e.g. more architectures, different versions, different compilers), the harder it gets for a vulnerability to survive all of those - -The more compilers, the merrier! Lisps are pretty good at this.### 11 - -if we get a bit-mismatch after DDC, not all hope is lost: Maybe the thing just isn't reproducible! - -- many reasons for failures -- timestamps are a classic! artifacts can be build logs, metadata in ZIP-files or whatever -- non-determinism is the devil -- sometimes people actively introduce build-randomness (NaCl)### 12 - -- Does that binary download on the project's website really match the source? - -- Your Linux packages are signed by someone - cool - but what does that mean?### 13 - -Two things should be achieved - gross oversimplification - to get to the ideal "desired state of the union": - -1. full-source bootstrap: without ever introducing any binaries, go from nothing to a full Linux distribution - -2. when packages are distributed, we should be able to know the expected output of a source package beforehand - -=> suddenly binary distributions become a cache! But more on Nix later.### 14 - -- Debian project does not seem as concerned with bootstrapping as with reproducibility -- Debian mostly bootstraps on new architectures (using cross-compilation and similar techniques, from an existing binary base) -- core bootstrap (GCC & friends) is performed with previous Debian version and depending on GCC### 15 - -... however! Debian cares about reproducibility. - -- automated testing of reproducibility -- information about the status of all packages is made available in repos -- Over 90% packages of packages are reproducible! - -< show reproducible builds website > - -Debian is still fundamentally a binary distribution though, but it doesn't have to be that way.### 16 - -Nix - a purely functional package manager - -It's not a new project (10+ years), been discussed here before, has multiple components: package manager, language, NixOS. - -Instead of describing *how* to build a thing, Nix describes *what* to build:### 17 -### 19 - -In Nix, it's impossible to say "GCC is the result of applying GCC to the GCC source", because that happens to be infinite recursion. - -Bootstrapping in Nix works by introducing a binary pinned by its full-hash, which was built on some previous Nix version. - -Unfortunately also just a magic binary blob ... ### 20 - -NixOS is not actively porting all of Debian's reproducibility patches, but builds are fully repeatable: - -- introducing a malicious compiler would produce a different input hash -> different package - -Future slide: hope is not lost! Things are underway.### 21 - -- bootstrappable.org (demo?) is an umbrella page for several projects working on bootstrappability - -- stage0 is an important piece: manually, small, auditable Hex programs to get to a Hex macro expander - -- end goal is a full-source bootrap, but pieces are missing### 22 - -MES is out of the GuixSD circles (explain Guix, GNU Hurd joke) - -- idea being that once you have a Lisp, you have all of computing (as Alan Key said) - -- includes MesCC in Scheme -> can *almost* make a working tinyCC -> can *almost* make a working gcc 4.7 - -- minimal Scheme interpreter, currently built in C to get the higher-level stuff to work, goal is rewrite in hex -- bootstrapping Guix is the end goal### 23 - -- userspace in Darwin has a Nix project -- unsure about other BSDs, but if anyone knows - input welcome! -- F-Droid has reproducible Android packages, but that's also userspace only -- All other mobile platforms are a lost cause - -Generally, all closed-source software is impossible to trust. diff --git a/users/tazjin/presentations/erlang-2016/.skip-subtree b/users/tazjin/presentations/erlang-2016/.skip-subtree deleted file mode 100644 index e69de29bb..000000000 diff --git a/users/tazjin/presentations/erlang-2016/README.md b/users/tazjin/presentations/erlang-2016/README.md deleted file mode 100644 index e1b6c83b9..000000000 --- a/users/tazjin/presentations/erlang-2016/README.md +++ /dev/null @@ -1,6 +0,0 @@ -These are the slides for a presentation I gave for the Oslo javaBin meetup in -2016. - -Unfortunately there is no recording of the presentation due to a technical error -(video was recorded, but no audio). This is a bit of a shame because I think -these are some of the best slides I've ever made. diff --git a/users/tazjin/presentations/erlang-2016/presentation.md b/users/tazjin/presentations/erlang-2016/presentation.md deleted file mode 100644 index 526564b88..000000000 --- a/users/tazjin/presentations/erlang-2016/presentation.md +++ /dev/null @@ -1,222 +0,0 @@ -slidenumbers: true -Erlang. -====== - -### Fault-tolerant, concurrent programming. - ---- - -## A brief history of Erlang - ---- - -![](https://www.ericsson.com/thinkingahead/the-networked-society-blog/wp-content/uploads/2014/09/bfW5FSr.jpg) - - -^ Telefontornet in Stockholm, around 1890. Used until 1913. - ---- - -![](https://3.bp.blogspot.com/-UF7W9yTUO2g/VBqw-1HNTzI/AAAAAAAAPeg/KvsMbNSAcII/s1600/6835942484_1531372d8f_b.jpg) - -^ Telephones were operated manually at Switchboards. Anyone old enough to remember? I'm certainly not. - ---- - -![fit](https://russcam.github.io/fsharp-akka-talk/images/ericsson-301-AXD.png) - -^ Eventually we did that in software, and we got better at it over time. Ericsson AXD 301, first commercial Erlang switch. But lets take a step back. - ---- - -## Phone switches must be ... - -Highly concurrent - -Fault-tolerant - -Distributed - -(Fast!) - -![right 150%](http://learnyousomeerlang.com/static/img/erlang-the-movie.png) - ---- - -## ... and so is Erlang! - ---- - -## Erlang as a whole: - -- Unique process model (actors!) -- Built-in fault-tolerance & error handling -- Distributed processes -- Three parts! - ---- - -## Part 1: Erlang, the language - -- Functional -- Prolog-inspired syntax -- Everything is immutable -- *Extreme* pattern-matching - ---- -### Hello Joe - -```erlang -hello_joe. -``` - ---- -### Hello Joe - -```erlang --module(hello1). --export([hello_joe/0]). - -hello_joe() -> - hello_joe. -``` - ---- -### Hello Joe - -```erlang --module(hello1). --export([hello_joe/0]). - -hello_joe() -> - hello_joe. - -% 1> c(hello1). -% {ok,hello1} -% 2> hello1:hello_joe(). -% hello_joe -``` - ---- -### Hello Joe - -```erlang --module(hello2). --export([hello/1]). - -hello(Name) -> - io:format("Hello ~s!~n", [Name]). - -% 3> c(hello2). -% {ok,hello2} -% 4> hello2:hello("Joe"). -% Hello Joe! -% ok -``` - ---- - -## [fit] Hello ~~world~~ Joe is boring! -## [fit] Lets do it with processes. - ---- -### Hello Server - -```erlang --module(hello_server). --export([start_server/0]). - -start_server() -> - spawn(fun() -> server() end). - -server() -> - receive - {greet, Name} -> - io:format("Hello ~s!~n", [Name]), - server() - end. -``` - ---- - -## [fit] Some issues with that ... - -- What about unused messages? -- What if the server crashes? - ---- - -## [fit] Part 2: Open Telecom Platform - -### **It's called Erlang/OTP for a reason.** - ---- - -# OTP: An Application Framework - -- Supervision - keep processes alive! - -- OTP Behaviours - common process patterns - -- Extensive standard library - -- Error handling, debuggers, testing, ... - -- Lots more! - -^ Standard library includes lots of things from simple network libraries over testing frameworks to cryptography, complete LDAP clients etc. - ---- - -# Supervision - -![inline](http://erlang.org/doc/design_principles/sup6.gif) - -^ Supervision keeps processes alive, different restart behaviours, everything should be supervised to avoid "process" (and therefore memory) leaks - ---- - -# OTP Behaviours - -* `gen_server` -* `gen_statem` -* `gen_event` -* `supervisor` - -^ gen = generic. explain server, explain statem, event = event handling with registered handlers, supervisor ... - ---- - -`gen_server` - ---- - -## [fit] Part 3: BEAM - -### Bogdan/Bjørn Erlang Abstract machine - ---- - -## A VM for Erlang - -* Many were written, BEAM survived -* Concurrent garbage-collection -* Lower-level bytecode than JVM -* Very open to new languages - (Elixir, LFE, Joxa, ...) - ---- - -## What next? - -* Ole's talk, obviously! -* Learn You Some Erlang! - www.learnyousomeerlang.com -* Watch *Erlang the Movie* -* (soon!) Join the Oslo BEAM meetup group - ---- - -# [fit] Questions? - -`@tazjin` diff --git a/users/tazjin/presentations/erlang-2016/presentation.pdf b/users/tazjin/presentations/erlang-2016/presentation.pdf deleted file mode 100644 index ec8d99670..000000000 Binary files a/users/tazjin/presentations/erlang-2016/presentation.pdf and /dev/null differ diff --git a/users/tazjin/presentations/erlang-2016/src/hello.erl b/users/tazjin/presentations/erlang-2016/src/hello.erl deleted file mode 100644 index 56404a0c5..000000000 --- a/users/tazjin/presentations/erlang-2016/src/hello.erl +++ /dev/null @@ -1,5 +0,0 @@ --module(hello). --export([hello_joe/0]). - -hello_joe() -> - hello_joe. diff --git a/users/tazjin/presentations/erlang-2016/src/hello1.erl b/users/tazjin/presentations/erlang-2016/src/hello1.erl deleted file mode 100644 index ca7826139..000000000 --- a/users/tazjin/presentations/erlang-2016/src/hello1.erl +++ /dev/null @@ -1,5 +0,0 @@ --module(hello1). --export([hello_joe/0]). - -hello_joe() -> - hello_joe. diff --git a/users/tazjin/presentations/erlang-2016/src/hello2.erl b/users/tazjin/presentations/erlang-2016/src/hello2.erl deleted file mode 100644 index 2d1f6c84c..000000000 --- a/users/tazjin/presentations/erlang-2016/src/hello2.erl +++ /dev/null @@ -1,11 +0,0 @@ --module(hello2). --export([hello/1]). - -hello(Name) -> - io:format("Hey ~s!~n", [Name]). - -% 3> c(hello2). -% {ok,hello2} -% 4> hello2:hello("Joe"). -% Hello Joe! -% ok diff --git a/users/tazjin/presentations/erlang-2016/src/hello_server.erl b/users/tazjin/presentations/erlang-2016/src/hello_server.erl deleted file mode 100644 index 01df14ac5..000000000 --- a/users/tazjin/presentations/erlang-2016/src/hello_server.erl +++ /dev/null @@ -1,12 +0,0 @@ --module(hello_server). --export([start_server/0, server/0]). - -start_server() -> - spawn(fun() -> server() end). - -server() -> - receive - {greet, Name} -> - io:format("Hello ~s!~n", [Name]), - hello_server:server() - end. diff --git a/users/tazjin/presentations/erlang-2016/src/hello_server2.erl b/users/tazjin/presentations/erlang-2016/src/hello_server2.erl deleted file mode 100644 index 24bb934ee..000000000 --- a/users/tazjin/presentations/erlang-2016/src/hello_server2.erl +++ /dev/null @@ -1,36 +0,0 @@ --module(hello_server2). --behaviour(gen_server). --compile(export_all). - -%%% Start callback for supervisor -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). - -%%% gen_server callbacks - -init([]) -> - {ok, sets:new()}. - -handle_call({greet, Name}, _From, State) -> - io:format("Hello ~s!~n", [Name]), - NewState = sets:add_element(Name, State), - {reply, ok, NewState}; - -handle_call({bye, Name}, _From, State) -> - io:format("Goodbye ~s!~n", [Name]), - NewState = sets:del_element(Name, State), - {reply, ok, NewState}. - -terminate(normal, State) -> - [io:format("Goodbye ~s!~n", [Name]) || Name <- State], - ok. - -%%% Unused gen_server callbacks -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - -handle_info(_Info, State) -> - {noreply, State}. - -handle_cast(_Request, State) -> - {noreply, State}. diff --git a/users/tazjin/presentations/erlang-2016/src/hello_sup.erl b/users/tazjin/presentations/erlang-2016/src/hello_sup.erl deleted file mode 100644 index 7fee0928c..000000000 --- a/users/tazjin/presentations/erlang-2016/src/hello_sup.erl +++ /dev/null @@ -1,24 +0,0 @@ --module(hello_sup). --behaviour(supervisor). --export([start_link/0, init/1]). - -%%% Module API - -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). - -%%% Supervisor callbacks - -init([]) -> - Children = [hello_spec()], - {ok, { {one_for_one, 5, 10}, Children}}. - -%%% Private - -hello_spec() -> - #{id => hello_server2, - start => {hello_server2, start_link, []}, - restart => permanent, - shutdown => 5000, - type => worker, - module => [hello_server2]}. diff --git a/users/tazjin/presentations/servant-2016/Makefile b/users/tazjin/presentations/servant-2016/Makefile deleted file mode 100644 index 96115ec2c..000000000 --- a/users/tazjin/presentations/servant-2016/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -all: slides - -slides: - lualatex --shell-escape slides.tex - -clean: - rm -f slides.aux slides.log slides.nav \ - slides.out slides.toc slides.snm diff --git a/users/tazjin/presentations/servant-2016/README.md b/users/tazjin/presentations/servant-2016/README.md deleted file mode 100644 index 8cfb04a42..000000000 --- a/users/tazjin/presentations/servant-2016/README.md +++ /dev/null @@ -1,7 +0,0 @@ -These are the slides for my presentation about [servant][] at [Oslo Haskell][]. - -A full video recording of the presentation is available [on Vimeo][]. - -[servant]: https://haskell-servant.github.io/ -[Oslo Haskell]: http://www.meetup.com/Oslo-Haskell/events/227107530/ -[on Vimeo]: https://vimeo.com/153901805 diff --git a/users/tazjin/presentations/servant-2016/slides.pdf b/users/tazjin/presentations/servant-2016/slides.pdf deleted file mode 100644 index 842a667e1..000000000 Binary files a/users/tazjin/presentations/servant-2016/slides.pdf and /dev/null differ diff --git a/users/tazjin/presentations/servant-2016/slides.pdfpc b/users/tazjin/presentations/servant-2016/slides.pdfpc deleted file mode 100644 index ed4600376..000000000 --- a/users/tazjin/presentations/servant-2016/slides.pdfpc +++ /dev/null @@ -1,75 +0,0 @@ -[file] -slides.pdf -[font_size] -10897 -[notes] -### 1 -13### 2 -Let's talk about servant, which is several things: -API description DSL, we'll speak about how this DSL works -and why it's at the type level - -Interpretations of the types resulting from that DSL, for example in -web servers or API clients - -Servant is commonly used or implementing services with APIs, or for accessing -other APIs with a simple, typed client -### 3 -Why type-level DSLs? -Type-level DSL: express *something*, e.g. endpoints of API, on type level by combining types. Types can be uninhabited - -Phil Wadler's: expression problem: things should be extensible both in the cases of a type, and in the functions operating on the type -Normal data types: can't add new constructors easily -Servant lifts thisup to simply allow the declaration of new types that can be included in the DSL, and new interpretations that can be attached to the types through typeclasses - -APIs become first-class citizens, can pass them around, combine them etc, they are separate from interpretations such as server implementations. In contrast, in most webframeworks, API declaration is implicit - -(Mention previous attemps at type-safe web, Yesod / web-routes + boomerang etc) -### 4 -Three extensions are necessary: -TypeOperators lets us use infix operators on the type level as constructors -DataKinds promotes new type declarations to the kind level, makes type-level literals (strings and natural numbers) available, lets us use type-level lists and pairs in combination with typeoperators -TypeFamilies: Type-level functions, map one set of types to another, come in two forms (type families, non-injective; data families, injective), more powerful than associated types -### 5 -Here you can see servant's general syntax, we define an API type as a simple alias of some other type combinations -strings are type-level strings, not actually values, represent path elements -endpoints are separated by :<|>, all endpoints end in a method with content types and return types -Capture captures path segments, but there are other combinators, for example for headers -Everything that is used from the request is expressed in types, enforcing checkability, no "escape hatch" inside handlers to get request -Every combinator has associated interpretations through typeclasses -### 6 -Explain type alias, point out Capture -Server is a type level function (type family), as mentioned earlier -### 7 -If we expand server (in ghci with kind!) we can see the actual type of the -function -### 8 -Lets speak about some interpretations of these things -### 9 -Servant server is the main interpretation that people are interested in, it's used -for taking a type specification and creating a server from it -Based on WAI, the web application interface, common abstraction for web servers which came out of the Yesod project. Implemented by the web server warp, which Yesod runs on -### 10 -Explain snippet, path gets removed from server type (irrelevant for handler), -route extracts string to value level -### 11 -Explain echo server quickly -### 12 -servant client allows generation of Haskell functions that query the API with the same types -this makes for easy to use RPC for example -### 13 -A lot of other interpretations exist for all kinds of things, mock servers for testing, foreign functions in various languages, documentation ... -### 14 -Demo! -1. Go quickly through code -2. Run server, query with curl -3. Open javascript function -4. Show JS code in the thing -5. Open the map itself -6. Open GHCi, use client -7. Generate docs -### 15 -Conclusion -Servant is pretty good, it's very easy to get started and it's great to raise the level of things that the compiler can tell you about when you do them wrong. -### 16 -Drawbacks. diff --git a/users/tazjin/presentations/servant-2016/slides.tex b/users/tazjin/presentations/servant-2016/slides.tex deleted file mode 100644 index d5947eb94..000000000 --- a/users/tazjin/presentations/servant-2016/slides.tex +++ /dev/null @@ -1,137 +0,0 @@ -\documentclass[12pt]{beamer} -\usetheme{metropolis} -\usepackage{minted} - -\newenvironment{code}{\ttfamily}{\par} - -\title{servant} -\subtitle{Defining web APIs at the type-level} - -\begin{document} -\metroset{titleformat frame=smallcaps} -\setminted{fontsize=\scriptsize} - - -\maketitle - -\section{Introduction} - -\begin{frame}{Type-level DSLs?} - \begin{itemize} - \item (Uninhabited) types with attached ``meaning'' - \item The Expression Problem (Wadler 1998) - \item API representation and interpretation are separated - \item APIs become first-class citizens - \end{itemize} -\end{frame} - -\begin{frame}{Haskell extensions} - \begin{itemize} - \item TypeOperators - \item DataKinds - \item TypeFamilies - \end{itemize} -\end{frame} - -\begin{frame}[fragile]{A servant example} - \begin{minted}{haskell} - type PubAPI = "pubs" :> Get ’[JSON] [Pub] - :<|> "pubs" :> "tagged" - :> Capture "tag" Text - :> Get ’[JSON] [Pub] - \end{minted} -\end{frame} - -\begin{frame}[fragile]{Computed types} - \begin{minted}{haskell} - type TaggedPubs = "tagged" :> Capture "tag" Text :> ... - - taggedPubsHandler :: Server TaggedPubs - taggedPubsHandler tag = ... - \end{minted} -\end{frame} - -\begin{frame}[fragile]{Computed types} - \begin{minted}{haskell} - type TaggedPubs = "tagged" :> Capture "tag" Text :> ... - - taggedPubsHandler :: Server TaggedPubs - taggedPubsHandler tag = ... - - Server TaggedPubs ~ - Text -> EitherT ServantErr IO [Pub] - \end{minted} -\end{frame} - -\section{Interpretations} - -\begin{frame}{servant-server} - The one everyone is interested in! - - \begin{itemize} - \item Based on WAI, can run on warp - \item Interprets combinators with a simple \texttt{HasServer c} class - \item Easy to use! - \end{itemize} -\end{frame} - -\begin{frame}[fragile]{HasServer ...} - \begin{minted}{haskell} - instance (KnownSymbol path, HasServer sublayout) - => HasServer (path :> sublayout) where - type ServerT (path :> sublayout) m = ServerT sublayout m - - route ... - where - pathString = symbolVal (Proxy :: Proxy path) - \end{minted} -\end{frame} - -\begin{frame}[fragile]{Server example} - \begin{minted}{haskell} - type Echo = Capture "echo" Text :> Get ’[PlainText] Text - - echoAPI :: Proxy Echo - echoAPI = Proxy - - echoServer :: Server Echo - echoServer = return - \end{minted} -\end{frame} - -\begin{frame}{servant-client} - \begin{itemize} - \item Generates Haskell client functions for API - \item Same types as API specification: For RPC the whole ``web layer'' is abstracted away - \item Also easy to use! - \end{itemize} -\end{frame} - -\begin{frame}{servant-docs, servant-js ...} - Many other interpretations exist already, for example: - \begin{itemize} - \item Documentation generation - \item Foreign function export (e.g. Elm, JavaScript) - \item Mock-server generation - \end{itemize} -\end{frame} - -\section{Demo} - -\section{Conclusion} - -\begin{frame}{Drawbacks} - \begin{itemize} - \item Haskell has no custom open kinds (yet) - \item Proxies are ugly - \item Errors can be a bit daunting - \end{itemize} -\end{frame} - -\begin{frame}{Questions?} - Ølkartet: github.com/tazjin/pubkartet \\ - Slides: github.com/tazjin/servant-presentation - - @tazjin -\end{frame} -\end{document} diff --git a/users/tazjin/presentations/systemd-2016/.gitignore b/users/tazjin/presentations/systemd-2016/.gitignore deleted file mode 100644 index 1a38620fe..000000000 --- a/users/tazjin/presentations/systemd-2016/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -slides.aux -slides.log -slides.nav -slides.out -slides.snm -slides.toc diff --git a/users/tazjin/presentations/systemd-2016/.skip-subtree b/users/tazjin/presentations/systemd-2016/.skip-subtree deleted file mode 100644 index 108b3507d..000000000 --- a/users/tazjin/presentations/systemd-2016/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -No Nix files will ever be under this tree ... diff --git a/users/tazjin/presentations/systemd-2016/Makefile b/users/tazjin/presentations/systemd-2016/Makefile deleted file mode 100644 index ac5dde3cb..000000000 --- a/users/tazjin/presentations/systemd-2016/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -all: slides.pdf - -slides.toc: - lualatex slides.tex - -slides.pdf: slides.toc - lualatex slides.tex - -clean: - rm -f slides.aux slides.log slides.nav \ - slides.out slides.toc slides.snm diff --git a/users/tazjin/presentations/systemd-2016/README.md b/users/tazjin/presentations/systemd-2016/README.md deleted file mode 100644 index 7f004b7d1..000000000 --- a/users/tazjin/presentations/systemd-2016/README.md +++ /dev/null @@ -1,6 +0,0 @@ -This repository contains the slides for my systemd presentation at Hackeriet. - -Requires LaTeX, [beamer][] and the [metropolis][] theme. - -[beamer]: http://mirror.hmc.edu/ctan/macros/latex/contrib/beamer/ -[metropolis]: https://github.com/matze/mtheme diff --git a/users/tazjin/presentations/systemd-2016/demo/demo-error.service b/users/tazjin/presentations/systemd-2016/demo/demo-error.service deleted file mode 100644 index b2d4c9d34..000000000 --- a/users/tazjin/presentations/systemd-2016/demo/demo-error.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Demonstrate failing units -OnFailure=demo-notify@%n.service - -[Service] -Type=oneshot -ExecStart=/usr/bin/false diff --git a/users/tazjin/presentations/systemd-2016/demo/demo-limits.slice b/users/tazjin/presentations/systemd-2016/demo/demo-limits.slice deleted file mode 100644 index 998185d26..000000000 --- a/users/tazjin/presentations/systemd-2016/demo/demo-limits.slice +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Limited resources demo -DefaultDependencies=no -Before=slices.target - -[Slice] -CPUQuota=10% diff --git a/users/tazjin/presentations/systemd-2016/demo/demo-notify@.service b/users/tazjin/presentations/systemd-2016/demo/demo-notify@.service deleted file mode 100644 index e25524b4e..000000000 --- a/users/tazjin/presentations/systemd-2016/demo/demo-notify@.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Demonstrate systemd templating by sending a notification - -[Service] -Type=oneshot -ExecStart=/usr/bin/notify-send 'Systemd notification' '%i' diff --git a/users/tazjin/presentations/systemd-2016/demo/demo-path.path b/users/tazjin/presentations/systemd-2016/demo/demo-path.path deleted file mode 100644 index 87f1342da..000000000 --- a/users/tazjin/presentations/systemd-2016/demo/demo-path.path +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Demonstrate systemd path units - -[Path] -DirectoryNotEmpty=/tmp/hackeriet -Unit=demo.service diff --git a/users/tazjin/presentations/systemd-2016/demo/demo-stress.service b/users/tazjin/presentations/systemd-2016/demo/demo-stress.service deleted file mode 100644 index 7e14f13e2..000000000 --- a/users/tazjin/presentations/systemd-2016/demo/demo-stress.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Stress test CPU - -[Service] -Slice=demo.slice -ExecStart=/usr/bin/stress -c 5 diff --git a/users/tazjin/presentations/systemd-2016/demo/demo-timer.timer b/users/tazjin/presentations/systemd-2016/demo/demo-timer.timer deleted file mode 100644 index 34eccb98b..000000000 --- a/users/tazjin/presentations/systemd-2016/demo/demo-timer.timer +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Demonstrate systemd timers - -[Timer] -OnActiveSec=2 -OnUnitActiveSec=5 -AccuracySec=5 -Unit=demo.service -# OnCalendar=Thu,Fri 2016-*-1,5 11:12:13 - -[Install] -WantedBy=multi-user.target diff --git a/users/tazjin/presentations/systemd-2016/demo/demo.service b/users/tazjin/presentations/systemd-2016/demo/demo.service deleted file mode 100644 index fcc710ad9..000000000 --- a/users/tazjin/presentations/systemd-2016/demo/demo.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Demo unit for systemd - -[Service] -Type=oneshot -ExecStart=/usr/bin/echo "Systemd unit activated. Hello Hackeriet." diff --git a/users/tazjin/presentations/systemd-2016/demo/notes.md b/users/tazjin/presentations/systemd-2016/demo/notes.md deleted file mode 100644 index b4866b164..000000000 --- a/users/tazjin/presentations/systemd-2016/demo/notes.md +++ /dev/null @@ -1,27 +0,0 @@ -# simple oneshot - -Run `demo-notify@hello.service` - -# simple timer - -Run `demo-timer.timer`, show both - -# enabling - -Enable `demo-timer.timer`, go to symlink folder, disable - -# OnError - -Show & run `demo-error.service` - -# cgroups demo - -Start `demo-stress.service` without, show in htop, stop -Show slice unit, start slice unit -Add Slice=demo-limits.slice -daemon-reload -Start stress again - -# Proper service - -Look at nginx unit diff --git a/users/tazjin/presentations/systemd-2016/slides.pdf b/users/tazjin/presentations/systemd-2016/slides.pdf deleted file mode 100644 index 384db2a6e..000000000 Binary files a/users/tazjin/presentations/systemd-2016/slides.pdf and /dev/null differ diff --git a/users/tazjin/presentations/systemd-2016/slides.pdfpc b/users/tazjin/presentations/systemd-2016/slides.pdfpc deleted file mode 100644 index 99326bd8b..000000000 --- a/users/tazjin/presentations/systemd-2016/slides.pdfpc +++ /dev/null @@ -1,85 +0,0 @@ -[file] -slides.pdf -[notes] -### 1 -### 2 -Let's start off by looking at what an init system is, how they used to work and what systemd does different before we go into more systemd-specific details. -### 3 -system processes that are started include for example FS mounts, network settings, powertop... -system services are long-running processes such as daemons, e.g. SSH, database or web servers, session managers, udev ... - -orphans: Process whose parent has finished somehow, gets adopted by init system --> when a process terminates its parent must call wait() to get its exit() code, if there is no init system adopting orphans the process would become a zombie -### 4 -Before systemd there were simple init systems that just did the tasks listed on the previous slide. -Init scripts -> increased greatly in complexity over time, look at incomprehensible skeleton for Debian service init scripts -Runlevels -> things such as single-user mode, full multiuser mode, reboot, halt - -Init will run all the scripts, but it will not do much more than print information on success/failure of started scripts - -Init scripts run strictly sequential - -Init is unaware of inter-service dependencies, expressed through prefixing scripts with numbers etc. - -Init will not watch processes after system is booted -> crashing daemons will not automatically restart -### 5 -### 6 -How systemd came to be - -Considering the lack of process monitoring, problematic things about init scripts -> legacy init systems have drawbacks - -Apple had already built launchd, a more featured init system that monitored running processes, could automatically restart them and allowed for certain advanced features -> however it is awful to use and wrap your head around - -Lennart Poettering of Pulseaudio fame and Kay Sievers decided to implement a new init system to address these problems, while taking certain clues from Apple's design -### 7 -Systemd's design goals -### 8 -No more init scripts with opaque effects -> services are clearly defined units -Unit dependencies -> systemd can figure out what can be started in parallel -Process supervision: Unit can be configured in many ways, e.g. always restart, only restart on success etc -Service logs: We'll talk more about this later -### 9 -Units are the core component of systemd that users deal with. They define services and everything else that systemd needs to start and manage. -Note that all these are the names of the respective man page on a system with systemd installed -Types: -systemd.service - processes controlled by systemd -systemd.target - equivalent to "runlevels", grouping of units for synchronisation -systemd.timer - more powerful replacement of cron that starts other units -systemd.path - systemd equvialent of inotify, watches files/folders -> launches units -systemd.socket - expose local IPC or network sockets, launch units on connections -systemd.device - trigger units when certain devices are connected -systemd.mount - systemd equivalent of fstab entries -systemd.swap - like mount -systemd.slice - unit groups for resource management purposes -... and a few more specialised ones -### 10 -Linux cgroups are a new resource management feature added quite a long time ago, but not used much. -Cgroups can be created manually and processes can be moved into them in order to control resource utilisation -Few people used them before systemd, limits.conf was often much easier but not as fine-grained -Systemd changed this -### 11 -Systemd collects standard output and stderr from all processes into its journal system -they provide a tool for querying the log, for example grouping service logs together with correct timestamps, querying, -### 12 -Systemd tooling, most important one is systemctl for general service management -journalctl is the query and management tool for journald -systemd-analyze is used for figuring out performance issues, for example by analysing the boot process, can make cool graphs of dependencies -systemd-cgtop is like top, but not on a process level - it's on a cgroup/slice level, shows combined usage of cgroups -systemd-cgls lists contents of systemd's cgroups to see which services are in what group -there also exist a bunch of others that we'll skip for now -### 13 -### 14 -### 15 -Systemd criticism comes from many directions and usually focuses on a few points -feature-creep: systemd is absorbing a lot of different services -### 16 -explain diagram a bit -### 17 -opaque: as a result, systemd has a lot more internal complexity that people can't easily wrap your mind around. However I argue that unless you're using something like suckless' sinit with your own scripts, you probably have no idea what your init does today anyways -unstable: this was definitely true even in the first stable release, with the binary log format getting corrupted for example. I haven't personally experienced any trouble with it recently though. -Another thing is that services start depending on systemd when they shouldn't, a problem for the BSD world (who cares (hey christoph!)) -### 18 -Despite criticism, systemd was adopted rapidly by large portions of the Linux -Initially in RedHat, because Poettering and co work there and it was clear from the beginning that it would be there -ArchLinux (which I'm using) and a few others followed suit quite quickly -Eventually, the big Debian init system discussion - after a lot of flaming - led to Debian adopting it as well, which had a ripple effect for related distros such as Ubuntu which abandoned upstart for it. \ No newline at end of file diff --git a/users/tazjin/presentations/systemd-2016/slides.tex b/users/tazjin/presentations/systemd-2016/slides.tex deleted file mode 100644 index c613cefd7..000000000 --- a/users/tazjin/presentations/systemd-2016/slides.tex +++ /dev/null @@ -1,160 +0,0 @@ -\documentclass[12pt]{beamer} -\usetheme{metropolis} - -\newenvironment{code}{\ttfamily}{\par} - -\title{systemd} -\subtitle{The standard Linux init system} - -\begin{document} -\metroset{titleformat frame=smallcaps} - -\maketitle - -\section{Introduction} - -\begin{frame}{What is an init system?} - An init system is the first userspace process (PID 1) started in a UNIX-like system. It handles: - - \begin{itemize} - \item Starting system processes and services to prepare the environment - \item Adopting and ``reaping'' orphaned processes - \end{itemize} -\end{frame} - -\begin{frame}{Classical init systems} - Init systems before systemd - such as SysVinit - were very simple. - - \begin{itemize} - \item Services and processes to run are organised into ``init scripts'' - \item Scripts are linked to specific runlevels - \item Init system is configured to boot into a runlevel - \end{itemize} - -\end{frame} - -\section{systemd} - -\begin{frame}{Can we do better?} - \begin{itemize} - \item ``legacy'' init systems have a lot of drawbacks - \item Apple is taking a different approach on OS X - \item Systemd project was founded to address these issues - \end{itemize} -\end{frame} - -\begin{frame}{Systemd design goals} - \begin{itemize} - \item Expressing service dependencies - \item Monitoring service status - \item Enable parallel service startups - \item Ease of use - \end{itemize} -\end{frame} - -\begin{frame}{Systemd - the basics} - \begin{itemize} - \item No scripts are executed, only declarative units - \item Units have explicit dependencies - \item Processes are supervised - \item cgroups are utilised to apply resource limits - \item Service logs are managed and centrally queryable - \item Much more! - \end{itemize} -\end{frame} - -\begin{frame}{Systemd units} - Units specify how and what to start. Several types exist: - \begin{code} - \small - \begin{columns}[T,onlytextwidth] - \column{0.5\textwidth} - \begin{itemize} - \item systemd.service - \item systemd.target - \item systemd.timer - \item systemd.path - \item systemd.socket - \end{itemize} - \column{0.5\textwidth} - \begin{itemize} - \item systemd.device - \item systemd.mount - \item systemd.swap - \item systemd.slice - \end{itemize} - \end{columns} - \end{code} -\end{frame} - - -\begin{frame}{Resource management} - Systemd utilises Linux \texttt{cgroups} for resource management, specifically CPU, disk I/O and memory usage. - - \begin{itemize} - \item Hierarchical setup of groups makes it easy to limit resources for a set of services - \item Units can be attached to a \texttt{systemd.slice} for controlling resources for a group of services - \item Resource limits can also be specified directly in the unit - \end{itemize} -\end{frame} - -\begin{frame}{journald} - Systemd comes with an integrated log management solution, replacing software such as \texttt{syslog-ng}. - \begin{itemize} - \item All process output is collected in the journal - \item \texttt{journalctl} tool provides many options for querying and tailing logs - \item Children of processes automatically log to the journal as well - \item \textbf{Caveat:} Hard to learn initially - \end{itemize} -\end{frame} - -\begin{frame}{Systemd tooling} - A variety of CLI-tools exist for managing systemd systems. - \begin{code} - \begin{itemize} - \item systemctl - \item journalctl - \item systemd-analyze - \item systemd-cgtop - \item systemd-cgls - \end{itemize} - \end{code} - - Let's look at some of them. -\end{frame} - -\section{Demo} - -\section{Controversies} - -\begin{frame}{Systemd criticism} - Systemd has been heavily criticised, usually focusing around a few points: - \begin{itemize} - \item Feature-creep: Systemd absorbs more and more other services - \end{itemize} -\end{frame} - -\begin{frame}{Systemd criticism} - \includegraphics[keepaspectratio=true,width=\textwidth]{systemdcomponents.png} -\end{frame} - -\begin{frame}{Systemd criticism} - Systemd has been heavily criticised, usually focusing around a few points: - \begin{itemize} - \item Feature-creep: Systemd absorbs more and more other services - \item Opaque: systemd's inner workings are harder to understand than old \texttt{init} - \item Unstable: development is quick and breakage happens - \end{itemize} -\end{frame} - -\begin{frame}{Systemd adoption} - Systemd was initially adopted by RedHat (and related distributions). - - It spread quickly to others, for example ArchLinux. - - Debian and Ubuntu were the last major players who decided to adopt it, but not without drama. -\end{frame} - -\section{Questions?} - -\end{document} diff --git a/users/tazjin/presentations/systemd-2016/systemdcomponents.png b/users/tazjin/presentations/systemd-2016/systemdcomponents.png deleted file mode 100644 index a22c762f7..000000000 Binary files a/users/tazjin/presentations/systemd-2016/systemdcomponents.png and /dev/null differ diff --git a/users/tazjin/presentations/tvix-eval-2023/README.md b/users/tazjin/presentations/tvix-eval-2023/README.md deleted file mode 100644 index b14ba8ff5..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/README.md +++ /dev/null @@ -1,12 +0,0 @@ -These are the slides for a talk at the Moscow Rust User Group / -ProgMSK on 2023-09-07. - -After building, the presentation can be launched with `pdfpc` -(available in `nixpkgs`), like this: - -``` -pdfpc --windowed=both result/presentation.pdf -R presentation.pdfpc -d 40 -``` - -I keep the JSON file formatted using `jq . presentation.pdfpc | sponge -presentation.pdfpc` for easier diffs. diff --git a/users/tazjin/presentations/tvix-eval-2023/cppnix-example-lexer.cpp b/users/tazjin/presentations/tvix-eval-2023/cppnix-example-lexer.cpp deleted file mode 100644 index 7c52bce8b..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/cppnix-example-lexer.cpp +++ /dev/null @@ -1,13 +0,0 @@ -attrpath - : attrpath '.' attr { - $$ = $1; $1->push_back(AttrName(data->symbols.create($3))); - } - | attrpath '.' string_attr - { $$ = $1; - ExprString * str = dynamic_cast($3); - if (str) { - $$->push_back(AttrName(data->symbols.create(str->s))); - delete str; - } else - $$->push_back(AttrName($3)); - } diff --git a/users/tazjin/presentations/tvix-eval-2023/cppnix-example-smuggling.cpp b/users/tazjin/presentations/tvix-eval-2023/cppnix-example-smuggling.cpp deleted file mode 100644 index 37b9219b2..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/cppnix-example-smuggling.cpp +++ /dev/null @@ -1,12 +0,0 @@ -struct Env { - // ... some struct fields ... - Value* values[0]; -}; - -// .... - -if (env->type == Env::HasWithExpr) { - // ... - evalAttrs(*env->up, (Expr *) env->values[0], *v, noPos, ""); - // ^^^^^^^^^^^^^^^^^^^^^^^ -} diff --git a/users/tazjin/presentations/tvix-eval-2023/default.nix b/users/tazjin/presentations/tvix-eval-2023/default.nix deleted file mode 100644 index 63323d5d8..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/default.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (pkgs) fontconfig texlive stdenv imagemagick runCommand qrencode; - - tex = texlive.combine { - inherit (texlive) - babel - babel-russian - beamer - beamertheme-metropolis - etoolbox - euenc - extsizes - fontspec - listings - xetex - minted - count1to - multitoc - prelim2e - ragged2e - pgfopts - scheme-basic - translator; - }; - - linksQrCode = runCommand "qrcode.png" { } '' - ${qrencode}/bin/qrencode -o code.png -s 8 \ - --background=fafafa \ - --foreground=000000 \ - 'https://tazj.in/blog/tvix-eval-talk-2023' - - # latex has trouble with the PDF produced by qrencode - ${imagemagick}/bin/convert code.png $out - ''; -in -stdenv.mkDerivation { - name = "progmsk-tvix-eval"; - src = ./.; - - nativeBuildInputs = [ tex imagemagick fontconfig ]; - - FONTCONFIG_FILE = pkgs.makeFontsConf { - fontDirectories = with pkgs; [ jetbrains-mono fira fira-code fira-mono ]; - }; - - buildPhase = '' - # LaTeX needs a cache folder in /home/ ... - mkdir home - export HOME=$PWD/home - - cp ${depot.tvix.logo}/logo.png tvix-logo.png - cp ${linksQrCode} qrcode.png - - # As usual, TeX needs to be run twice ... - ${tex}/bin/xelatex presentation.tex - ${tex}/bin/xelatex presentation.tex - ''; - - installPhase = '' - mkdir -p $out - cp presentation.pdf $out/ - cp $src/presentation.pdfpc $out/ - ''; -} diff --git a/users/tazjin/presentations/tvix-eval-2023/presentation.pdfpc b/users/tazjin/presentations/tvix-eval-2023/presentation.pdfpc deleted file mode 100644 index ab5cba68b..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/presentation.pdfpc +++ /dev/null @@ -1,98 +0,0 @@ -{ - "pdfpcFormat": 2, - "duration": 40, - "disableMarkdown": false, - "noteFontSize": 20, - "pages": [ - { - "idx": 1, - "label": "2", - "overlay": 0, - "note": "Привет, меня зовут .... Я уже много лет, с 2016г. примерно, пишу на Расте, и хотя на работе у меня часто бывают другие языки, Раст - любимый мой язык.\n\nПару лет назад, во время Кодида, я создал онлайн-коммюнити ТВЛ, и сегодня хочу вам об одном из наших проектов рассказать." - }, - { - "idx": 2, - "label": "3", - "overlay": 0, - "note": "монорепо: объяснить. Весь код орга в одном месте. Единный тулинг. Много из нас раньше работали в компаниях, где так делают (нп Гугл).\n\nМы хотели создать такой же тулинг, но открыто. Но у нас меньше ресурсов чем у Гугла, намного меньше. Пришлось выбрать эфф. способ.\nФокусируем на Никс, потому что (...). Есть доклад.\n\nМы начали его не только для пакетов использовать (конфиг и тд.), хотелось решение, которое работает везде." - }, - { - "idx": 3, - "label": "4", - "overlay": 0, - "note": "Будем фокусировать только на язык сейчас. Остальные части интересные, но не сегодня.\nЯзык ленивый, значит только вычисляем код, когда его результат нужен где-то.\nЗначит, нам нужен рантайм-представление отложенных вычислений.\nОрганично развивался: добавили фичи, когда нуждались. Много функтции работают только случайно, комбинации фич - часто странно. (шутка про С++?)\nНо есть хороший фактор: весь публичный код в принципе в одном репо. Объяснять nixpkgs." - }, - { - "idx": 4, - "label": "5", - "overlay": 0, - "note": "Текушая имплементация на С++. Вот пример. Кто-то здесь понимает, что мы видем? Это часть парсера в як, но тут создают рантайм-значения во время парсинга. Очень сложно понимать, читать, дебажить и так далее.\nЧитали парсер, и даже нашли там неизвестные фичи языка." - }, - { - "idx": 5, - "label": "6", - "overlay": 0, - "note": "Второй пример. Есть стракт Env, которая используется во многих местах в коде. Там массив типа Value.\nВот использование этого массива. Что мы видем? Кто понимает?\nДа, там на самом деле происходит каст на другой тип. Значит, в структуре добавляют данные, которые не подойдет. Очень unsafe!\n\nДа, что же делать? Пытались почистить код, но случилось burnout очень быстро. Меняешь одну маленькую штуку -> segfaults.\nПочему код вот такой? -> объяснять.\nПришлась очевидная идея." - }, - { - "idx": 6, - "label": "6", - "overlay": 1, - "note": "Переписать проекты полностью, обычно очень сложно. Но мы можем менять арх., и обходить переписивание некоторых частей.\nРаст - нам очевидный выбор для имплементация языка. Много нас знают Раст, и в целом, почему именно Раст, вы уже сами понимаете.\n\nМы от NLNet, организация, ..., получили денги за этого и начали с языком. Этот проект называем tvix-eval.\n\nЕсть еще одна важная причина для выбора Раста." - }, - { - "idx": 7, - "label": "6", - "overlay": 2, - "note": "Пару лет назад, шведский парень юзернеймом, который нельзя происносить, написал на Расте очень быстрый и в целом хороший парсер для Никса.\nЭтот парсер уже используется в разных с Никсом связанных проектах. Он скорее всего в пути стать дефольтним парсером Никса.\nКонечно, неплохо если мы его тоже используем.\nК сожалению, автор рникса умерл в 2021 году. Мали исвестно о том, что случилось. Мы ему очень благодарные, и я просто хотел его здесь упомянуть." - }, - { - "idx": 9, - "label": "8", - "overlay": 0, - "note": "показать opcode.rs, compiler/mod (compile_binop)\n\nчтобы он не разжирел (про variant_size_differences)\n" - }, - { - "idx": 10, - "label": "9", - "overlay": 0, - "note": "показать value/mod.rs, потом value/list.rs\n\nкороткая объяснение ситуации с Gc<...> vs. Rc<...>" - }, - { - "idx": 11, - "label": "10", - "overlay": 0, - "note": "показать vm/mod.rs\n\nпоследовательно выпольняет инструктции в execute_bytecode\n\nсначала на алфавитным порядке, потом с помощью профайлера меняли это" - }, - { - "idx": 12, - "label": "10", - "overlay": 1, - "note": "показать диаграмму\n\nгенераторый можно приостановить\n\nTCO - хвостовый вызов\n\nasync - очень наязчивный (intrusive), надо было его везде добавить, неудоб" - }, - { - "idx": 13, - "label": "10", - "overlay": 2, - "note": "Зависимо от времени, можно либо только про tvixbolt, либо тоже про тесты из cppnix" - }, - { - "idx": 14, - "label": "11", - "overlay": 0, - "note": "на самом деле удивительно легко, но сталкивались с проблемой, что он иногда перестал работать\n\nпоказать пример с SystemTime::now\n\nесть кое-какие библиотеки, которые мб помогут, но мы их пока не проверили\n\nв целом, wasm на расте довольно удобно" - }, - { - "idx": 15, - "label": "12", - "overlay": 0, - "note": "открытый проект, принимаем коммиты от всех\n\nесть еще баги, TODOs, и тд в tvix-eval\n\nно есть тоже остальные части твикса, что-то найдется" - }, - { - "idx": 16, - "label": "13", - "overlay": 0, - "note": "спасибо всем, вот ссылки, на QR-коде есть все вот этот вот, и там тоже потом добавлю сам доклад\n\nеще завтра начинается NixCon, если вам вдруг интересно, можно онлайн посмотреть. Там будет доклад про tvix тоже, но об остальных частях." - } - ] -} diff --git a/users/tazjin/presentations/tvix-eval-2023/presentation.tex b/users/tazjin/presentations/tvix-eval-2023/presentation.tex deleted file mode 100644 index 294dad794..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/presentation.tex +++ /dev/null @@ -1,148 +0,0 @@ -\documentclass[12pt]{beamer} - -\usepackage[utf8]{inputenc} -\usepackage[main=russian,english]{babel} -\usepackage{fontspec} -\usepackage{listings} - -\setmainfont{JetBrains Mono} -\setsansfont{JetBrains Mono} - -\usetheme{metropolis} -\newenvironment{code}{\ttfamily}{\par} -\title{tvix-eval \\ компилятор и рантайм для Nix, на Rust} - -\titlegraphic{\vspace{4.8cm}\flushright\includegraphics[width=6cm,keepaspectratio=true]{tvix-logo.png}} - -\date{2023-09-07} -\author{Винсент Амбо} -\institute{TVL} - -\begin{document} - %% Slide -1 (before counter): - \begin{frame} - \begin{center} - \titlepage - \end{center} - \end{frame} - - %% Slide 0 (title): - \begin{frame} - \begin{center} - \titlepage - \end{center} - \end{frame} - - %% Slide 1: - \begin{frame}{\textbf{Т}he \textbf{V}irus \textbf{L}ounge} - \begin{itemize} - \item онлайн-комьюнити, занимающееся тулингом для монорепо - \item основной фокус на Nix - \item Nix не только для сборки пакетов - \item Хотелось решение, чтобы использовать Nix везде - \end{itemize} - \end{frame} - - %% Slide 2: - \begin{frame}{Особенности языка Nix} - \begin{itemize} - \item Ленивый язык. Вычислять все сразу нельзя. - \item Язык развивался органично. - \item Большинство кода на Nix --- в одном месте: \begin{code}nixpkgs\end{code} - \end{itemize} - \end{frame} - - %% Slide 3: - \begin{frame}{Текущая имплементация: C++ Nix} - \lstinputlisting[ - language=c++, - basicstyle={\scriptsize} - ]{cppnix-example-lexer.cpp} - \end{frame} - - %% Slide 4: - \begin{frame}{Текущая имплементация: C++ Nix} - \lstinputlisting[ - language=c++, - basicstyle={\scriptsize} - ]{cppnix-example-smuggling.cpp} - \end{frame} - - %% Slide 5: - \section{``Let's rewrite it in Rust!''} - - %% Slide 6: - \section*{Спасибо, jD91mZM2!\\\normalsize{автор ``rnix-parser''; *2002 - \textdagger 2021}} - - %% Slide 7: - \begin{frame}{tvix-eval, - (язык) Nix, на Rust} - \begin{itemize} - \item написано с существующим парсером - \item bytecode-интерпретатор, вместо tree-walk - \item должна работать не только для остальных частей tvix - \end{itemize} - \end{frame} - - %% Slide 8: - \begin{frame}{tvix-eval, основные части} - \begin{enumerate} - \item собственный байткод и компилятор - \end{enumerate} - \end{frame} - - %% показать opcode.rs, быстро показать compiler/mod.rs - - %% Slide 9: - \begin{frame}{tvix-eval, основные части} - \begin{enumerate} - \item собственный байткод и компилятор - \item представление значений языка в рантайме - \end{enumerate} - \end{frame} - - %% показать Value - - %% Slide 10: - \begin{frame}{tvix-eval, основные части} - \begin{enumerate} - \item собственный байткод и компилятор - \item представление значении языка в рантайме - \item ... и сам рантайм! - \end{enumerate} - \end{frame} - - %% показать VM - - \section{``Подожди, написать рантайм же не так просто?''} - - %% объяснить проблему со стеком и решение, показать диаграмму - - \section{``А откуда знаешь, что это все правильно работает?''} - - %% показать как тесты работают - %% объяснить дебагинг, Твиксболт и тд - - %% Slide 10: - \begin{frame}{tvix-eval, в браузере} - \begin{itemize} - \item удивительно легко делать - \item но есть сложности в \begin{code}std::\end{code} - % показать пример - \end{itemize} - \end{frame} - - %% Slide 11: - \begin{frame}{А что дальше?} - В tvix-eval есть еще кое-какие интересные проблемы. Может ты их - решишь? - \end{frame} - - \begin{frame}{Спасибо!} - \begin{center} - \includegraphics[width=6cm,keepaspectratio=true]{qrcode.png} - - https://tazj.in/blog/tvix-eval-talk-2023 \\ - t.me/tazjin | t.me/tazlog - \end{center} - \end{frame} -\end{document} diff --git a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/.gitignore b/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/.gitignore deleted file mode 100644 index 73b9c106d..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -target/ -dist/ diff --git a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/Cargo.lock b/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/Cargo.lock deleted file mode 100644 index ef879254c..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/Cargo.lock +++ /dev/null @@ -1,899 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "anymap2" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "boolinator" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" - -[[package]] -name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "gloo" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28999cda5ef6916ffd33fb4a7b87e1de633c47c0dc6d97905fee1cdaa142b94d" -dependencies = [ - "gloo-console", - "gloo-dialogs", - "gloo-events", - "gloo-file", - "gloo-history", - "gloo-net", - "gloo-render", - "gloo-storage", - "gloo-timers", - "gloo-utils", - "gloo-worker", -] - -[[package]] -name = "gloo-console" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-dialogs" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-events" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b107f8abed8105e4182de63845afcc7b69c098b7852a813ea7462a320992fc" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-file" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" -dependencies = [ - "gloo-events", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-history" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f" -dependencies = [ - "gloo-events", - "gloo-utils", - "serde", - "serde-wasm-bindgen", - "serde_urlencoded", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-net" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66b4e3c7d9ed8d315fd6b97c8b1f74a7c6ecbbc2320e65ae7ed38b7068cc620" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils", - "http", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-render" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" -dependencies = [ - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-storage" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-utils" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037fcb07216cb3a30f7292bd0176b050b7b9a052ba830ef7d5d65f6dc64ba58e" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-worker" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" -dependencies = [ - "anymap2", - "bincode", - "gloo-console", - "gloo-utils", - "js-sys", - "serde", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "implicit-clone" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6ecbd987bb94f1f3c76c6787879756cf4b6f73bfff48d79308e8c56b46f65f" -dependencies = [ - "indexmap", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pinned" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" -dependencies = [ - "futures", - "rustversion", - "thiserror", -] - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prokio" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" -dependencies = [ - "futures", - "gloo", - "num_cpus", - "once_cell", - "pin-project", - "pinned", - "tokio", - "tokio-stream", - "wasm-bindgen-futures", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "serde" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde_derive" -version = "1.0.188" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "serde_json" -version = "1.0.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "tokio" -version = "1.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" -dependencies = [ - "backtrace", - "pin-project-lite", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", -] - -[[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "unicode-ident" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasm-bindgen" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.29", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.29", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "wasm-fs-demo" -version = "0.1.0" -dependencies = [ - "yew", -] - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "yew" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" -dependencies = [ - "console_error_panic_hook", - "futures", - "gloo", - "implicit-clone", - "indexmap", - "js-sys", - "prokio", - "rustversion", - "serde", - "slab", - "thiserror", - "tokio", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "yew-macro", -] - -[[package]] -name = "yew-macro" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" -dependencies = [ - "boolinator", - "once_cell", - "prettyplease", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] diff --git a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/Cargo.toml b/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/Cargo.toml deleted file mode 100644 index 4a445065e..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "wasm-fs-demo" -version = "0.1.0" -edition = "2021" - -[dependencies] -yew = { version = "0.20.0", features = [ "csr" ]} diff --git a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/index.html b/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/index.html deleted file mode 100644 index e024c466c..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/index.html +++ /dev/null @@ -1,7 +0,0 @@ - - - - - wasm-fs-demo - - diff --git a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/src/main.rs b/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/src/main.rs deleted file mode 100644 index 4ad177ad7..000000000 --- a/users/tazjin/presentations/tvix-eval-2023/wasm-fs-demo/src/main.rs +++ /dev/null @@ -1,41 +0,0 @@ -use std::time::{SystemTime, UNIX_EPOCH}; -use yew::prelude::*; - -fn time_example() -> Html { - let epoch = match SystemTime::now().duration_since(UNIX_EPOCH) { - Ok(duration) => duration.as_secs(), - Err(err) => { - return html! { - format!("failed to calculate duration: {}", err) - } - } - }; - - html! { -

    - {"Seconds since epoch: "}{epoch} -

    - } -} - -struct App; -impl Component for App { - type Message = (); - type Properties = (); - - fn create(_: &Context) -> Self { - Self - } - - fn update(&mut self, _: &Context, _: Self::Message) -> bool { - false - } - - fn view(&self, _: &Context) -> Html { - time_example() - } -} - -fn main() { - yew::Renderer::::new().render(); -} diff --git a/users/tazjin/rlox/.gitignore b/users/tazjin/rlox/.gitignore deleted file mode 100644 index 29e65519b..000000000 --- a/users/tazjin/rlox/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -result -/target -**/*.rs.bk diff --git a/users/tazjin/rlox/Cargo.lock b/users/tazjin/rlox/Cargo.lock deleted file mode 100644 index d8107726e..000000000 --- a/users/tazjin/rlox/Cargo.lock +++ /dev/null @@ -1,6 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "rlox" -version = "0.1.0" - diff --git a/users/tazjin/rlox/Cargo.toml b/users/tazjin/rlox/Cargo.toml deleted file mode 100644 index b66af6ba8..000000000 --- a/users/tazjin/rlox/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "rlox" -version = "0.1.0" -authors = ["Vincent Ambo "] -edition = "2018" - -[features] -# Enables debugging/disassembling in the bytecode interpreter. Off by -# default as it is quite spammy. -disassemble = [] diff --git a/users/tazjin/rlox/README.md b/users/tazjin/rlox/README.md deleted file mode 100644 index 1d2692d09..000000000 --- a/users/tazjin/rlox/README.md +++ /dev/null @@ -1,7 +0,0 @@ -This is an interpreter for the Lox language, based on the book "[Crafting -Interpreters](https://craftinginterpreters.com/)". - -The book's original code uses Java, but I don't want to use Java, so I've -decided to take on the extra complexity of porting it to Rust. - -Note: This implements the first of two Lox interpreters. diff --git a/users/tazjin/rlox/default.nix b/users/tazjin/rlox/default.nix deleted file mode 100644 index e50ac32be..000000000 --- a/users/tazjin/rlox/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ depot, ... }: - -depot.third_party.naersk.buildPackage { - src = ./.; -} diff --git a/users/tazjin/rlox/examples/builtins.lox b/users/tazjin/rlox/examples/builtins.lox deleted file mode 100644 index 39af1d73c..000000000 --- a/users/tazjin/rlox/examples/builtins.lox +++ /dev/null @@ -1 +0,0 @@ -print clock(); diff --git a/users/tazjin/rlox/examples/fib.lox b/users/tazjin/rlox/examples/fib.lox deleted file mode 100644 index 1b91e9db9..000000000 --- a/users/tazjin/rlox/examples/fib.lox +++ /dev/null @@ -1,6 +0,0 @@ -fun fib(n) { - if (n <= 1) return n; - return fib(n - 2) + fib(n - 1); -} - -print fib(30); diff --git a/users/tazjin/rlox/examples/func.lox b/users/tazjin/rlox/examples/func.lox deleted file mode 100644 index d197ad113..000000000 --- a/users/tazjin/rlox/examples/func.lox +++ /dev/null @@ -1,5 +0,0 @@ -fun foo(name) { - print("hello " + name); -} - -foo("bar"); diff --git a/users/tazjin/rlox/examples/hello.lox b/users/tazjin/rlox/examples/hello.lox deleted file mode 100644 index 31752d9e2..000000000 --- a/users/tazjin/rlox/examples/hello.lox +++ /dev/null @@ -1,34 +0,0 @@ -var a = 12; -var b = a * 2; - -{ - var b = a * 3; - a = 42; - print b; -} - -print a; -print b; - -if (5 > 4) - print "it's true"; -else - print "it's false"; - -if (false) - print "it's not true"; - -if (true and false) - print "won't happen"; - -if (true or false) - print "will happen"; - -var n = 5; -while (n > 0) { - print "counting down"; - n = n - 1; -} - -for(var i = 0; i < 10; i = i + 1) - print "bla"; diff --git a/users/tazjin/rlox/examples/if.lox b/users/tazjin/rlox/examples/if.lox deleted file mode 100644 index 5f335c0e8..000000000 --- a/users/tazjin/rlox/examples/if.lox +++ /dev/null @@ -1,7 +0,0 @@ -if (false) { - print "yes"; -} else { - print "no"; -} - -print "afterwards"; diff --git a/users/tazjin/rlox/examples/scope.lox b/users/tazjin/rlox/examples/scope.lox deleted file mode 100644 index d56380794..000000000 --- a/users/tazjin/rlox/examples/scope.lox +++ /dev/null @@ -1,19 +0,0 @@ -var a = "global a"; -var b = "global b"; -var c = "global c"; -{ - var a = "outer a"; - var b = "outer b"; - { - var a = "inner a"; - print a; - print b; - print c; - } - print a; - print b; - print c; -} -print a; -print b; -print c; diff --git a/users/tazjin/rlox/examples/scope2.lox b/users/tazjin/rlox/examples/scope2.lox deleted file mode 100644 index f826c8658..000000000 --- a/users/tazjin/rlox/examples/scope2.lox +++ /dev/null @@ -1,10 +0,0 @@ -var a = "global"; -{ - fun showA() { - print a; - } - - showA(); - var a = "block"; - showA(); -} diff --git a/users/tazjin/rlox/examples/slow.lox b/users/tazjin/rlox/examples/slow.lox deleted file mode 100644 index dd6fb5e4b..000000000 --- a/users/tazjin/rlox/examples/slow.lox +++ /dev/null @@ -1,9 +0,0 @@ -fun fib(n) { - if (n < 2) return n; - return fib(n - 1) + fib(n - 2); -} - -var before = clock(); -print fib(40); -var after = clock(); -print after - before; diff --git a/users/tazjin/rlox/examples/var.lox b/users/tazjin/rlox/examples/var.lox deleted file mode 100644 index 7af90b3f0..000000000 --- a/users/tazjin/rlox/examples/var.lox +++ /dev/null @@ -1,8 +0,0 @@ -var a = 10; -var b = 5; - -{ - var b = 10; - var c = 2; - a * b * c; -} diff --git a/users/tazjin/rlox/rustfmt.toml b/users/tazjin/rlox/rustfmt.toml deleted file mode 100644 index df99c6919..000000000 --- a/users/tazjin/rlox/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -max_width = 80 diff --git a/users/tazjin/rlox/src/bytecode/chunk.rs b/users/tazjin/rlox/src/bytecode/chunk.rs deleted file mode 100644 index fc5cd34fd..000000000 --- a/users/tazjin/rlox/src/bytecode/chunk.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::ops::Index; - -use super::opcode::{CodeIdx, ConstantIdx, OpCode}; -use super::value; - -// In the book, this type is a hand-rolled dynamic array -// implementation in C. The main benefit of following that approach -// would be avoiding issues with OpCode variants not having equal -// sizes, but for the purpose of this I'm going to ignore that -// problem. -#[derive(Debug, Default)] -pub struct Chunk { - pub code: Vec, - lines: Vec, - constants: Vec, -} - -#[derive(Debug)] -struct Span { - /// Source code line - line: usize, - - /// Number of instructions derived from this line - count: usize, -} - -impl Chunk { - pub fn add_op(&mut self, data: OpCode, line: usize) -> CodeIdx { - let idx = self.code.len(); - self.code.push(data); - self.add_line(line); - CodeIdx(idx) - } - - pub fn add_constant(&mut self, data: value::Value) -> usize { - let idx = self.constants.len(); - self.constants.push(data); - idx - } - - pub fn constant(&self, idx: ConstantIdx) -> &value::Value { - self.constants.index(idx.0) - } - - fn add_line(&mut self, line: usize) { - match self.lines.last_mut() { - Some(span) if span.line == line => span.count += 1, - _ => self.lines.push(Span { line, count: 1 }), - } - } - - pub fn get_line(&self, offset: usize) -> usize { - let mut pos = 0; - for span in &self.lines { - pos += span.count; - if pos > offset { - return span.line; - } - } - - panic!("invalid chunk state: line missing for offset {}", offset); - } -} - -// Disassembler - -/// Print a single disassembled instruction at the specified offset. -/// Some instructions are printed "raw", others have special handling. -#[cfg(feature = "disassemble")] -pub fn disassemble_instruction(chunk: &Chunk, offset: usize) { - print!("{:04} ", offset); - - let line = chunk.get_line(offset); - if offset > 0 && line == chunk.get_line(offset - 1) { - print!(" | "); - } else { - print!("{:4} ", line); - } - - match chunk.code.index(offset) { - OpCode::OpConstant(idx) => { - println!("OpConstant({:?}) '{:?}'", idx, chunk.constant(*idx)) - } - op => println!("{:?}", op), - } -} - -#[cfg(feature = "disassemble")] -pub fn disassemble_chunk(chunk: &Chunk) { - for (idx, _) in chunk.code.iter().enumerate() { - disassemble_instruction(chunk, idx); - } -} diff --git a/users/tazjin/rlox/src/bytecode/compiler.rs b/users/tazjin/rlox/src/bytecode/compiler.rs deleted file mode 100644 index 89584f19d..000000000 --- a/users/tazjin/rlox/src/bytecode/compiler.rs +++ /dev/null @@ -1,702 +0,0 @@ -use super::chunk::Chunk; -use super::errors::{Error, ErrorKind, LoxResult}; -use super::interner::{InternedStr, Interner}; -use super::opcode::{CodeIdx, CodeOffset, ConstantIdx, OpCode, StackIdx}; -use super::value::Value; -use crate::scanner::{self, Token, TokenKind}; - -#[cfg(feature = "disassemble")] -use super::chunk; - -#[derive(Debug)] -enum Depth { - Unitialised, - At(usize), -} - -impl Depth { - fn above(&self, theirs: usize) -> bool { - match self { - Depth::Unitialised => false, - Depth::At(ours) => *ours > theirs, - } - } - - fn below(&self, theirs: usize) -> bool { - match self { - Depth::Unitialised => false, - Depth::At(ours) => *ours < theirs, - } - } -} - -#[derive(Debug)] -struct Local { - name: Token, - depth: Depth, -} - -#[derive(Debug, Default)] -struct Locals { - locals: Vec, - scope_depth: usize, -} - -struct Compiler> { - tokens: T, - chunk: Chunk, - panic: bool, - errors: Vec, - strings: Interner, - locals: Locals, - - current: Option, - previous: Option, -} - -#[derive(Debug, PartialEq, PartialOrd)] -enum Precedence { - None, - Assignment, // = - Or, // or - And, // and - Equality, // == != - Comparison, // < > <= >= - Term, // + - - Factor, // - // - // * / - Unary, // ! - - Call, // . () - Primary, -} - -type ParseFn = fn(&mut Compiler) -> LoxResult<()>; - -struct ParseRule> { - prefix: Option>, - infix: Option>, - precedence: Precedence, -} - -impl> ParseRule { - fn new(prefix: Option>, infix: Option>, precedence: Precedence) -> Self { - ParseRule { - prefix, - infix, - precedence, - } - } -} - -impl Precedence { - // Return the next highest precedence, if there is one. - fn next(&self) -> Self { - match self { - Precedence::None => Precedence::Assignment, - Precedence::Assignment => Precedence::Or, - Precedence::Or => Precedence::And, - Precedence::And => Precedence::Equality, - Precedence::Equality => Precedence::Comparison, - Precedence::Comparison => Precedence::Term, - Precedence::Term => Precedence::Factor, - Precedence::Factor => Precedence::Unary, - Precedence::Unary => Precedence::Call, - Precedence::Call => Precedence::Primary, - Precedence::Primary => { - panic!("invalid parser state: no higher precedence than Primary") - } - } - } -} - -fn rule_for>(token: &TokenKind) -> ParseRule { - match token { - TokenKind::LeftParen => ParseRule::new(Some(Compiler::grouping), None, Precedence::None), - - TokenKind::Minus => ParseRule::new( - Some(Compiler::unary), - Some(Compiler::binary), - Precedence::Term, - ), - - TokenKind::Plus => ParseRule::new(None, Some(Compiler::binary), Precedence::Term), - - TokenKind::Slash => ParseRule::new(None, Some(Compiler::binary), Precedence::Factor), - - TokenKind::Star => ParseRule::new(None, Some(Compiler::binary), Precedence::Factor), - - TokenKind::Number(_) => ParseRule::new(Some(Compiler::number), None, Precedence::None), - - TokenKind::True => ParseRule::new(Some(Compiler::literal), None, Precedence::None), - - TokenKind::False => ParseRule::new(Some(Compiler::literal), None, Precedence::None), - - TokenKind::Nil => ParseRule::new(Some(Compiler::literal), None, Precedence::None), - - TokenKind::Bang => ParseRule::new(Some(Compiler::unary), None, Precedence::None), - - TokenKind::BangEqual => ParseRule::new(None, Some(Compiler::binary), Precedence::Equality), - - TokenKind::EqualEqual => ParseRule::new(None, Some(Compiler::binary), Precedence::Equality), - - TokenKind::Greater => ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison), - - TokenKind::GreaterEqual => { - ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison) - } - - TokenKind::Less => ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison), - - TokenKind::LessEqual => { - ParseRule::new(None, Some(Compiler::binary), Precedence::Comparison) - } - - TokenKind::Identifier(_) => { - ParseRule::new(Some(Compiler::variable), None, Precedence::None) - } - - TokenKind::String(_) => ParseRule::new(Some(Compiler::string), None, Precedence::None), - - _ => ParseRule::new(None, None, Precedence::None), - } -} - -macro_rules! consume { - ( $self:ident, $expected:pat, $err:expr ) => { - match $self.current().kind { - $expected => $self.advance(), - _ => $self.error_at($self.current().line, $err), - } - }; -} - -impl> Compiler { - fn compile(&mut self) -> LoxResult<()> { - self.advance(); - - while !self.match_token(&TokenKind::Eof) { - self.declaration()?; - } - - self.end_compiler() - } - - fn advance(&mut self) { - self.previous = self.current.take(); - self.current = self.tokens.next(); - } - - fn expression(&mut self) -> LoxResult<()> { - self.parse_precedence(Precedence::Assignment) - } - - fn var_declaration(&mut self) -> LoxResult<()> { - let idx = self.parse_variable()?; - - if self.match_token(&TokenKind::Equal) { - self.expression()?; - } else { - self.emit_op(OpCode::OpNil); - } - - self.expect_semicolon("expect ';' after variable declaration")?; - self.define_variable(idx) - } - - fn define_variable(&mut self, var: Option) -> LoxResult<()> { - if self.locals.scope_depth == 0 { - self.emit_op(OpCode::OpDefineGlobal(var.expect("should be global"))); - } else { - self.locals - .locals - .last_mut() - .expect("fatal: variable not yet added at definition") - .depth = Depth::At(self.locals.scope_depth); - } - - Ok(()) - } - - fn declaration(&mut self) -> LoxResult<()> { - if self.match_token(&TokenKind::Var) { - self.var_declaration()?; - } else { - self.statement()?; - } - - if self.panic { - self.synchronise(); - } - - Ok(()) - } - - fn statement(&mut self) -> LoxResult<()> { - if self.match_token(&TokenKind::Print) { - self.print_statement() - } else if self.match_token(&TokenKind::If) { - self.if_statement() - } else if self.match_token(&TokenKind::LeftBrace) { - self.begin_scope(); - self.block()?; - self.end_scope(); - Ok(()) - } else { - self.expression_statement() - } - } - - fn print_statement(&mut self) -> LoxResult<()> { - self.expression()?; - self.expect_semicolon("expect ';' after print statement")?; - self.emit_op(OpCode::OpPrint); - Ok(()) - } - - fn begin_scope(&mut self) { - self.locals.scope_depth += 1; - } - - fn end_scope(&mut self) { - debug_assert!(self.locals.scope_depth > 0, "tried to end global scope"); - self.locals.scope_depth -= 1; - - while self.locals.locals.len() > 0 - && self.locals.locals[self.locals.locals.len() - 1] - .depth - .above(self.locals.scope_depth) - { - self.emit_op(OpCode::OpPop); - self.locals.locals.remove(self.locals.locals.len() - 1); - } - } - - fn block(&mut self) -> LoxResult<()> { - while !self.check(&TokenKind::RightBrace) && !self.check(&TokenKind::Eof) { - self.declaration()?; - } - - consume!( - self, - TokenKind::RightBrace, - ErrorKind::ExpectedToken("Expected '}' after block.") - ); - Ok(()) - } - - fn expression_statement(&mut self) -> LoxResult<()> { - self.expression()?; - self.expect_semicolon("expect ';' after expression")?; - // TODO(tazjin): Why did I add this originally? - // self.emit_op(OpCode::OpPop); - Ok(()) - } - - fn if_statement(&mut self) -> LoxResult<()> { - consume!( - self, - TokenKind::LeftParen, - ErrorKind::ExpectedToken("Expected '(' after 'if'") - ); - - self.expression()?; - - consume!( - self, - TokenKind::RightParen, - ErrorKind::ExpectedToken("Expected ')' after condition") - ); - - let then_jump = self.emit_op(OpCode::OpJumpPlaceholder(false)); - self.emit_op(OpCode::OpPop); - self.statement()?; - let else_jump = self.emit_op(OpCode::OpJumpPlaceholder(true)); - self.patch_jump(then_jump); - self.emit_op(OpCode::OpPop); - - if self.match_token(&TokenKind::Else) { - self.statement()?; - } - - self.patch_jump(else_jump); - - Ok(()) - } - - fn number(&mut self) -> LoxResult<()> { - if let TokenKind::Number(num) = self.previous().kind { - self.emit_constant(Value::Number(num), true); - return Ok(()); - } - - unreachable!("internal parser error: entered number() incorrectly") - } - - fn grouping(&mut self) -> LoxResult<()> { - self.expression()?; - consume!( - self, - TokenKind::RightParen, - ErrorKind::ExpectedToken("Expected ')' after expression") - ); - Ok(()) - } - - fn unary(&mut self) -> LoxResult<()> { - // TODO(tazjin): Avoid clone - let kind = self.previous().kind.clone(); - - // Compile the operand - self.parse_precedence(Precedence::Unary)?; - - // Emit operator instruction - match kind { - TokenKind::Bang => self.emit_op(OpCode::OpNot), - TokenKind::Minus => self.emit_op(OpCode::OpNegate), - _ => unreachable!("only called for unary operator tokens"), - }; - - Ok(()) - } - - fn binary(&mut self) -> LoxResult<()> { - // Remember the operator - let operator = self.previous().kind.clone(); - - // Compile the right operand - let rule: ParseRule = rule_for(&operator); - self.parse_precedence(rule.precedence.next())?; - - // Emit operator instruction - match operator { - TokenKind::Minus => self.emit_op(OpCode::OpSubtract), - TokenKind::Plus => self.emit_op(OpCode::OpAdd), - TokenKind::Star => self.emit_op(OpCode::OpMultiply), - TokenKind::Slash => self.emit_op(OpCode::OpDivide), - - TokenKind::BangEqual => { - self.emit_op(OpCode::OpEqual); - self.emit_op(OpCode::OpNot) - } - - TokenKind::EqualEqual => self.emit_op(OpCode::OpEqual), - TokenKind::Greater => self.emit_op(OpCode::OpGreater), - - TokenKind::GreaterEqual => { - self.emit_op(OpCode::OpLess); - self.emit_op(OpCode::OpNot) - } - - TokenKind::Less => self.emit_op(OpCode::OpLess), - TokenKind::LessEqual => { - self.emit_op(OpCode::OpGreater); - self.emit_op(OpCode::OpNot) - } - - _ => unreachable!("only called for binary operator tokens"), - }; - - Ok(()) - } - - fn literal(&mut self) -> LoxResult<()> { - match self.previous().kind { - TokenKind::Nil => self.emit_op(OpCode::OpNil), - TokenKind::True => self.emit_op(OpCode::OpTrue), - TokenKind::False => self.emit_op(OpCode::OpFalse), - _ => unreachable!("only called for literal value tokens"), - }; - - Ok(()) - } - - fn string(&mut self) -> LoxResult<()> { - let val = match &self.previous().kind { - TokenKind::String(s) => s.clone(), - _ => unreachable!("only called for strings"), - }; - - let id = self.strings.intern(val); - self.emit_constant(Value::String(id.into()), true); - - Ok(()) - } - - fn named_variable(&mut self, name: Token) -> LoxResult<()> { - let local_idx = self.resolve_local(&name); - - let ident = if local_idx.is_some() { - None - } else { - Some(self.identifier_constant(&name)?) - }; - - if self.match_token(&TokenKind::Equal) { - self.expression()?; - match local_idx { - Some(idx) => self.emit_op(OpCode::OpSetLocal(idx)), - None => self.emit_op(OpCode::OpSetGlobal(ident.unwrap())), - }; - } else { - match local_idx { - Some(idx) => self.emit_op(OpCode::OpGetLocal(idx)), - None => self.emit_op(OpCode::OpGetGlobal(ident.unwrap())), - }; - } - - Ok(()) - } - - fn variable(&mut self) -> LoxResult<()> { - let name = self.previous().clone(); - self.named_variable(name) - } - - fn parse_precedence(&mut self, precedence: Precedence) -> LoxResult<()> { - self.advance(); - let rule: ParseRule = rule_for(&self.previous().kind); - let prefix_fn = match rule.prefix { - None => unimplemented!("expected expression or something, unclear"), - Some(func) => func, - }; - - prefix_fn(self)?; - - while precedence <= rule_for::(&self.current().kind).precedence { - self.advance(); - match rule_for::(&self.previous().kind).infix { - Some(func) => { - func(self)?; - } - None => { - unreachable!("invalid compiler state: error in parse rules") - } - } - } - - Ok(()) - } - - fn identifier_str(&mut self, token: &Token) -> LoxResult { - let ident = match &token.kind { - TokenKind::Identifier(ident) => ident.to_string(), - _ => { - return Err(Error { - line: self.current().line, - kind: ErrorKind::ExpectedToken("Expected identifier"), - }) - } - }; - - Ok(self.strings.intern(ident)) - } - - fn identifier_constant(&mut self, name: &Token) -> LoxResult { - let ident = self.identifier_str(name)?; - Ok(self.emit_constant(Value::String(ident.into()), false)) - } - - fn resolve_local(&self, name: &Token) -> Option { - for (idx, local) in self.locals.locals.iter().enumerate().rev() { - if name.lexeme == local.name.lexeme { - if let Depth::Unitialised = local.depth { - // TODO(tazjin): *return* err - panic!("can't read variable in its own initialiser"); - } - return Some(StackIdx(idx)); - } - } - - None - } - - fn add_local(&mut self, name: Token) { - let local = Local { - name, - depth: Depth::Unitialised, - }; - - self.locals.locals.push(local); - } - - fn declare_variable(&mut self) -> LoxResult<()> { - if self.locals.scope_depth == 0 { - return Ok(()); - } - - let name = self.previous().clone(); - - for local in self.locals.locals.iter().rev() { - if local.depth.below(self.locals.scope_depth) { - break; - } - - if name.lexeme == local.name.lexeme { - return Err(Error { - kind: ErrorKind::VariableShadowed(name.lexeme.into()), - line: name.line, - }); - } - } - - self.add_local(name); - Ok(()) - } - - fn parse_variable(&mut self) -> LoxResult> { - consume!( - self, - TokenKind::Identifier(_), - ErrorKind::ExpectedToken("expected identifier") - ); - - self.declare_variable()?; - if self.locals.scope_depth > 0 { - return Ok(None); - } - - let name = self.previous().clone(); - let id = self.identifier_str(&name)?; - Ok(Some(self.emit_constant(Value::String(id.into()), false))) - } - - fn current_chunk(&mut self) -> &mut Chunk { - &mut self.chunk - } - - fn end_compiler(&mut self) -> LoxResult<()> { - self.emit_op(OpCode::OpReturn); - - #[cfg(feature = "disassemble")] - { - chunk::disassemble_chunk(&self.chunk); - println!("== compilation finished =="); - } - - Ok(()) - } - - fn emit_op(&mut self, op: OpCode) -> CodeIdx { - let line = self.previous().line; - self.current_chunk().add_op(op, line) - } - - fn emit_constant(&mut self, val: Value, with_op: bool) -> ConstantIdx { - let idx = ConstantIdx(self.chunk.add_constant(val)); - - if with_op { - self.emit_op(OpCode::OpConstant(idx)); - } - - idx - } - - fn patch_jump(&mut self, idx: CodeIdx) { - let offset = CodeOffset(self.chunk.code.len() - idx.0 - 1); - - if let OpCode::OpJumpPlaceholder(true) = self.chunk.code[idx.0] { - self.chunk.code[idx.0] = OpCode::OpJump(offset); - return; - } - - if let OpCode::OpJumpPlaceholder(false) = self.chunk.code[idx.0] { - self.chunk.code[idx.0] = OpCode::OpJumpIfFalse(offset); - return; - } - - panic!( - "attempted to patch unsupported op: {:?}", - self.chunk.code[idx.0] - ); - } - - fn previous(&self) -> &Token { - self.previous - .as_ref() - .expect("invalid internal compiler state: missing previous token") - } - - fn current(&self) -> &Token { - self.current - .as_ref() - .expect("invalid internal compiler state: missing current token") - } - - fn error_at(&mut self, line: usize, kind: ErrorKind) { - if self.panic { - return; - } - - self.panic = true; - self.errors.push(Error { kind, line }) - } - - fn match_token(&mut self, token: &TokenKind) -> bool { - if !self.check(token) { - return false; - } - - self.advance(); - true - } - - fn check(&self, token: &TokenKind) -> bool { - return self.current().kind == *token; - } - - fn synchronise(&mut self) { - self.panic = false; - - while self.current().kind != TokenKind::Eof { - if self.previous().kind == TokenKind::Semicolon { - return; - } - - match self.current().kind { - TokenKind::Class - | TokenKind::Fun - | TokenKind::Var - | TokenKind::For - | TokenKind::If - | TokenKind::While - | TokenKind::Print - | TokenKind::Return => return, - - _ => { - self.advance(); - } - } - } - } - - fn expect_semicolon(&mut self, msg: &'static str) -> LoxResult<()> { - consume!(self, TokenKind::Semicolon, ErrorKind::ExpectedToken(msg)); - Ok(()) - } -} - -pub fn compile(code: &str) -> Result<(Interner, Chunk), Vec> { - let chars = code.chars().collect::>(); - let tokens = scanner::scan(&chars) - .map_err(|errors| errors.into_iter().map(Into::into).collect::>())?; - - let mut compiler = Compiler { - tokens: tokens.into_iter().peekable(), - chunk: Default::default(), - panic: false, - errors: vec![], - strings: Interner::with_capacity(1024), - locals: Default::default(), - current: None, - previous: None, - }; - - compiler.compile()?; - - if compiler.errors.is_empty() { - Ok((compiler.strings, compiler.chunk)) - } else { - Err(compiler.errors) - } -} diff --git a/users/tazjin/rlox/src/bytecode/errors.rs b/users/tazjin/rlox/src/bytecode/errors.rs deleted file mode 100644 index 988031f76..000000000 --- a/users/tazjin/rlox/src/bytecode/errors.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::scanner::ScannerError; - -use std::fmt; - -#[derive(Debug)] -pub enum ErrorKind { - UnexpectedChar(char), - UnterminatedString, - ExpectedToken(&'static str), - InternalError(&'static str), - TypeError(String), - VariableShadowed(String), -} - -#[derive(Debug)] -pub struct Error { - pub kind: ErrorKind, - pub line: usize, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[line NYI] Error: {:?}", self.kind) - } -} - -impl From for Error { - fn from(err: ScannerError) -> Self { - match err { - ScannerError::UnexpectedChar { line, unexpected } => Error { - line, - kind: ErrorKind::UnexpectedChar(unexpected), - }, - - ScannerError::UnterminatedString { line } => Error { - line, - kind: ErrorKind::UnterminatedString, - }, - } - } -} - -// Convenience implementation as we're often dealing with vectors of -// errors (to report as many issues as possible before terminating) -impl From for Vec { - fn from(err: Error) -> Self { - vec![err] - } -} - -pub type LoxResult = Result; diff --git a/users/tazjin/rlox/src/bytecode/interner/mod.rs b/users/tazjin/rlox/src/bytecode/interner/mod.rs deleted file mode 100644 index 1da1a24b2..000000000 --- a/users/tazjin/rlox/src/bytecode/interner/mod.rs +++ /dev/null @@ -1,87 +0,0 @@ -//! String-interning implementation for values that are likely to -//! benefit from fast comparisons and deduplication (e.g. instances of -//! variable names). -//! -//! This uses a trick from the typed-arena crate for guaranteeing -//! stable addresses by never resizing the existing String buffer, and -//! collecting full buffers in a vector. - -use std::collections::HashMap; - -#[cfg(test)] -mod tests; - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub struct InternedStr { - id: usize, -} - -#[derive(Default)] -pub struct Interner { - map: HashMap<&'static str, InternedStr>, - vec: Vec<&'static str>, - buf: String, - full: Vec, -} - -impl Interner { - pub fn with_capacity(cap: usize) -> Self { - Interner { - buf: String::with_capacity(cap), - ..Default::default() - } - } - - pub fn intern>(&mut self, name: S) -> InternedStr { - let name = name.as_ref(); - if let Some(&id) = self.map.get(name) { - return id; - } - - let name = self.alloc(name); - let id = InternedStr { - id: self.vec.len() as usize, - }; - - self.map.insert(name, id); - self.vec.push(name); - - debug_assert!(self.lookup(id) == name); - debug_assert!(self.intern(name) == id); - - id - } - - pub fn lookup<'a>(&'a self, id: InternedStr) -> &'a str { - self.vec[id.id] - } - - fn alloc<'a>(&'a mut self, name: &str) -> &'static str { - let cap = self.buf.capacity(); - if cap < self.buf.len() + name.len() { - let new_cap = (cap.max(name.len()) + 1).next_power_of_two(); - let new_buf = String::with_capacity(new_cap); - let old_buf = std::mem::replace(&mut self.buf, new_buf); - self.full.push(old_buf); - } - - let interned: &'a str = { - let start = self.buf.len(); - self.buf.push_str(name); - &self.buf[start..] - }; - - unsafe { - // This is sound for two reasons: - // - // 1. This function (Interner::alloc) is private, which - // prevents users from allocating a supposedly static - // reference. - // - // 2. Interner::lookup explicitly shortens the lifetime of - // references that are handed out to that of the - // reference to self. - return &*(interned as *const str); - } - } -} diff --git a/users/tazjin/rlox/src/bytecode/interner/tests.rs b/users/tazjin/rlox/src/bytecode/interner/tests.rs deleted file mode 100644 index b34bf6835..000000000 --- a/users/tazjin/rlox/src/bytecode/interner/tests.rs +++ /dev/null @@ -1,24 +0,0 @@ -use super::*; - -#[test] -fn interns_strings() { - let mut interner = Interner::with_capacity(128); - let id = interner.intern("hello world"); - assert_eq!("hello world", interner.lookup(id)); -} - -#[test] -fn deduplicates_strings() { - let mut interner = Interner::with_capacity(128); - let id_1 = interner.intern("hello world"); - let id_2 = interner.intern("hello world"); - assert_eq!(id_1, id_2); -} - -#[test] -fn ids_survive_growing() { - let mut interner = Interner::with_capacity(16); - let id = interner.intern("hello"); - interner.intern("excessively large string that will cause eallocation"); - assert_eq!("hello", interner.lookup(id)); -} diff --git a/users/tazjin/rlox/src/bytecode/mod.rs b/users/tazjin/rlox/src/bytecode/mod.rs deleted file mode 100644 index 117f17824..000000000 --- a/users/tazjin/rlox/src/bytecode/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Bytecode interpreter for Lox. -//! -//! https://craftinginterpreters.com/chunks-of-bytecode.html - -mod chunk; -mod compiler; -mod errors; -mod interner; -mod opcode; -mod value; -mod vm; - -#[cfg(test)] -mod tests; - -pub struct Interpreter {} - -impl crate::Lox for Interpreter { - type Error = errors::Error; - type Value = value::Value; - - fn create() -> Self { - Interpreter {} - } - - fn interpret(&mut self, code: String) -> Result> { - let (strings, chunk) = compiler::compile(&code)?; - vm::interpret(strings, chunk).map_err(|e| vec![e]) - } -} diff --git a/users/tazjin/rlox/src/bytecode/opcode.rs b/users/tazjin/rlox/src/bytecode/opcode.rs deleted file mode 100644 index 8a106f969..000000000 --- a/users/tazjin/rlox/src/bytecode/opcode.rs +++ /dev/null @@ -1,56 +0,0 @@ -#[derive(Clone, Copy, Debug)] -pub struct ConstantIdx(pub usize); - -#[derive(Clone, Copy, Debug)] -pub struct StackIdx(pub usize); - -#[derive(Clone, Copy, Debug)] -pub struct CodeIdx(pub usize); - -#[derive(Clone, Copy, Debug)] -pub struct CodeOffset(pub usize); - -#[derive(Debug)] -pub enum OpCode { - /// Push a constant onto the stack. - OpConstant(ConstantIdx), - - // Literal pushes - OpNil, - OpTrue, - OpFalse, - - /// Return from the current function. - OpReturn, - - // Boolean & comparison operators - OpNot, - OpEqual, - OpGreater, - OpLess, - - /// Unary negation - OpNegate, - - // Arithmetic operators - OpAdd, - OpSubtract, - OpMultiply, - OpDivide, - - // Built in operations - OpPrint, - OpPop, - - // Variable management - OpDefineGlobal(ConstantIdx), - OpGetGlobal(ConstantIdx), - OpSetGlobal(ConstantIdx), - OpGetLocal(StackIdx), - OpSetLocal(StackIdx), - - // Control flow - OpJumpPlaceholder(bool), - OpJump(CodeOffset), - OpJumpIfFalse(CodeOffset), -} diff --git a/users/tazjin/rlox/src/bytecode/tests.rs b/users/tazjin/rlox/src/bytecode/tests.rs deleted file mode 100644 index bc7d6cb87..000000000 --- a/users/tazjin/rlox/src/bytecode/tests.rs +++ /dev/null @@ -1,152 +0,0 @@ -use super::value::Value; -use super::*; - -use crate::Lox; - -fn expect(code: &str, value: Value) { - let result = Interpreter::create() - .interpret(code.into()) - .expect("evaluation failed"); - assert_eq!(result, value); -} - -fn expect_num(code: &str, value: f64) { - expect(code, Value::Number(value)) -} - -fn expect_bool(code: &str, value: bool) { - expect(code, Value::Bool(value)) -} - -fn expect_str(code: &str, value: &str) { - expect(code, Value::String(value.to_string().into())) -} - -#[test] -fn numbers() { - expect_num("1;", 1.0); - expect_num("13.37;", 13.37); -} - -#[test] -fn negative_numbers() { - // Note: This technically tests unary operators. - expect_num("-1;", -1.0); - expect_num("-13.37;", -13.37); -} - -#[test] -fn terms() { - expect_num("1 + 2;", 3.0); - expect_num("3 - 1;", 2.0); - expect_num("0.7 + 0.3;", 1.0); - expect_num("1 + -3;", -2.0); - expect_num("-1 - -1;", 0.0); - expect_num("10 - -10 + 10;", 30.0); -} - -#[test] -fn factors() { - expect_num("1 * 2;", 2.0); - expect_num("10 / 5;", 2.0); - expect_num("0.7 * 4 / 1.4;", 2.0); - expect_num("10 * -10 / 10;", -10.0); -} - -#[test] -fn arithmetic() { - expect_num("10 - 3 * 2;", 4.0); - expect_num("-4 * -4 + (14 - 5);", 25.0); - expect_num("(702 + 408) - ((239 - 734) / -5) + -4;", 1007.0); -} - -#[test] -fn trivial_literals() { - expect("true;", Value::Bool(true)); - expect("false;", Value::Bool(false)); - expect("nil;", Value::Nil); -} - -#[test] -fn negation() { - expect_bool("!true;", false); - expect_bool("!false;", true); - expect_bool("!nil;", true); - expect_bool("!13.5;", false); - expect_bool("!-42;", false); -} - -#[test] -fn equality() { - expect_bool("42 == 42;", true); - expect_bool("42 != 42;", false); - expect_bool("42 == 42.0;", true); - - expect_bool("true == true;", true); - expect_bool("true == false;", false); - expect_bool("true == !false;", true); - expect_bool("true != true;", false); - expect_bool("true != false;", true); - - expect_bool("42 == false;", false); - expect_bool("42 == true;", false); - expect_bool("!42 == !true;", true); -} - -#[test] -fn comparisons() { - expect_bool("42 > 23;", true); - expect_bool("42 < 23;", false); - expect_bool("42 <= 42;", true); - expect_bool("42 <= 23;", false); - expect_bool("42 >= 42;", true); - expect_bool("42 >= 23;", true); -} - -#[test] -fn strings() { - expect_str("\"hello\";", "hello"); - expect_str("\"hello\" + \" world\";", "hello world"); -} - -#[test] -fn global_variables() { - expect_num("var a = 5; a;", 5.0); - expect_num("var a = 5; var b = 2; a * b;", 10.0); - expect_str( - "var greeting = \"hello\"; var name = \"Zubnog\"; greeting + \" \" + name;", - "hello Zubnog", - ); -} - -#[test] -fn global_assignment() { - expect_str( - r#" - var breakfast = "beignets"; - var beverage = "cafe au lait"; - breakfast = "beignets with " + beverage; - breakfast; - "#, - "beignets with cafe au lait", - ); -} - -#[test] -fn local_variables() { - expect_num( - r#" - var a = 10; - var b = 5; - var result = 0; - { - var b = 10; - var c = 2; - result = a * b * c; - } - - result; - "#, - 200.0, - ); -} diff --git a/users/tazjin/rlox/src/bytecode/value.rs b/users/tazjin/rlox/src/bytecode/value.rs deleted file mode 100644 index 4170efadf..000000000 --- a/users/tazjin/rlox/src/bytecode/value.rs +++ /dev/null @@ -1,37 +0,0 @@ -use super::interner::InternedStr; - -#[derive(Clone, Debug, PartialEq)] -pub enum Value { - Nil, - Bool(bool), - Number(f64), - String(LoxString), -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum LoxString { - Heap(String), - Interned(InternedStr), -} - -impl From for LoxString { - fn from(s: String) -> Self { - LoxString::Heap(s) - } -} - -impl From for LoxString { - fn from(s: InternedStr) -> Self { - LoxString::Interned(s) - } -} - -impl Value { - pub fn is_falsey(&self) -> bool { - match self { - Value::Nil => true, - Value::Bool(false) => true, - _ => false, - } - } -} diff --git a/users/tazjin/rlox/src/bytecode/vm.rs b/users/tazjin/rlox/src/bytecode/vm.rs deleted file mode 100644 index 30ffebc79..000000000 --- a/users/tazjin/rlox/src/bytecode/vm.rs +++ /dev/null @@ -1,272 +0,0 @@ -use std::collections::HashMap; - -use super::chunk; -use super::errors::*; -use super::interner::Interner; -use super::opcode::OpCode; -use super::value::{LoxString, Value}; - -pub struct VM { - chunk: chunk::Chunk, - - // TODO(tazjin): Accessing array elements constantly is not ideal, - // lets see if something clever can be done with iterators. - ip: usize, - - stack: Vec, - strings: Interner, - - globals: HashMap, - - // Operations that consume values from the stack without pushing - // anything leave their last value in this slot, which makes it - // possible to return values from interpreters that ran code which - // ended with a statement. - last_drop: Option, -} - -impl VM { - fn push(&mut self, value: Value) { - self.stack.push(value) - } - - fn pop(&mut self) -> Value { - self.stack.pop().expect("fatal error: stack empty!") - } -} - -macro_rules! with_type { - ( $self:ident, $val:ident, $type:pat, $body:expr ) => { - match $val { - $type => $body, - _ => { - return Err(Error { - line: $self.chunk.get_line($self.ip - 1), - kind: ErrorKind::TypeError(format!( - "Expected type {}, but found value: {:?}", - stringify!($type), - $val, - )), - }) - } - } - }; -} - -macro_rules! binary_op { - ( $vm:ident, $type:tt, $op:tt ) => { - binary_op!($vm, $type, $type, $op) - }; - - ( $vm:ident, $in_type:tt, $out_type:tt, $op:tt ) => {{ - let b = $vm.pop(); - let a = $vm.pop(); - - with_type!($vm, b, Value::$in_type(val_b), { - with_type!($vm, a, Value::$in_type(val_a), { - $vm.push(Value::$out_type(val_a $op val_b)) - }) - }) - }}; -} - -impl VM { - fn run(&mut self) -> LoxResult { - loop { - let op = &self.chunk.code[self.ip]; - - #[cfg(feature = "disassemble")] - chunk::disassemble_instruction(&self.chunk, self.ip); - - self.ip += 1; - - match op { - OpCode::OpReturn => { - if !self.stack.is_empty() { - let val = self.pop(); - return Ok(self.return_value(val)); - } else if self.last_drop.is_some() { - let val = self.last_drop.take().unwrap(); - return Ok(self.return_value(val)); - } else { - return Ok(Value::Nil); - } - } - - OpCode::OpConstant(idx) => { - let c = self.chunk.constant(*idx).clone(); - self.push(c); - } - - OpCode::OpNil => self.push(Value::Nil), - OpCode::OpTrue => self.push(Value::Bool(true)), - OpCode::OpFalse => self.push(Value::Bool(false)), - - OpCode::OpNot => { - let v = self.pop(); - self.push(Value::Bool(v.is_falsey())); - } - - OpCode::OpEqual => { - let b = self.pop(); - let a = self.pop(); - self.push(Value::Bool(a == b)); - } - - OpCode::OpLess => binary_op!(self, Number, Bool, <), - OpCode::OpGreater => binary_op!(self, Number, Bool, >), - - OpCode::OpNegate => { - let v = self.pop(); - with_type!(self, v, Value::Number(num), self.push(Value::Number(-num))); - } - - OpCode::OpSubtract => binary_op!(self, Number, -), - OpCode::OpMultiply => binary_op!(self, Number, *), - OpCode::OpDivide => binary_op!(self, Number, /), - - OpCode::OpAdd => { - let b = self.pop(); - let a = self.pop(); - - match (a, b) { - (Value::String(s_a), Value::String(s_b)) => { - let mut new_s = self.resolve_str(&s_a).to_string(); - new_s.push_str(self.resolve_str(&s_b)); - self.push(Value::String(new_s.into())); - } - - (Value::Number(n_a), Value::Number(n_b)) => { - self.push(Value::Number(n_a + n_b)) - } - - _ => { - return Err(Error { - line: self.chunk.get_line(self.ip - 1), - kind: ErrorKind::TypeError( - "'+' operator only works on strings and numbers".into(), - ), - }) - } - } - } - - OpCode::OpPrint => { - let val = self.pop(); - println!("{}", self.print_value(val)); - } - - OpCode::OpPop => { - self.last_drop = Some(self.pop()); - } - - OpCode::OpDefineGlobal(name_idx) => { - let name = self.chunk.constant(*name_idx); - with_type!(self, name, Value::String(name), { - let name = name.clone(); - let val = self.pop(); - self.globals.insert(name, val); - }); - } - - OpCode::OpGetGlobal(name_idx) => { - let name = self.chunk.constant(*name_idx); - with_type!(self, name, Value::String(name), { - let val = match self.globals.get(name) { - None => unimplemented!("variable not found error"), - Some(val) => val.clone(), - }; - self.push(val) - }); - } - - OpCode::OpSetGlobal(name_idx) => { - let name = self.chunk.constant(*name_idx).clone(); - let new_val = self.pop(); - with_type!(self, name, Value::String(name), { - match self.globals.get_mut(&name) { - None => unimplemented!("variable not found error"), - Some(val) => { - *val = new_val; - } - } - }); - } - - OpCode::OpGetLocal(local_idx) => { - let value = self.stack[local_idx.0].clone(); - self.push(value); - } - - OpCode::OpSetLocal(local_idx) => { - debug_assert!( - self.stack.len() > local_idx.0, - "stack is not currently large enough for local" - ); - self.stack[local_idx.0] = self.stack.last().unwrap().clone(); - } - - OpCode::OpJumpPlaceholder(_) => { - panic!("unpatched jump detected - this is a fatal compiler error!"); - } - - OpCode::OpJump(offset) => { - self.ip += offset.0; - } - - OpCode::OpJumpIfFalse(offset) => { - if self - .stack - .last() - .expect("condition should leave a value on the stack") - .is_falsey() - { - self.ip += offset.0; - } - } - } - - #[cfg(feature = "disassemble")] - println!("=> {:?}", self.stack); - } - } - - // For some types of values (e.g. interned strings), returns - // should no longer include any references into the interpreter. - fn return_value(&self, val: Value) -> Value { - match val { - Value::String(string @ LoxString::Interned(_)) => { - Value::String(self.resolve_str(&string).to_string().into()) - } - _ => val, - } - } - - fn resolve_str<'a>(&'a self, string: &'a LoxString) -> &'a str { - match string { - LoxString::Heap(s) => s.as_str(), - LoxString::Interned(id) => self.strings.lookup(*id), - } - } - - fn print_value(&self, val: Value) -> String { - match val { - Value::String(LoxString::Heap(s)) => s, - Value::String(LoxString::Interned(id)) => self.strings.lookup(id).into(), - _ => format!("{:?}", val), - } - } -} - -pub fn interpret(strings: Interner, chunk: chunk::Chunk) -> LoxResult { - let mut vm = VM { - chunk, - strings, - globals: HashMap::new(), - ip: 0, - stack: vec![], - last_drop: None, - }; - - vm.run() -} diff --git a/users/tazjin/rlox/src/main.rs b/users/tazjin/rlox/src/main.rs deleted file mode 100644 index ee61ae01a..000000000 --- a/users/tazjin/rlox/src/main.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::io::Write; -use std::{env, fs, io, process}; - -mod bytecode; -mod scanner; -mod treewalk; - -/// Trait for making the different interpreters callable in the same -/// way. -pub trait Lox { - type Value: std::fmt::Debug; - type Error: std::fmt::Display; - - fn create() -> Self; - fn interpret(&mut self, source: String) -> Result>; -} - -fn main() { - let mut args = env::args(); - if args.len() > 2 { - println!("Usage: rlox [script]"); - process::exit(1); - } - - match env::var("LOX_INTERPRETER").as_ref().map(String::as_str) { - Ok("treewalk") => pick::(args.nth(1)), - _ => pick::(args.nth(1)), - } -} - -fn pick(file_arg: Option) { - if let Some(file) = file_arg { - run_file::(&file); - } else { - run_prompt::(); - } -} - -// Run Lox code from a file and print results to stdout -fn run_file(file: &str) { - let contents = fs::read_to_string(file).expect("failed to read the input file"); - let mut lox = I::create(); - run(&mut lox, contents); -} - -// Evaluate Lox code interactively in a shitty REPL. -fn run_prompt() { - let mut line = String::new(); - let mut lox = I::create(); - - loop { - print!("> "); - io::stdout().flush().unwrap(); - io::stdin() - .read_line(&mut line) - .expect("failed to read user input"); - run(&mut lox, std::mem::take(&mut line)); - line.clear(); - } -} - -fn run(lox: &mut I, code: String) { - match lox.interpret(code) { - Ok(result) => println!("=> {:?}", result), - Err(errors) => { - for error in errors { - eprintln!("{}", error); - } - } - } -} diff --git a/users/tazjin/rlox/src/scanner.rs b/users/tazjin/rlox/src/scanner.rs deleted file mode 100644 index 314b56d6d..000000000 --- a/users/tazjin/rlox/src/scanner.rs +++ /dev/null @@ -1,284 +0,0 @@ -#[derive(Clone, Debug, PartialEq)] -pub enum TokenKind { - // Single-character tokens. - LeftParen, - RightParen, - LeftBrace, - RightBrace, - Comma, - Dot, - Minus, - Plus, - Semicolon, - Slash, - Star, - - // One or two character tokens. - Bang, - BangEqual, - Equal, - EqualEqual, - Greater, - GreaterEqual, - Less, - LessEqual, - - // Literals. - Identifier(String), - String(String), - Number(f64), - True, - False, - Nil, - - // Keywords. - And, - Class, - Else, - Fun, - For, - If, - Or, - Print, - Return, - Super, - This, - Var, - While, - - // Special things - Eof, -} - -#[derive(Clone, Debug)] -pub struct Token { - pub kind: TokenKind, - pub lexeme: String, - pub line: usize, -} - -pub enum ScannerError { - UnexpectedChar { line: usize, unexpected: char }, - UnterminatedString { line: usize }, -} - -struct Scanner<'a> { - source: &'a [char], - tokens: Vec, - errors: Vec, - start: usize, // offset of first character in current lexeme - current: usize, // current offset into source - line: usize, // current line in source -} - -impl<'a> Scanner<'a> { - fn is_at_end(&self) -> bool { - return self.current >= self.source.len(); - } - - fn advance(&mut self) -> char { - self.current += 1; - self.source[self.current - 1] - } - - fn add_token(&mut self, kind: TokenKind) { - let lexeme = &self.source[self.start..self.current]; - self.tokens.push(Token { - kind, - lexeme: lexeme.into_iter().collect(), - line: self.line, - }) - } - - fn scan_token(&mut self) { - match self.advance() { - // simple single-character tokens - '(' => self.add_token(TokenKind::LeftParen), - ')' => self.add_token(TokenKind::RightParen), - '{' => self.add_token(TokenKind::LeftBrace), - '}' => self.add_token(TokenKind::RightBrace), - ',' => self.add_token(TokenKind::Comma), - '.' => self.add_token(TokenKind::Dot), - '-' => self.add_token(TokenKind::Minus), - '+' => self.add_token(TokenKind::Plus), - ';' => self.add_token(TokenKind::Semicolon), - '*' => self.add_token(TokenKind::Star), - - // possible multi-character tokens - '!' => self.add_if_next('=', TokenKind::BangEqual, TokenKind::Bang), - '=' => self.add_if_next('=', TokenKind::EqualEqual, TokenKind::Equal), - '<' => self.add_if_next('=', TokenKind::LessEqual, TokenKind::Less), - '>' => self.add_if_next('=', TokenKind::GreaterEqual, TokenKind::Greater), - - '/' => { - // support comments until EOL by discarding characters - if self.match_next('/') { - while self.peek() != '\n' && !self.is_at_end() { - self.advance(); - } - } else { - self.add_token(TokenKind::Slash); - } - } - - // ignore whitespace - ws if ws.is_whitespace() => { - if ws == '\n' { - self.line += 1 - } - } - - '"' => self.scan_string(), - - digit if digit.is_digit(10) => self.scan_number(), - - chr if chr.is_alphabetic() || chr == '_' => self.scan_identifier(), - - unexpected => self.errors.push(ScannerError::UnexpectedChar { - line: self.line, - unexpected, - }), - }; - } - - fn match_next(&mut self, expected: char) -> bool { - if self.is_at_end() || self.source[self.current] != expected { - false - } else { - self.current += 1; - true - } - } - - fn add_if_next(&mut self, expected: char, then: TokenKind, or: TokenKind) { - if self.match_next(expected) { - self.add_token(then); - } else { - self.add_token(or); - } - } - - fn peek(&self) -> char { - if self.is_at_end() { - return '\0'; - } else { - return self.source[self.current]; - } - } - - fn peek_next(&self) -> char { - if self.current + 1 >= self.source.len() { - return '\0'; - } else { - return self.source[self.current + 1]; - } - } - - fn scan_string(&mut self) { - while self.peek() != '"' && !self.is_at_end() { - if self.peek() == '\n' { - self.line += 1; - } - - self.advance(); - } - - if self.is_at_end() { - self.errors - .push(ScannerError::UnterminatedString { line: self.line }); - return; - } - - // closing '"' - self.advance(); - - // add token without surrounding quotes - let string: String = self.source[(self.start + 1)..(self.current - 1)] - .iter() - .collect(); - self.add_token(TokenKind::String(string)); - } - - fn scan_number(&mut self) { - while self.peek().is_digit(10) { - self.advance(); - } - - // Look for a fractional part - if self.peek() == '.' && self.peek_next().is_digit(10) { - // consume '.' - self.advance(); - - while self.peek().is_digit(10) { - self.advance(); - } - } - - let num: f64 = self.source[self.start..self.current] - .iter() - .collect::() - .parse() - .expect("float parsing should always work"); - - self.add_token(TokenKind::Number(num)); - } - - fn scan_identifier(&mut self) { - while self.peek().is_alphanumeric() || self.peek() == '_' { - self.advance(); - } - - let ident: String = self.source[self.start..self.current].iter().collect(); - - // Determine whether this is an identifier, or a keyword: - let token_kind = match ident.as_str() { - "and" => TokenKind::And, - "class" => TokenKind::Class, - "else" => TokenKind::Else, - "false" => TokenKind::False, - "for" => TokenKind::For, - "fun" => TokenKind::Fun, - "if" => TokenKind::If, - "nil" => TokenKind::Nil, - "or" => TokenKind::Or, - "print" => TokenKind::Print, - "return" => TokenKind::Return, - "super" => TokenKind::Super, - "this" => TokenKind::This, - "true" => TokenKind::True, - "var" => TokenKind::Var, - "while" => TokenKind::While, - _ => TokenKind::Identifier(ident), - }; - - self.add_token(token_kind); - } - - fn scan_tokens(&mut self) { - while !self.is_at_end() { - self.start = self.current; - self.scan_token(); - } - - self.add_token(TokenKind::Eof); - } -} - -pub fn scan<'a>(input: &'a [char]) -> Result, Vec> { - let mut scanner = Scanner { - source: &input, - tokens: vec![], - errors: vec![], - start: 0, - current: 0, - line: 0, - }; - - scanner.scan_tokens(); - - if !scanner.errors.is_empty() { - return Err(scanner.errors); - } - - return Ok(scanner.tokens); -} diff --git a/users/tazjin/rlox/src/treewalk/errors.rs b/users/tazjin/rlox/src/treewalk/errors.rs deleted file mode 100644 index 391663d51..000000000 --- a/users/tazjin/rlox/src/treewalk/errors.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::scanner::ScannerError; -use crate::treewalk::interpreter::Value; - -use std::fmt; - -#[derive(Debug)] -pub enum ErrorKind { - UnexpectedChar(char), - UnterminatedString, - UnmatchedParens, - ExpectedExpression(String), - ExpectedSemicolon, - ExpectedClosingBrace, - ExpectedToken(&'static str), - TypeError(String), - UndefinedVariable(String), - InternalError(String), - InvalidAssignmentTarget(String), - RuntimeError(String), - StaticError(String), - - // This variant is not an error, rather it is used for - // short-circuiting out of a function body that hits a `return` - // statement. - // - // It's implemented this way because in the original book the - // author uses exceptions for control flow, and this is the - // closest equivalent that I had available without diverging too - // much. - FunctionReturn(Value), -} - -#[derive(Debug)] -pub struct Error { - pub line: usize, - pub kind: ErrorKind, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[line {}] Error: {:?}", self.line, self.kind) - } -} - -impl From for Error { - fn from(err: ScannerError) -> Self { - match err { - ScannerError::UnexpectedChar { line, unexpected } => Error { - line, - kind: ErrorKind::UnexpectedChar(unexpected), - }, - - ScannerError::UnterminatedString { line } => Error { - line, - kind: ErrorKind::UnterminatedString, - }, - } - } -} diff --git a/users/tazjin/rlox/src/treewalk/interpreter.rs b/users/tazjin/rlox/src/treewalk/interpreter.rs deleted file mode 100644 index 3285775bb..000000000 --- a/users/tazjin/rlox/src/treewalk/interpreter.rs +++ /dev/null @@ -1,498 +0,0 @@ -use crate::treewalk::errors::{Error, ErrorKind}; -use crate::treewalk::parser::{self, Block, Expr, Literal, Statement}; -use crate::treewalk::resolver; -use crate::treewalk::scanner::{self, TokenKind}; -use crate::Lox; -use std::collections::HashMap; -use std::rc::Rc; -use std::sync::RwLock; - -// Implementation of built-in functions. -mod builtins; - -#[cfg(test)] -mod tests; - -// Tree-walk interpreter - -// Representation of all callables, including builtins & user-defined -// functions. -#[derive(Clone, Debug)] -pub enum Callable { - Builtin(&'static dyn builtins::Builtin), - Function { - func: Rc, - closure: Rc>, - }, -} - -impl Callable { - fn arity(&self) -> usize { - match self { - Callable::Builtin(builtin) => builtin.arity(), - Callable::Function { func, .. } => func.params.len(), - } - } - - fn call(&self, lox: &mut Interpreter, args: Vec) -> Result { - match self { - Callable::Builtin(builtin) => builtin.call(args), - - Callable::Function { func, closure } => { - let mut fn_env: Environment = Default::default(); - fn_env.enclosing = Some(closure.clone()); - - for (param, value) in func.params.iter().zip(args.into_iter()) { - fn_env.define(param, value)?; - } - - let result = - lox.interpret_block_with_env(Some(Rc::new(RwLock::new(fn_env))), &func.body); - - match result { - // extract returned values if applicable - Err(Error { - kind: ErrorKind::FunctionReturn(value), - .. - }) => Ok(value), - - // otherwise just return the result itself - _ => result, - } - } - } - } -} - -// Representation of an in-language value. -#[derive(Clone, Debug)] -pub enum Value { - Literal(Literal), - Callable(Callable), -} - -impl PartialEq for Value { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Value::Literal(lhs), Value::Literal(rhs)) => lhs == rhs, - // functions do not have equality - _ => false, - } - } -} - -impl From for Value { - fn from(lit: Literal) -> Value { - Value::Literal(lit) - } -} - -impl Value { - fn expect_literal(self) -> Result { - match self { - Value::Literal(lit) => Ok(lit), - _ => unimplemented!(), // which error? which line? - } - } -} - -#[derive(Debug, Default)] -pub struct Environment { - enclosing: Option>>, - values: HashMap, -} - -impl Environment { - fn define(&mut self, name: &scanner::Token, value: Value) -> Result<(), Error> { - let ident = identifier_str(name)?; - self.values.insert(ident.into(), value); - Ok(()) - } - - fn get(&self, ident: &str, line: usize, depth: usize) -> Result { - if depth > 0 { - match &self.enclosing { - None => { - return Err(Error { - line, - kind: ErrorKind::InternalError(format!( - "invalid depth {} for {}", - depth, ident - )), - }) - } - Some(parent) => { - let env = parent.read().expect("fatal: environment lock poisoned"); - return env.get(ident, line, depth - 1); - } - } - } - - self.values - .get(ident) - .map(Clone::clone) - .ok_or_else(|| Error { - line, - kind: ErrorKind::UndefinedVariable(ident.into()), - }) - } - - fn assign(&mut self, name: &scanner::Token, value: Value) -> Result<(), Error> { - let ident = identifier_str(name)?; - - match self.values.get_mut(ident) { - Some(target) => { - *target = value; - Ok(()) - } - None => { - if let Some(parent) = &self.enclosing { - return parent.write().unwrap().assign(name, value); - } - - Err(Error { - line: name.line, - kind: ErrorKind::UndefinedVariable(ident.into()), - }) - } - } - } -} - -fn identifier_str(name: &scanner::Token) -> Result<&str, Error> { - if let TokenKind::Identifier(ident) = &name.kind { - Ok(ident) - } else { - Err(Error { - line: name.line, - kind: ErrorKind::InternalError("unexpected identifier kind".into()), - }) - } -} - -#[derive(Debug)] -pub struct Interpreter { - env: Rc>, -} - -impl Lox for Interpreter { - type Value = Value; - type Error = Error; - - /// Create a new interpreter and configure the initial global - /// variable set. - fn create() -> Self { - let mut globals = HashMap::new(); - - globals.insert( - "clock".into(), - Value::Callable(Callable::Builtin(&builtins::Clock {})), - ); - - Interpreter { - env: Rc::new(RwLock::new(Environment { - enclosing: None, - values: globals, - })), - } - } - - fn interpret(&mut self, code: String) -> Result> { - let chars: Vec = code.chars().collect(); - - let mut program = scanner::scan(&chars) - .map_err(|errors| errors.into_iter().map(Into::into).collect()) - .and_then(|tokens| parser::parse(tokens))?; - - let globals = self - .env - .read() - .expect("static globals lock poisoned") - .values - .keys() - .map(Clone::clone) - .collect::>(); - - resolver::resolve(&globals, &mut program).map_err(|e| vec![e])?; - self.interpret_block_with_env(None, &program) - .map_err(|e| vec![e]) - } -} - -impl Interpreter { - // Environment modification helpers - fn define_var(&mut self, name: &scanner::Token, value: Value) -> Result<(), Error> { - self.env - .write() - .expect("environment lock is poisoned") - .define(name, value) - } - - fn assign_var(&mut self, name: &scanner::Token, value: Value) -> Result<(), Error> { - self.env - .write() - .expect("environment lock is poisoned") - .assign(name, value) - } - - fn get_var(&mut self, var: &parser::Variable) -> Result { - let ident = identifier_str(&var.name)?; - let depth = var.depth.ok_or_else(|| Error { - line: var.name.line, - kind: ErrorKind::UndefinedVariable(ident.into()), - })?; - - self.env - .read() - .expect("environment lock is poisoned") - .get(ident, var.name.line, depth) - } - - /// Interpret the block in the supplied environment. If no - /// environment is supplied, a new one is created using the - /// current one as its parent. - fn interpret_block_with_env( - &mut self, - env: Option>>, - block: &parser::Block, - ) -> Result { - let env = match env { - Some(env) => env, - None => { - let env: Rc> = Default::default(); - set_enclosing_env(&env, self.env.clone()); - env - } - }; - - let previous = std::mem::replace(&mut self.env, env); - let result = self.interpret_block(block); - - // Swap it back, discarding the child env. - self.env = previous; - - return result; - } - - fn interpret_block(&mut self, program: &Block) -> Result { - let mut value = Value::Literal(Literal::Nil); - - for stmt in program { - value = self.interpret_stmt(stmt)?; - } - - Ok(value) - } - - fn interpret_stmt(&mut self, stmt: &Statement) -> Result { - let value = match stmt { - Statement::Expr(expr) => self.eval(expr)?, - Statement::Print(expr) => { - let result = self.eval(expr)?; - let output = format!("{:?}", result); - println!("{}", output); - Value::Literal(Literal::String(output)) - } - Statement::Var(var) => return self.interpret_var(var), - Statement::Block(block) => return self.interpret_block_with_env(None, block), - Statement::If(if_stmt) => return self.interpret_if(if_stmt), - Statement::While(while_stmt) => return self.interpret_while(while_stmt), - Statement::Function(func) => return self.interpret_function(func.clone()), - Statement::Return(ret) => { - return Err(Error { - line: 0, - kind: ErrorKind::FunctionReturn(self.eval(&ret.value)?), - }) - } - }; - - Ok(value) - } - - fn interpret_var(&mut self, var: &parser::Var) -> Result { - let init = var.initialiser.as_ref().ok_or_else(|| Error { - line: var.name.line, - kind: ErrorKind::InternalError("missing variable initialiser".into()), - })?; - let value = self.eval(init)?; - self.define_var(&var.name, value.clone())?; - Ok(value) - } - - fn interpret_if(&mut self, if_stmt: &parser::If) -> Result { - let condition = self.eval(&if_stmt.condition)?; - - if eval_truthy(&condition) { - self.interpret_stmt(&if_stmt.then_branch) - } else if let Some(else_branch) = &if_stmt.else_branch { - self.interpret_stmt(else_branch) - } else { - Ok(Value::Literal(Literal::Nil)) - } - } - - fn interpret_while(&mut self, stmt: &parser::While) -> Result { - let mut value = Value::Literal(Literal::Nil); - while eval_truthy(&self.eval(&stmt.condition)?) { - value = self.interpret_stmt(&stmt.body)?; - } - - Ok(value) - } - - fn interpret_function(&mut self, func: Rc) -> Result { - let name = func.name.clone(); - let value = Value::Callable(Callable::Function { - func, - closure: self.env.clone(), - }); - self.define_var(&name, value.clone())?; - Ok(value) - } - - fn eval(&mut self, expr: &Expr) -> Result { - match expr { - Expr::Assign(assign) => self.eval_assign(assign), - Expr::Literal(lit) => Ok(lit.clone().into()), - Expr::Grouping(grouping) => self.eval(&*grouping.0), - Expr::Unary(unary) => self.eval_unary(unary), - Expr::Binary(binary) => self.eval_binary(binary), - Expr::Variable(var) => self.get_var(var), - Expr::Logical(log) => self.eval_logical(log), - Expr::Call(call) => self.eval_call(call), - } - } - - fn eval_unary(&mut self, expr: &parser::Unary) -> Result { - let right = self.eval(&*expr.right)?; - - match (&expr.operator.kind, right) { - (TokenKind::Minus, Value::Literal(Literal::Number(num))) => { - Ok(Literal::Number(-num).into()) - } - (TokenKind::Bang, right) => Ok(Literal::Boolean(!eval_truthy(&right)).into()), - - (op, right) => Err(Error { - line: expr.operator.line, - kind: ErrorKind::TypeError(format!( - "Operator '{:?}' can not be called with argument '{:?}'", - op, right - )), - }), - } - } - - fn eval_binary(&mut self, expr: &parser::Binary) -> Result { - let left = self.eval(&*expr.left)?.expect_literal()?; - let right = self.eval(&*expr.right)?.expect_literal()?; - - let result = match (&expr.operator.kind, left, right) { - // Numeric - (TokenKind::Minus, Literal::Number(l), Literal::Number(r)) => Literal::Number(l - r), - (TokenKind::Slash, Literal::Number(l), Literal::Number(r)) => Literal::Number(l / r), - (TokenKind::Star, Literal::Number(l), Literal::Number(r)) => Literal::Number(l * r), - (TokenKind::Plus, Literal::Number(l), Literal::Number(r)) => Literal::Number(l + r), - - // Strings - (TokenKind::Plus, Literal::String(l), Literal::String(r)) => { - Literal::String(format!("{}{}", l, r)) - } - - // Comparators (on numbers only?) - (TokenKind::Greater, Literal::Number(l), Literal::Number(r)) => Literal::Boolean(l > r), - (TokenKind::GreaterEqual, Literal::Number(l), Literal::Number(r)) => { - Literal::Boolean(l >= r) - } - (TokenKind::Less, Literal::Number(l), Literal::Number(r)) => Literal::Boolean(l < r), - (TokenKind::LessEqual, Literal::Number(l), Literal::Number(r)) => { - Literal::Boolean(l <= r) - } - - // Equality - (TokenKind::Equal, l, r) => Literal::Boolean(l == r), - (TokenKind::BangEqual, l, r) => Literal::Boolean(l != r), - - (op, left, right) => { - return Err(Error { - line: expr.operator.line, - kind: ErrorKind::TypeError(format!( - "Operator '{:?}' can not be called with arguments '({:?}, {:?})'", - op, left, right - )), - }) - } - }; - - Ok(result.into()) - } - - fn eval_assign(&mut self, assign: &parser::Assign) -> Result { - let value = self.eval(&assign.value)?; - self.assign_var(&assign.name, value.clone())?; - Ok(value) - } - - fn eval_logical(&mut self, logical: &parser::Logical) -> Result { - let left = eval_truthy(&self.eval(&logical.left)?); - let right = eval_truthy(&self.eval(&logical.right)?); - - match &logical.operator.kind { - TokenKind::And => Ok(Literal::Boolean(left && right).into()), - TokenKind::Or => Ok(Literal::Boolean(left || right).into()), - kind => Err(Error { - line: logical.operator.line, - kind: ErrorKind::InternalError(format!("Invalid logical operator: {:?}", kind)), - }), - } - } - - fn eval_call(&mut self, call: &parser::Call) -> Result { - let callable = match self.eval(&call.callee)? { - Value::Callable(c) => c, - Value::Literal(v) => { - return Err(Error { - line: call.paren.line, - kind: ErrorKind::RuntimeError(format!("not callable: {:?}", v)), - }) - } - }; - - let mut args = vec![]; - for arg in &call.args { - args.push(self.eval(arg)?); - } - - if callable.arity() != args.len() { - return Err(Error { - line: call.paren.line, - kind: ErrorKind::RuntimeError(format!( - "Expected {} arguments, but got {}", - callable.arity(), - args.len(), - )), - }); - } - - callable.call(self, args) - } -} - -// Interpreter functions not dependent on interpreter-state. - -fn eval_truthy(lit: &Value) -> bool { - if let Value::Literal(lit) = lit { - match lit { - Literal::Nil => false, - Literal::Boolean(b) => *b, - _ => true, - } - } else { - false - } -} - -fn set_enclosing_env(this: &RwLock, parent: Rc>) { - this.write() - .expect("environment lock is poisoned") - .enclosing = Some(parent); -} diff --git a/users/tazjin/rlox/src/treewalk/interpreter/builtins.rs b/users/tazjin/rlox/src/treewalk/interpreter/builtins.rs deleted file mode 100644 index c502d2a17..000000000 --- a/users/tazjin/rlox/src/treewalk/interpreter/builtins.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::fmt; -use std::time::{SystemTime, UNIX_EPOCH}; - -use crate::treewalk::errors::Error; -use crate::treewalk::interpreter::Value; -use crate::treewalk::parser::Literal; - -pub trait Builtin: fmt::Debug { - fn arity(&self) -> usize; - fn call(&self, args: Vec) -> Result; -} - -// Builtin to return the current timestamp. -#[derive(Debug)] -pub struct Clock {} -impl Builtin for Clock { - fn arity(&self) -> usize { - 0 - } - - fn call(&self, _args: Vec) -> Result { - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - Ok(Value::Literal(Literal::Number(now.as_secs() as f64))) - } -} diff --git a/users/tazjin/rlox/src/treewalk/interpreter/tests.rs b/users/tazjin/rlox/src/treewalk/interpreter/tests.rs deleted file mode 100644 index 2fc6f4fee..000000000 --- a/users/tazjin/rlox/src/treewalk/interpreter/tests.rs +++ /dev/null @@ -1,97 +0,0 @@ -use super::*; - -/// Evaluate a code snippet, returning a value. -fn parse_eval(code: &str) -> Value { - Interpreter::create() - .interpret(code.into()) - .expect("could not interpret code") -} - -#[test] -fn test_if() { - let result = parse_eval( - r#" -if (42 > 23) - "pass"; -else - "fail"; -"#, - ); - - assert_eq!(Value::Literal(Literal::String("pass".into())), result,); -} - -#[test] -fn test_scope() { - let result = parse_eval( - r#" -var result = ""; - -var a = "global a, "; -var b = "global b, "; -var c = "global c"; - -{ - var a = "outer a, "; - var b = "outer b, "; - - { - var a = "inner a, "; - result = a + b + c; - } -} -"#, - ); - - assert_eq!( - Value::Literal(Literal::String("inner a, outer b, global c".into())), - result, - ); -} - -#[test] -fn test_binary_operators() { - assert_eq!(Value::Literal(Literal::Number(42.0)), parse_eval("40 + 2;")); - - assert_eq!( - Value::Literal(Literal::String("foobar".into())), - parse_eval("\"foo\" + \"bar\";") - ); -} - -#[test] -fn test_functions() { - let result = parse_eval( - r#" -fun add(a, b, c) { - a + b + c; -} - -add(1, 2, 3); -"#, - ); - - assert_eq!(Value::Literal(Literal::Number(6.0)), result); -} - -#[test] -fn test_closure() { - let result = parse_eval( - r#" -fun makeCounter() { - var i = 0; - fun count() { - i = i + 1; - } - - return count; -} - -var counter = makeCounter(); -counter(); // "1". -counter(); // "2". -"#, - ); - - assert_eq!(Value::Literal(Literal::Number(2.0)), result); -} diff --git a/users/tazjin/rlox/src/treewalk/mod.rs b/users/tazjin/rlox/src/treewalk/mod.rs deleted file mode 100644 index 2d82b3320..000000000 --- a/users/tazjin/rlox/src/treewalk/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -use crate::scanner; - -mod errors; -pub mod interpreter; -mod parser; -mod resolver; diff --git a/users/tazjin/rlox/src/treewalk/parser.rs b/users/tazjin/rlox/src/treewalk/parser.rs deleted file mode 100644 index 5794b42d1..000000000 --- a/users/tazjin/rlox/src/treewalk/parser.rs +++ /dev/null @@ -1,700 +0,0 @@ -// This implements the grammar of Lox as described starting in the -// Crafting Interpreters chapter "Representing Code". Note that the -// upstream Java implementation works around Java being bad at value -// classes by writing a code generator for Java. -// -// My Rust implementation skips this step because it's unnecessary, we -// have real types. -use crate::treewalk::errors::{Error, ErrorKind}; -use crate::treewalk::scanner::{Token, TokenKind}; -use std::rc::Rc; - -// AST - -#[derive(Debug)] -pub struct Assign { - pub name: Token, - pub value: Box, - pub depth: Option, -} - -#[derive(Debug)] -pub struct Binary { - pub left: Box, - pub operator: Token, - pub right: Box, -} - -#[derive(Debug)] -pub struct Logical { - pub left: Box, - pub operator: Token, - pub right: Box, -} - -#[derive(Debug)] -pub struct Grouping(pub Box); - -#[derive(Debug, Clone, PartialEq)] -pub enum Literal { - Boolean(bool), - Number(f64), - String(String), - Nil, -} - -#[derive(Debug)] -pub struct Unary { - pub operator: Token, - pub right: Box, -} - -#[derive(Debug)] -pub struct Call { - pub callee: Box, - pub paren: Token, - pub args: Vec, -} - -// Not to be confused with `Var`, which is for assignment. -#[derive(Debug)] -pub struct Variable { - pub name: Token, - pub depth: Option, -} - -#[derive(Debug)] -pub enum Expr { - Assign(Assign), - Binary(Binary), - Grouping(Grouping), - Literal(Literal), - Unary(Unary), - Call(Call), - Variable(Variable), - Logical(Logical), -} - -// Variable assignment. Not to be confused with `Variable`, which is -// for access. -#[derive(Debug)] -pub struct Var { - pub name: Token, - pub initialiser: Option, -} - -#[derive(Debug)] -pub struct Return { - pub value: Expr, -} - -#[derive(Debug)] -pub struct If { - pub condition: Expr, - pub then_branch: Box, - pub else_branch: Option>, -} - -#[derive(Debug)] -pub struct While { - pub condition: Expr, - pub body: Box, -} - -pub type Block = Vec; - -#[derive(Debug)] -pub struct Function { - pub name: Token, - pub params: Vec, - pub body: Block, -} - -#[derive(Debug)] -pub enum Statement { - Expr(Expr), - Print(Expr), - Var(Var), - Block(Block), - If(If), - While(While), - Function(Rc), - Return(Return), -} - -// Parser - -// program → declaration* EOF ; -// -// declaration → funDecl -// | varDecl -// | statement ; -// -// funDecl → "fun" function ; -// function → IDENTIFIER "(" parameters? ")" block ; -// parameters → IDENTIFIER ( "," IDENTIFIER )* ; -// -// -// statement → exprStmt -// | forStmt -// | ifStmt -// | printStmt -// | returnStmt -// | whileStmt -// | block ; -// -// forStmt → "for" "(" ( varDecl | exprStmt | ";" ) -// expression? ";" -// expression? ")" statement ; -// -// returnStmt → "return" expression? ";" ; -// -// whileStmt → "while" "(" expression ")" statement ; -// -// exprStmt → expression ";" ; -// -// ifStmt → "if" "(" expression ")" statement -// ( "else" statement )? ; -// -// printStmt → "print" expression ";" ; -// -// expression → assignment ; -// assignment → IDENTIFIER "=" assignment -// | logic_or ; -// logic_or → logic_and ( "or" logic_and )* ; -// logic_and → equality ( "and" equality )* ; -// equality → comparison ( ( "!=" | "==" ) comparison )* ; -// comparison → term ( ( ">" | ">=" | "<" | "<=" ) term )* ; -// term → factor ( ( "-" | "+" ) factor )* ; -// factor → unary ( ( "/" | "*" ) unary )* ; -// unary → ( "!" | "-" ) unary | call ; -// call → primary ( "(" arguments? ")" )* ; -// arguments → expression ( "," expression )* ; -// primary → NUMBER | STRING | "true" | "false" | "nil" -// | "(" expression ")" ; - -struct Parser { - tokens: Vec, - current: usize, -} - -type ExprResult = Result; -type StmtResult = Result; - -impl Parser { - // recursive-descent parser functions - - fn declaration(&mut self) -> StmtResult { - if self.match_token(&TokenKind::Fun) { - return self.function(); - } - - if self.match_token(&TokenKind::Var) { - return self.var_declaration(); - } - - self.statement() - } - - fn function(&mut self) -> StmtResult { - let name = self.identifier("Expected function name.")?; - - self.consume( - &TokenKind::LeftParen, - ErrorKind::ExpectedToken("Expect '(' after function name."), - )?; - - let mut params = vec![]; - - if !self.check_token(&TokenKind::RightParen) { - loop { - if params.len() >= 255 { - return Err(Error { - line: self.peek().line, - kind: ErrorKind::InternalError("255 parameter limit exceeded.".into()), - }); - } - - params.push(self.identifier("Expected parameter name.")?); - - if !self.match_token(&TokenKind::Comma) { - break; - } - } - } - - self.consume( - &TokenKind::RightParen, - ErrorKind::ExpectedToken("Expect ')' after parameters."), - )?; - - self.consume( - &TokenKind::LeftBrace, - ErrorKind::ExpectedToken("Expect '{' before function body."), - )?; - - Ok(Statement::Function(Rc::new(Function { - name, - params, - body: self.block_statement()?, - }))) - } - - fn var_declaration(&mut self) -> StmtResult { - // Since `TokenKind::Identifier` carries data, we can't use - // `consume`. - let mut var = Var { - name: self.identifier("Expected variable name.")?, - initialiser: None, - }; - - if self.match_token(&TokenKind::Equal) { - var.initialiser = Some(self.expression()?); - } - - self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; - Ok(Statement::Var(var)) - } - - fn statement(&mut self) -> StmtResult { - if self.match_token(&TokenKind::Print) { - self.print_statement() - } else if self.match_token(&TokenKind::LeftBrace) { - Ok(Statement::Block(self.block_statement()?)) - } else if self.match_token(&TokenKind::If) { - self.if_statement() - } else if self.match_token(&TokenKind::While) { - self.while_statement() - } else if self.match_token(&TokenKind::For) { - self.for_statement() - } else if self.match_token(&TokenKind::Return) { - self.return_statement() - } else { - self.expr_statement() - } - } - - fn print_statement(&mut self) -> StmtResult { - let expr = self.expression()?; - self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; - Ok(Statement::Print(expr)) - } - - fn block_statement(&mut self) -> Result { - let mut block: Block = vec![]; - - while !self.check_token(&TokenKind::RightBrace) && !self.is_at_end() { - block.push(self.declaration()?); - } - - self.consume(&TokenKind::RightBrace, ErrorKind::ExpectedClosingBrace)?; - - Ok(block) - } - - fn if_statement(&mut self) -> StmtResult { - self.consume( - &TokenKind::LeftParen, - ErrorKind::ExpectedToken("Expected '(' after 'if'"), - )?; - let condition = self.expression()?; - self.consume( - &TokenKind::RightParen, - ErrorKind::ExpectedToken("Expected ')' after condition"), - )?; - - let then_branch = Box::new(self.statement()?); - - let mut stmt = If { - condition, - then_branch, - else_branch: Option::None, - }; - - if self.match_token(&TokenKind::Else) { - stmt.else_branch = Some(Box::new(self.statement()?)); - } - - Ok(Statement::If(stmt)) - } - - fn while_statement(&mut self) -> StmtResult { - self.consume( - &TokenKind::LeftParen, - ErrorKind::ExpectedToken("Expected '(' after 'while'"), - )?; - - let condition = self.expression()?; - - self.consume( - &TokenKind::RightParen, - ErrorKind::ExpectedToken("Expected ')' after 'while'"), - )?; - - Ok(Statement::While(While { - condition, - body: Box::new(self.statement()?), - })) - } - - fn for_statement(&mut self) -> StmtResult { - // Parsing of clauses ... - self.consume( - &TokenKind::LeftParen, - ErrorKind::ExpectedToken("Expected '(' after 'for'"), - )?; - - let initialiser = if self.match_token(&TokenKind::Semicolon) { - None - } else if self.match_token(&TokenKind::Var) { - Some(self.var_declaration()?) - } else { - Some(self.expr_statement()?) - }; - - let condition = if self.check_token(&TokenKind::Semicolon) { - // unspecified condition => infinite loop - Expr::Literal(Literal::Boolean(true)) - } else { - self.expression()? - }; - - self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; - - let increment = if self.check_token(&TokenKind::RightParen) { - None - } else { - Some(self.expression()?) - }; - - self.consume( - &TokenKind::RightParen, - ErrorKind::ExpectedToken("Expected ')' after for clauses"), - )?; - - let mut body = self.statement()?; - - // ... desugaring to while - - if let Some(inc) = increment { - body = Statement::Block(vec![body, Statement::Expr(inc)]); - } - - body = Statement::While(While { - condition, - body: Box::new(body), - }); - - if let Some(init) = initialiser { - body = Statement::Block(vec![init, body]); - } - - Ok(body) - } - - fn return_statement(&mut self) -> StmtResult { - let value = self.expression()?; - self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; - Ok(Statement::Return(Return { value })) - } - - fn expr_statement(&mut self) -> StmtResult { - let expr = self.expression()?; - self.consume(&TokenKind::Semicolon, ErrorKind::ExpectedSemicolon)?; - Ok(Statement::Expr(expr)) - } - - fn expression(&mut self) -> ExprResult { - self.assignment() - } - - fn assignment(&mut self) -> ExprResult { - let expr = self.logic_or()?; - - if self.match_token(&TokenKind::Equal) { - let equals = self.previous().clone(); - let value = self.assignment()?; - - if let Expr::Variable(Variable { name, .. }) = expr { - return Ok(Expr::Assign(Assign { - name, - value: Box::new(value), - depth: None, - })); - } - - return Err(Error { - line: equals.line, - kind: ErrorKind::InvalidAssignmentTarget(format!("{:?}", equals)), - }); - } - - Ok(expr) - } - - fn logic_or(&mut self) -> ExprResult { - let mut expr = self.logic_and()?; - - while self.match_token(&TokenKind::Or) { - expr = Expr::Logical(Logical { - left: Box::new(expr), - operator: self.previous().clone(), - right: Box::new(self.logic_and()?), - }) - } - - Ok(expr) - } - - fn logic_and(&mut self) -> ExprResult { - let mut expr = self.equality()?; - - while self.match_token(&TokenKind::And) { - expr = Expr::Logical(Logical { - left: Box::new(expr), - operator: self.previous().clone(), - right: Box::new(self.equality()?), - }) - } - - Ok(expr) - } - - fn equality(&mut self) -> ExprResult { - self.binary_operator( - &[TokenKind::BangEqual, TokenKind::EqualEqual], - Self::comparison, - ) - } - - fn comparison(&mut self) -> ExprResult { - self.binary_operator( - &[ - TokenKind::Greater, - TokenKind::GreaterEqual, - TokenKind::Less, - TokenKind::LessEqual, - ], - Self::term, - ) - } - - fn term(&mut self) -> ExprResult { - self.binary_operator(&[TokenKind::Minus, TokenKind::Plus], Self::factor) - } - - fn factor(&mut self) -> ExprResult { - self.binary_operator(&[TokenKind::Slash, TokenKind::Star], Self::unary) - } - - fn unary(&mut self) -> ExprResult { - if self.match_token(&TokenKind::Bang) || self.match_token(&TokenKind::Minus) { - return Ok(Expr::Unary(Unary { - operator: self.previous().clone(), - right: Box::new(self.unary()?), - })); - } - - return self.call(); - } - - fn call(&mut self) -> ExprResult { - let mut expr = self.primary()?; - - loop { - if self.match_token(&TokenKind::LeftParen) { - expr = self.finish_call(expr)?; - } else { - break; - } - } - - Ok(expr) - } - - fn finish_call(&mut self, callee: Expr) -> ExprResult { - let mut args = vec![]; - - if !self.check_token(&TokenKind::RightParen) { - loop { - // TODO(tazjin): Check for max args count - args.push(self.expression()?); - if !self.match_token(&TokenKind::Comma) { - break; - } - } - } - - let paren = self.consume( - &TokenKind::RightParen, - ErrorKind::ExpectedToken("Expect ')' after arguments."), - )?; - - Ok(Expr::Call(Call { - args, - callee: Box::new(callee), - paren, - })) - } - - fn primary(&mut self) -> ExprResult { - let next = self.advance(); - let literal = match next.kind { - TokenKind::True => Literal::Boolean(true), - TokenKind::False => Literal::Boolean(false), - TokenKind::Nil => Literal::Nil, - TokenKind::Number(num) => Literal::Number(num), - TokenKind::String(string) => Literal::String(string), - - TokenKind::LeftParen => { - let expr = self.expression()?; - self.consume(&TokenKind::RightParen, ErrorKind::UnmatchedParens)?; - return Ok(Expr::Grouping(Grouping(Box::new(expr)))); - } - - TokenKind::Identifier(_) => { - return Ok(Expr::Variable(Variable { - name: next, - depth: None, - })) - } - - unexpected => { - eprintln!("encountered {:?}", unexpected); - return Err(Error { - line: next.line, - kind: ErrorKind::ExpectedExpression(next.lexeme), - }); - } - }; - - Ok(Expr::Literal(literal)) - } - - // internal helpers - - fn identifier(&mut self, err: &'static str) -> Result { - if let TokenKind::Identifier(_) = self.peek().kind { - Ok(self.advance()) - } else { - Err(Error { - line: self.peek().line, - kind: ErrorKind::ExpectedToken(err), - }) - } - } - - /// Check if the next token is in `oneof`, and advance if it is. - fn match_token(&mut self, token: &TokenKind) -> bool { - if self.check_token(token) { - self.advance(); - return true; - } - - false - } - - /// Return the next token and advance parser state. - fn advance(&mut self) -> Token { - if !self.is_at_end() { - self.current += 1; - } - - return self.previous().clone(); - } - - fn is_at_end(&self) -> bool { - self.check_token(&TokenKind::Eof) - } - - /// Is the next token `token`? - fn check_token(&self, token: &TokenKind) -> bool { - self.peek().kind == *token - } - - fn peek(&self) -> &Token { - &self.tokens[self.current] - } - - fn previous(&self) -> &Token { - &self.tokens[self.current - 1] - } - - fn consume(&mut self, kind: &TokenKind, err: ErrorKind) -> Result { - if self.check_token(kind) { - return Ok(self.advance()); - } - - Err(Error { - line: self.peek().line, - kind: err, - }) - } - - fn synchronise(&mut self) { - self.advance(); - - while !self.is_at_end() { - if self.previous().kind == TokenKind::Semicolon { - return; - } - - match self.peek().kind { - TokenKind::Class - | TokenKind::Fun - | TokenKind::Var - | TokenKind::For - | TokenKind::If - | TokenKind::While - | TokenKind::Print - | TokenKind::Return => return, - - _ => { - self.advance(); - } - } - } - } - - fn binary_operator( - &mut self, - oneof: &[TokenKind], - each: fn(&mut Parser) -> ExprResult, - ) -> ExprResult { - let mut expr = each(self)?; - - while oneof.iter().any(|t| self.match_token(t)) { - expr = Expr::Binary(Binary { - left: Box::new(expr), - operator: self.previous().clone(), - right: Box::new(each(self)?), - }) - } - - return Ok(expr); - } -} - -pub fn parse(tokens: Vec) -> Result> { - let mut parser = Parser { tokens, current: 0 }; - let mut program: Block = vec![]; - let mut errors: Vec = vec![]; - - while !parser.is_at_end() { - match parser.declaration() { - Err(err) => { - errors.push(err); - parser.synchronise(); - } - Ok(decl) => { - program.push(decl); - } - } - } - - if errors.is_empty() { - Ok(program) - } else { - Err(errors) - } -} diff --git a/users/tazjin/rlox/src/treewalk/resolver.rs b/users/tazjin/rlox/src/treewalk/resolver.rs deleted file mode 100644 index 3d12973aa..000000000 --- a/users/tazjin/rlox/src/treewalk/resolver.rs +++ /dev/null @@ -1,199 +0,0 @@ -// Resolves variable access to their specific instances in the -// environment chain. -// -// https://craftinginterpreters.com/resolving-and-binding.html - -use std::collections::HashMap; -use std::rc::Rc; - -use crate::treewalk::errors::{Error, ErrorKind}; -use crate::treewalk::parser::{self, Expr, Statement}; -use crate::treewalk::scanner::Token; - -#[derive(Default)] -struct Resolver<'a> { - scopes: Vec>, -} - -impl<'a> Resolver<'a> { - // AST traversal - fn resolve(&mut self, program: &'a mut parser::Block) -> Result<(), Error> { - self.begin_scope(); - for stmt in program { - self.resolve_stmt(stmt)?; - } - self.end_scope(); - - Ok(()) - } - - fn resolve_stmt(&mut self, stmt: &'a mut Statement) -> Result<(), Error> { - match stmt { - Statement::Expr(expr) => self.resolve_expr(expr), - Statement::Print(expr) => self.resolve_expr(expr), - Statement::Var(var) => self.resolve_var(var), - Statement::Return(ret) => self.resolve_expr(&mut ret.value), - Statement::Block(block) => self.resolve(block), - - Statement::If(if_stmt) => { - self.resolve_expr(&mut if_stmt.condition)?; - self.resolve_stmt(&mut if_stmt.then_branch)?; - - if let Some(branch) = if_stmt.else_branch.as_mut() { - self.resolve_stmt(branch)?; - } - - Ok(()) - } - - Statement::While(while_stmt) => { - self.resolve_expr(&mut while_stmt.condition)?; - self.resolve_stmt(&mut while_stmt.body) - } - - Statement::Function(func) => match Rc::get_mut(func) { - Some(func) => self.resolve_function(func), - // The resolver does not clone references, so unless - // the interpreter is called before the resolver this - // case should never happen. - None => { - return Err(Error { - line: 0, - kind: ErrorKind::InternalError( - "multiple function references before interpretation".into(), - ), - }) - } - }, - } - } - - fn resolve_var(&mut self, var: &'a mut parser::Var) -> Result<(), Error> { - self.declare(&var.name.lexeme); - - if let Some(init) = &mut var.initialiser { - self.resolve_expr(init)?; - } - - self.define(&var.name.lexeme); - - Ok(()) - } - - fn resolve_function(&mut self, func: &'a mut parser::Function) -> Result<(), Error> { - self.declare(&func.name.lexeme); - self.define(&func.name.lexeme); - - self.begin_scope(); - - for param in &func.params { - self.declare(¶m.lexeme); - self.define(¶m.lexeme); - } - - for stmt in &mut func.body { - self.resolve_stmt(stmt)?; - } - - self.end_scope(); - - Ok(()) - } - - fn resolve_expr(&mut self, expr: &'a mut Expr) -> Result<(), Error> { - match expr { - Expr::Variable(var) => self.resolve_variable(var), - Expr::Assign(assign) => self.resolve_assign(assign), - Expr::Grouping(grouping) => self.resolve_expr(&mut grouping.0), - Expr::Call(call) => self.resolve_call(call), - Expr::Literal(_) => Ok(()), - Expr::Unary(unary) => self.resolve_expr(&mut unary.right), - - Expr::Logical(log) => { - self.resolve_expr(&mut log.left)?; - self.resolve_expr(&mut log.right) - } - - Expr::Binary(binary) => { - self.resolve_expr(&mut binary.left)?; - self.resolve_expr(&mut binary.right) - } - } - } - - fn resolve_variable(&mut self, var: &'a mut parser::Variable) -> Result<(), Error> { - if let Some(scope) = self.scopes.last_mut() { - if let Some(false) = scope.get(var.name.lexeme.as_str()) { - return Err(Error { - line: var.name.line, - kind: ErrorKind::StaticError( - "can't read local variable in its own initialiser".into(), - ), - }); - } - } - - var.depth = self.resolve_local(&var.name); - Ok(()) - } - - fn resolve_assign(&mut self, assign: &'a mut parser::Assign) -> Result<(), Error> { - self.resolve_expr(&mut assign.value)?; - assign.depth = self.resolve_local(&assign.name); - Ok(()) - } - - fn resolve_local(&mut self, name: &'a Token) -> Option { - for (c, scope) in self.scopes.iter().rev().enumerate() { - if scope.contains_key(name.lexeme.as_str()) { - return Some(c); - } - } - - None - } - - fn resolve_call(&mut self, call: &'a mut parser::Call) -> Result<(), Error> { - self.resolve_expr(&mut call.callee)?; - - for arg in call.args.iter_mut() { - self.resolve_expr(arg)?; - } - - Ok(()) - } - - // Internal helpers - - fn declare(&mut self, name: &'a str) { - if let Some(scope) = self.scopes.last_mut() { - scope.insert(&name, false); - } - } - - fn define(&mut self, name: &'a str) { - if let Some(scope) = self.scopes.last_mut() { - scope.insert(&name, true); - } - } - - fn begin_scope(&mut self) { - self.scopes.push(Default::default()); - } - - fn end_scope(&mut self) { - self.scopes.pop(); - } -} - -pub fn resolve(globals: &[String], block: &mut parser::Block) -> Result<(), Error> { - let mut resolver: Resolver = Default::default(); - - // Scope for static globals only starts, never ends. - resolver.begin_scope(); - for global in globals { - resolver.define(global); - } - - resolver.resolve(block) -} diff --git a/users/tazjin/russian/helpers.el b/users/tazjin/russian/helpers.el deleted file mode 100644 index 41d4aa34f..000000000 --- a/users/tazjin/russian/helpers.el +++ /dev/null @@ -1,7 +0,0 @@ -;; Helper functions for creating the other files. - -(defun wiktionary-lookup-at-point (ask-lang) - (interactive "P") - (let ((language (if ask-lang (read-string "Language code? ") "ru"))) - (eww (concat "https://ru.wiktionary.org/wiki/" - (thing-at-point 'word))))) diff --git a/users/tazjin/russian/roots.el b/users/tazjin/russian/roots.el deleted file mode 100644 index 77d09b472..000000000 --- a/users/tazjin/russian/roots.el +++ /dev/null @@ -1,28 +0,0 @@ -;; '(root explanation) -;; -;; All roots without explanations are TODOs. -;; -;; In some cases, roots are not direct morphological roots of their -;; descendent words (e.g. -голов- => главный) - -'(("-весь-" "everything, all, every, etc.") - ("-вид-" "seeing, viewing etc.") - ("-врем-" "time") - ("-говор-" "related to talking") - ("-голов-" "head, main, etc.") - ("-друг-" nil) - ("-дум-" "thinking, thoughts") - ("-жи-" "life") - ("-зна-" "knowing, knowledge") - ("-имя-" "name") - ("-й-" "walking, moving to") - ("-мочь-" "ability, permission") - ("-нов-" "new") - ("-общ-" "common?") - ("-правд-" "truth") - ("-прос-" "question") - ("-сказ-" nil) - ("-смотр-" "watching, viewing") - ("-стран-" "country?") - ("-ход-" "movement") - ("-хорош-" "goodness, niceness")) diff --git a/users/tazjin/russian/russian.el b/users/tazjin/russian/russian.el deleted file mode 100644 index 28f1addea..000000000 --- a/users/tazjin/russian/russian.el +++ /dev/null @@ -1,97 +0,0 @@ -(require 'cl-macs) -(require 'ht) -(require 'seq) -(require 's) - -;; Type definitions for Russian structures - -(cl-defstruct russian-word - "Definition and metadata of a single Russian word." - (word nil :type string) - (translations :type list - :documentation "List of lists of strings, each a set of translations.") - - (notes nil :type list ;; of string - :documentation "free-form notes about this word") - - (roots nil :type list ;; of string - :documentation "list of strings that correspond with roots (exact string match)")) - -(defun russian--merge-words (previous new) - "Merge two Russian word definitions together. If no previous - definition exists, only the new one will be returned." - (if (not previous) new - (cl-assert (equal (russian-word-word previous) - (russian-word-word new)) - "different words passed into merge function") - (make-russian-word :word (russian-word-word previous) - :translations (-concat (russian-word-translations previous) - (russian-word-translations new)) - :notes (-concat (russian-word-notes previous) - (russian-word-notes new)) - :roots (-concat (russian-word-roots previous) - (russian-word-roots new))))) - -;; Definitions for creating a data structure of all Russian words. - -(defvar russian-words (make-hash-table) - "Table of all Russian words in the corpus.") - -(defun russian--define-word (word) - "Define a single word in the corpus, optionally merging it with - another entry." - (let ((key (russian-word-word word))) - (ht-set russian-words key (russian--merge-words - (ht-get russian-words key) - word)))) - -(defmacro define-russian-words (&rest words) - "Define the list of all available words. There may be more than - one entry for a word in some cases." - (declare (indent defun)) - - ;; Clear the table before proceeding with insertion - (setq russian-words (make-hash-table)) - - (seq-map - (lambda (word) - (russian--define-word (make-russian-word :word (car word) - :translations (cadr word) - :notes (caddr word) - :roots (cadddr word)))) - words) - - '(message "Defined %s unique words." (ht-size russian-words))) - -;; Helpers to train Russian words through passively. - -(defun russian--format-word (word) - "Format a Russian word suitable for echo display." - (apply #'s-concat - (-flatten - (list (russian-word-word word) - " - " - (s-join ", " (russian-word-translations word)) - (when-let ((roots (russian-word-roots word))) - (list " [" (s-join ", " roots) "]")) - (when-let ((notes (russian-word-notes word))) - (list " (" (s-join "; " notes) ")")))))) - -(defun display-russian-words () - "Convert Russian words to passively terms and start passively." - (interactive) - (setq passively-learn-terms (make-hash-table)) - (ht-map - (lambda (k v) - (ht-set passively-learn-terms k (russian--format-word v))) - russian-words) - (passively-enable)) - -(defun lookup-last-russian-word (in-eww) - "Look up the last Russian word in Wiktionary" - (interactive "P") - (let ((url (concat "https://ru.wiktionary.org/wiki/" passively-last-displayed))) - (if in-eww (eww url) - (browse-url url)))) - -(provide 'russian) diff --git a/users/tazjin/russian/words.el b/users/tazjin/russian/words.el deleted file mode 100644 index 784e5bddd..000000000 --- a/users/tazjin/russian/words.el +++ /dev/null @@ -1,723 +0,0 @@ -;; entries :: '(entry ...)' -;; entry :: '(word translations note roots) -;; note :: (or nil string) -;; translations :: '(translation ...) -;; roots :: '(root ...) - -(require 'russian) - -(define-russian-words - ;; 1-50 - ("и" ("and" "though")) - ("в" ("in" "at")) - ("не" ("not")) - ("он" ("he")) - ("на" ("on" "it" "at" "to")) - ("я" ("I")) - ("что" ("what" "that" "why")) - ("тот" ("that")) - ("быть" ("to be")) - ("с" ("with" "and" "from" "of")) - ("а" ("while" "and" "but")) - ("весь" ("all" "everything") nil ("-весь-")) - ("это" ("that" "this" "it")) - ("как" ("how" "what" "as" "like")) - ("она" ("she")) - ("по" ("on" "along" "by")) - ("но" ("but")) - ("они" ("they")) - ("к" ("to" "for" "by")) - ("у" ("by" "with" "of")) - ("ты" ("you")) - ("из" ("from" "of" "in")) - ("мы" ("we")) - ("за" ("behind" "over" "at" "after")) - ("вы" ("you")) - ("так" ("so" "thus" "then")) - ("же" ("and" "as for" "but" "same")) - ("от" ("from" "of" "for")) - ("сказать" ("to say" "to speak") nil ("-сказ-")) - ("этот" ("this")) - ("который" ("which" "who" "that")) - ("мочь" ("be able" "can") nil ("-мочь-")) - ("человек" ("man" "person")) - ("о" ("of" "about" "against")) - ("один" ("one" "some" "alone")) - ("ещё" ("still" "yet")) - ("бы" ("would")) - ("такой" ("such" "so" "some")) - ("только" ("only" "merely" "but")) - ("себя" ("myself" "himself" "herself")) - ("своё" ("one's own" "my" "our")) - ("какой" ("what" "which" "how")) - ("когда" ("when" "while" "as")) - ("уже" ("already" "by now")) - ("для" ("for" "to")) - ("вот" ("here" "there" "this is" "that's") - ("calling attention to something")) - ("кто" ("who" "that" "some")) - ("да" ("yes" "but") ("affirmation (..., right?)")) - ("говорить" ("to say" "to tell" "to speak") nil ("-говор-")) - ("год" ("year")) - - ;; 51 - 100 - ("знать" ("to know" "be aware") nil ("-зна-")) - ("мой" ("my" "mine")) - ("до" ("to" "up to" "about" "before")) - ("или" ("or")) - ("если" ("if")) - ("время" ("time" "season") nil ("-врем-")) - ("рука" ("hand" "arm")) - ("нет" ("no" "not" "but")) - ("самый" ("most" "the very" "the same")) - ("ни" ("not a" "not" "neither ... nor")) - ("стать" ("to become" "begin" "come")) - ("большой" ("big" "large" "important")) - ("даже" ("even")) - ("другой" ("other" "another" "different") nil ("-друг-")) - ("наш" ("our" "ours")) - ("свой" ("one's own")) - ("ну" ("now" "right" "well" "come on")) - ("под" ("under" "for" "towards" "to")) - ("где" ("where")) - ("дело" ("business" "affair" "matter")) - ("есть" ("to eat" "to be")) - ("сам" ("oneself")) - ("раз" ("time" "once" "since")) - ("чтобы" ("that" "in order that")) - ("два" ("two")) - ("там" ("there" "then")) - ("чем" ("than" "instead of") - ("чем ..., тем ...")) - ("глаз" ("eye" "sight")) - ("жизнь" ("life") nil ("-жи-")) - ("первый" ("first" "front" "former")) - ("день" ("day")) - ("тут" ("here" "now" "then")) - ("во" ("in" "at") - ("as particle also: wow, exactly, ...")) - ("ничто" ("nothing")) - ("потом" ("afterwards" "then")) - ("очень" ("very")) - ("со" ("with")) - ("хотеть" ("to want")) - ("ли" ("whether" "if")) - ("при" ("attached to" "in the presence of" "by" "about")) - ("голова" ("head" "mind" "brains") nil ("-голов-")) - ("надо" ("over" "above" "ought to")) - ("без" ("without")) - ("видеть" ("to see") nil ("-вид-")) - ("идти" ("to go" "to come")) - ("теперь" ("now" "nowadays")) - ("тоже" ("also" "as well" "too")) - ("стоять" ("to stand" "be" "stand up")) - ("друг" ("friend")) - ("дом" ("house" "home")) - - ;; 101-150 - ("сейчас" ("now" "presently" "soon")) - ("можно" ("possible" "permitted") nil ("-мочь-")) - ("после" ("after" "afterwards")) - ("слово" ("word")) - ("здесь" ("here")) - ("думать" ("to think" "to believe") nil ("-дум-")) - ("место" ("place" "seat")) - ("спросить" ("to ask") nil ("-прос-")) - ("через" ("through" "across")) - ("лицо" ("face" "person")) - ("что" ("what" "which" "that")) - ("тогда" ("then")) - ("хороший" ("good" "nice") nil ("-хорош-")) - ("каждый" ("every" "each")) - ("новый" ("new" "modern") nil ("-нов-")) - ("жить" ("to live") nil ("-жи-")) - ("должный" ("due" "proper" "should")) - ("смотреть" ("to look" "watch")) - ("почему" ("why")) - ("потому" ("that's why")) - ("сторона" ("side" "party")) - ("просто" ("simply")) - ("нога" ("foot" "leg")) - ("сидеть" ("to sit")) - ("понять" ("to understand" "to realise")) - ("иметь" ("to own" "to have")) - ("конечный" ("final" "last")) - ("делать" ("to do" "make")) - ("вдруг" ("suddenly")) - ("над" ("above" "over")) - ("взять" ("to take")) - ("никто" ("nobody")) - ("понимать" ("to understand")) - ("казаться" ("to seem" "to appear")) - ("работа" ("work" "job")) - ("три" ("three")) - ("ваш" ("yours")) - ("уж" ("really" "already")) - ("земля" ("earth" "land" "soil")) - ("конец" ("end" "distance")) - ("несколько" ("several" "some")) - ("час" ("hour" "time")) - ("голос" ("voice")) - ("город" ("town" "city")) - ("последний" ("last" "the latest" "new")) - - ;; 151-200 - ("пока" ("for the present")) ;; TODO(tazjin): review - ("хорошо" ("well") nil ("-хорош-")) - ("давать" ("to give" "to grant")) - ("вода" ("water")) - ("более" ("more")) - ("хотя" ("although")) - ("всегда" ("always")) - ("второй" ("second")) - ("куда" ("where" "what for" "much")) - ("пойти" ("to go") nil ("-й-")) - ("стол" ("table" "desk" "board")) - ("ребёнок" ("child" "kid" "infant")) - ("увидеть" ("to see")) - ("сила" ("strength" "force")) - ("отец" ("father")) - ("женщина" ("woman")) - ("машина" ("car" "machine" "engine")) - ("случай" ("case" "occasion" "incident")) - ("ночь" ("night")) - ("сразу" ("at once" "right away" "just")) - ("мир" ("world" "peace")) - ("совсем" ("quite" "entirely" "totally")) - ("остаться" ("to remain" "to stay")) - ("об" ("about" "of")) - ("вид" ("appearance" "look" "view")) - ("выйти" ("to go out" "to exit" "to come out" "to appear") nil ("-й-")) - ("дать" ("to give")) - ("работать" ("to work")) - ("любить" ("to work")) - ("старый" ("old")) - ("почти" ("almost")) - ("ряд" ("row" "line")) - ("оказаться" ("find oneself" "turn out")) - ("начало" ("beginning" "origin" "source")) - ("твой" ("your" "yours")) - ("вопрос" ("question" "matter" "problem") nil ("-прос-")) - ("много" ("many" "much")) - ("война" ("war")) - ("снова" ("again")) - ("ответить" ("to answer" "to reply")) - ("между" ("between" "among")) - ("подумать" ("to think")) - ("опять" ("again")) - ("белый" ("white")) - ("деньги" ("money")) - ("значить" ("to mean" "to signify") nil ("-зна-")) - ("про" ("about" "for")) - ("лишь" ("only" "as soon as")) - ("минута" ("minute" "moment")) - ("жена" ("wife")) - - ;; 201-300 - ("посмотреть" ("to watch" "to look" "to inspect") nil ("-смотр-")) - ("правда" ("truth") nil ("-правд-")) - ("главный" ("main" "chief") nil ("-голов-")) - ("страна" ("country") nil ("-стран-")) - ("свет" ("light" "world")) - ("ждать" ("to wait")) - ("мать" ("mother")) - ("будто" ("as if" "as though")) - ("никогда" ("never")) - ("товариш" ("comrade" "friend")) - ("дорога" ("road" "way" "journey")) - ("однако" ("however" "although")) - ("лежать" ("to lie" "to be situated")) - ("именно" ("namely" "just" "exactly") nil ("-имя-")) - ("окно" ("window")) - ("никакой" ("no" "none")) - ("найти" ("to find" "to discover") nil ("-й-")) - ("писать" ("to write")) - ("комната" ("room")) - ("Москва" ("Moscow")) - ("часть" ("part" "share" "department")) - ("вообще" ("in general" "altogether" "on the whole") nil ("-общ-")) - ("книга" ("book")) - ("маленький" ("small" "little")) - ("улица" ("street")) - ("режить" ("to decide" "to solve")) - ("далекий" ("distant" "remote")) - ("душа" ("soul" "spirit")) - ("чуть" ("hardly" "slightly")) - ("вернуться" ("to return")) - ("утро" ("morning")) - ("некоторый" ("some")) - ("считать" ("to count" "to consider")) - ("сколько" ("how much" "how many")) - ("помнить" ("to remember")) - ("вечер" ("evening")) - ("пол" ("floor" "gender")) - ("таки" ("after all")) - ("получить" ("to receive" "to get" "to obtain")) - ("народ" ("people" "nation")) - ("плечо" ("shoulder" "upper arm")) - ("хоть" ("even" "if you want" "though")) - ("сегодня" ("today")) - ("бог" ("god")) - ("вместе" ("together")) - ("взгляд" ("look" "glance" "view")) - ("ходить" ("to go" "to walk") nil ("-ход-")) - ("зачем" ("what for" "why")) - ("советский" ("Soviet")) - ("русский" ("Russian")) - ("бывать" ("to be" "to visit" "to happen")) - ("полный" ("full" "complete" "whole")) - ("прийти" ("to arrive" "to come") nil ("-й-")) - ("палец" ("finger" "toe")) - ("Россия" ("Russia")) - ("любой" ("any" "every")) - ("история" ("history" "story" "event")) - ("наконец" ("finally" "at least")) - ("мысль" ("thought" "idea")) - ("узнать" ("to know" "to learn" "to recognise") nil ("-зна-")) - ("назад" ("back" "backwards" "ago")) - ("общий" ("general" "common") nil ("-общ-")) - ("заметить" ("to notice" "to observe")) - ("словно" ("as if" "like")) - ("прошлый" ("past" "vergangen") nil ("-й-")) - ("уйти" ("to leave" "to go away") nil ("-й-")) - ("известный" ("well-known" "famous")) - ("давно" ("long ago")) - ("слышать" ("to hear")) - ("слушать" ("to listen" "to hear")) - ("бояться" ("to be afraid" "fear")) - ("сын" ("son")) - ("нельзя" ("it is impossible" "can't")) - ("прямо" ("straight" "frankly")) - ("долго" ("for a long time")) - ("быстро" ("fast" "quickly")) - ("лес" ("forest")) - ("похожий" ("similar" "alike") nil ("-ход-")) - ("пора" ("time" "pore")) - ("пять" ("five")) - ("глядеть" ("to look" "to gaze")) - ("оно" ("it")) - ("сесть" ("to sit")) - ("имя" ("name") nil ("-имя-")) - ("ж" ("and" "as for" "but")) - ("разговор" ("conversation" "talk") nil ("-говор-")) - ("тело" ("body")) - ("молодой" ("young")) - ("стена" ("wall")) - ("красный" ("red")) - ("читать" ("to read")) - ("право" ("right")) - ("старик" ("old man")) - ("ранний" ("early")) - ("хотеться" ("to want" "to like")) - ("мама" ("mummy" "mum")) - ("оставаться" ("to remain" "to stay")) - ("высокий" ("tall" "high")) - ("путь" ("way" "track" "path")) - ("поэтому" ("therefore")) - - ;; 301-400 - ("совершенно" ("absolutely" "quite")) - ("кроме" ("except" "besides")) - ("тысяча" ("a thousand")) - ("месяц" ("month")) - ("брать" ("to take" "to hire")) - ("написать" ("to write")) - ("целый" ("intact" "whole" "entire")) - ("огромный" ("huge" "enormous")) - ("начинать" ("to begin")) - ("спина" ("back")) - ("настоящий" ("present" "real" "true")) - ("пусть" ("let's" "though")) - ("язык" ("tongue" "language")) - ("точно" ("exactly")) - ("среди" ("among")) - ("чуствовать" ("to feel")) - ("сердце" ("heart")) - ("вести" ("to lead")) - ("иногда" ("sometimes")) - ("мальчик" ("boy")) - ("успеть" ("to be in time" "to be successful")) - ("небо" ("sky")) - ("живой" ("living" "lively" "alive")) - ("смерть" ("death")) - ("продолжать" ("to continue")) - ("девушка" ("girl")) - ("образ" ("shape" "form" "image")) - ("ко" ("to" "towards" "by")) - ("забыть" ("to forget")) - ("вокруг" ("around")) - ("письмо" ("letter")) - ("власть" ("power")) - ("чёрный" ("black")) - ("пройти" ("to pass" "go by" "be over") nil ("-й-")) - ("появиться" ("to appear" "to show up")) - ("воздух" ("air")) - ("разный" ("different")) - ("выходить" ("to go out" "to exit") ("MR says 'to nurse'??") ("-ход-")) - ("просить" ("to ask")) - ("брат" ("brat")) - ("собственный" ("one's own")) - ("отношение" ("relationship" "attitude")) - ("затем" ("then" "after that")) - ("пытаться" ("to try")) - ("показать" ("to show" "to display")) - ("вспомнить" ("to remember" "to recall")) - ("система" ("system")) - ("четыре" ("four")) - ("квартира" ("flat" "apartment")) - ("держать" ("to hold" "to keep")) - ("также" ("also" "as well" "too")) - ("любовь" ("love")) - ("солдат" ("soldier")) - ("откуда" ("from where")) - ("чтоб" ("that" "in order that")) - ("называть" ("to call" "to name")) - ("третий" ("third")) - ("хозяин" ("master" "boss" "host")) - ("вроде" ("like" "not unlike")) - ("уходить" ("to leave" "to go away") nil ("-ход-")) - ("подойти" ("to approach" "to come up") nil ("-й-")) - ("поднять" ("to lift" "to raise")) - ("спрашивать" ("to ask" "to inquire")) - ("начальник" ("chief" "head" "superior")) - ("оба" ("both")) - ("бросить" ("to throw")) - ("школа" ("school")) - ("парень" ("boy" "fellow" "guy")) - ("кровь" ("blood")) - ("двадцать" ("twenty")) - ("солнце" ("sun")) - ("неделя" ("week")) - ("послать" ("to send" "to dispatch")) - ("находиться" ("to be found" "to turn up") nil ("-ход-")) - ("ребята" ("guys" "children")) - ("поставить" ("to put" "to place" "to set")) - ("встать" ("to get up" "to rise" "to stand up")) - ("например" ("for example" "for instance")) - ("шаг" ("step")) - ("мужчина" ("man" "male")) - ("равно" ("alike" "in like manner")) - ("нос" ("nose")) - ("мало" ("little" "few")) - ("внимание" ("attention")) - ("капитан" ("captain" "master")) - ("ухо" ("ear")) - ("туда" ("to there")) - ("сюда" ("to here")) - ("играть" ("to play")) - ("следовать" ("to follow" "to come next")) - ("рассказать" ("to tell" "to narrate")) - ("великий" ("great")) - ("действительно" ("indeed" "really")) - ("слишком" ("too much")) - ("тяжёлый" ("heavy")) - ("спать" ("to sleep")) - ("оставить" ("to leave" "to abandon")) - ("войти" ("to enter" "to come in") nil ("-й-")) - ("длинный" ("long")) - - ;; 401 - 500 - ("чувство" ("feeling")) - ("иолчать" ("to keep silence" "make no complaint" "say nothing")) - ("рассказывать" ("to tell" "narrate")) - ("отвечать" ("to answer" "to reply")) - ("становиться" ("to stand" "to become")) - ("остановиться" ("to stop")) - ("берег" ("bank" "shore" "coast")) - ("семья" ("family")) - ("искать" ("to search")) - ("генерал" ("general")) - ("момент" ("moment" "instant")) - ("десять" ("ten")) - ("начать" ("to begin")) - ("следуюший" ("next" "following")) - ("личный" ("personal")) - ("труд" ("labour" "work")) - ("верить" ("to believe")) - ("группа" ("group")) - ("немного" ("a little")) - ("впрочем" ("however" "though")) - ("видно" ("evidently" "obviously")) - ("являться" ("to appear")) - ("муж" ("husband")) - ("разве" ("really?" "perhaps") ("when pondering something")) - ("движение" ("movement" "motion")) - ("порядок" ("order")) - ("ответ" ("answer" "reply")) - ("тихо" ("quietly" "silently") ("also as exclamation")) - ("знакомый" ("familiar" "acquainted")) - ("газета" ("newspaper")) - ("помощь" ("help")) - ("сильный" ("strong" "powerful")) - ("скорый" ("quick" "fast")) - ("собака" ("dog")) - ("дерево" ("tree")) - ("снег" ("snow")) - ("сон" ("dream")) - ("смысл" ("sense" "meaning" "purpose") ("making sense" "in the sense")) - ("смочь" ("to be able") ("св")) - ("против" ("against" "opposite" "contrary to")) - ("бежать" ("to run" "to hurry")) - ("двор" ("yard" "court")) - ("форма" ("form" "shape" "uniform")) - ("простой" ("simple" "easy" "plain")) - ("приехать" ("to arrive" "to come")) - ("иной" ("different" "other")) - ("кричать" ("to cry" "to shout")) - ("возможность" ("possibility" "opportunity" "chance")) - ("общество" ("society")) - ("зелёный" ("green")) - ("грудь" ("breast" "chest")) - ("угол" ("corner" "angle")) - ("открыть" ("to open")) - ("происходить" ("to happen" "to occur" "to take place")) - ("ладно" ("well" "all right" "okay")) - ("чёрный" ("black") ("noun (m.): as in 'she wears black'")) - ("век" ("century" "age")) - ("карман" ("pocket")) - ("ехать" ("to go" "ride" "drive" "travel")) - ("немец" ("German")) - ("наверное" ("probably" "most likely")) - ("губа" ("lip")) - ("дядя" ("uncle")) - ("приходить" ("to come" "to arrive")) - ("часто" ("often")) - ("домой" ("home") ("as in direction")) - ("огонь" ("fire")) - ("писатель" ("writer")) - ("армия" ("army")) - ("состояние" ("state" "condition" "fortune")) - ("зуб" ("tooth")) - ("очередь" ("queue" "line" "turn")) - ("кой" ("which") ("old-fashioned, literary (in set expressions)")) - ("подняться" ("to rise" "to climb")) - ("камень" ("stone")) - ("гость" ("guest")) - ("показаться" ("to appear" "to come in sight")) - ("ветер" ("window")) - ("собираться" ("to gather" "to assemble" "to intend") ("TODO: intend??")) - ("попасть" ("to hit" "to find oneself") ("to get (in phrases)")) - ("принять" ("to take" "to admit" "to accept")) - ("сначала" ("at first" "from the beginning")) - ("либо" ("or")) - ("поехать" ("to depart" "to set off")) - ("услышать" ("to hear")) - ("уметь" ("to be able" "know" "can")) - ("случиться" ("to happen")) - ("странный" ("strange")) - ("единственный" ("only" "sole")) - ("рота" ("company") ("(military)")) - ("закон" ("law" "act" "statute")) - ("короткий" ("short")) - ("море" ("sea")) - ("добрый" ("kind")) - ("тёмный" ("dark")) - ("гора" ("mountain" "hill")) - ("врач" ("doctor")) - ("край" ("border, edge" "land, country")) - ("стараться" ("to try" "to endeavour")) - ("лучший" ("better" "best")) - - ;; 501 - 600 - ("река" ("river")) - ("военный" ("military")) - ("мера" ("measure" "step")) - ("страшный" ("terrible" "frightful")) - ("вполне" ("quite" "fully")) - ("звать" ("to call")) - ("произойти" ("to happen" "to occur" "take place")) - ("вперед" ("forward")) - ("медленно" ("slowly")) - ("возле" ("by" "near" "close by")) - ("никак" ("in no way" "by no means")) - ("заниматься" ("to be occupied" "to engage")) - ("действие" ("action" "effort")) - ("довольно" ("enough" "rather")) - ("вещь" ("thing")) - ("необходимый" ("necessary") ("not possible to go around")) - ("ход" ("move")) - ("боль" ("pain")) - ("судьба" ("fate" "fortune" "destiny")) - ("причина" ("cause" "reason" "motive")) - ("положить" ("to lay down" "put down" "place")) - ("едва" ("hardly" "just" "barely")) - ("черта" ("line" "boundary" "trait")) - ("девочка" ("girl" "little girl")) - ("лёгкий" ("light" "easy")) - ("волос" ("hair")) - ("купить" ("to buy" "purchase")) - ("номер" ("number" "size" "room" "issue")) - ("основной" ("main")) - ("широкий" ("wide")) - ("умереть" ("to die")) - ("далеко" ("far" "far off")) - ("плохо" ("badly")) - ("глава" ("head" "chief")) - ("красивый" ("beautiful")) - ("серый" ("grey" "dull")) - ("пить" ("to drink")) - ("командир" ("commander" "officer")) - ("обычно" ("usually")) - ("партия" ("party")) - ("проблема" ("problem" "issue")) - ("страх" ("fear")) - ("проходить" ("to pass" "go" "study")) - ("ясно" ("clear" "clearly")) - ("снять" ("to take away" "take off")) - ("бумага" ("paper")) - ("герой" ("hero")) - ("пара" ("pair" "couple")) - ("государство" ("State")) - ("деревня" ("village")) - ("речь" ("speech")) - ("начаться" ("to begin")) - ("средство" ("means" "remedy")) - ("положение" ("position" "posture" "condition" "state")) - ("связь" ("tie, bond" "connection, relation")) - ("небольшой" ("small" "not great")) - ("представлять" ("to present" "introduce" "imagine")) - ("завтра" ("tomorrow")) - ("объяснить" ("to explain")) - ("пустой" ("empty" "hollow" "idle")) - ("произнести" ("to pronounce" "say" "utter")) - ("человеческий" ("human")) - ("нравиться" ("to please" "be likeable to")) - ("однажды" ("once" "one day")) - ("мимо" ("past" "by")) - ("иначе" ("otherwise" "differently|")) - ("существровать" ("to exist" "to be")) - ("класс" ("class")) - ("удаться" ("turn out well" "succeed" "manage")) - ("толстый" ("thick" "heavy" "fat")) - ("цель" ("goal" "object" "target")) - ("сквозь" ("through")) - ("прийтись" ("to fit" "fall" "have to") ("тебе придётся - you have to")) - ("чистый" ("clean" "pure")) - ("знать" ("to know")) - ("прежний" ("former")) - ("профессор" ("professor")) - ("господин" ("gentleman" "Mr.")) - ("счастье" ("happiness" "luck")) - ("худой" ("thin" "skinny")) - ("дух" ("spirit")) - ("план" ("plan")) - ("чужой" ("somebody else's" "strange" "foreign")) - ("зал" ("hall")) - ("представить" ("to present" "produce" "introduce")) - ("особый" ("special")) - ("директор" ("director" "manager")) - ("бывший" ("former" "ex-")) - ("память" ("memory")) - ("близкий" ("near" "similar" "intimate")) - ("сей" ("this")) - ("результат" ("result" "outcome")) - ("больной" ("sick")) - ("данный" ("given" "present")) - ("кстати" ("to the point" "at the same time")) - ("назвать" ("to call" "name")) - ("след" ("track" "footprint")) - ("улыбаться" ("to smile") ("нсв")) - ("бутылка" ("bottle")) - - ;; 601 - 700 - ("трудно" ("with difficulty")) - ("условие" ("condition" "term")) - ("прежде" ("before")) - ("ум" ("mind" "brains" "intellect")) - ("улыбнуться" ("to smile")) - ("процесс" ("process")) - ("картина" ("picture" "painting")) - ("вместо" ("instead")) - ("старший" ("elder" "senior")) - ("легко" ("easily" "lightly")) - ("центр" ("center")) - ("подобный" ("similar" "like")) - ("возможно" ("possible") ("as ... as possible")) - ("около" ("by" "near")) - ("смеяться" ("to laugh")) - ("сто" ("hundred")) - ("будущее" ("future")) - ("хватать" ("to snatch" "to seize" "to suffice") ("нсв")) - ("число" ("number")) - ("всякое" ("any" "every")) - ("рубль" ("ruble")) - ("почувствовать" ("to feel") ("св")) - ("принести" ("to bring")) - ("вера" ("faith" "belief")) - ("вовсе" ("quiet" "not ... at all")) - ("удар" ("blow" "stroke")) - ("телефон" ("telephone")) - ("колено" ("knee")) - ("согласиться" ("to agree" "to consent")) - ("мало" ("little" "few" "not enough")) - ("коридор" ("corridor" "passage")) - ("мужик" ("man")) - ("правый" ("right")) - ("автор" ("author")) - ("холодный" ("cold" "cool")) - ("хватит" ("to snatch" "to seize" "to suffice") ("св")) - ("многие" ("many")) - ("встреча" ("meeting" "reception")) - ("кабинет" ("study" "room" "office suite")) - ("документ" ("document")) - ("самолёт" ("airplane")) - ("вниз" ("down" "downwards")) - ("принимать" ("to take" "to admit" "to accept")) - ("игра" ("game" "play")) - ("рассказ" ("story")) - ("хлеб" ("bread")) - ("развитие" ("development")) - ("убить" ("to kill")) - ("родной" ("own" "native" "dear")) - ("открытый" ("open")) - ("менее" ("less")) - ("предложить" ("to offer" "to propose" "to suggest")) - ("жёлтый" ("yellow")) - ("приходиться" ("to fit" "to fall" "to have to")) - ("выпить" ("to drink")) - ("крикнуть" ("to cry" "to shout")) - ("трубка" ("tube" "roll" "pipe")) - ("враг" ("enemy")) - ("показывать" ("to show" "to display")) - ("двое" ("two") ("cardinal number")) - ("доктор" ("doctor")) - ("ладонь" ("palm")) - ("вызвать" ("to call" "to send")) - ("спокойно" ("quietly")) - ("попросить" ("to ask")) - ("наука" ("science")) - ("лейтенант" ("lieutenant")) - ("служба" ("service" "work")) - ("оказываться" ("to turn out" "to find oneself")) - ("привести" ("to bring")) - ("сорок" ("forty")) - ("счёт" ("bill" "account")) - ("возвращаться" ("to return")) - ("золотой" ("golden")) - ("местный" ("local")) - ("кухня" ("kitchen")) - ("крупный" ("large" "big" "prominent")) - ("решение" ("decision" "conclusion")) - ("молодая" ("bride" "young")) - ("тридцать" ("thirty")) - ("роман" ("novel" "romance")) - ("компания" ("company")) - ("частый" ("frequent")) - ("российский" ("Russian")) - ("рабочий" ("worky")) - ("потерять" ("to lose")) - ("течение" ("current")) - ("синий" ("dark blue")) - ("столько" ("so much" "so many")) - ("тёплый" ("warm")) - ("метр" ("metre")) - ("достать" ("to reach" "get" "obtain")) - ("железный" ("ferreous" "iron")) - ("институт" ("institute")) - ("сообщить" ("to report" "to let know")) - ("интерес" ("interest")) - ("обычный" ("usual" "ordinary")) - ("появляться" ("to appear" "to show up")) - ("упасть" ("to fall"))) - -(provide 'russian-words) diff --git a/users/tazjin/rustfmt.toml b/users/tazjin/rustfmt.toml deleted file mode 100644 index 0c719dcfe..000000000 --- a/users/tazjin/rustfmt.toml +++ /dev/null @@ -1,22 +0,0 @@ -edition = "2021" -newline_style = "Unix" - -# Default code with is 100 characters, comments should follow -# suit. -wrap_comments = true - -# The default of this option creates hard-to-read nesting of -# conditionals, turn it off. -combine_control_expr = false - -# Group imports by module, but no higher. This avoids hard-to-read -# nested use statements. -imports_granularity = "Module" - -# Avoid vertical visual clutter by unnecessarily exploding -# block-like arguments. -overflow_delimited_expr = true - -# Miscellaneous -format_code_in_doc_comments = true -normalize_comments = true diff --git a/users/tazjin/secrets/default.nix b/users/tazjin/secrets/default.nix deleted file mode 100644 index 5550103c5..000000000 --- a/users/tazjin/secrets/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ depot, ... }: - -depot.ops.secrets.mkSecrets ./. (import ./secrets.nix) diff --git a/users/tazjin/secrets/geesefs-tazjins-files.age b/users/tazjin/secrets/geesefs-tazjins-files.age deleted file mode 100644 index 9132c7d10..000000000 --- a/users/tazjin/secrets/geesefs-tazjins-files.age +++ /dev/null @@ -1,18 +0,0 @@ -age-encryption.org/v1 --> ssh-ed25519 dcsaLw SrmIul/C/aRTYy5+vVBB0H2bS65XayYf2TXrOSTEbGg -Js016EtAxiFmyJ4gTmXEjsKT9JmIntcMNgAds+qT7Js --> ssh-ed25519 zcCuhA NfUQBKL1KgvUosB2y3oI5HwPjA+4kf8kbBbpNf43JAk -oE4R2rz1sdBitKzQlzMzneyu8Rvc5utHYRyCeGCQR8g --> ssh-rsa zXi7VA -aDDiygAF5benqqJ1387F9qVDyvb48BkBLAwRi7eUYWkG41s9XUdmK5ppjFdxy1c8 -fx5YcPjO3m84pIv0RxiK7rZhkVi1/eiHhT5lId83wIzQdybjKFSc85YjFO3mGv9A -EeFMEmlfsRkBHYq/j6Npbg4M5kMxSuSwGSyt6qnoHSWT2phS+41WLA/XT9ln4pRR -dBDO0ZyK/CpgfDuGo/JARLiGeEMwt7SvkyXidcbD8glg9buu1VGxb/8m/ob1yrbn -y3mjfOFzO2zF8ZHuScWQlZgvaVk412Xne+n+wva12tS52dEX4FRSMtmUOB8Ai4oq -wvWB6Ikru5jXRxe8NgDoZw --> ssh-ed25519 At5Mag yBwWJVhArq9iwngwaIph56iGfje8T55Ig0nW9268Kic -T9IWxRJF1U0STinVlBJoaGoegERnWRjnGZeW0HHGQ9Y --> C"!?nfs%-grease >>.%|I mA Fd7?aw2m 37I -vRH3yR7+Ow ---- AKc40DwXghKw6GHzJUYNJYE0JqMr4M+hR41VRA1IvS4 -tڜ)u;T '8=S7R ssh-ed25519 dcsaLw SJBK+ym6o6dcB/+HFWzArbXS9RmyDjnglVxcXduJA1g -pPWIi2A4G4X7I14HoZUWsNd/MOfhW1ZanwB/5OROSrw --> ssh-ed25519 zcCuhA oo/8OTqpV85g/9pha0qkmxwlYAlsc7v+nXbbtj67Jmc -AexsAIgW6e5fYoPNJJZYdP61OvON2bKiL9ZJgLdG/zU --> ssh-ed25519 ph9lig 4evTl0M3SfdlmTixm3WnVqfHMPf/TYIyBKPdlfPisC0 -AK4GyhgqXN2wxbcFRGwbNNQJ4/2iFPt3CKGHosNJbmY --> ssh-ed25519 At5Mag JJ8r/qD5i+LLAY7jnnHXAgykAuHtzxtGGzdqw7BAogY -wotjW3yaTq1IdqVUwoCVwzglXsmnzniQIt7SDBrF4jY --> sPHo{W-grease , h6 =mEp^w `ccnF -QQEb+Vh1+Fv++oPQwdTfOB2Cg5JaP4GCOq0o3J+xSqCY1gE0cguwLGXwa6+Tylu2 -Kuh4pMovAxnlHUt44u6f ---- yWQyncCrxJzVHffFaFT704BEp8hjUn09a+23r4S39N4 -}ң l I&m_ {X̮?f1Mɧ|JVL<H5 NQQV#>s2M0I \ No newline at end of file diff --git a/users/tazjin/secrets/secrets.nix b/users/tazjin/secrets/secrets.nix deleted file mode 100644 index a29bd30b7..000000000 --- a/users/tazjin/secrets/secrets.nix +++ /dev/null @@ -1,17 +0,0 @@ -let - myKeys = import ../keys { }; - allKeys = [ - # local keys - myKeys.tverskoy_ed25519 - myKeys.zamalek_ed25519 - myKeys.khamovnik_agenix - # koptevo - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMw2ZfdNZCXCOtbQNT6hztXCIkTcO9MBrOuDqMlmGOYK root@koptevo" - ]; -in -{ - "geesefs-tazjins-files.age".publicKeys = allKeys; - "miniflux.age".publicKeys = allKeys; - "tgsa-yandex.age".publicKeys = allKeys; - "lego-yandex.age".publicKeys = allKeys; -} diff --git a/users/tazjin/secrets/tgsa-yandex.age b/users/tazjin/secrets/tgsa-yandex.age deleted file mode 100644 index b1400d067..000000000 Binary files a/users/tazjin/secrets/tgsa-yandex.age and /dev/null differ diff --git a/users/tazjin/tgsa/.gitignore b/users/tazjin/tgsa/.gitignore deleted file mode 100644 index 29e65519b..000000000 --- a/users/tazjin/tgsa/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -result -/target -**/*.rs.bk diff --git a/users/tazjin/tgsa/Cargo.lock b/users/tazjin/tgsa/Cargo.lock deleted file mode 100644 index 6be9c490d..000000000 --- a/users/tazjin/tgsa/Cargo.lock +++ /dev/null @@ -1,1567 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" - -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] -name = "autocfg" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - -[[package]] -name = "bumpalo" -version = "3.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cc" -version = "1.0.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "windows-targets 0.52.4", -] - -[[package]] -name = "chunked_transfer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "crimp" -version = "4087.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ead2c83f7d1f9b8e5a6f7a25985d0d1759ccd2cd72abb1eee2db65d05e12b39" -dependencies = [ - "curl", - "serde", - "serde_json", -] - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.57", -] - -[[package]] -name = "curl" -version = "0.4.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "windows-sys", -] - -[[package]] -name = "curl-sys" -version = "0.4.72+curl-8.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", -] - -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dtoa-short" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" -dependencies = [ - "dtoa", -] - -[[package]] -name = "ego-tree" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "fastrand" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" - -[[package]] -name = "filetime" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "windows-sys", -] - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "idna" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.153" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - -[[package]] -name = "libz-sys" -version = "1.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "multipart" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" -dependencies = [ - "buf_redux", - "httparse", - "log", - "mime", - "mime_guess", - "quick-error", - "rand 0.8.5", - "safemem", - "tempfile", - "twoway", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.57", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.12", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rouille" -version = "3.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3716fbf57fc1084d7a706adf4e445298d123e4a44294c4e8213caf1b85fcc921" -dependencies = [ - "base64 0.13.1", - "chrono", - "filetime", - "multipart", - "percent-encoding", - "rand 0.8.5", - "serde", - "serde_derive", - "serde_json", - "sha1_smol", - "threadpool", - "time", - "tiny_http", - "url", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "ryu" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scraper" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5684396b456f3eb69ceeb34d1b5cb1a2f6acf7ca4452131efa3ba0ee2c2d0a70" -dependencies = [ - "cssparser", - "ego-tree", - "getopts", - "html5ever", - "matches", - "selectors", - "smallvec", - "tendril", -] - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "semver" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" - -[[package]] -name = "serde" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.197" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.57", -] - -[[package]] -name = "serde_json" -version = "1.0.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" -dependencies = [ - "itoa 1.0.11", - "ryu", - "serde", -] - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "tgsa" -version = "0.1.0" -dependencies = [ - "anyhow", - "base64 0.21.7", - "crimp", - "ego-tree", - "lazy_static", - "openssl", - "ring", - "rouille", - "scraper", - "serde", - "serde_json", - "url", -] - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "time" -version = "0.3.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" -dependencies = [ - "deranged", - "libc", - "num-conv", - "num_threads", - "powerfmt", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "tiny_http" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389915df6413a2e74fb181895f933386023c71110878cd0825588928e64cdc82" -dependencies = [ - "ascii", - "chunked_transfer", - "httpdate", - "log", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "url" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.57", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.57", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.4", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.4", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" -dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" diff --git a/users/tazjin/tgsa/Cargo.toml b/users/tazjin/tgsa/Cargo.toml deleted file mode 100644 index 8764ef652..000000000 --- a/users/tazjin/tgsa/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "tgsa" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow = "1.0" -crimp = "4087.0" -rouille = { version = "3.5", default-features = false } -url = "2.3" -scraper = "0.13" -ego-tree = "0.6" # in tandem with 'scraper' -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -ring = "0.16.20" -openssl = "0.10.54" -base64 = "0.21.2" -lazy_static = "1.4.0" diff --git a/users/tazjin/tgsa/default.nix b/users/tazjin/tgsa/default.nix deleted file mode 100644 index 063781047..000000000 --- a/users/tazjin/tgsa/default.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ depot, pkgs, ... }: - -depot.third_party.naersk.buildPackage { - src = depot.nix.sparseTree { - root = ./.; - paths = [ - ./Cargo.lock - ./Cargo.toml - ./src - ]; - }; - - buildInputs = with pkgs; [ - pkg-config - openssl - ]; -} diff --git a/users/tazjin/tgsa/src/main.rs b/users/tazjin/tgsa/src/main.rs deleted file mode 100644 index d9a5d4abc..000000000 --- a/users/tazjin/tgsa/src/main.rs +++ /dev/null @@ -1,403 +0,0 @@ -use anyhow::{anyhow, Context, Result}; -use scraper::{Html, Selector}; -use std::collections::HashMap; -use std::sync::RwLock; -use std::time::{Duration, Instant}; - -mod translate; - -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -struct TgLink { - username: String, - message_id: usize, - translated: bool, -} - -impl TgLink { - fn human_friendly_url(&self) -> String { - format!("t.me/{}/{}", self.username, self.message_id) - } - - fn to_url(&self, embed: bool) -> String { - format!( - "https://t.me/{}/{}{}", - self.username, - self.message_id, - if embed { "?embed=1" } else { "" } - ) - } - - fn parse(url: &str, translated: bool) -> Option { - let url = url.strip_prefix('/')?; - let parsed = url::Url::parse(url).ok()?; - - if parsed.host()? != url::Host::Domain("t.me") { - // only t.me links are supported - return None; - } - - let parts = parsed.path_segments()?.collect::>(); - if parts.len() != 2 { - // only message links are supported - return None; - } - - Some(TgLink { - username: parts[0].into(), - message_id: parts[1].parse().ok()?, - translated, - }) - } -} - -fn fetch_post(link: &TgLink, embed: bool) -> Result { - println!("fetching {}#{}", link.username, link.message_id); - let response = crimp::Request::get(&link.to_url(embed)) - .send() - .context("failed to fetch embed data")? - .as_string() - .context("failed to decode embed data")? - .error_for_status(|resp| { - anyhow!("telegram request failed: {} ({})", resp.body, resp.status) - })?; - - Ok(response.body) -} - -// in some cases, posts can not be embedded, but telegram still -// includes their content in metadata tags for content previews. -// -// we skip images in this case, as they are scaled down to thumbnail -// size and not useful. -fn fetch_fallback(link: &TgLink) -> Result> { - let post = fetch_post(link, false)?; - let doc = Html::parse_document(&post); - let desc_sel = Selector::parse("meta[property=\"og:description\"]").unwrap(); - let desc_elem = match doc.select(&desc_sel).next() { - None => return Ok(None), - Some(elem) => elem, - }; - - let content = match desc_elem.value().attr("content") { - None => return Ok(None), - Some(content) => content.to_string(), - }; - - Ok(Some(content)) -} - -#[derive(Debug)] -struct TgMessage { - author: String, - message: Option, - photos: Vec, - videos: Vec, - has_audio: bool, -} - -fn extract_photo_url(style: &str) -> Option<&str> { - let url_start = style.find("url('")? + 5; - let url_end = style.find("')")?; - - Some(&style[url_start..url_end]) -} - -fn parse_tgmessage(embed: &str) -> Result { - let doc = Html::parse_document(embed); - - let author_sel = Selector::parse("a.tgme_widget_message_owner_name").unwrap(); - let author = doc - .select(&author_sel) - .next() - .ok_or_else(|| anyhow!("failed to find message author"))? - .text() - .collect::>() - .concat(); - - let msg_sel = Selector::parse("div.tgme_widget_message_text.js-message_text").unwrap(); - - // The ElementRef::text() iterator does not yield newlines present - // in the message, so it is partially reimplemented here. - let message = if let Some(msg_elem) = doc.select(&msg_sel).next() { - use ego_tree::iter::Edge; - use scraper::node::Node; - - let mut out = String::new(); - - for edge in &mut msg_elem.traverse() { - if let Edge::Open(node) = edge { - match node.value() { - Node::Text(ref text) => out.push_str(text), - Node::Element(elem) if elem.name() == "br" => out.push('\n'), - _ => {} - } - } - } - - Some(out) - } else { - // Not all Telegram messages have a textual message. - None - }; - - let photo_sel = Selector::parse("a.tgme_widget_message_photo_wrap").unwrap(); - let mut photos = vec![]; - - for photo in doc.select(&photo_sel) { - if let Some(style) = photo.value().attr("style") { - if let Some(url) = extract_photo_url(style) { - photos.push(url.to_string()) - } - } - } - - let video_sel = Selector::parse("i.tgme_widget_message_video_thumb").unwrap(); - let mut videos = vec![]; - - for video in doc.select(&video_sel) { - if let Some(style) = video.value().attr("style") { - if let Some(url) = extract_photo_url(style) { - videos.push(url.to_string()) - } - } - } - - let audio_sel = Selector::parse("audio.tgme_widget_message_voice.js-message_voice").unwrap(); - let mut has_audio = false; - if doc.select(&audio_sel).next().is_some() { - has_audio = true; - } - - Ok(TgMessage { - author, - message, - photos, - videos, - has_audio, - }) -} - -// create a permanent media url that tgsa can redirect if telegram -// changes its upstream links. -// -// assumes that tgsa lives at tgsa.tazj.in (which it does) -fn media_url(link: &TgLink, idx: usize) -> String { - format!( - "https://tgsa.tazj.in/img/{}/{}/{}", - link.username, link.message_id, idx - ) -} - -fn to_bbcode(link: &TgLink, msg: &TgMessage) -> String { - let mut out = String::new(); - - out.push_str(&format!("[quote=\"{}\"]\n", msg.author)); - - for video in 0..msg.videos.len() { - out.push_str(&format!("[url=\"{}\"]", link.to_url(true))); - - // video thumbnail links are appended to the photos, hence the - // addition here - out.push_str(&format!( - "[img]{}[/img]", - media_url(link, video + msg.photos.len()) - )); - - out.push_str("[/url]\n"); - out.push_str("[sub](Click thumbnail to open video)[/sub]\n") - } - - for photo in 0..msg.photos.len() { - out.push_str(&format!("[timg]{}[/timg]\n", media_url(link, photo))); - } - - if msg.has_audio { - out.push_str(&format!( - "[i]This message has audio attached. Go [url=\"{}\"]to Telegram[/url] to listen.[/i]", - link.to_url(true), - )); - } - - if let Some(message) = &msg.message { - out.push_str(message); - } - - out.push_str("\n[/quote]\n"); - - out.push_str(&format!( - "[sub](from [url=\"{}\"]{}[/url], via [url=\"https://tgsa.tazj.in\"]tgsa[/url])[/sub]\n", - link.to_url(true), - link.human_friendly_url(), - )); - - out -} - -// cache everything for one hour -const CACHE_EXPIRY: Duration = Duration::from_secs(60 * 60); - -#[derive(Clone)] -struct TgPost { - bbcode: String, - at: Instant, - media: Vec, -} - -type Cache = RwLock>; - -fn fetch_with_cache(cache: &Cache, link: &TgLink) -> Result { - if let Some(entry) = cache.read().unwrap().get(link) { - if Instant::now() - entry.at < CACHE_EXPIRY { - println!("serving {}#{} from cache", link.username, link.message_id); - return Ok(entry.clone()); - } - } - - // limit concurrent fetching - // TODO(tazjin): per link? - let mut writer = cache.write().unwrap(); - - let post = fetch_post(link, true)?; - let mut msg = parse_tgmessage(&post)?; - - if msg.message.is_none() { - msg.message = fetch_fallback(link)?; - } - - if let Some(message) = &msg.message { - if link.translated { - println!("translating {}#{}", link.username, link.message_id); - msg.message = Some(translate::fetch_translation(message)?); - } - } - - let bbcode = to_bbcode(link, &msg); - - let mut media = vec![]; - media.append(&mut msg.photos); - media.append(&mut msg.videos); - - let post = TgPost { - bbcode, - media, - at: Instant::now(), - }; - - writer.insert(link.clone(), post.clone()); - - Ok(post) -} - -fn handle_img_redirect(cache: &Cache, img_path: &str) -> Result { - // img_path: - // - // RWApodcast/113/1 - // ^ ^ ^ - // | | | - // | | image (0-indexed) - // | post ID - // username - - let img_parts: Vec<&str> = img_path.split('/').collect(); - - if img_parts.len() != 3 { - println!("invalid image link: {}", img_path); - return Err(anyhow!("not a valid image link: {}", img_path)); - } - - let link = TgLink { - username: img_parts[0].into(), - message_id: img_parts[1].parse().context("failed to parse message_id")?, - translated: false, - }; - - let img_idx: usize = img_parts[2].parse().context("failed to parse img_idx")?; - let post = fetch_with_cache(cache, &link)?; - - if img_idx >= post.media.len() { - return Err(anyhow!( - "there is no {}. image in {}/{}", - img_idx, - link.username, - link.message_id - )); - } - - Ok(rouille::Response::redirect_303(post.media[img_idx].clone())) -} - -fn handle_tg_link(cache: &Cache, link: &TgLink) -> Result { - let post = fetch_with_cache(cache, link)?; - Ok(rouille::Response::text(post.bbcode)) -} - -fn main() { - crimp::init(); - - let cache: Cache = RwLock::new(HashMap::new()); - - rouille::start_server("0.0.0.0:8472", move |request| { - let mut raw_url = request.raw_url(); - let mut translate = false; - - let response = loop { - if raw_url.starts_with("/img/") { - break handle_img_redirect(&cache, &raw_url[5..]); - } - - if raw_url.starts_with("/translate/") { - translate = true; - raw_url = &raw_url[10..]; - } - - break match TgLink::parse(raw_url, translate) { - None => Ok(rouille::Response::text( - r#"tgsa ----- - -this is a stupid program that lets you turn telegram message links -into BBcode suitable for pasting on somethingawful dot com - -you can use it by putting a valid telegram message link in the url and -waiting for some bbcode to show up. - -for example: - - https://tgsa.tazj.in/https://t.me/RWApodcast/113 - -yes, that looks stupid, but it works - -if you see this message and think you did the above correctly, you -didn't. try again. idiot. - -it can also translate posts from russian, ukrainian or whatever other -dumb language you speak into english by adding `/translate/`, for -example: - - https://tgsa.tazj.in/translate/https://t.me/strelkovii/4329 - -expect this to be slow though. that's the price to pay for translating -shitty slang. - -pm me on the forums if any of this makes you mad or something. -"#, - )), - Some(link) => handle_tg_link(&cache, &link), - }; - }; - - match response { - Ok(resp) => resp, - Err(err) => { - println!("something failed: {}", err); - rouille::Response::text(format!( - r#"ugh, something broke: {} - -nobody has been alerted about this and it has probably not been -logged. pm me on the forums if you think it's important."#, - err - )) - } - } - }); -} diff --git a/users/tazjin/tgsa/src/translate.rs b/users/tazjin/tgsa/src/translate.rs deleted file mode 100644 index 35d7b35ca..000000000 --- a/users/tazjin/tgsa/src/translate.rs +++ /dev/null @@ -1,191 +0,0 @@ -//! integration with yandex cloud translate api, for automatically -//! translating telegram posts. -//! -//! most of this module is concerned with handling the authentication -//! tokens for yandex cloud, as jwt signing needs to be handled -//! manually (none of the rust jwt libraries that i tried actually -//! work). - -use anyhow::{anyhow, Context, Result}; -use base64::prelude::BASE64_URL_SAFE_NO_PAD as B64; -use base64::Engine; -use lazy_static::lazy_static; -use ring::signature as sig; -use serde::Deserialize; -use serde_json::{json, Value}; -use std::sync::Mutex; -use std::time::{Duration, SystemTime}; - -/// token exchange url (exchanging a signed jwt for an iam token -/// understood by the translation service) -const TOKEN_URL: &str = "https://iam.api.cloud.yandex.net/iam/v1/tokens"; - -/// translation endpoint -const TRANSLATE_URL: &str = "https://translate.api.cloud.yandex.net/translate/v2/translate"; - -/// describes the private key as downloaded from yandex, pem-encoded. -#[derive(Deserialize)] -struct AuthorizedKey { - id: String, - service_account_id: String, - private_key: String, -} - -/// cached iam token for yandex cloud -struct Token { - token: String, - expiry: SystemTime, -} - -impl Token { - fn is_expired(&self) -> bool { - self.expiry < SystemTime::now() - } -} - -lazy_static! { - static ref KEY_FILE: String = - std::env::var("YANDEX_KEY_FILE").expect("`YANDEX_KEY_FILE` variable should be set"); - static ref CACHED_TOKEN: Mutex = { - let token = refresh_token().expect("fetching initial translation token must not fail"); - Mutex::new(token) - }; -} - -/// wrap all the authentication logic below into a single function. -fn refresh_token() -> Result { - let file = std::fs::File::open(KEY_FILE.as_str())?; - let key: AuthorizedKey = serde_json::from_reader(file)?; - let jwt = sign_yandex_jwt(&key)?; - let token = fetch_iam_token(&jwt)?; - - Ok(Token { - token, - expiry: SystemTime::now() + Duration::from_secs(3600), - }) -} - -/// wrapper around the cached token that refreshes if required. -fn current_token() -> Result { - let mut token = CACHED_TOKEN - .lock() - .expect("thread operating on token should never fail"); - - if token.is_expired() { - println!("refreshing translation token"); - *token = refresh_token().context("refreshing translation token")?; - } - - Ok(token.token.clone()) -} - -/// use openssl to read the pem-encoded key, as ring itself is not -/// capable of this. -fn read_pem_key(key: &AuthorizedKey) -> Result { - let rsa = openssl::rsa::Rsa::private_key_from_pem(key.private_key.as_bytes()) - .context("parsing RSA key")?; - - let der = rsa - .private_key_to_der() - .context("encoding key as DER for ring")?; - - sig::RsaKeyPair::from_der(&der).map_err(|err| anyhow!("decoding DER key in ring: {}", err)) -} - -/// manually construct and sign the jwt required to perform the -/// iam-token key exchange with yandex. -fn sign_yandex_jwt(key: &AuthorizedKey) -> Result { - let iat = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH)? - .as_secs(); - - let header = json!({ - "typ": "JWT", - "alg": "PS256", - "kid": key.id, - }) - .to_string(); - - let payload = json!({ - "iss": key.service_account_id, - "aud": TOKEN_URL, - "iat": iat, - "exp": iat + 60, - }) - .to_string(); - - let unsigned = format!("{}.{}", B64.encode(header), B64.encode(payload)); - let key_pair = read_pem_key(key)?; - - let rng = ring::rand::SystemRandom::new(); - let mut signature = vec![0; key_pair.public_modulus_len()]; - key_pair - .sign( - &sig::RSA_PSS_SHA256, - &rng, - unsigned.as_bytes(), - &mut signature, - ) - .map_err(|err| anyhow!("while signing JWT: {}", err))?; - - Ok(format!("{}.{}", unsigned, B64.encode(&signature))) -} - -/// exchange the jwt for an iam token -fn fetch_iam_token(token: &str) -> Result { - #[derive(Deserialize)] - #[serde(rename_all = "camelCase")] - struct TokenResponse { - iam_token: String, - } - - let response = crimp::Request::post(TOKEN_URL) - .json(&json!({ - "jwt": token, - }))? - .send()? - .error_for_status(|resp| { - anyhow::anyhow!("{} ({})", String::from_utf8_lossy(&resp.body), resp.status) - })? - .as_json::() - .context("deserialising IAM token")?; - - Ok(response.body.iam_token) -} - -pub fn fetch_translation(message: &str) -> Result { - let request_body = json!({ - "folderId": "b1g5k8f0tgimg06i6p5h", - "texts": [ message ], - "targetLanguageCode": "en", - }); - - let response = crimp::Request::post(TRANSLATE_URL) - .bearer_auth(¤t_token()?) - .context("adding 'Bearer' token")? - .json(&request_body) - .context("preparing JSON body")? - .send() - .context("failed to fetch translation from yandex")? - .error_for_status(|resp| { - anyhow!( - "translation request failed: {} ({})", - String::from_utf8_lossy(&resp.body), - resp.status - ) - })? - .as_json::()? - .body; - - let translation = response - .get("translations") - .ok_or_else(|| anyhow!("missing 'translations' key"))? - .get(0) - .ok_or_else(|| anyhow!("translations list is empty"))? - .get("text") - .ok_or_else(|| anyhow!("translation missing 'text' key"))? - .as_str() - .ok_or_else(|| anyhow!("'text' was not a string"))?; - - Ok(translation.to_string()) -} diff --git a/users/tazjin/tvix-eval-value.d2 b/users/tazjin/tvix-eval-value.d2 deleted file mode 100644 index dad2dbcef..000000000 --- a/users/tazjin/tvix-eval-value.d2 +++ /dev/null @@ -1,98 +0,0 @@ -# D2 diagram of tvix-eval's `Value` type. -# -# can be rendered at https://play.d2lang.com/ -# -# colours have meanings: -# -# yellow: recurses -# orange: heap allocation -# red: refcount -# -# this intentionally does *not* include some internal variants - -Value -> Null -Value -> Bool -Value -> Integer -Value -> Float - -Box*.style.fill: "lightsalmon" -Rc*.style.fill: "salmon" -Vec\<*.style.fill: "salmon" - -Value -> String -> NixString -> "Box" - -Value -> Path -> "Box" -> PathBuf -PathBuf.style.fill: "lightsalmon" - -# attribute sets are kinda complicated -Value -> Attrs -> "Box" -> NixAttrs -NixAttrs -> Empty -NixAttrs -> KV -KV.style.fill: "LemonChiffon" -KV -> Value -KV -> Value -NixAttrs -> Map -Map -> "OrdMap" -> "MapEntry" -"OrdMap".style.fill: "lightsalmon" -"MapEntry".style.fill: "salmon" -"MapEntry".style.multiple: true -"MapEntry" -> NixString -"MapEntry" -> Value -"MapEntry".style.stroke-width: 15 -"MapEntry".style.stroke: "lemonchiffon" - -Value -> List -> NixList -> "Rc>" -"Rc>" -> "VecEntry" -> Value -"VecEntry".style.multiple: true -"VecEntry".style.fill: "salmon" -"VecEntry".style.stroke-width: 15 -"VecEntry".style.stroke: "lemonchiffon" - -# closures - -Value -> Closure -> "Rc" -> Closure -Closure -> "Rc" -> Lambda - -Lambda -> Chunk -Lambda -> SmolStr: sometimes allocates -SmolStr.style.fill: "lightsalmon" -Lambda -> usize -Lambda -> "Option" -> Formals - -Formals -> "HashMap" -> "MapEntry" -"HashMap".style.fill: "lightsalmon" -"MapEntry".style.fill: "salmon" -"MapEntry".style.multiple: true -"MapEntry" -> NixString - -Closure -> "Rc" -> Upvalues - -Upvalues -> "Vec" -"Vec" -> Value -"Vec".style.stroke-width: 15 -"Vec".style.stroke: "lemonchiffon" -Upvalues -> "Option>" -"Option>" -> Value -"Option>".style.fill: "lightsalmon" -"Option>".style.stroke-width: 15 -"Option>".style.stroke: "lemonchiffon" - -Value -> Blueprint -> "Rc" - -# builtins - -Value -> Builtin -> "Box" -> BuiltinRepr -BuiltinRepr -> "Rc" -BuiltinRepr -> "Vec" - -# thunks - -Value -> Thunk -> "Rc>" -> ThunkRepr -ThunkRepr -> Suspended -Suspended -> "Rc" -Suspended -> "Rc" - -ThunkRepr -> Native -> "Box Result>" -ThunkRepr -> Blackhole -ThunkRepr -> Evaluated -> Value -Evaluated.style.fill: "lemonchiffon" diff --git a/users/tazjin/wallpapers/alphasoft.webp b/users/tazjin/wallpapers/alphasoft.webp deleted file mode 100644 index 10c404eff..000000000 Binary files a/users/tazjin/wallpapers/alphasoft.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/bio_thehost_1920.webp b/users/tazjin/wallpapers/bio_thehost_1920.webp deleted file mode 100644 index 1b904c06f..000000000 Binary files a/users/tazjin/wallpapers/bio_thehost_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/busride2_1920.webp b/users/tazjin/wallpapers/busride2_1920.webp deleted file mode 100644 index ad6ec446f..000000000 Binary files a/users/tazjin/wallpapers/busride2_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/by_belltowers_2880.webp b/users/tazjin/wallpapers/by_belltowers_2880.webp deleted file mode 100644 index f7477f168..000000000 Binary files a/users/tazjin/wallpapers/by_belltowers_2880.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/by_crossing_2560.webp b/users/tazjin/wallpapers/by_crossing_2560.webp deleted file mode 100644 index efa263790..000000000 Binary files a/users/tazjin/wallpapers/by_crossing_2560.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/by_gathering3_2880.webp b/users/tazjin/wallpapers/by_gathering3_2880.webp deleted file mode 100644 index e6b83bdcd..000000000 Binary files a/users/tazjin/wallpapers/by_gathering3_2880.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/by_mainservers1_1920.webp b/users/tazjin/wallpapers/by_mainservers1_1920.webp deleted file mode 100644 index f88d237e2..000000000 Binary files a/users/tazjin/wallpapers/by_mainservers1_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/by_warmachines1_2560.webp b/users/tazjin/wallpapers/by_warmachines1_2560.webp deleted file mode 100644 index 848bf62bd..000000000 Binary files a/users/tazjin/wallpapers/by_warmachines1_2560.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/by_warmachines3_1920.webp b/users/tazjin/wallpapers/by_warmachines3_1920.webp deleted file mode 100644 index 6002ad695..000000000 Binary files a/users/tazjin/wallpapers/by_warmachines3_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/clever-man_2880.webp b/users/tazjin/wallpapers/clever-man_2880.webp deleted file mode 100644 index eb4d3f1bf..000000000 Binary files a/users/tazjin/wallpapers/clever-man_2880.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/december1994_1920.webp b/users/tazjin/wallpapers/december1994_1920.webp deleted file mode 100644 index d2c4da801..000000000 Binary files a/users/tazjin/wallpapers/december1994_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/flyby_1920.webp b/users/tazjin/wallpapers/flyby_1920.webp deleted file mode 100644 index 8df5b1132..000000000 Binary files a/users/tazjin/wallpapers/flyby_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/gaussfraktarna_1920_badge.webp b/users/tazjin/wallpapers/gaussfraktarna_1920_badge.webp deleted file mode 100644 index 3274a3a2d..000000000 Binary files a/users/tazjin/wallpapers/gaussfraktarna_1920_badge.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/kraftahq_1920.webp b/users/tazjin/wallpapers/kraftahq_1920.webp deleted file mode 100644 index 62a6debf4..000000000 Binary files a/users/tazjin/wallpapers/kraftahq_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/peripheral2_1920.webp b/users/tazjin/wallpapers/peripheral2_1920.webp deleted file mode 100644 index e454072ac..000000000 Binary files a/users/tazjin/wallpapers/peripheral2_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/ship14_1920.webp b/users/tazjin/wallpapers/ship14_1920.webp deleted file mode 100644 index 502f5dac9..000000000 Binary files a/users/tazjin/wallpapers/ship14_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/shipyard_1920.webp b/users/tazjin/wallpapers/shipyard_1920.webp deleted file mode 100644 index 3d4115305..000000000 Binary files a/users/tazjin/wallpapers/shipyard_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/specky_1920.webp b/users/tazjin/wallpapers/specky_1920.webp deleted file mode 100644 index b8246618b..000000000 Binary files a/users/tazjin/wallpapers/specky_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/summerlove2_1920.webp b/users/tazjin/wallpapers/summerlove2_1920.webp deleted file mode 100644 index d64a1cb86..000000000 Binary files a/users/tazjin/wallpapers/summerlove2_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/svema_02_big.webp b/users/tazjin/wallpapers/svema_02_big.webp deleted file mode 100644 index 5b7f18715..000000000 Binary files a/users/tazjin/wallpapers/svema_02_big.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/svema_07_big.webp b/users/tazjin/wallpapers/svema_07_big.webp deleted file mode 100644 index 070654347..000000000 Binary files a/users/tazjin/wallpapers/svema_07_big.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/svema_09_big.webp b/users/tazjin/wallpapers/svema_09_big.webp deleted file mode 100644 index 4983efef2..000000000 Binary files a/users/tazjin/wallpapers/svema_09_big.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/svema_14_big.webp b/users/tazjin/wallpapers/svema_14_big.webp deleted file mode 100644 index c74542807..000000000 Binary files a/users/tazjin/wallpapers/svema_14_big.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/t50_1920_badge.webp b/users/tazjin/wallpapers/t50_1920_badge.webp deleted file mode 100644 index f8cb6107f..000000000 Binary files a/users/tazjin/wallpapers/t50_1920_badge.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/theflood1_1920.webp b/users/tazjin/wallpapers/theflood1_1920.webp deleted file mode 100644 index 335efb057..000000000 Binary files a/users/tazjin/wallpapers/theflood1_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/thelan_1920.webp b/users/tazjin/wallpapers/thelan_1920.webp deleted file mode 100644 index 55e6c22ad..000000000 Binary files a/users/tazjin/wallpapers/thelan_1920.webp and /dev/null differ diff --git a/users/tazjin/wallpapers/vadrare_1920_badge.webp b/users/tazjin/wallpapers/vadrare_1920_badge.webp deleted file mode 100644 index 887c891da..000000000 Binary files a/users/tazjin/wallpapers/vadrare_1920_badge.webp and /dev/null differ diff --git a/users/tazjin/yddns/.gitignore b/users/tazjin/yddns/.gitignore deleted file mode 100644 index 2f7896d1d..000000000 --- a/users/tazjin/yddns/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target/ diff --git a/users/tazjin/yddns/Cargo.lock b/users/tazjin/yddns/Cargo.lock deleted file mode 100644 index 58b37d553..000000000 --- a/users/tazjin/yddns/Cargo.lock +++ /dev/null @@ -1,1425 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - -[[package]] -name = "anyhow" -version = "1.0.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[package]] -name = "async-trait" -version = "0.1.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.0.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8e7c90afad890484a21653d08b6e209ae34770fb5ee298f9c699fcc1e5c856" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crimp" -version = "4087.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ead2c83f7d1f9b8e5a6f7a25985d0d1759ccd2cd72abb1eee2db65d05e12b39" -dependencies = [ - "curl", - "serde", - "serde_json", -] - -[[package]] -name = "curl" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2 0.4.10", - "winapi", -] - -[[package]] -name = "curl-sys" -version = "0.4.68+curl-8.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a0d18d88360e374b16b2273c832b5e57258ffc1d4aa4f96b108e0738d5752f" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "windows-sys", -] - -[[package]] -name = "either" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c18ee0ed65a5f1f81cac6b1d213b69c35fa47d4252ad41f1486dbd8226fe36e" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "futures-channel" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" - -[[package]] -name = "futures-sink" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" - -[[package]] -name = "futures-task" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" - -[[package]] -name = "futures-util" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "getrandom" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "h2" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 1.9.3", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "home" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "http" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95b9abcae896730d42b78e09c155ed4ddf82c07b4de772c64aee5b2d8b7c150" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.4.10", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown 0.14.2", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" - -[[package]] -name = "libz-sys" -version = "1.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829" - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" -dependencies = [ - "libc", - "wasi", - "windows-sys", -] - -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap 2.1.0", -] - -[[package]] -name = "pin-project" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" -dependencies = [ - "bytes", - "heck", - "itertools", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.109", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - -[[package]] -name = "ring" -version = "0.17.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" -dependencies = [ - "cc", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" -dependencies = [ - "bitflags 2.4.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "rustls" -version = "0.21.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64", -] - -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.192" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.192" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[package]] -name = "serde_json" -version = "1.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "tempfile" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys", -] - -[[package]] -name = "tokio" -version = "1.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2 0.5.5", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tonic" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64", - "bytes", - "flate2", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "rustls-native-certs", - "rustls-pemfile", - "tokio", - "tokio-rustls", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-build" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.39", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "walkdir" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "yandex-cloud" -version = "2023.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98f67140264e8e090e26b70925096adf295569c057a8b2ad2cd7e0f10c01cfae" -dependencies = [ - "prost", - "prost-types", - "tonic", - "tonic-build", - "walkdir", -] - -[[package]] -name = "yddns" -version = "0.1.0" -dependencies = [ - "anyhow", - "crimp", - "tokio", - "yandex-cloud", -] diff --git a/users/tazjin/yddns/Cargo.toml b/users/tazjin/yddns/Cargo.toml deleted file mode 100644 index 78691f303..000000000 --- a/users/tazjin/yddns/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "yddns" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow = "1.0" -crimp = "4087.0" -tokio = "*" # pulled in by yandex-cloud -yandex-cloud = "2023.6.13" diff --git a/users/tazjin/yddns/default.nix b/users/tazjin/yddns/default.nix deleted file mode 100644 index 40b0d1c24..000000000 --- a/users/tazjin/yddns/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ depot, pkgs, ... }: - -depot.third_party.naersk.buildPackage { - src = ./.; - buildInputs = with pkgs; [ - pkg-config - openssl - ]; -} diff --git a/users/tazjin/yddns/src/main.rs b/users/tazjin/yddns/src/main.rs deleted file mode 100644 index 2e2f9fe02..000000000 --- a/users/tazjin/yddns/src/main.rs +++ /dev/null @@ -1,142 +0,0 @@ -use anyhow::{anyhow, bail, Context, Result}; -use crimp::Request; -use std::env; -use std::net::Ipv4Addr; -use tokio::runtime; -use yandex_cloud::tonic_exports::{Channel, Endpoint, InterceptedService}; -use yandex_cloud::yandex::cloud::dns::v1 as dns; -use yandex_cloud::yandex::cloud::dns::v1::dns_zone_service_client::DnsZoneServiceClient; -use yandex_cloud::{AuthInterceptor, TokenProvider}; - -type DnsClient = DnsZoneServiceClient>>; - -/// Fetch the current IP from the given URL. It should be the URL of a -/// site that responds only with the IP in plain text, and nothing else. -fn get_current_ip(source: &str) -> Result { - let response = Request::get(source) - .send() - .context("failed to fetch current IP")? - .error_for_status(|resp| anyhow!("error response ({})", resp.status)) - .context("received error response for IP")? - .as_string()? - .body; - - Ok(response.trim().parse().with_context(|| { - format!( - "failed to parse IP address from response body: {}", - response - ) - })?) -} - -/// Fetch the current address of the target record. -async fn fetch_current_record_addr( - client: &mut DnsClient, - zone_id: &str, - record_name: &str, -) -> Result { - let req = dns::GetDnsZoneRecordSetRequest { - dns_zone_id: zone_id.into(), - name: record_name.into(), - r#type: "A".into(), - }; - - let response = client - .get_record_set(req) - .await - .context("failed to fetch current record set")? - .into_inner(); - - if response.data.len() != 1 { - bail!( - "expected exactly one record for 'A {}', but found {}", - record_name, - response.data.len() - ); - } - - Ok(response.data[0] - .parse() - .context("failed to parse returned record")?) -} - -/// Update the record with the new address, if required. -async fn update_record( - client: &mut DnsClient, - zone_id: &str, - record_name: &str, - new_address: Ipv4Addr, -) -> Result<()> { - let request = dns::UpsertRecordSetsRequest { - dns_zone_id: zone_id.into(), - replacements: vec![dns::RecordSet { - name: record_name.into(), - r#type: "A".into(), - ttl: 3600, // 1 hour - data: vec![new_address.to_string()], - }], - ..Default::default() - }; - - client - .upsert_record_sets(request) - .await - .context("failed to update record")?; - - Ok(()) -} - -/// Compare the record with the expected value, and issue an update if -/// necessary. -async fn compare_update_record( - client: &mut DnsClient, - zone_id: &str, - record_name: &str, - new_ip: Ipv4Addr, -) -> Result<()> { - let old_ip = fetch_current_record_addr(client, zone_id, record_name).await?; - - if old_ip == new_ip { - println!("IP address unchanged ({})", old_ip); - return Ok(()); - } - - println!( - "IP address changed: current record points to {}, but address is {}", - old_ip, new_ip - ); - - update_record(client, zone_id, record_name, new_ip).await?; - println!("successfully updated '{}' to 'A {}'", record_name, new_ip); - - Ok(()) -} - -fn main() -> Result<()> { - let token = - env::var("YANDEX_CLOUD_TOKEN").context("Yandex Cloud authentication token unset")?; - let target_zone_id = - env::var("TARGET_ZONE").unwrap_or_else(|_| "dnsd0tif5mokfu0mg8i5".to_string()); - let target_record = env::var("TARGET_RECORD").unwrap_or_else(|_| "khtrsk".to_string()); - - let current_ip = get_current_ip("http://ifconfig.me")?; - println!("current IP address is '{}'", current_ip); - - let rt = runtime::Builder::new_current_thread() - .enable_time() - .enable_io() - .build()?; - - rt.block_on(async move { - let channel = Endpoint::from_static("https://dns.api.cloud.yandex.net") - .connect() - .await?; - - let mut client = - DnsZoneServiceClient::with_interceptor(channel, AuthInterceptor::new(token)); - - compare_update_record(&mut client, &target_zone_id, &target_record, current_ip).await - })?; - - Ok(()) -} diff --git a/users/thk/OWNERS b/users/thk/OWNERS deleted file mode 100644 index 0741ad977..000000000 --- a/users/thk/OWNERS +++ /dev/null @@ -1,3 +0,0 @@ -set noparent - -thk diff --git a/users/tvlbot.jpg b/users/tvlbot.jpg deleted file mode 100644 index f0811418d..000000000 Binary files a/users/tvlbot.jpg and /dev/null differ diff --git a/users/wpcarro/.envrc b/users/wpcarro/.envrc deleted file mode 100644 index 3e1e1a35f..000000000 --- a/users/wpcarro/.envrc +++ /dev/null @@ -1,5 +0,0 @@ -source_up - -export PATH="${PWD}/bin:${PATH}" -export REPO_ROOT=$(git rev-parse --show-toplevel) -export WPCARRO="${REPO_ROOT}/users/wpcarro" diff --git a/users/wpcarro/.gitignore b/users/wpcarro/.gitignore deleted file mode 100644 index 64703ed12..000000000 --- a/users/wpcarro/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -.vim -./configs/secrets -**/*/.emacs.d/quelpa/**/* -**/*/.emacs.d/elpa/**/* -**/*/.emacs.d/emojis -**/*/.emacs.d/auto-save-list/**/* -**/*/.emacs.d/eshell/ -**/*/.emacs.d/var/**/* -**/*/.emacs.d/.cache/**/* -**/*/.emacs.d/request -**/*/.emacs.d/network-security.data -**/*/.emacs.d/smex-items -**/*/.gnupg/random_seed -**/*/.gnupg/private-keys-v1.d -.netrwhist -Vundle.vim -**/*/.emacs.d/custom.el -**/*/.emacs.d/projectile-bookmarks.eld -**/*/.emacs.d/bookmarks -**/*/transient/history.el -*.hi -*.o -__pycache__ -*.class -node_modules/ -/configs/.config/fish/config.fish -/configs/.config/fish/fish_variables -/website/blog/public/ -/emacs/.emacs.d/tramp -.gitsecret/keys/random_seed -!*.secret -secrets.json - -# Nix gcroots symlinks created by .envrc -/.gcroots/* diff --git a/users/wpcarro/.gitsecret/keys/pubring.kbx b/users/wpcarro/.gitsecret/keys/pubring.kbx deleted file mode 100644 index 692d5c67b..000000000 Binary files a/users/wpcarro/.gitsecret/keys/pubring.kbx and /dev/null differ diff --git a/users/wpcarro/.gitsecret/keys/pubring.kbx~ b/users/wpcarro/.gitsecret/keys/pubring.kbx~ deleted file mode 100644 index c0a748ce2..000000000 Binary files a/users/wpcarro/.gitsecret/keys/pubring.kbx~ and /dev/null differ diff --git a/users/wpcarro/.gitsecret/keys/trustdb.gpg b/users/wpcarro/.gitsecret/keys/trustdb.gpg deleted file mode 100644 index 369485be0..000000000 Binary files a/users/wpcarro/.gitsecret/keys/trustdb.gpg and /dev/null differ diff --git a/users/wpcarro/.gitsecret/paths/mapping.cfg b/users/wpcarro/.gitsecret/paths/mapping.cfg deleted file mode 100644 index fda2c84fb..000000000 --- a/users/wpcarro/.gitsecret/paths/mapping.cfg +++ /dev/null @@ -1 +0,0 @@ -secrets.json:7d596a3ed16403040d89dd7e033a2af58e7aaabb6f246f44751b80a1863a2949 diff --git a/users/wpcarro/OWNERS b/users/wpcarro/OWNERS deleted file mode 100644 index ac1283f56..000000000 --- a/users/wpcarro/OWNERS +++ /dev/null @@ -1 +0,0 @@ -wpcarro diff --git a/users/wpcarro/README.md b/users/wpcarro/README.md deleted file mode 100644 index be0aacf24..000000000 --- a/users/wpcarro/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# wpcarro - -Welcome to my monorepo. - -Herein you will find a variety of libraries, packages, and documents. Some of -this work in finished and other work is incomplete or just a sketch for a -future project. - -Where applicable, I try to include `README.md` files in some of the -subdirectories to help orient both myself and any onlookers. - -## Sign posts - -Below I have outlined a few projects that you might find interesting. - -- `boilerplate`: scaffolding for projects. Boilerplate's goal is to reduce the - startup costs of a project. -- `configs`: my dotfiles (e.g. `config.fish`, `init.vim`). -- `emacs`: Emacs is both my preferred text editor and my window manager; with - tens of thousands of lines of Emacs Lisp, you can safely assume that this - directory hosts a lot of libraries and packages. -- `monzo_ynab`: `systemd` timer unit that imports my Monzo (i.e. a U.K.-based - online bank) transactions into the personal finance tool YNAB (i.e. - youneedabudget.com). -- `nixos`: my declarative configuration for my NixOS machines. If you are - unfamiliar with Nix, I recommend reading about the NixOS project. -- `tools`: some scripts and projects that simplify my life. -- `website`: everything required to build my website, https://wpcarro.dev. - -## Installation - -### Google Machine - -- ensure `/google-briefcase` exists -- read `/google-briefcase/README.md` - -### NixOS Machine - -```shell -$ nix-shell -p nixos.{git,direnv} -$ git clone https://code.tvl.fyi/depot.git /depot -$ cd /depot -$ eval "$(direnv hook bash)" -$ HOSTNAME=base rebuild-system -$ sudo tailscale up -$ git clone 'user@host:~/.passage' ~/.passage -``` diff --git a/users/wpcarro/assessments/brilliant/.ghci b/users/wpcarro/assessments/brilliant/.ghci deleted file mode 100644 index efc88e630..000000000 --- a/users/wpcarro/assessments/brilliant/.ghci +++ /dev/null @@ -1,2 +0,0 @@ -:set prompt "> " -:set -Wall diff --git a/users/wpcarro/assessments/brilliant/App.hs b/users/wpcarro/assessments/brilliant/App.hs deleted file mode 100644 index 0272988f3..000000000 --- a/users/wpcarro/assessments/brilliant/App.hs +++ /dev/null @@ -1,41 +0,0 @@ --------------------------------------------------------------------------------- -module App where --------------------------------------------------------------------------------- -import Keyboard (Keyboard(..)) -import Transforms (Transform(..)) -import Utils ((|>)) - -import qualified Data.Char as Char -import qualified Utils -import qualified Data.List.Split as Split -import qualified Keyboard -import qualified Data.HashMap.Strict as HM --------------------------------------------------------------------------------- - -transform :: Keyboard -> Transform -> Keyboard - -transform (Keyboard xs) xform = - case xform of - HorizontalFlip -> - xs - |> fmap reverse - |> Keyboard - - VerticalFlip -> - xs - |> reverse - |> Keyboard - - Shift n -> - xs - |> concat - |> Utils.rotate n - |> Split.chunksOf 10 - |> Keyboard - -retypePassage :: String -> Keyboard -> Maybe String -retypePassage passage newKeyboard = - passage - |> fmap Char.toUpper - |> traverse (\c -> HM.lookup c Keyboard.charToCoord) - >>= traverse (Keyboard.coordToChar newKeyboard) diff --git a/users/wpcarro/assessments/brilliant/Keyboard.hs b/users/wpcarro/assessments/brilliant/Keyboard.hs deleted file mode 100644 index 13b5de014..000000000 --- a/users/wpcarro/assessments/brilliant/Keyboard.hs +++ /dev/null @@ -1,58 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} --------------------------------------------------------------------------------- -module Keyboard where --------------------------------------------------------------------------------- -import Utils -import Data.Coerce -import Data.Hashable (Hashable) -import GHC.Generics (Generic) - -import qualified Data.List as List -import qualified Data.HashMap.Strict as HM --------------------------------------------------------------------------------- - -newtype Keyboard = Keyboard [[Char]] - deriving (Eq) - -instance Show Keyboard where - show (Keyboard xxs) = - xxs |> fmap printRow |> List.intercalate "\n" - where - printRow :: [Char] -> String - printRow xs = - xs |> fmap (\x -> '[':x:']':"") |> List.intercalate "" - -data Coord = Coord - { row :: Int - , col :: Int - } deriving (Eq, Show, Generic) - -instance Hashable Coord - --- | List of characters to their QWERTY coordinatees. -coords :: [(Char, Coord)] -coords = - qwerty - |> coerce - |> fmap (zip [0..]) - |> zip [0..] - |> fmap (\(row, xs) -> xs |> fmap (\(col, char) -> (char, Coord row col))) - |> mconcat - --- | Mapping of characters to their coordinates on a QWERTY keyboard with the --- top-left corner as 0,0. -charToCoord :: HM.HashMap Char Coord -charToCoord = HM.fromList coords - -coordToChar :: Keyboard -> Coord -> Maybe Char -coordToChar (Keyboard xxs) Coord{..} = - Just $ xxs !! row !! col - -qwerty :: Keyboard -qwerty = Keyboard [ ['1','2','3','4','5','6','7','8','9','0'] - , ['Q','W','E','R','T','Y','U','I','O','P'] - , ['A','S','D','F','G','H','J','K','L',';'] - , ['Z','X','C','V','B','N','M',',','.','/'] - ] diff --git a/users/wpcarro/assessments/brilliant/Main.hs b/users/wpcarro/assessments/brilliant/Main.hs deleted file mode 100644 index e94c73bea..000000000 --- a/users/wpcarro/assessments/brilliant/Main.hs +++ /dev/null @@ -1,43 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Main where --------------------------------------------------------------------------------- -import Options.Applicative -import Data.Semigroup ((<>)) - -import qualified Transforms -import qualified Keyboard -import qualified App --------------------------------------------------------------------------------- - -data CommandArgs = CommandArgs - { transforms :: String - , passage :: String - } deriving (Eq, Show) - -parseArgs :: Parser CommandArgs -parseArgs = - CommandArgs <$> strOption - ( long "transforms" - <> short 't' - <> help "String of transforms where (e.g. \"HHVS12VHVHS3\")" ) - <*> strOption - ( long "passage" - <> short 'p' - <> help "Input text to re-type" ) - -main :: IO () -main = do - CommandArgs{..} <- execParser opts - case Transforms.fromString transforms of - Nothing -> putStrLn "You must provide valid input (e.g. \"HHVS12VHVHS3\")" - Just xs -> do - let keyboard = foldl App.transform Keyboard.qwerty (Transforms.optimize xs) - putStrLn $ "Typing: \"" ++ passage ++ "\"\nOn this keyboard:\n" ++ show keyboard - case App.retypePassage passage keyboard of - Nothing -> putStrLn $ "Looks like at least one of the characters in your input passage doesn't fit on our QWERTY keyboard: \n" ++ show Keyboard.qwerty - Just result -> putStrLn $ "Result: " ++ result - where - opts = info (parseArgs <**> helper) - ( fullDesc - <> progDesc "Transform a QWERTY keyboard using a string of commands") diff --git a/users/wpcarro/assessments/brilliant/README.md b/users/wpcarro/assessments/brilliant/README.md deleted file mode 100644 index 60d7de4e2..000000000 --- a/users/wpcarro/assessments/brilliant/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# Transform QWERTY - -Apply a series of transforms to a QWERTY keyboard then use the new keyboard to -re-type a passage of text. - -## Environment - -You will need [Nix][nix] to build this program on your machine. The good news is -that you won't need any Haskell-specific dependencies like `ghc`, `cabal`, or -`stack`: just Nix. - -Once you have Nix installed, to build the program, run the following from this -project's top-level directory: - -```shell -$ nix-build -``` - -This should output an executable named `transform-keyboard` within a `result` -directory: - -```shell -$ tree result -result -└── transform-keyboard -``` - -### Testing - -To run the test suite, run the following from the project's top-level directory: - -```shell -$ nix-shell -$ runhaskell Spec.hs -``` - -[nix]: https://nixos.org/download.html - -## Usage - -Here are some `--help` and usage examples: - -```shell -$ ./result/transform-keyboard --help -Usage: transform-keyboard (-t|--transforms ARG) (-p|--passage ARG) - Transform a QWERTY keyboard using a string of commands - -Available options: - -t,--transforms ARG String of transforms where (e.g. "HHVS12VHVHS3") - -p,--passage ARG Input text to re-type - -h,--help Show this help text -``` - -Now a working example: - -```shell -$ ./result/transform-keyboard --transforms=HHVS12VHVHS3 --passage='Hello,Brilliant.' -Typing: "Hello,Brilliant." -On this keyboard: -[H][J][K][L][;][Q][W][E][R][T] -[Y][U][I][O][P][1][2][3][4][5] -[6][7][8][9][0][Z][X][C][V][B] -[N][M][,][.][/][A][S][D][F][G] -Result: ZIVV4D/O3VV36APF -``` - -...and an example with an erroneous input (i.e. `!`): - -```shell -$ ./result/transform-keyboard --transforms=HHVS12VHVHS3 --passage='Hello,Brilliant!' -Typing: "Hello,Brilliant!" -On this keyboard: -[H][J][K][L][;][Q][W][E][R][T] -[Y][U][I][O][P][1][2][3][4][5] -[6][7][8][9][0][Z][X][C][V][B] -[N][M][,][.][/][A][S][D][F][G] -Looks like at least one of the characters in your input passage doesn't fit on our QWERTY keyboard: -[1][2][3][4][5][6][7][8][9][0] -[Q][W][E][R][T][Y][U][I][O][P] -[A][S][D][F][G][H][J][K][L][;] -[Z][X][C][V][B][N][M][,][.][/] -``` diff --git a/users/wpcarro/assessments/brilliant/Spec.hs b/users/wpcarro/assessments/brilliant/Spec.hs deleted file mode 100644 index e99e02564..000000000 --- a/users/wpcarro/assessments/brilliant/Spec.hs +++ /dev/null @@ -1,103 +0,0 @@ --------------------------------------------------------------------------------- -module Spec where --------------------------------------------------------------------------------- -import Test.Hspec -import Test.QuickCheck -import Keyboard (Keyboard(..)) -import Transforms (Transform(..)) -import Data.Coerce -import Utils - -import qualified App -import qualified Keyboard -import qualified Transforms --------------------------------------------------------------------------------- - -main :: IO () -main = hspec $ do - describe "Keyboard.print" $ do - it "pretty-prints the keyboard" $ do - show Keyboard.qwerty == "[1][2][3][4][5][6][7][8][9][0]\n[Q][W][E][R][T][Y][U][I][O][P]\n[A][S][D][F][G][H][J][K][L][;]\n[Z][X][C][V][B][N][M][,][.][/]" - - describe "Transforms.fromString" $ do - it "successfully parses a string of commands" $ do - Transforms.fromString "HHVS-12VHVHS3" == - Just [ HorizontalFlip - , HorizontalFlip - , VerticalFlip - , Shift (-12) - , VerticalFlip - , HorizontalFlip - , VerticalFlip - , HorizontalFlip - , Shift 3 - ] - - it "returns Nothing when the input is invalid" $ do - Transforms.fromString "potato" == Nothing - - it "return Nothing when the input is valid except for the end" $ do - Transforms.fromString "HVS10potato" == Nothing - - describe "App.transform" $ do - it "flips any keyboard horizontally" $ do - property $ \first second third fourth -> - App.transform (Keyboard [first, second, third, fourth]) HorizontalFlip == do - Keyboard [ reverse first - , reverse second - , reverse third - , reverse fourth - ] - - it "flips any keyboard vertically" $ do - property $ \first second third fourth -> - App.transform (Keyboard [first, second, third, fourth]) VerticalFlip == do - Keyboard $ reverse [first, second, third, fourth] - - it "shifts any keyboard" $ do - property $ \first second third fourth n -> - App.transform (Keyboard [first, second, third, fourth]) (Shift n) - |> (coerce :: Keyboard -> [[Char]]) - |> concat == - [first, second, third, fourth] - |> concat - |> Utils.rotate n - - it "flips a QWERTY keyboard horizontally" $ do - App.transform Keyboard.qwerty HorizontalFlip == do - Keyboard [ ['0','9','8','7','6','5','4','3','2','1'] - , ['P','O','I','U','Y','T','R','E','W','Q'] - , [';','L','K','J','H','G','F','D','S','A'] - , ['/','.',',','M','N','B','V','C','X','Z'] - ] - - it "flips a keyboard vertically" $ do - App.transform Keyboard.qwerty VerticalFlip == do - Keyboard [ ['Z','X','C','V','B','N','M',',','.','/'] - , ['A','S','D','F','G','H','J','K','L',';'] - , ['Q','W','E','R','T','Y','U','I','O','P'] - , ['1','2','3','4','5','6','7','8','9','0'] - ] - - it "shifts a keyboard left N times" $ do - App.transform Keyboard.qwerty (Shift 2) == do - Keyboard [ ['3','4','5','6','7','8','9','0','Q','W'] - , ['E','R','T','Y','U','I','O','P','A','S'] - , ['D','F','G','H','J','K','L',';','Z','X'] - , ['C','V','B','N','M',',','.','/','1','2'] - ] - - it "shifts right negative amounts" $ do - App.transform Keyboard.qwerty (Shift (-3)) == do - Keyboard [ [',','.','/','1','2','3','4','5','6','7'] - , ['8','9','0','Q','W','E','R','T','Y','U'] - , ['I','O','P','A','S','D','F','G','H','J'] - , ['K','L',';','Z','X','C','V','B','N','M'] - ] - - describe "Transforms.optimize" $ do - it "removes superfluous horizontal transformations" $ do - Transforms.optimize [HorizontalFlip, HorizontalFlip] == [] - - it "removes superfluous vertical transformations" $ do - Transforms.optimize [VerticalFlip, VerticalFlip] == [] diff --git a/users/wpcarro/assessments/brilliant/Transforms.hs b/users/wpcarro/assessments/brilliant/Transforms.hs deleted file mode 100644 index d8df8f837..000000000 --- a/users/wpcarro/assessments/brilliant/Transforms.hs +++ /dev/null @@ -1,52 +0,0 @@ --------------------------------------------------------------------------------- -module Transforms where --------------------------------------------------------------------------------- -import Control.Applicative ((<|>)) -import Text.ParserCombinators.ReadP --------------------------------------------------------------------------------- - -data Transform = VerticalFlip - | HorizontalFlip - | Shift Int - deriving (Eq, Show) - -digit :: ReadP Char -digit = - satisfy (\c -> c >= '0' && c <= '9') - -command :: ReadP Transform -command = vertical - <|> horizontal - <|> shift - where - vertical = - char 'V' >> pure VerticalFlip - - horizontal = - char 'H' >> pure HorizontalFlip - - shift = do - _ <- char 'S' - negative <- option Nothing $ fmap Just (satisfy (== '-')) - n <- read <$> many1 digit - case negative of - Nothing -> pure $ Shift n - Just _ -> pure $ Shift (-1 * n) - --- | Attempt to remove redundant transformations. --- | Here are some rules that I'd like to support but may not have time for: --- | - All even-numbered flips (w/o intermittent shifts) can become zero --- | - All odd-numbered flips (w/o intermittent shifts) can become 1 --- | - All shifts can be be reduce to the absolute value of shifts -optimize :: [Transform] -> [Transform] -optimize [] = [] -optimize [x] = [x] -optimize (VerticalFlip:VerticalFlip:xs) = optimize xs -optimize (HorizontalFlip:HorizontalFlip:xs) = optimize xs -optimize xs = xs - -fromString :: String -> Maybe [Transform] -fromString x = - case readP_to_S (manyTill command eof) x of - [(res, "")] -> Just res - _ -> Nothing diff --git a/users/wpcarro/assessments/brilliant/Utils.hs b/users/wpcarro/assessments/brilliant/Utils.hs deleted file mode 100644 index c69d00333..000000000 --- a/users/wpcarro/assessments/brilliant/Utils.hs +++ /dev/null @@ -1,13 +0,0 @@ --------------------------------------------------------------------------------- -module Utils where --------------------------------------------------------------------------------- -import Data.Function ((&)) --------------------------------------------------------------------------------- - -(|>) :: a -> (a -> b) -> b -(|>) = (&) - --- | Rotate `xs` as a cycle `n` times. -rotate :: Int -> [a] -> [a] -rotate n xs = take size . drop (n `mod` size) . cycle $ xs - where size = length xs diff --git a/users/wpcarro/assessments/brilliant/default.nix b/users/wpcarro/assessments/brilliant/default.nix deleted file mode 100644 index 0628679c0..000000000 --- a/users/wpcarro/assessments/brilliant/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ depot, ... }: - -depot.users.wpcarro.buildHaskell.program { - name = "transform-keyboard"; - srcs = builtins.path { - path = ./.; - name = "transform-keyboard-src"; - }; - deps = hpkgs: with hpkgs; [ - optparse-applicative - unordered-containers - split - rio - ]; - ghcExtensions = [ ]; -} diff --git a/users/wpcarro/assessments/brilliant/shell.nix b/users/wpcarro/assessments/brilliant/shell.nix deleted file mode 100644 index e08399c09..000000000 --- a/users/wpcarro/assessments/brilliant/shell.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, ... }: - -pkgs.mkShell { - buildInputs = with pkgs; [ - (haskellPackages.ghcWithPackages (hpkgs: with hpkgs; [ - hspec - optparse-applicative - unordered-containers - split - ])) - ]; -} diff --git a/users/wpcarro/assessments/dotted-squares/.envrc b/users/wpcarro/assessments/dotted-squares/.envrc deleted file mode 100644 index a4a62da52..000000000 --- a/users/wpcarro/assessments/dotted-squares/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -use_nix diff --git a/users/wpcarro/assessments/dotted-squares/.ghci b/users/wpcarro/assessments/dotted-squares/.ghci deleted file mode 100644 index b100af443..000000000 --- a/users/wpcarro/assessments/dotted-squares/.ghci +++ /dev/null @@ -1 +0,0 @@ -:set -Wall diff --git a/users/wpcarro/assessments/dotted-squares/Main.hs b/users/wpcarro/assessments/dotted-squares/Main.hs deleted file mode 100644 index 44f91e2b2..000000000 --- a/users/wpcarro/assessments/dotted-squares/Main.hs +++ /dev/null @@ -1,218 +0,0 @@ -{-# LANGUAGE DeriveGeneric #-} --------------------------------------------------------------------------------- -module Main where --------------------------------------------------------------------------------- -import Data.Hashable -import Data.Function ((&)) -import GHC.Generics -import Text.ParserCombinators.ReadP -import Control.Applicative - -import qualified Data.HashSet as HS --------------------------------------------------------------------------------- - -data Direction - = DirLeft - | DirRight - | DirUp - | DirDown - deriving (Eq, Show) - -data Point = Point Int Int - deriving (Eq, Show, Ord, Generic) -instance Hashable Point - -data Orientation - = Horizontal - | Vertical - deriving (Eq, Show) - -data Anchor - = Beg - | End - deriving (Eq, Show) - -data Rotation - = CW - | CCW - deriving (Eq, Show) - -data Line = Line Point Point - deriving (Show, Generic) -instance Hashable Line - -instance Eq Line where - Line begA endA == Line begB endB = - (begA == begB && endA == endB) || - (begA == endB && endA == begB) - -data Game = Game (HS.HashSet Line) [Line] - deriving (Eq, Show) - -data Scoreboard = Scoreboard Int Int - deriving (Eq) - -instance Semigroup Scoreboard where - (Scoreboard a b) <> (Scoreboard x y) = - Scoreboard (a + x) (b + y) - -instance Monoid Scoreboard where - mempty = Scoreboard 0 0 - -data Turn - = Player1 - | Player2 - deriving (Eq, Show) - -next :: Turn -> Turn -next Player1 = Player2 -next Player2 = Player1 - -instance Show Scoreboard where - show (Scoreboard p1 p2) = - "Player 1: " ++ show (p1) ++ " Player 2: " ++ show (p2) - -digit :: ReadP Char -digit = satisfy (\c -> c >= '0' && c <= '9') - -int :: ReadP Int -int = read <$> many1 digit - -inputLine :: ReadP String -inputLine = manyTill get (char '\n') - -direction :: ReadP Direction -direction = do - c <- char 'L' <|> char 'R' <|> char 'U' <|> char 'D' - case c of - 'L' -> pure DirLeft - 'R' -> pure DirRight - 'U' -> pure DirUp - 'D' -> pure DirDown - _ -> fail $ "Unexpected direction: " ++ show c - -validMove :: Int -> Int -> ReadP Line -validMove w h = do - x <- int - skipSpaces - y <- int - skipSpaces - dir <- direction - _ <- char '\n' - if x >= 0 && x <= w && y >= 0 && y <= h then do - let beg = Point x y - pure $ mkLine beg (shiftPoint dir beg) - else - fail "Expected a move on the game board" - -game :: ReadP Game -game = do - w <- read <$> inputLine - h <- read <$> inputLine - locs <- read <$> inputLine - moves <- count locs (validMove w h) - eof - pure $ Game mempty moves - -parseInput :: String -> Maybe Game -parseInput x = do - case readP_to_S game x of - [(res, "")] -> Just res - _ -> Nothing - --- | Smart constructor to ensure that beg is always < end. -mkLine :: Point -> Point -> Line -mkLine beg end = - if beg < end then Line beg end else Line end beg - -mkLineDir :: Int -> Int -> Direction -> Line -mkLineDir x y dir = - let beg = Point x y - in mkLine beg (shiftPoint dir beg) - -mkLineDir' :: Point -> Direction -> Line -mkLineDir' (Point x y) dir = mkLineDir x y dir - -shiftPoint :: Direction -> Point -> Point -shiftPoint DirLeft (Point x y) = Point (x - 1) y -shiftPoint DirRight (Point x y) = Point (x + 1) y -shiftPoint DirUp (Point x y) = Point x (y + 1) -shiftPoint DirDown (Point x y) = Point x (y - 1) - -shiftLine :: Direction -> Line -> Line -shiftLine dir (Line beg end) = - mkLine (shiftPoint dir beg) (shiftPoint dir end) - -rotateLine :: Anchor -> Rotation -> Line -> Line -rotateLine anchor rotation line = - doRotateLine (classifyOrientation line) anchor rotation line - -doRotateLine :: Orientation -> Anchor -> Rotation -> Line -> Line -doRotateLine Horizontal Beg CW (Line beg _) = mkLineDir' beg DirDown -doRotateLine Horizontal Beg CCW (Line beg _) = mkLineDir' beg DirUp -doRotateLine Horizontal End CW (Line _ end) = mkLineDir' end DirUp -doRotateLine Horizontal End CCW (Line _ end) = mkLineDir' end DirDown -doRotateLine Vertical Beg CW (Line beg _) = mkLineDir' beg DirRight -doRotateLine Vertical Beg CCW (Line beg _) = mkLineDir' beg DirLeft -doRotateLine Vertical End CW (Line _ end) = mkLineDir' end DirLeft -doRotateLine Vertical End CCW (Line _ end) = mkLineDir' end DirRight - -classifyOrientation :: Line -> Orientation -classifyOrientation (Line (Point _ y1) (Point _ y2)) = - if y1 == y2 then Horizontal else Vertical - -closesAnySquare :: HS.HashSet Line -> Line -> Bool -closesAnySquare allMoves line = do - let alreadyDrawn x = HS.member x allMoves - case classifyOrientation line of - Horizontal -> - all alreadyDrawn - [ shiftLine DirUp line - , rotateLine Beg CCW line - , rotateLine End CW line - ] || - all alreadyDrawn - [ shiftLine DirDown line - , rotateLine Beg CW line - , rotateLine End CCW line - ] - Vertical -> - all alreadyDrawn - [ shiftLine DirLeft line - , rotateLine Beg CCW line - , rotateLine End CW line - ] || - all alreadyDrawn - [ shiftLine DirRight line - , rotateLine Beg CW line - , rotateLine End CCW line - ] - -incScoreboard :: Turn -> Scoreboard -> Scoreboard -incScoreboard Player1 score = score <> Scoreboard 1 0 -incScoreboard Player2 score = score <> Scoreboard 0 1 - -scoreGame :: Turn -> Game -> Scoreboard -> Maybe Scoreboard -scoreGame _ (Game _ []) score = Just $ score -scoreGame player (Game allMoves (line:rest)) score = - if HS.member line allMoves then - Nothing - else do - let allMoves' = HS.insert line allMoves - score' = if closesAnySquare allMoves line then - incScoreboard player score - else score - scoreGame (next player) (Game allMoves' rest) score' - -(|>) :: a -> (a -> b) -> b -(|>) = (&) - -main :: IO () -main = do - input <- readFile "game.txt" - case parseInput input of - Nothing -> putStrLn "invalid" - Just parsedGame -> - case scoreGame Player1 parsedGame mempty of - Nothing -> putStrLn "invalid" - Just score -> print score diff --git a/users/wpcarro/assessments/dotted-squares/README.md b/users/wpcarro/assessments/dotted-squares/README.md deleted file mode 100644 index 3d13da1cb..000000000 --- a/users/wpcarro/assessments/dotted-squares/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Dotted Squares - -This is my second attempt at solving this problem. I had an hour to solve it the -first time, and I unfortunately came up short although I made good progress. - -The problem asks to read input from a text file that looks like this: - -``` -1 -- board width -1 -- board height -4 -- number of lines of "moves" (below) -0 0 R -- create a unit vector (0,0) facing right -0 0 U -- create a unit vector (0,0) facing up -0 1 L -- create a unit vector (0,1) facing left -1 1 D -- create a unit vector (1,1) facing down -``` - -After parsing and validating the input, score the outcome a game where players -one and two alternatively take turns drawing lines on a board. Anytime one of -the players draws a line that creates a square from existing lines, they get a -point. diff --git a/users/wpcarro/assessments/dotted-squares/Spec.hs b/users/wpcarro/assessments/dotted-squares/Spec.hs deleted file mode 100644 index b5d604085..000000000 --- a/users/wpcarro/assessments/dotted-squares/Spec.hs +++ /dev/null @@ -1,80 +0,0 @@ --------------------------------------------------------------------------------- -module Spec where --------------------------------------------------------------------------------- -import Test.Hspec -import Main hiding (main) -import qualified Data.HashSet as HS --------------------------------------------------------------------------------- - -main :: IO () -main = hspec $ do - describe "dotted-squares" $ do - describe "parseInput" $ do - it "works as expected" $ do - input <- readFile "input-a.txt" - parseInput input `shouldBe` Just (Game mempty [ mkLine (Point 0 0) (Point 1 0) - , mkLine (Point 0 0) (Point 0 1) - ]) - - it "fails when the game has too many user moves" $ do - input <- readFile "too-many-moves.txt" - parseInput input `shouldBe` Nothing - - it "fails when the game has too few user moves" $ do - input <- readFile "too-few-moves.txt" - parseInput input `shouldBe` Nothing - - describe "shiftLine" $ do - let horizontal = mkLineDir 1 1 DirRight - vertical = mkLineDir 1 1 DirUp - it "can move a horizontal line up" $ - shiftLine DirUp horizontal `shouldBe` mkLineDir 1 2 DirRight - it "can move a horizontal line down" $ - shiftLine DirDown horizontal `shouldBe` mkLineDir 1 0 DirRight - it "can move a horizontal line left" $ - shiftLine DirLeft horizontal `shouldBe` mkLineDir 0 1 DirRight - it "can move a horizontal line right" $ - shiftLine DirRight horizontal `shouldBe` mkLineDir 2 1 DirRight - it "can move a vertical line up" $ - shiftLine DirUp vertical `shouldBe` mkLineDir 1 2 DirUp - it "can move a vertical line down" $ - shiftLine DirDown vertical `shouldBe` mkLineDir 1 0 DirUp - it "can move a vertical line left" $ - shiftLine DirLeft vertical `shouldBe` mkLineDir 0 1 DirUp - it "can move a vertical line right" $ - shiftLine DirRight vertical `shouldBe` mkLineDir 2 1 DirUp - - describe "rotateLine" $ do - let horizontal = mkLineDir 1 1 DirRight -- 1,1;2,1 - vertical = mkLineDir 1 1 DirUp -- 1,1;1,2 - it "can rotate a horizontal line CW anchored at its beginning" $ - rotateLine Beg CW horizontal `shouldBe` mkLineDir 1 1 DirDown - it "can rotate a horizontal line CCW anchored at its beginning" $ - rotateLine Beg CCW horizontal `shouldBe` mkLineDir 1 1 DirUp - it "can rotate a horizontal line CW anchored at its end" $ - rotateLine End CW horizontal `shouldBe` mkLineDir 2 1 DirUp - it "can rotate a horizontal line CCW anchored at its end" $ - rotateLine End CCW horizontal `shouldBe` mkLineDir 2 1 DirDown - - it "can rotate a vertical line CW anchored at its beginning" $ - rotateLine Beg CW vertical `shouldBe` mkLineDir 1 1 DirRight - it "can rotate a vertical line CCW anchored at its beginning" $ - rotateLine Beg CCW vertical `shouldBe` mkLineDir 1 1 DirLeft - it "can rotate a vertical line CW anchored at its end" $ - rotateLine End CW vertical `shouldBe` mkLineDir 1 2 DirLeft - it "can rotate a vertical line CCW anchored at its end" $ - rotateLine End CCW vertical `shouldBe` mkLineDir 1 2 DirRight - - describe "closesAnySquare" $ do - let threeSides = [ (0, 0, DirRight) - , (0, 0, DirUp) - , (0, 1, DirRight) - ] - |> fmap (\(x, y, dir) -> mkLineDir x y dir) - |> HS.fromList - it "returns true the line we supply makes a square" $ - closesAnySquare threeSides (mkLineDir 1 1 DirDown) `shouldBe` True - it "returns false the line we supply doesn't make a square" $ - closesAnySquare threeSides (mkLineDir 1 1 DirUp) `shouldBe` False - it "returns false when we have no existing lines" $ - closesAnySquare mempty (mkLineDir 1 1 DirUp) `shouldBe` False diff --git a/users/wpcarro/assessments/dotted-squares/colliding-moves.txt b/users/wpcarro/assessments/dotted-squares/colliding-moves.txt deleted file mode 100644 index a831fa95c..000000000 --- a/users/wpcarro/assessments/dotted-squares/colliding-moves.txt +++ /dev/null @@ -1,7 +0,0 @@ -1 -1 -4 -0 0 R -0 0 R -0 1 R -0 1 R diff --git a/users/wpcarro/assessments/dotted-squares/game.txt b/users/wpcarro/assessments/dotted-squares/game.txt deleted file mode 100644 index 0af71d1f5..000000000 --- a/users/wpcarro/assessments/dotted-squares/game.txt +++ /dev/null @@ -1,7 +0,0 @@ -1 -1 -4 -0 0 R -0 0 U -0 1 R -1 1 D diff --git a/users/wpcarro/assessments/dotted-squares/input-a.txt b/users/wpcarro/assessments/dotted-squares/input-a.txt deleted file mode 100644 index b9e871ece..000000000 --- a/users/wpcarro/assessments/dotted-squares/input-a.txt +++ /dev/null @@ -1,5 +0,0 @@ -1 -1 -2 -0 0 R -0 0 U diff --git a/users/wpcarro/assessments/dotted-squares/shell.nix b/users/wpcarro/assessments/dotted-squares/shell.nix deleted file mode 100644 index 868668ca5..000000000 --- a/users/wpcarro/assessments/dotted-squares/shell.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ depot, ... }: - -depot.users.wpcarro.buildHaskell.shell { - deps = hpkgs: with hpkgs; [ - hspec - unordered-containers - ]; -} diff --git a/users/wpcarro/assessments/dotted-squares/too-few-moves.txt b/users/wpcarro/assessments/dotted-squares/too-few-moves.txt deleted file mode 100644 index d684679d2..000000000 --- a/users/wpcarro/assessments/dotted-squares/too-few-moves.txt +++ /dev/null @@ -1,6 +0,0 @@ -1 -1 -4 -0 0 R -0 0 U -0 1 R diff --git a/users/wpcarro/assessments/dotted-squares/too-many-moves.txt b/users/wpcarro/assessments/dotted-squares/too-many-moves.txt deleted file mode 100644 index bfcced43b..000000000 --- a/users/wpcarro/assessments/dotted-squares/too-many-moves.txt +++ /dev/null @@ -1,7 +0,0 @@ -1 -1 -3 -0 0 R -0 0 U -0 1 R -1 1 D diff --git a/users/wpcarro/assessments/ramp/solution-emacs-elixir-format.py b/users/wpcarro/assessments/ramp/solution-emacs-elixir-format.py deleted file mode 100644 index d0d948402..000000000 --- a/users/wpcarro/assessments/ramp/solution-emacs-elixir-format.py +++ /dev/null @@ -1,29 +0,0 @@ -# The file '2010.census.txt' contains summary statistics from the 2010 United -# States census including household income. The data is in an unspecified -# format. - -# Find the average of the column called: - -# 'MEDIAN HOUSEHOLD INCOME' - -# Ideally the solution should be a command line script, of the form: - -# $ ./solution [options] [file...] - -# The solution may be written in any language, Python is preferred but not -# required. - -# Google, stack overflow, etc. usage is allowed. - -import requests - -url = "https://assets.tryramp.com/interview/census/2010.census.txt" - -def main(): - res = requests.get(url) - if res.status not in {200}: - raise Exception("Unexpected status code: {}".format(res.status_code)) - # download the content - # parse row - # select 'MEDIAN HOUSEHOLD INCOME' column - pass diff --git a/users/wpcarro/assessments/ramp/solution.py b/users/wpcarro/assessments/ramp/solution.py deleted file mode 100644 index 28060bfb3..000000000 --- a/users/wpcarro/assessments/ramp/solution.py +++ /dev/null @@ -1,87 +0,0 @@ -# The file '2010.census.txt' contains summary statistics from the 2010 United -# States census including household income. The data is in an unspecified -# format. - -# Find the average of the column called: - -# 'MEDIAN HOUSEHOLD INCOME' - -# Ideally the solution should be a command line script, of the form: - -# $ ./solution [options] [file...] - -# The solution may be written in any language, Python is preferred but not -# required. - -# Google, stack overflow, etc. usage is allowed. - -import requests -import csv - -url = "https://assets.tryramp.com/interview/census/2010.census.txt" -column = 'MEDIAN HOUSEHOLD INCOME' -columns = [ - 'CENSUS YEAR', - 'TRACT', - 'BLOCK GROUP', - 'FIPS ID', - 'TOTAL POPULATION', - 'POPULATION WHITE', - 'POPULATION BLACK', - 'POPULATION ASIAN', - 'POPULATION OTHER', - 'POPULATION AMERICAN INDIAN', - 'POPULATION PACIFIC ISLANDER', - 'POPULATION ONE RACE', - 'POPULATION MULTI RACE', - 'POPULATION 25 OLDER', - 'MEDIAN AGE', - 'MEDIAN HOUSEHOLD INCOME', - 'HIGH SCHOOL MALE', - 'HIGH SCHOOL MORE MALE', - 'COLLEGE 1 YR LESS MALE', - 'COLLEGE 1 YR MORE MALE', - 'ASSOCIATES DEGREE MALE', - 'BACHELORS DEGREE MALE', - 'MASTERS DEGREE MALE', - 'PROFESSIONAL DEGREE MALE', - 'DOCTORAL DEGREE MALE', - 'HIGH SCHOOL FEMALE', - 'HIGH SCHOOL MORE FEMALE', - 'COLLEGE 1 YR LESS FEMALE', - 'COLLEGE 1 YR MORE FEMALE', - 'ASSOCIATES DEGREE FEMALE', - 'BACHELORS DEGREE FEMALE', - 'MASTERS DEGREE FEMALE', - 'PROFESSIONAL DEGREE FEMALE', - 'DOCTORAL DEGREE FEMALE', - 'PERCENT 25 YR OVER HIGH SCHOOL MORE', - 'HOUSING UNITS', - 'OCCUPIED HOUSING UNITS', - 'OWNER OCCUPIED HOUSING', - 'RENTER OCCUPIED HOUSING', - 'PERCENT OWNER OCCUPIED', - 'PERCENT RENTER OCCUPIED', - 'MEDIAN HOUSE VALUE OWNER OCCUPIED', - 'MEDIAN YEAR BUILT', - 'VACANCY RATES', -] - - -def average(xs): - return sum(xs) / len(xs) - - -def parse_body(body): - return list(csv.DictReader(body.split('\n')[1:], delimiter='|', fieldnames=columns)) - - -def main(): - res = requests.get(url) - if res.status_code not in {200}: - raise Exception("Unexpected status code: {}".format(res.status_code)) - return average([int(d.get(column)) - for d in parse_body(res.text) - if int(d.get(column)) >= 0]) - -print(main()) diff --git a/users/wpcarro/assessments/semiprimes/.gitignore b/users/wpcarro/assessments/semiprimes/.gitignore deleted file mode 100644 index b5b25bd64..000000000 --- a/users/wpcarro/assessments/semiprimes/.gitignore +++ /dev/null @@ -1 +0,0 @@ -default.nix diff --git a/users/wpcarro/assessments/semiprimes/README.md b/users/wpcarro/assessments/semiprimes/README.md deleted file mode 100644 index 7d5a15482..000000000 --- a/users/wpcarro/assessments/semiprimes/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# Semiprimes Service - -## Introduction - -A **composite** is a number containing at least two prime factors. For example: - -``` -15 = 3 × 5 -9 = 3 × 3 -12 = 2 × 2 × 3 -``` - -There are ten composites below thirty containing precisely two, not necessarily -distinct, prime factors: `4, 6, 9, 10, 14, 15, 21, 22, 25, 26`. Let’s call such -numbers *Semiprimes*. - -## Task - -- Write a module which provides a function to tell whether a given number, `N`, - is a semiprime. `N` will be less than 100,000 -- Please implement an API (RESTful or GraphQL) to factor a given number into two - prime numbers if it’s a semiprime, otherwise, return an error message. - -## Stretch Goals - -- Handle the invalid inputs. -- Support batch requests: i.e. users could provide 100 numbers, and the API - return the answer for all. -- Considering this module will be used by a long running service, could you - optimize it to give answers faster? - -## Usage - -To run the application you'll need to have `elixir` installed. Assuming `elixir` -is already installed, consult the following steps to start the application: - -```shell -$ cd server -$ mix deps.get -$ iex -S mix -``` - -Now open a web browser and visit `http://localhost:8080`! - diff --git a/users/wpcarro/assessments/semiprimes/server/.formatter.exs b/users/wpcarro/assessments/semiprimes/server/.formatter.exs deleted file mode 100644 index d2cda26ed..000000000 --- a/users/wpcarro/assessments/semiprimes/server/.formatter.exs +++ /dev/null @@ -1,4 +0,0 @@ -# Used by "mix format" -[ - inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] -] diff --git a/users/wpcarro/assessments/semiprimes/server/.gitignore b/users/wpcarro/assessments/semiprimes/server/.gitignore deleted file mode 100644 index db9704a85..000000000 --- a/users/wpcarro/assessments/semiprimes/server/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# The directory Mix will write compiled artifacts to. -/_build/ - -# If you run "mix test --cover", coverage assets end up here. -/cover/ - -# The directory Mix downloads your dependencies sources to. -/deps/ - -# Where third-party dependencies like ExDoc output generated docs. -/doc/ - -# Ignore .fetch files in case you like to edit your project deps locally. -/.fetch - -# If the VM crashes, it generates a dump, let's ignore it too. -erl_crash.dump - -# Also ignore archive artifacts (built via "mix archive.build"). -*.ez - -# Ignore package tarball (built via "mix hex.build"). -server-*.tar - diff --git a/users/wpcarro/assessments/semiprimes/server/lib/app.ex b/users/wpcarro/assessments/semiprimes/server/lib/app.ex deleted file mode 100644 index 7a6fa5ea2..000000000 --- a/users/wpcarro/assessments/semiprimes/server/lib/app.ex +++ /dev/null @@ -1,8 +0,0 @@ -defmodule App do - use Application - - @impl true - def start(_type, _args) do - Sup.start_link() - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/lib/cache.ex b/users/wpcarro/assessments/semiprimes/server/lib/cache.ex deleted file mode 100644 index cd064cc1a..000000000 --- a/users/wpcarro/assessments/semiprimes/server/lib/cache.ex +++ /dev/null @@ -1,41 +0,0 @@ -defmodule Cache do - @moduledoc """ - Cache is an in-memory key-value store. - """ - use Agent - - @doc """ - Inititalize the key-value store. - """ - def start_link(_) do - Agent.start_link(fn -> %{} end, name: __MODULE__) - end - - @doc """ - Attempt to return the value stored at `key` - """ - def get(key) do - Agent.get(__MODULE__, &Map.get(&1, key)) - end - - @doc """ - Write the `value` under the `key`. Last writer wins. - """ - def put(key, value) do - Agent.update(__MODULE__, &Map.put(&1, key, value)) - end - - @doc """ - List the contents of the cache. Useful for debugging purposes. - """ - def list() do - Agent.get(__MODULE__, & &1) - end - - @doc """ - Invalidate the entire cache. - """ - def clear() do - Agent.update(__MODULE__, fn _ -> %{} end) - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/lib/extras.ex b/users/wpcarro/assessments/semiprimes/server/lib/extras.ex deleted file mode 100644 index f0c2ea4b9..000000000 --- a/users/wpcarro/assessments/semiprimes/server/lib/extras.ex +++ /dev/null @@ -1,22 +0,0 @@ -defmodule Extras do - @moduledoc """ - Hosts utility functions intended to supplement the standard library. - """ - - @doc """ - Return an ascending range starting at `a` and ending at `b` (exclusive). - - ## Examples - - iex> Extras.range(2, 5) - [2, 3, 4] - - """ - def range(a, b) do - if b <= a do - [] - else - [a] ++ range(a + 1, b) - end - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/lib/math.ex b/users/wpcarro/assessments/semiprimes/server/lib/math.ex deleted file mode 100644 index 8a33be475..000000000 --- a/users/wpcarro/assessments/semiprimes/server/lib/math.ex +++ /dev/null @@ -1,26 +0,0 @@ -defmodule Math do - @moduledoc """ - Math utilities. - """ - alias Extras - - @doc """ - Returns the prime factors for `n`. - - ## Examples - - iex> Math.factor(15) - [3, 5] - - """ - def factor(1), do: [] - - def factor(n) do - Extras.range(2, n - 1) - |> Enum.find(&(rem(n, &1) == 0)) - |> case do - nil -> [n] - x -> [x | factor(div(n, x))] - end - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/lib/router.ex b/users/wpcarro/assessments/semiprimes/server/lib/router.ex deleted file mode 100644 index cb5552092..000000000 --- a/users/wpcarro/assessments/semiprimes/server/lib/router.ex +++ /dev/null @@ -1,86 +0,0 @@ -defmodule Router do - use Plug.Router - use Plug.Debugger - require Logger - - plug(Plug.Logger, log: :debug) - plug(Plug.Parsers, parsers: [:urlencoded]) - plug(:match) - plug(:dispatch) - - @usage """ - Usage: Try querying some of the following endpoints... - GET / - GET /help - GET /semiprime?number= - GET /semiprimes?numbers= - """ - - get "/" do - send_resp(conn, 200, "Welcome to Semiprimes Service!\n\n#{@usage}") - end - - get "/help" do - send_resp(conn, 200, @usage) - end - - get "/semiprime" do - case conn |> Map.get(:query_params) |> Map.get("number") do - nil -> - send_resp(conn, 400, "You must pass an integer as a query parameter. #{@usage}") - - val -> - case Integer.parse(val) do - {n, ""} -> - send_resp(conn, 200, semiprime_response(n)) - - _ -> - send_resp(conn, 400, "We could not parse the number you provided.\n\n#{@usage}") - end - end - end - - get "/semiprimes" do - case conn |> Map.get(:query_params) |> Map.get("numbers") do - nil -> - send_resp( - conn, - 400, - "You must pass a comma-separated list of integers as a query parameter.\n\n#{@usage}" - ) - - xs -> - response = - xs - |> String.split(",") - |> Stream.map(&Integer.parse/1) - |> Stream.filter(fn - {n, ""} -> true - _ -> false - end) - |> Stream.map(fn {n, ""} -> semiprime_response(n) end) - |> Enum.join("\n") - - send_resp(conn, 200, response) - end - end - - match _ do - send_resp(conn, 404, "Not found.") - end - - ################################################################################ - # Utils - ################################################################################ - - defp semiprime_response(n) do - case Server.semiprime(n) do - nil -> - "#{n} is not a semiprime. Try another number!" - - {hit_or_miss, factors} -> - response = "#{n} is a semiprime! Its factors are #{Enum.join(factors, " and ")}." - "Cache #{Atom.to_string(hit_or_miss)} - #{response}" - end - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/lib/server.ex b/users/wpcarro/assessments/semiprimes/server/lib/server.ex deleted file mode 100644 index 7ab5e905b..000000000 --- a/users/wpcarro/assessments/semiprimes/server/lib/server.ex +++ /dev/null @@ -1,33 +0,0 @@ -defmodule Server do - @moduledoc """ - Documentation for `Server`. - """ - - @doc """ - If `n` contains exactly two prime factors, return those prime factors; - otherwise, return nothing. - """ - def semiprime(n) do - case Cache.get(n) do - nil -> - case do_semiprime(n) do - nil -> - nil - - res -> - Cache.put(n, res) - {:miss, res} - end - - hit -> - {:hit, hit} - end - end - - defp do_semiprime(n) do - case Math.factor(n) do - [_, _] = res -> res - _ -> nil - end - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/lib/sup.ex b/users/wpcarro/assessments/semiprimes/server/lib/sup.ex deleted file mode 100644 index 13a6ab374..000000000 --- a/users/wpcarro/assessments/semiprimes/server/lib/sup.ex +++ /dev/null @@ -1,23 +0,0 @@ -defmodule Sup do - @moduledoc """ - Top-level supervisor for our OTP application. For now, this supervisor starts - and monitors our cache. - """ - - use Supervisor - alias Plug.Adapters.Cowboy - - def start_link(opts \\ []) do - Supervisor.start_link(__MODULE__, :ok, opts) - end - - @impl true - def init(:ok) do - children = [ - Cache, - Cowboy.child_spec(scheme: :http, plug: Router, options: [port: 8000]) - ] - - Supervisor.init(children, strategy: :one_for_one) - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/mix.exs b/users/wpcarro/assessments/semiprimes/server/mix.exs deleted file mode 100644 index 9062f927e..000000000 --- a/users/wpcarro/assessments/semiprimes/server/mix.exs +++ /dev/null @@ -1,32 +0,0 @@ -defmodule Server.MixProject do - use Mix.Project - - def project do - [ - app: :server, - version: "0.1.0", - elixir: "~> 1.10", - start_permanent: Mix.env() == :prod, - deps: deps() - ] - end - - # Run "mix help compile.app" to learn about applications. - def application do - [ - extra_applications: [:logger], - mod: {App, []} - ] - end - - # Run "mix help deps" to learn about dependencies. - defp deps do - [ - {:cortex, "~> 0.1", only: [:dev, :test]}, - {:plug_cowboy, "~> 2.4.1"}, - {:cowboy, "~> 2.8.0"}, - {:plug, "~> 1.11.0"}, - {:poison, "~> 4.0.1"} - ] - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/mix.lock b/users/wpcarro/assessments/semiprimes/server/mix.lock deleted file mode 100644 index 2ae7efbb3..000000000 --- a/users/wpcarro/assessments/semiprimes/server/mix.lock +++ /dev/null @@ -1,14 +0,0 @@ -%{ - "cortex": {:hex, :cortex, "0.6.0", "8094830fae266eb0ae34d1a58983c0c49484341f5044fb4dfb81746647bd2993", [:mix], [{:file_system, "~> 0.2", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "d0ef5a2b1269626149118684dc4ea77dbfbc67017f4b4065b71dcefa26cfcc49"}, - "cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"}, - "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"}, - "cowlib": {:hex, :cowlib, "2.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"}, - "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "mime": {:hex, :mime, "1.5.0", "203ef35ef3389aae6d361918bf3f952fa17a09e8e43b5aa592b93eba05d0fb8d", [:mix], [], "hexpm", "55a94c0f552249fc1a3dd9cd2d3ab9de9d3c89b559c2bd01121f824834f24746"}, - "plug": {:hex, :plug, "1.11.0", "f17217525597628298998bc3baed9f8ea1fa3f1160aa9871aee6df47a6e4d38e", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2d9c633f0499f9dc5c2fd069161af4e2e7756890b81adcbb2ceaa074e8308876"}, - "plug_cowboy": {:hex, :plug_cowboy, "2.4.1", "779ba386c0915027f22e14a48919a9545714f849505fa15af2631a0d298abf0f", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d72113b6dff7b37a7d9b2a5b68892808e3a9a752f2bf7e503240945385b70507"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.0", "1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm", "a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"}, - "poison": {:hex, :poison, "4.0.1", "bcb755a16fac91cad79bfe9fc3585bb07b9331e50cfe3420a24bcc2d735709ae", [:mix], [], "hexpm", "ba8836feea4b394bb718a161fc59a288fe0109b5006d6bdf97b6badfcf6f0f25"}, - "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"}, - "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"}, -} diff --git a/users/wpcarro/assessments/semiprimes/server/test/extras_test.exs b/users/wpcarro/assessments/semiprimes/server/test/extras_test.exs deleted file mode 100644 index 67d0b8875..000000000 --- a/users/wpcarro/assessments/semiprimes/server/test/extras_test.exs +++ /dev/null @@ -1,18 +0,0 @@ -defmodule ExtrasTest do - use ExUnit.Case - doctest Extras - - describe "range" do - test "returns an empty list for descending sequences" do - assert Extras.range(0, -2) == [] - end - - test "returns an empty list for non-ascending sequences" do - assert Extras.range(8, 8) == [] - end - - test "returns an exclusive range" do - assert Extras.range(3, 6) == [3, 4, 5] - end - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/test/math_test.exs b/users/wpcarro/assessments/semiprimes/server/test/math_test.exs deleted file mode 100644 index c7186c824..000000000 --- a/users/wpcarro/assessments/semiprimes/server/test/math_test.exs +++ /dev/null @@ -1,30 +0,0 @@ -defmodule MathTest do - use ExUnit.Case - doctest Math - - describe "factor" do - test "returns the prime factors for an input" do - [ - {15, [3, 5]}, - {12, [2, 2, 3]}, - {9, [3, 3]}, - {21, [3, 7]} - ] - |> Enum.map(fn {input, expected} -> - assert Math.factor(input) == expected - end) - end - - test "handles large numbers" do - assert Math.factor(104_023) == [17, 29, 211] - end - - test "returns an empty list for 1" do - assert Math.factor(1) == [] - end - - test "returns the prime number itself when the input is prime" do - assert Math.factor(7) == [7] - end - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/test/server_test.exs b/users/wpcarro/assessments/semiprimes/server/test/server_test.exs deleted file mode 100644 index 08d559734..000000000 --- a/users/wpcarro/assessments/semiprimes/server/test/server_test.exs +++ /dev/null @@ -1,34 +0,0 @@ -defmodule ServerTest do - use ExUnit.Case - doctest Server - - describe "semiprime" do - test "returns the factors when the number is semiprime" do - Cache.clear() - # Semiprimes below 30 - [ - {4, [2, 2]}, - {6, [2, 3]}, - {9, [3, 3]}, - {10, [2, 5]}, - {14, [2, 7]}, - {15, [3, 5]}, - {21, [3, 7]}, - {22, [2, 11]}, - {25, [5, 5]}, - {26, [2, 13]} - ] - |> Enum.each(fn {input, expected} -> - assert Server.semiprime(input) == {:miss, expected} - end) - end - - test "returns nothing when the number is a composite number" do - # Composite numbers below 30 - [1, 2, 3, 5, 7, 8, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, 27, 28, 29] - |> Enum.each(fn x -> - assert Server.semiprime(x) == nil - end) - end - end -end diff --git a/users/wpcarro/assessments/semiprimes/server/test/test_helper.exs b/users/wpcarro/assessments/semiprimes/server/test/test_helper.exs deleted file mode 100644 index 869559e70..000000000 --- a/users/wpcarro/assessments/semiprimes/server/test/test_helper.exs +++ /dev/null @@ -1 +0,0 @@ -ExUnit.start() diff --git a/users/wpcarro/assessments/tt/.gitignore b/users/wpcarro/assessments/tt/.gitignore deleted file mode 100644 index d4d62d436..000000000 --- a/users/wpcarro/assessments/tt/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.envrc -*.db -*.sqlite3 -!populate.sqlite3 -*.db-shm -*.db-wal \ No newline at end of file diff --git a/users/wpcarro/assessments/tt/README.md b/users/wpcarro/assessments/tt/README.md deleted file mode 100644 index 0231ef3ab..000000000 --- a/users/wpcarro/assessments/tt/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# TT - -All of the commands defined herein should be run from the top-level directory of -this repository (i.e. the directory in which this file exists). - -## Server - -To create the environment that contains all of this application's dependencies, -run: - -```shell -$ nix-shell -``` - -To run the server interactively, run: - -```shell -$ cd src/ -$ ghci -``` - -Now compile and load the server with: - -``` -Prelude> :l Main.hs -*Main> main -``` - -## Database - -Create a new database named `db.sqlite3` with: - -```shell -$ sqlite3 db.sqlite3 -``` - -Populate the database with: - -``` -sqlite3> .read populate.sqlite3 -``` - -You can verify that everything is setup with: - -``` -sqlite3> .tables -sqlite3> .schema -sqlite3> SELECT * FROM Accounts; -sqlite3> SELECT * FROM Trips; -``` diff --git a/users/wpcarro/assessments/tt/client/.gitignore b/users/wpcarro/assessments/tt/client/.gitignore deleted file mode 100644 index 1cb4f3034..000000000 --- a/users/wpcarro/assessments/tt/client/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/elm-stuff -/Main.min.js -/output.css diff --git a/users/wpcarro/assessments/tt/client/README.md b/users/wpcarro/assessments/tt/client/README.md deleted file mode 100644 index 04804ad94..000000000 --- a/users/wpcarro/assessments/tt/client/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Elm - -Elm has one of the best developer experiences that I'm aware of. The error -messages are helpful and the entire experience is optimized to improve the ease -of writing web applications. - -## Developing - -If you're interested in contributing, the following will create an environment -in which you can develop: - -```shell -$ nix-shell -$ npx tailwindcss build index.css -o output.css -$ elm-live -- src/Main.elm --output=Main.min.js -``` - -You can now view your web client at `http://localhost:8000`! diff --git a/users/wpcarro/assessments/tt/client/elm.json b/users/wpcarro/assessments/tt/client/elm.json deleted file mode 100644 index c4095e118..000000000 --- a/users/wpcarro/assessments/tt/client/elm.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "type": "application", - "source-directories": [ - "src" - ], - "elm-version": "0.19.1", - "dependencies": { - "direct": { - "CurrySoftware/elm-datepicker": "4.0.0", - "elm/browser": "1.0.2", - "elm/core": "1.0.5", - "elm/html": "1.0.0", - "elm/http": "2.0.0", - "elm/json": "1.1.3", - "elm/random": "1.0.0", - "elm/svg": "1.0.1", - "elm/time": "1.0.0", - "elm/url": "1.0.0", - "elm-community/json-extra": "4.2.0", - "elm-community/list-extra": "8.2.3", - "elm-community/maybe-extra": "5.2.0", - "elm-community/random-extra": "3.1.0", - "justinmimbs/date": "3.2.1", - "krisajenkins/remotedata": "6.0.1", - "ryannhg/date-format": "2.3.0" - }, - "indirect": { - "elm/bytes": "1.0.8", - "elm/file": "1.0.5", - "elm/parser": "1.1.0", - "elm/virtual-dom": "1.0.2", - "owanturist/elm-union-find": "1.0.0", - "rtfeldman/elm-iso8601-date-strings": "1.1.3" - } - }, - "test-dependencies": { - "direct": {}, - "indirect": {} - } -} diff --git a/users/wpcarro/assessments/tt/client/index.css b/users/wpcarro/assessments/tt/client/index.css deleted file mode 100644 index 52114e0e9..000000000 --- a/users/wpcarro/assessments/tt/client/index.css +++ /dev/null @@ -1,142 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -.elm-datepicker--container { - position: relative; -} - -.elm-datepicker--input:focus { - outline: 0; -} - -.elm-datepicker--picker { - position: absolute; - border: 1px solid #CCC; - z-index: 10; - background-color: white; -} - -.elm-datepicker--picker-header, -.elm-datepicker--weekdays { - background: #F2F2F2; -} - -.elm-datepicker--picker-header { - display: flex; - align-items: center; -} - -.elm-datepicker--prev-container, -.elm-datepicker--next-container { - flex: 0 1 auto; - cursor: pointer; -} - -.elm-datepicker--month-container { - flex: 1 1 auto; - padding: 0.5em; - display: flex; - flex-direction: column; -} - -.elm-datepicker--month, -.elm-datepicker--year { - flex: 1 1 auto; - cursor: default; - text-align: center; -} - -.elm-datepicker--year { - font-size: 0.6em; - font-weight: 700; -} - -.elm-datepicker--prev, -.elm-datepicker--next { - border: 6px solid transparent; - background-color: inherit; - display: block; - width: 0; - height: 0; - padding: 0 0.2em; -} - -.elm-datepicker--prev { - border-right-color: #AAA; -} - -.elm-datepicker--prev:hover { - border-right-color: #BBB; -} - -.elm-datepicker--next { - border-left-color: #AAA; -} - -.elm-datepicker--next:hover { - border-left-color: #BBB; -} - -.elm-datepicker--table { - border-spacing: 0; - border-collapse: collapse; - font-size: 0.8em; -} - -.elm-datepicker--table td { - width: 2em; - height: 2em; - text-align: center; -} - -.elm-datepicker--row { - border-top: 1px solid #F2F2F2; -} - -.elm-datepicker--dow { - border-bottom: 1px solid #CCC; - cursor: default; -} - -.elm-datepicker--day { - cursor: pointer; -} - -.elm-datepicker--day:hover { - background: #F2F2F2; -} - -.elm-datepicker--disabled { - cursor: default; - color: #DDD; -} - -.elm-datepicker--disabled:hover { - background: inherit; -} - -.elm-datepicker--picked { - color: white; - background: darkblue; -} - -.elm-datepicker--picked:hover { - background: darkblue; -} - -.elm-datepicker--today { - font-weight: bold; -} - -.elm-datepicker--other-month { - color: #AAA; -} - -.elm-datepicker--other-month.elm-datepicker--disabled { - color: #EEE; -} - -.elm-datepicker--other-month.elm-datepicker--picked { - color: white; -} diff --git a/users/wpcarro/assessments/tt/client/index.html b/users/wpcarro/assessments/tt/client/index.html deleted file mode 100644 index 9e6cef70d..000000000 --- a/users/wpcarro/assessments/tt/client/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - Elm SPA - - - - - - -
    - - - diff --git a/users/wpcarro/assessments/tt/client/print.css b/users/wpcarro/assessments/tt/client/print.css deleted file mode 100644 index 3cfb27923..000000000 --- a/users/wpcarro/assessments/tt/client/print.css +++ /dev/null @@ -1,3 +0,0 @@ -.no-print { - display: none; -} diff --git a/users/wpcarro/assessments/tt/client/shell.nix b/users/wpcarro/assessments/tt/client/shell.nix deleted file mode 100644 index 78f55385d..000000000 --- a/users/wpcarro/assessments/tt/client/shell.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ pkgs, ... }: - -pkgs.mkShell { - buildInputs = with pkgs; [ - nodejs - elmPackages.elm - elmPackages.elm-format - elmPackages.elm-live - ]; -} diff --git a/users/wpcarro/assessments/tt/client/src/Admin.elm b/users/wpcarro/assessments/tt/client/src/Admin.elm deleted file mode 100644 index d95609ee1..000000000 --- a/users/wpcarro/assessments/tt/client/src/Admin.elm +++ /dev/null @@ -1,189 +0,0 @@ -module Admin exposing (render) - -import Common -import Date -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import Maybe.Extra as ME -import RemoteData -import State -import Tailwind -import UI -import Utils - - -roleToggle : State.Model -> State.Role -> Html State.Msg -roleToggle model role = - div [ [ "px-1", "inline" ] |> Tailwind.use |> class ] - [ UI.toggleButton - { toggled = model.inviteRole == Just role - , label = State.roleToString role - , handleEnable = State.UpdateInviteRole (Just role) - , handleDisable = State.UpdateInviteRole Nothing - } - ] - - -inviteUser : State.Model -> Html State.Msg -inviteUser model = - div [ [ "pb-6" ] |> Tailwind.use |> class ] - [ UI.header 3 "Invite a user" - , UI.textField - { handleInput = State.UpdateInviteEmail - , inputId = "invite-email" - , inputValue = model.inviteEmail - , pholder = "Email..." - } - , div [ [ "pt-4" ] |> Tailwind.use |> class ] - [ roleToggle model State.User - , roleToggle model State.Manager - , roleToggle model State.Admin - ] - , UI.baseButton - { enabled = - List.all - identity - [ String.length model.inviteEmail > 0 - , ME.isJust model.inviteRole - ] - , extraClasses = [ "my-4" ] - , label = - case model.inviteResponseStatus of - RemoteData.Loading -> - "Sending..." - - _ -> - "Send invitation" - , handleClick = - case model.inviteRole of - Nothing -> - State.DoNothing - - Just role -> - State.AttemptInviteUser role - } - ] - - -allTrips : State.Model -> Html State.Msg -allTrips model = - case model.trips of - RemoteData.NotAsked -> - UI.absentData { handleFetch = State.AttemptGetTrips } - - RemoteData.Loading -> - UI.paragraph "Loading..." - - RemoteData.Failure e -> - UI.paragraph ("Error: " ++ Utils.explainHttpError e) - - RemoteData.Success xs -> - ul [] - (xs - |> List.map - (\trip -> - li [] - [ UI.paragraph (Date.toIsoString trip.startDate ++ " - " ++ Date.toIsoString trip.endDate ++ ", " ++ trip.username ++ " is going " ++ trip.destination) - , UI.textButton - { label = "delete" - , handleClick = State.AttemptDeleteTrip trip - } - ] - ) - ) - - -allUsers : State.Model -> Html State.Msg -allUsers model = - case model.accounts of - RemoteData.NotAsked -> - UI.absentData { handleFetch = State.AttemptGetAccounts } - - RemoteData.Loading -> - UI.paragraph "Loading..." - - RemoteData.Failure e -> - UI.paragraph ("Error: " ++ Utils.explainHttpError e) - - RemoteData.Success xs -> - ul [] - (xs - |> List.map - (\account -> - li [] - [ UI.paragraph - (account.username - ++ " - " - ++ State.roleToString account.role - ) - , UI.textButton - { label = "delete" - , handleClick = State.AttemptDeleteAccount account.username - } - ] - ) - ) - - -users : List String -> Html State.Msg -users xs = - ul [] - (xs - |> List.map - (\x -> - li [ [ "py-4", "flex" ] |> Tailwind.use |> class ] - [ p [ [ "flex-1" ] |> Tailwind.use |> class ] [ text x ] - , div [ [ "flex-1" ] |> Tailwind.use |> class ] - [ UI.simpleButton - { label = "Delete" - , handleClick = State.AttemptDeleteAccount x - } - ] - ] - ) - ) - - -render : State.Model -> Html State.Msg -render model = - div - [ [ "container" - , "mx-auto" - , "text-center" - ] - |> Tailwind.use - |> class - ] - [ UI.header 2 "Welcome!" - , div [] - [ UI.textButton - { label = "Logout" - , handleClick = State.AttemptLogout - } - ] - , div [ [ "py-3" ] |> Tailwind.use |> class ] - [ case model.adminTab of - State.Accounts -> - UI.textButton - { label = "Switch to trips" - , handleClick = State.UpdateAdminTab State.Trips - } - - State.Trips -> - UI.textButton - { label = "Switch to accounts" - , handleClick = State.UpdateAdminTab State.Accounts - } - ] - , case model.adminTab of - State.Accounts -> - div [] - [ inviteUser model - , allUsers model - ] - - State.Trips -> - allTrips model - , Common.allErrors model - ] diff --git a/users/wpcarro/assessments/tt/client/src/Common.elm b/users/wpcarro/assessments/tt/client/src/Common.elm deleted file mode 100644 index 63ba97b79..000000000 --- a/users/wpcarro/assessments/tt/client/src/Common.elm +++ /dev/null @@ -1,37 +0,0 @@ -module Common exposing (..) - -import Html exposing (..) -import Maybe.Extra as ME -import State -import UI -import Utils - - -allErrors : State.Model -> Html State.Msg -allErrors model = - div [] - (State.allErrors - model - |> List.map - (\( mError, title ) -> - case mError of - Nothing -> - text "" - - Just err -> - UI.errorBanner - { title = title - , body = Utils.explainHttpError err - } - ) - ) - - -withSession : State.Model -> (State.Session -> Html State.Msg) -> Html State.Msg -withSession model renderWithSession = - case model.session of - Nothing -> - div [] [ UI.paragraph "You need a valid session to view this page. Please attempt to log in." ] - - Just session -> - renderWithSession session diff --git a/users/wpcarro/assessments/tt/client/src/Login.elm b/users/wpcarro/assessments/tt/client/src/Login.elm deleted file mode 100644 index b1a436098..000000000 --- a/users/wpcarro/assessments/tt/client/src/Login.elm +++ /dev/null @@ -1,199 +0,0 @@ -module Login exposing (render) - -import Common -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import State -import Tailwind -import UI -import Utils - - -googleSignIn : Html State.Msg -googleSignIn = - div - [ class "g-signin2" - , attribute "onsuccess" "onSignIn" - , onClick State.GoogleSignIn - ] - [] - - -loginForm : State.Model -> Html State.Msg -loginForm model = - div - [ [ "w-full" - , "max-w-xs" - , "mx-auto" - ] - |> Tailwind.use - |> class - ] - [ div - [ [ "bg-white" - , "shadow-md" - , "rounded" - , "px-8" - , "pt-6" - , "pb-8" - , "mb-4" - , "text-left" - ] - |> Tailwind.use - |> class - ] - [ div [ [ "text-center", "pb-6" ] |> Tailwind.use |> class ] - [ UI.textButton - { handleClick = State.ToggleLoginForm - , label = - case model.loginTab of - State.LoginForm -> - "Switch to sign up" - - State.SignUpForm -> - "Switch to login" - } - ] - , div - [ [ "mb-4" ] |> Tailwind.use |> class ] - [ UI.label_ { for_ = "username", text_ = "Username" } - , UI.textField - { inputId = "Username" - , pholder = "Username" - , handleInput = State.UpdateUsername - , inputValue = model.username - } - ] - , case model.loginTab of - State.LoginForm -> - text "" - - State.SignUpForm -> - div - [ [ "mb-4" ] |> Tailwind.use |> class ] - [ UI.label_ { for_ = "email", text_ = "Email" } - , input - [ [ "shadow" - , "appearance-none" - , "border" - , "rounded" - , "w-full" - , "py-2" - , "px-3" - , "text-gray-700" - , "leading-tight" - , "focus:outline-none" - , "focus:shadow-outline" - ] - |> Tailwind.use - |> class - , id "email" - , placeholder "who@domain.tld" - , onInput State.UpdateEmail - ] - [] - ] - , div - [ [ "mb-4" ] |> Tailwind.use |> class ] - [ UI.label_ { for_ = "password", text_ = "Password" } - , input - [ [ "shadow" - , "appearance-none" - , "border" - , "rounded" - , "w-full" - , "py-2" - , "px-3" - , "text-gray-700" - , "leading-tight" - , "focus:outline-none" - , "focus:shadow-outline" - ] - |> Tailwind.use - |> class - , id "password" - , type_ "password" - , placeholder "******************" - , onInput State.UpdatePassword - ] - [] - ] - , case model.loginTab of - State.LoginForm -> - div [ [ "flex", "space-around" ] |> Tailwind.use |> class ] - [ UI.simpleButton - { handleClick = State.AttemptLogin - , label = "Login" - } - , div [ [ "pl-4" ] |> Tailwind.use |> class ] [ googleSignIn ] - ] - - State.SignUpForm -> - if - List.all identity - [ String.length model.username > 0 - , String.length model.email > 0 - , String.length model.password > 0 - ] - then - div [] - [ UI.simpleButton - { handleClick = State.AttemptSignUp - , label = "Sign up" - } - ] - - else - UI.disabledButton { label = "Sign up" } - ] - ] - - -login : - State.Model - -> Html State.Msg -login model = - div - [ [ "text-center" - , "py-20" - , "bg-gray-200" - , "h-screen" - ] - |> Tailwind.use - |> class - ] - [ UI.header 3 "Welcome to Trip Planner" - , loginForm model - , Common.allErrors model - ] - - -logout : State.Model -> Html State.Msg -logout model = - div - [ [ "text-center" - , "py-20" - , "bg-gray-200" - , "h-screen" - ] - |> Tailwind.use - |> class - ] - [ UI.header 3 "Looks like you're already signed in..." - , UI.simpleButton - { label = "Logout" - , handleClick = State.AttemptLogout - } - , Common.allErrors model - ] - - -render : State.Model -> Html State.Msg -render model = - case model.session of - Nothing -> - login model - - Just x -> - logout model diff --git a/users/wpcarro/assessments/tt/client/src/Main.elm b/users/wpcarro/assessments/tt/client/src/Main.elm deleted file mode 100644 index de71a72db..000000000 --- a/users/wpcarro/assessments/tt/client/src/Main.elm +++ /dev/null @@ -1,62 +0,0 @@ -module Main exposing (main) - -import Admin -import Browser -import Html exposing (..) -import Login -import Manager -import State -import Url -import User - - -viewForRoute : State.Route -> (State.Model -> Html State.Msg) -viewForRoute route = - case route of - State.Login -> - Login.render - - State.UserHome -> - User.render - - State.ManagerHome -> - Manager.render - - State.AdminHome -> - Admin.render - - -view : State.Model -> Browser.Document State.Msg -view model = - { title = "TripPlanner" - , body = - [ case ( model.session, model.route ) of - -- Redirect to /login when someone is not authenticated. - -- TODO(wpcarro): We should ensure that /login shows in the URL - -- bar. - ( Nothing, _ ) -> - Login.render model - - ( Just session, Nothing ) -> - Login.render model - - -- Authenticated - ( Just session, Just route ) -> - if State.isAuthorized session.role route then - viewForRoute route model - - else - text "Access denied. You are not authorized to be here. Evacuate the area immediately" - ] - } - - -main = - Browser.application - { init = State.init - , onUrlChange = State.UrlChanged - , onUrlRequest = State.LinkClicked - , subscriptions = \_ -> Sub.none - , update = State.update - , view = view - } diff --git a/users/wpcarro/assessments/tt/client/src/Manager.elm b/users/wpcarro/assessments/tt/client/src/Manager.elm deleted file mode 100644 index cd15c99a3..000000000 --- a/users/wpcarro/assessments/tt/client/src/Manager.elm +++ /dev/null @@ -1,70 +0,0 @@ -module Manager exposing (render) - -import Array -import Common -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import RemoteData -import State -import Tailwind -import UI -import Utils - - -allUsers : State.Model -> Html State.Msg -allUsers model = - case model.accounts of - RemoteData.NotAsked -> - UI.absentData { handleFetch = State.AttemptGetAccounts } - - RemoteData.Loading -> - UI.paragraph "Loading..." - - RemoteData.Failure e -> - UI.paragraph ("Error: " ++ Utils.explainHttpError e) - - RemoteData.Success xs -> - ul [] - (xs - |> List.map - (\account -> - li [] - [ UI.paragraph - (account.username - ++ " - " - ++ State.roleToString account.role - ) - , UI.textButton - { label = "delete" - , handleClick = State.AttemptDeleteAccount account.username - } - ] - ) - ) - - -render : State.Model -> Html State.Msg -render model = - Common.withSession model - (\session -> - div - [ class - ([ "container" - , "mx-auto" - , "text-center" - ] - |> Tailwind.use - ) - ] - [ h1 [] - [ UI.header 2 ("Welcome back, " ++ session.username ++ "!") - , UI.textButton - { label = "Logout" - , handleClick = State.AttemptLogout - } - , allUsers model - , Common.allErrors model - ] - ] - ) diff --git a/users/wpcarro/assessments/tt/client/src/Shared.elm b/users/wpcarro/assessments/tt/client/src/Shared.elm deleted file mode 100644 index addb0a4ff..000000000 --- a/users/wpcarro/assessments/tt/client/src/Shared.elm +++ /dev/null @@ -1,7 +0,0 @@ -module Shared exposing (..) - -clientOrigin = - "http://localhost:8000" - -serverOrigin = - "http://localhost:3000" diff --git a/users/wpcarro/assessments/tt/client/src/State.elm b/users/wpcarro/assessments/tt/client/src/State.elm deleted file mode 100644 index b3f78bb16..000000000 --- a/users/wpcarro/assessments/tt/client/src/State.elm +++ /dev/null @@ -1,1014 +0,0 @@ -port module State exposing (..) - -import Array exposing (Array) -import Browser -import Browser.Navigation as Nav -import Date -import DatePicker -import Http -import Json.Decode as JD -import Json.Decode.Extra as JDE -import Json.Encode as JE -import Json.Encode.Extra as JEE -import Process -import RemoteData exposing (WebData) -import Shared -import Task -import Time -import Url -import Url.Builder as UrlBuilder -import Url.Parser exposing ((), Parser, int, map, oneOf, s, string) -import Utils - - - --------------------------------------------------------------------------------- --- Types --------------------------------------------------------------------------------- - - -type Msg - = DoNothing - | UpdateUsername String - | UpdateEmail String - | UpdatePassword String - | UpdateRole String - | UpdateAdminTab AdminTab - | UpdateTripDestination String - | UpdateTripStartDate DatePicker.Msg - | UpdateTripEndDate DatePicker.Msg - | UpdateTripComment String - | UpdateEditTripDestination String - | UpdateEditTripComment String - | ClearErrors - | ToggleLoginForm - | PrintPage - | GoogleSignIn - | GoogleSignOut - | UpdateInviteEmail String - | UpdateInviteRole (Maybe Role) - | ReceiveTodaysDate Date.Date - | EditTrip Trip - | CancelEditTrip - -- SPA - | LinkClicked Browser.UrlRequest - | UrlChanged Url.Url - -- Outbound network - | AttemptGetAccounts - | AttemptGetTrips - | AttemptSignUp - | AttemptLogin - | AttemptLogout - | AttemptDeleteAccount String - | AttemptCreateTrip Date.Date Date.Date - | AttemptDeleteTrip Trip - | AttemptInviteUser Role - | AttemptUpdateTrip TripPK Trip - -- Inbound network - | GotAccounts (WebData (List Account)) - | GotTrips (WebData (List Trip)) - | GotSignUp (Result Http.Error Session) - | GotLogin (Result Http.Error Session) - | GotLogout (Result Http.Error String) - | GotDeleteAccount (Result Http.Error String) - | GotCreateTrip (Result Http.Error ()) - | GotDeleteTrip (Result Http.Error ()) - | GotInviteUser (Result Http.Error ()) - | GotUpdateTrip (Result Http.Error ()) - - -type Route - = Login - | UserHome - | ManagerHome - | AdminHome - - -type Role - = User - | Manager - | Admin - - -type alias Account = - { username : String - , role : Role - } - - -type alias Session = - { role : Role - , username : String - } - - -type alias Review = - { rowid : Int - , content : String - , rating : Int - , user : String - , dateOfVisit : String - } - - -type AdminTab - = Accounts - | Trips - - -type LoginTab - = LoginForm - | SignUpForm - - -type alias Trip = - { username : String - , destination : String - , startDate : Date.Date - , endDate : Date.Date - , comment : String - } - - -type alias TripPK = - { username : String - , destination : String - , startDate : Date.Date - } - - -type alias Model = - { route : Maybe Route - , url : Url.Url - , key : Nav.Key - , session : Maybe Session - , todaysDate : Maybe Date.Date - , username : String - , email : String - , password : String - , role : Maybe Role - , accounts : WebData (List Account) - , startDatePicker : DatePicker.DatePicker - , endDatePicker : DatePicker.DatePicker - , tripDestination : String - , tripStartDate : Maybe Date.Date - , tripEndDate : Maybe Date.Date - , tripComment : String - , trips : WebData (List Trip) - , editingTrip : Maybe Trip - , editTripDestination : String - , editTripComment : String - , adminTab : AdminTab - , loginTab : LoginTab - , inviteEmail : String - , inviteRole : Maybe Role - , inviteResponseStatus : WebData () - , updateTripStatus : WebData () - , loginError : Maybe Http.Error - , logoutError : Maybe Http.Error - , signUpError : Maybe Http.Error - , deleteUserError : Maybe Http.Error - , createTripError : Maybe Http.Error - , deleteTripError : Maybe Http.Error - , inviteUserError : Maybe Http.Error - } - - -allErrors : Model -> List ( Maybe Http.Error, String ) -allErrors model = - [ ( model.loginError, "Error attempting to authenticate" ) - , ( model.logoutError, "Error attempting to log out" ) - , ( model.signUpError, "Error attempting to create your account" ) - , ( model.deleteUserError, "Error attempting to delete a user" ) - , ( model.createTripError, "Error attempting to create a trip" ) - , ( model.inviteUserError, "Error attempting to invite a user" ) - ] - - - --------------------------------------------------------------------------------- --- Functions --------------------------------------------------------------------------------- - - -roleToString : Role -> String -roleToString role = - case role of - User -> - "user" - - Manager -> - "manager" - - Admin -> - "admin" - - -endpoint : List String -> List UrlBuilder.QueryParameter -> String -endpoint = - UrlBuilder.crossOrigin Shared.serverOrigin - - -encodeRole : Role -> JE.Value -encodeRole x = - case x of - User -> - JE.string "user" - - Manager -> - JE.string "manager" - - Admin -> - JE.string "admin" - - -decodeRole : JD.Decoder Role -decodeRole = - let - toRole : String -> JD.Decoder Role - toRole s = - case s of - "user" -> - JD.succeed User - - "manager" -> - JD.succeed Manager - - "admin" -> - JD.succeed Admin - - x -> - JD.fail ("Invalid input: " ++ x) - in - JD.string |> JD.andThen toRole - - -decodeSession : JD.Decoder Session -decodeSession = - JD.map2 - Session - (JD.field "role" decodeRole) - (JD.field "username" JD.string) - - -encodeLoginRequest : String -> String -> JE.Value -encodeLoginRequest username password = - JE.object - [ ( "username", JE.string username ) - , ( "password", JE.string password ) - ] - - -login : String -> String -> Cmd Msg -login username password = - Utils.postWithCredentials - { url = endpoint [ "login" ] [] - , body = Http.jsonBody (encodeLoginRequest username password) - , expect = Http.expectJson GotLogin decodeSession - } - - -logout : Cmd Msg -logout = - Utils.getWithCredentials - { url = endpoint [ "logout" ] [] - , expect = Http.expectString GotLogout - } - - -signUp : - { username : String - , email : String - , password : String - } - -> Cmd Msg -signUp { username, email, password } = - Utils.postWithCredentials - { url = endpoint [ "accounts" ] [] - , body = - Http.jsonBody - (JE.object - [ ( "username", JE.string username ) - , ( "email", JE.string username ) - , ( "password", JE.string password ) - , ( "role", JE.string "user" ) - ] - ) - , expect = Http.expectJson GotSignUp decodeSession - } - - -updateTrip : TripPK -> Trip -> Cmd Msg -updateTrip tripKey trip = - Utils.putWithCredentials - { url = endpoint [ "trips" ] [] - , body = - Http.jsonBody - (JE.object - [ ( "tripKey", encodeTripKey tripKey ) - , ( "destination", JE.string trip.destination ) - , ( "startDate", encodeDate trip.startDate ) - , ( "endDate", encodeDate trip.endDate ) - , ( "comment", JE.string trip.comment ) - ] - ) - , expect = Http.expectWhatever GotUpdateTrip - } - - -inviteUser : { email : String, role : Role } -> Cmd Msg -inviteUser { email, role } = - Utils.postWithCredentials - { url = endpoint [ "invite" ] [] - , body = - Http.jsonBody - (JE.object - [ ( "email", JE.string email ) - , ( "role", encodeRole role ) - ] - ) - , expect = Http.expectWhatever GotInviteUser - } - - -createTrip : - { username : String - , destination : String - , startDate : Date.Date - , endDate : Date.Date - , comment : String - } - -> Cmd Msg -createTrip { username, destination, startDate, endDate, comment } = - Utils.postWithCredentials - { url = endpoint [ "trips" ] [] - , body = - Http.jsonBody - (JE.object - [ ( "username", JE.string username ) - , ( "destination", JE.string destination ) - , ( "startDate", encodeDate startDate ) - , ( "endDate", encodeDate endDate ) - , ( "comment", JE.string comment ) - ] - ) - , expect = Http.expectWhatever GotCreateTrip - } - - -deleteTrip : - { username : String - , destination : String - , startDate : Date.Date - } - -> Cmd Msg -deleteTrip { username, destination, startDate } = - Utils.deleteWithCredentials - { url = endpoint [ "trips" ] [] - , body = - Http.jsonBody - (JE.object - [ ( "username", JE.string username ) - , ( "destination", JE.string destination ) - , ( "startDate", encodeDate startDate ) - ] - ) - , expect = Http.expectWhatever GotDeleteTrip - } - - -deleteAccount : String -> Cmd Msg -deleteAccount username = - Utils.deleteWithCredentials - { url = endpoint [ "accounts" ] [ UrlBuilder.string "username" username ] - , body = Http.emptyBody - , expect = Http.expectString GotDeleteAccount - } - - -decodeReview : JD.Decoder Review -decodeReview = - JD.map5 - Review - (JD.field "rowid" JD.int) - (JD.field "content" JD.string) - (JD.field "rating" JD.int) - (JD.field "user" JD.string) - (JD.field "timestamp" JD.string) - - -encodeTripKey : TripPK -> JE.Value -encodeTripKey tripKey = - JE.object - [ ( "username", JE.string tripKey.username ) - , ( "destination", JE.string tripKey.destination ) - , ( "startDate", encodeDate tripKey.startDate ) - ] - - -encodeDate : Date.Date -> JE.Value -encodeDate date = - date |> Date.toIsoString |> JE.string - - -decodeDate : JD.Decoder Date.Date -decodeDate = - JD.string |> JD.andThen (Date.fromIsoString >> JDE.fromResult) - - -fetchTrips : Cmd Msg -fetchTrips = - Utils.getWithCredentials - { url = endpoint [ "trips" ] [] - , expect = - Http.expectJson - (RemoteData.fromResult >> GotTrips) - (JD.list - (JD.map5 - Trip - (JD.field "username" JD.string) - (JD.field "destination" JD.string) - (JD.field "startDate" decodeDate) - (JD.field "endDate" decodeDate) - (JD.field "comment" JD.string) - ) - ) - } - - -fetchAccounts : Cmd Msg -fetchAccounts = - Utils.getWithCredentials - { url = endpoint [ "accounts" ] [] - , expect = - Http.expectJson - (RemoteData.fromResult >> GotAccounts) - (JD.list - (JD.map2 - Account - (JD.field "username" JD.string) - (JD.field "role" decodeRole) - ) - ) - } - - -sleepAndClearErrors : Cmd Msg -sleepAndClearErrors = - Process.sleep 4000 - |> Task.perform (\_ -> ClearErrors) - - -isAuthorized : Role -> Route -> Bool -isAuthorized role route = - case ( role, route ) of - ( User, _ ) -> - True - - ( Manager, _ ) -> - True - - ( Admin, _ ) -> - True - - -homeRouteForRole : Role -> String -homeRouteForRole role = - case role of - User -> - "/user" - - Manager -> - "/manager" - - Admin -> - "/admin" - - -routeParser : Parser (Route -> a) a -routeParser = - oneOf - [ map Login (s "topic") - , map UserHome (s "user") - , map ManagerHome (s "manager") - , map AdminHome (s "admin") - ] - - -{-| Set init to `prod` when going live. --} -prod : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg ) -prod _ url key = - let - ( startDatePicker, startDatePickerCmd ) = - DatePicker.init - - ( endDatePicker, endDatePickerCmd ) = - DatePicker.init - in - ( { route = Nothing - , url = url - , key = key - , session = Nothing - , todaysDate = Nothing - , username = "" - , email = "" - , password = "" - , role = Nothing - , accounts = RemoteData.NotAsked - , tripDestination = "" - , tripStartDate = Nothing - , tripEndDate = Nothing - , tripComment = "" - , trips = RemoteData.NotAsked - , editingTrip = Nothing - , editTripDestination = "" - , editTripComment = "" - , startDatePicker = startDatePicker - , endDatePicker = endDatePicker - , adminTab = Accounts - , loginTab = LoginForm - , inviteEmail = "" - , inviteRole = Nothing - , inviteResponseStatus = RemoteData.NotAsked - , updateTripStatus = RemoteData.NotAsked - , loginError = Nothing - , logoutError = Nothing - , signUpError = Nothing - , deleteUserError = Nothing - , createTripError = Nothing - , deleteTripError = Nothing - , inviteUserError = Nothing - } - , Cmd.batch - [ Cmd.map UpdateTripStartDate startDatePickerCmd - , Cmd.map UpdateTripEndDate endDatePickerCmd - , Date.today |> Task.perform ReceiveTodaysDate - ] - ) - - -{-| When working on a feature for the UserHome, use this. --} -userHome : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg ) -userHome flags url key = - let - ( model, cmd ) = - prod flags url key - in - ( { model - | route = Just UserHome - , session = Just { username = "mimi", role = User } - , trips = - RemoteData.Success - [ { username = "mimi" - , destination = "Barcelona" - , startDate = Date.fromCalendarDate 2020 Time.Sep 25 - , endDate = Date.fromCalendarDate 2020 Time.Oct 5 - , comment = "Blah" - } - , { username = "mimi" - , destination = "Paris" - , startDate = Date.fromCalendarDate 2021 Time.Jan 1 - , endDate = Date.fromCalendarDate 2021 Time.Feb 1 - , comment = "Bon voyage!" - } - ] - } - , cmd - ) - - -managerHome : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg ) -managerHome flags url key = - let - ( model, cmd ) = - prod flags url key - in - ( { model - | route = Just ManagerHome - , session = Just { username = "bill", role = Manager } - } - , cmd - ) - - -adminHome : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg ) -adminHome flags url key = - let - ( model, cmd ) = - prod flags url key - in - ( { model - | route = Just AdminHome - , session = Just { username = "wpcarro", role = Admin } - } - , cmd - ) - - -port printPage : () -> Cmd msg - - -port googleSignIn : () -> Cmd msg - - -port googleSignOut : () -> Cmd msg - - -{-| The initial state for the application. --} -init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg ) -init flags url key = - prod flags url key - - -{-| Now that we have state, we need a function to change the state. --} -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = - case msg of - DoNothing -> - ( model, Cmd.none ) - - UpdateUsername x -> - ( { model | username = x }, Cmd.none ) - - UpdatePassword x -> - ( { model | password = x }, Cmd.none ) - - UpdateEmail x -> - ( { model | email = x }, Cmd.none ) - - UpdateAdminTab x -> - ( { model | adminTab = x }, Cmd.none ) - - UpdateRole x -> - let - maybeRole = - case x of - "user" -> - Just User - - "manager" -> - Just Manager - - "admin" -> - Just Admin - - _ -> - Nothing - in - ( { model | role = maybeRole }, Cmd.none ) - - UpdateTripDestination x -> - ( { model | tripDestination = x }, Cmd.none ) - - UpdateTripStartDate dpMsg -> - let - ( newDatePicker, dateEvent ) = - DatePicker.update DatePicker.defaultSettings dpMsg model.startDatePicker - - newDate = - case dateEvent of - DatePicker.Picked changedDate -> - Just changedDate - - _ -> - model.tripStartDate - in - ( { model - | tripStartDate = newDate - , startDatePicker = newDatePicker - } - , Cmd.none - ) - - UpdateTripEndDate dpMsg -> - let - ( newDatePicker, dateEvent ) = - DatePicker.update DatePicker.defaultSettings dpMsg model.endDatePicker - - newDate = - case dateEvent of - DatePicker.Picked changedDate -> - Just changedDate - - _ -> - model.tripEndDate - in - ( { model - | tripEndDate = newDate - , endDatePicker = newDatePicker - } - , Cmd.none - ) - - UpdateTripComment x -> - ( { model | tripComment = x }, Cmd.none ) - - UpdateEditTripDestination x -> - ( { model | editTripDestination = x }, Cmd.none ) - - UpdateEditTripComment x -> - ( { model | editTripComment = x }, Cmd.none ) - - ClearErrors -> - ( { model - | loginError = Nothing - , logoutError = Nothing - , signUpError = Nothing - , deleteUserError = Nothing - , createTripError = Nothing - } - , Cmd.none - ) - - ToggleLoginForm -> - ( { model - | loginTab = - case model.loginTab of - LoginForm -> - SignUpForm - - SignUpForm -> - LoginForm - } - , Cmd.none - ) - - PrintPage -> - ( model, printPage () ) - - GoogleSignIn -> - ( model, googleSignIn () ) - - GoogleSignOut -> - ( model, googleSignOut () ) - - UpdateInviteEmail x -> - ( { model | inviteEmail = x }, Cmd.none ) - - UpdateInviteRole mRole -> - ( { model | inviteRole = mRole }, Cmd.none ) - - ReceiveTodaysDate date -> - ( { model | todaysDate = Just date }, Cmd.none ) - - EditTrip trip -> - ( { model - | editingTrip = Just trip - , editTripDestination = trip.destination - , editTripComment = trip.comment - } - , Cmd.none - ) - - CancelEditTrip -> - ( { model - | editingTrip = Nothing - , editTripDestination = "" - , editTripComment = "" - } - , Cmd.none - ) - - LinkClicked urlRequest -> - case urlRequest of - Browser.Internal url -> - ( model, Nav.pushUrl model.key (Url.toString url) ) - - Browser.External href -> - ( model, Nav.load href ) - - UrlChanged url -> - let - route = - Url.Parser.parse routeParser url - in - case route of - Just UserHome -> - ( { model - | url = url - , route = route - , trips = RemoteData.Loading - } - , fetchTrips - ) - - Just ManagerHome -> - ( { model - | url = url - , route = route - , accounts = RemoteData.Loading - } - , fetchAccounts - ) - - Just AdminHome -> - ( { model - | url = url - , route = route - , accounts = RemoteData.Loading - , trips = RemoteData.Loading - } - , Cmd.batch - [ fetchAccounts - , fetchTrips - ] - ) - - _ -> - ( { model - | url = url - , route = route - } - , Cmd.none - ) - - -- GET /accounts - AttemptGetAccounts -> - ( { model | accounts = RemoteData.Loading }, fetchAccounts ) - - GotAccounts xs -> - ( { model | accounts = xs }, Cmd.none ) - - -- DELETE /accounts - AttemptDeleteAccount username -> - ( model, deleteAccount username ) - - GotDeleteAccount result -> - case result of - Ok _ -> - ( model, fetchAccounts ) - - Err e -> - ( { model | deleteUserError = Just e } - , sleepAndClearErrors - ) - - -- POST /trips - AttemptCreateTrip startDate endDate -> - ( model - , case model.session of - Nothing -> - Cmd.none - - Just session -> - createTrip - { username = session.username - , destination = model.tripDestination - , startDate = startDate - , endDate = endDate - , comment = model.tripComment - } - ) - - GotCreateTrip result -> - case result of - Ok _ -> - ( { model - | tripDestination = "" - , tripStartDate = Nothing - , tripEndDate = Nothing - , tripComment = "" - } - , fetchTrips - ) - - Err e -> - ( { model - | createTripError = Just e - , tripDestination = "" - , tripStartDate = Nothing - , tripEndDate = Nothing - , tripComment = "" - } - , sleepAndClearErrors - ) - - -- DELETE /trips - AttemptDeleteTrip trip -> - ( model - , deleteTrip - { username = trip.username - , destination = trip.destination - , startDate = trip.startDate - } - ) - - GotDeleteTrip result -> - case result of - Ok _ -> - ( model, fetchTrips ) - - Err e -> - ( { model | deleteTripError = Just e } - , sleepAndClearErrors - ) - - AttemptInviteUser role -> - ( { model | inviteResponseStatus = RemoteData.Loading } - , inviteUser - { email = model.inviteEmail - , role = role - } - ) - - GotInviteUser result -> - case result of - Ok _ -> - ( { model - | inviteEmail = "" - , inviteRole = Nothing - , inviteResponseStatus = RemoteData.Success () - } - , Cmd.none - ) - - Err e -> - ( { model - | inviteUserError = Just e - , inviteResponseStatus = RemoteData.Failure e - } - , sleepAndClearErrors - ) - - -- PATCH /trips - AttemptUpdateTrip tripKey trip -> - ( { model | updateTripStatus = RemoteData.Loading } - , updateTrip tripKey trip - ) - - GotUpdateTrip result -> - case result of - Ok _ -> - ( { model | updateTripStatus = RemoteData.Success () } - , fetchTrips - ) - - Err e -> - ( { model | updateTripStatus = RemoteData.Failure e } - , Cmd.none - ) - - -- POST /accounts - AttemptSignUp -> - ( model - , signUp - { username = model.username - , email = model.email - , password = model.password - } - ) - - GotSignUp result -> - case result of - Ok session -> - ( { model | session = Just session } - , Nav.pushUrl model.key (homeRouteForRole session.role) - ) - - Err x -> - ( { model | signUpError = Just x } - , sleepAndClearErrors - ) - - -- GET /trips - AttemptGetTrips -> - ( { model | trips = RemoteData.Loading }, fetchTrips ) - - GotTrips xs -> - ( { model | trips = xs }, Cmd.none ) - - -- POST /login - AttemptLogin -> - ( model, login model.username model.password ) - - GotLogin result -> - case result of - Ok session -> - ( { model | session = Just session } - , Nav.pushUrl model.key (homeRouteForRole session.role) - ) - - Err x -> - ( { model | loginError = Just x } - , sleepAndClearErrors - ) - - -- GET /logout - AttemptLogout -> - ( model, logout ) - - GotLogout result -> - case result of - Ok _ -> - ( { model | session = Nothing } - , Nav.pushUrl model.key "/login" - ) - - Err e -> - ( { model | logoutError = Just e } - , sleepAndClearErrors - ) diff --git a/users/wpcarro/assessments/tt/client/src/Tailwind.elm b/users/wpcarro/assessments/tt/client/src/Tailwind.elm deleted file mode 100644 index 57d419db5..000000000 --- a/users/wpcarro/assessments/tt/client/src/Tailwind.elm +++ /dev/null @@ -1,29 +0,0 @@ -module Tailwind exposing (..) - -{-| Functions to make Tailwind development in Elm even more pleasant. --} - - -{-| Conditionally use `class` selection when `condition` is true. --} -when : Bool -> String -> String -when condition class = - if condition then - class - - else - "" - - -if_ : Bool -> String -> String -> String -if_ condition whenTrue whenFalse = - if condition then - whenTrue - - else - whenFalse - - -use : List String -> String -use styles = - String.join " " styles diff --git a/users/wpcarro/assessments/tt/client/src/UI.elm b/users/wpcarro/assessments/tt/client/src/UI.elm deleted file mode 100644 index 7f8f37979..000000000 --- a/users/wpcarro/assessments/tt/client/src/UI.elm +++ /dev/null @@ -1,318 +0,0 @@ -module UI exposing (..) - -import Date -import DatePicker exposing (defaultSettings) -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import State -import Tailwind - - -label_ : { for_ : String, text_ : String } -> Html msg -label_ { for_, text_ } = - label - [ [ "block" - , "text-gray-700" - , "text-sm" - , "font-bold" - , "mb-2" - ] - |> Tailwind.use - |> class - , for for_ - ] - [ text text_ ] - - -errorBanner : { title : String, body : String } -> Html msg -errorBanner { title, body } = - div - [ [ "text-left" - , "fixed" - , "container" - , "top-0" - , "mt-6" - ] - |> Tailwind.use - |> class - , style "left" "50%" - - -- TODO(wpcarro): Consider supporting breakpoints, but for now - -- don't. - , style "width" "800px" - , style "margin-left" "-400px" - ] - [ div - [ [ "bg-red-500" - , "text-white" - , "font-bold" - , "rounded-t" - , "px-4" - , "py-2" - ] - |> Tailwind.use - |> class - ] - [ text title ] - , div - [ [ "border" - , "border-t-0" - , "border-red-400" - , "rounded-b" - , "bg-red-100" - , "px-4" - , "py-3" - , "text-red-700" - ] - |> Tailwind.use - |> class - ] - [ p [] [ text body ] ] - ] - - -baseButton : - { label : String - , enabled : Bool - , handleClick : msg - , extraClasses : List String - } - -> Html msg -baseButton { label, enabled, handleClick, extraClasses } = - button - [ [ if enabled then - "bg-blue-500" - - else - "bg-gray-500" - , if enabled then - "hover:bg-blue-700" - - else - "" - , if enabled then - "" - - else - "cursor-not-allowed" - , "text-white" - , "font-bold" - , "py-1" - , "shadow-lg" - , "px-4" - , "rounded" - , "focus:outline-none" - , "focus:shadow-outline" - ] - ++ extraClasses - |> Tailwind.use - |> class - , onClick handleClick - , disabled (not enabled) - ] - [ text label ] - - -simpleButton : - { label : String - , handleClick : msg - } - -> Html msg -simpleButton { label, handleClick } = - baseButton - { label = label - , enabled = True - , handleClick = handleClick - , extraClasses = [] - } - - -disabledButton : - { label : String } - -> Html State.Msg -disabledButton { label } = - baseButton - { label = label - , enabled = False - , handleClick = State.DoNothing - , extraClasses = [] - } - - -textButton : - { label : String - , handleClick : msg - } - -> Html msg -textButton { label, handleClick } = - button - [ [ "text-blue-600" - , "hover:text-blue-500" - , "font-bold" - , "hover:underline" - , "focus:outline-none" - ] - |> Tailwind.use - |> class - , onClick handleClick - ] - [ text label ] - - -textField : - { pholder : String - , inputId : String - , handleInput : String -> msg - , inputValue : String - } - -> Html msg -textField { pholder, inputId, handleInput, inputValue } = - input - [ [ "shadow" - , "appearance-none" - , "border" - , "rounded" - , "w-full" - , "py-2" - , "px-3" - , "text-gray-700" - , "leading-tight" - , "focus:outline-none" - , "focus:shadow-outline" - ] - |> Tailwind.use - |> class - , id inputId - , value inputValue - , placeholder pholder - , onInput handleInput - ] - [] - - -toggleButton : - { toggled : Bool - , label : String - , handleEnable : msg - , handleDisable : msg - } - -> Html msg -toggleButton { toggled, label, handleEnable, handleDisable } = - button - [ [ if toggled then - "bg-blue-700" - - else - "bg-blue-500" - , "hover:bg-blue-700" - , "text-white" - , "font-bold" - , "py-2" - , "px-4" - , "rounded" - , "focus:outline-none" - , "focus:shadow-outline" - ] - |> Tailwind.use - |> class - , onClick - (if toggled then - handleDisable - - else - handleEnable - ) - ] - [ text label ] - - -paragraph : String -> Html msg -paragraph x = - p [ [ "text-xl" ] |> Tailwind.use |> class ] [ text x ] - - -header : Int -> String -> Html msg -header which x = - let - hStyles = - case which of - 1 -> - [ "text-6xl" - , "py-12" - ] - - 2 -> - [ "text-3xl" - , "py-6" - ] - - _ -> - [ "text-2xl" - , "py-2" - ] - in - h1 - [ hStyles - ++ [ "font-bold" - , "text-gray-700" - ] - |> Tailwind.use - |> class - ] - [ text x ] - - -link : String -> String -> Html msg -link path label = - a - [ href path - , [ "underline" - , "text-blue-600" - , "text-xl" - ] - |> Tailwind.use - |> class - ] - [ text label ] - - -absentData : { handleFetch : msg } -> Html msg -absentData { handleFetch } = - div [] - [ paragraph "Welp... it looks like you've caught us in a state that we considered impossible: we did not fetch the data upon which this page depends. Maybe you can help us out by clicking the super secret, highly privileged \"Fetch data\" button below (we don't normally show people this)." - , div [ [ "py-4" ] |> Tailwind.use |> class ] - [ simpleButton - { label = "Fetch data" - , handleClick = handleFetch - } - ] - ] - - -datePicker : - { mDate : Maybe Date.Date - , prompt : String - , prefix : String - , picker : DatePicker.DatePicker - , onUpdate : DatePicker.Msg -> State.Msg - } - -> Html State.Msg -datePicker { mDate, prompt, prefix, picker, onUpdate } = - let - settings = - { defaultSettings - | placeholder = prompt - , inputClassList = - [ ( "text-center", True ) - , ( "py-2", True ) - ] - } - in - div [ [ "w-1/2", "py-4", "mx-auto" ] |> Tailwind.use |> class ] - [ DatePicker.view mDate settings picker |> Html.map onUpdate ] - - -wrapNoPrint : Html State.Msg -> Html State.Msg -wrapNoPrint component = - div [ [ "no-print" ] |> Tailwind.use |> class ] [ component ] diff --git a/users/wpcarro/assessments/tt/client/src/User.elm b/users/wpcarro/assessments/tt/client/src/User.elm deleted file mode 100644 index 87871b78d..000000000 --- a/users/wpcarro/assessments/tt/client/src/User.elm +++ /dev/null @@ -1,245 +0,0 @@ -module User exposing (render) - -import Common -import Date -import DatePicker -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import Maybe.Extra as ME -import RemoteData -import State -import Tailwind -import UI -import Utils - - -createTrip : State.Model -> Html State.Msg -createTrip model = - div [] - [ UI.header 3 "Plan Upcoming Trip" - , UI.textField - { pholder = "Where are you going?" - , inputId = "destination" - , handleInput = State.UpdateTripDestination - , inputValue = model.tripDestination - } - , div [ [ "flex" ] |> Tailwind.use |> class ] - [ UI.datePicker - { mDate = model.tripStartDate - , prompt = "Set departure date" - , prefix = "Departure: " - , picker = model.startDatePicker - , onUpdate = State.UpdateTripStartDate - } - , UI.datePicker - { mDate = model.tripEndDate - , prompt = "Set return date" - , prefix = "Return: " - , picker = model.endDatePicker - , onUpdate = State.UpdateTripEndDate - } - ] - , UI.textField - { pholder = "Comments?" - , inputId = "comment" - , handleInput = State.UpdateTripComment - , inputValue = model.tripComment - } - , UI.baseButton - { enabled = - List.all - identity - [ String.length model.tripDestination > 0 - , String.length model.tripComment > 0 - , ME.isJust model.tripStartDate - , ME.isJust model.tripEndDate - ] - , extraClasses = [ "my-4" ] - , handleClick = - case ( model.tripStartDate, model.tripEndDate ) of - ( Nothing, _ ) -> - State.DoNothing - - ( _, Nothing ) -> - State.DoNothing - - ( Just startDate, Just endDate ) -> - State.AttemptCreateTrip startDate endDate - , label = "Schedule trip" - } - ] - - -renderEditTrip : State.Model -> State.Trip -> Html State.Msg -renderEditTrip model trip = - li [] - [ div [] - [ UI.textField - { handleInput = State.UpdateEditTripDestination - , inputId = "edit-trip-destination" - , inputValue = model.editTripDestination - , pholder = "Destination" - } - , UI.textField - { handleInput = State.UpdateEditTripComment - , inputId = "edit-trip-comment" - , inputValue = model.editTripComment - , pholder = "Comment" - } - ] - , div [] - [ UI.baseButton - { enabled = - case model.updateTripStatus of - RemoteData.Loading -> - False - - _ -> - True - , extraClasses = [] - , label = - case model.updateTripStatus of - RemoteData.Loading -> - "Saving..." - - _ -> - "Save" - , handleClick = - State.AttemptUpdateTrip - { username = trip.username - , destination = trip.destination - , startDate = trip.startDate - } - { username = trip.username - , destination = model.editTripDestination - , startDate = trip.startDate - , endDate = trip.endDate - , comment = model.editTripComment - } - } - , UI.simpleButton - { label = "Cancel" - , handleClick = State.CancelEditTrip - } - ] - ] - - -renderTrip : Date.Date -> State.Trip -> Html State.Msg -renderTrip today trip = - li - [ [ "py-2" ] - |> Tailwind.use - |> class - ] - [ if Date.compare today trip.startDate == GT then - UI.paragraph - (String.fromInt (Date.diff Date.Days trip.startDate today) - ++ " days until you're travelling to " - ++ trip.destination - ++ " for " - ++ String.fromInt - (Date.diff - Date.Days - trip.startDate - trip.endDate - ) - ++ " days." - ) - - else - UI.paragraph - (String.fromInt (Date.diff Date.Days today trip.endDate) - ++ " days ago you returned from your trip to " - ++ trip.destination - ) - , UI.paragraph ("\"" ++ trip.comment ++ "\"") - , UI.wrapNoPrint - (UI.textButton - { label = "Edit" - , handleClick = State.EditTrip trip - } - ) - , UI.wrapNoPrint - (UI.textButton - { label = "Delete" - , handleClick = State.AttemptDeleteTrip trip - } - ) - ] - - -trips : State.Model -> Html State.Msg -trips model = - div [] - [ UI.header 3 "Your Trips" - , case model.trips of - RemoteData.NotAsked -> - UI.paragraph "Somehow we've reached the user home page without requesting your trips data. Please report this to our engineering team at bugs@tripplaner.tld" - - RemoteData.Loading -> - UI.paragraph "Loading your trips..." - - RemoteData.Failure e -> - UI.paragraph ("Error: " ++ Utils.explainHttpError e) - - RemoteData.Success xs -> - case model.todaysDate of - Nothing -> - text "" - - Just today -> - div [ [ "mb-10" ] |> Tailwind.use |> class ] - [ ul [ [ "my-4" ] |> Tailwind.use |> class ] - (xs - |> List.sortWith (\x y -> Date.compare y.startDate x.startDate) - |> List.map - (\trip -> - case model.editingTrip of - Nothing -> - renderTrip today trip - - Just x -> - if x == trip then - renderEditTrip model trip - - else - renderTrip today trip - ) - ) - , UI.wrapNoPrint - (UI.simpleButton - { label = "Print iternary" - , handleClick = State.PrintPage - } - ) - ] - ] - - -render : State.Model -> Html State.Msg -render model = - Common.withSession model - (\session -> - div - [ class - ([ "container" - , "mx-auto" - , "text-center" - ] - |> Tailwind.use - ) - ] - [ UI.wrapNoPrint (UI.header 2 ("Welcome, " ++ session.username ++ "!")) - , UI.wrapNoPrint (createTrip model) - , trips model - , UI.wrapNoPrint - (UI.textButton - { label = "Logout" - , handleClick = State.AttemptLogout - } - ) - , Common.allErrors model - ] - ) diff --git a/users/wpcarro/assessments/tt/client/src/Utils.elm b/users/wpcarro/assessments/tt/client/src/Utils.elm deleted file mode 100644 index 60343cd87..000000000 --- a/users/wpcarro/assessments/tt/client/src/Utils.elm +++ /dev/null @@ -1,109 +0,0 @@ -module Utils exposing (..) - -import DateFormat -import Http -import Time -import Shared - - -explainHttpError : Http.Error -> String -explainHttpError e = - case e of - Http.BadUrl _ -> - "Bad URL: you may have supplied an improperly formatted URL" - - Http.Timeout -> - "Timeout: the resource you requested did not arrive within the interval of time that you claimed it should" - - Http.BadStatus s -> - "Bad Status: the server returned a bad status code: " ++ String.fromInt s - - Http.BadBody b -> - "Bad Body: our application had trouble decoding the body of the response from the server: " ++ b - - Http.NetworkError -> - "Network Error: something went awry in the network stack. I recommend checking the server logs if you can." - - -getWithCredentials : - { url : String - , expect : Http.Expect msg - } - -> Cmd msg -getWithCredentials { url, expect } = - Http.riskyRequest - { url = url - , headers = [ Http.header "Origin" Shared.clientOrigin ] - , method = "GET" - , timeout = Nothing - , tracker = Nothing - , body = Http.emptyBody - , expect = expect - } - - -postWithCredentials : - { url : String - , body : Http.Body - , expect : Http.Expect msg - } - -> Cmd msg -postWithCredentials { url, body, expect } = - Http.riskyRequest - { url = url - , headers = [ Http.header "Origin" Shared.clientOrigin ] - , method = "POST" - , timeout = Nothing - , tracker = Nothing - , body = body - , expect = expect - } - - -deleteWithCredentials : - { url : String - , body : Http.Body - , expect : Http.Expect msg - } - -> Cmd msg -deleteWithCredentials { url, body, expect } = - Http.riskyRequest - { url = url - , headers = [ Http.header "Origin" Shared.clientOrigin ] - , method = "DELETE" - , timeout = Nothing - , tracker = Nothing - , body = body - , expect = expect - } - -putWithCredentials : - { url : String - , body : Http.Body - , expect : Http.Expect msg - } - -> Cmd msg -putWithCredentials { url, body, expect } = - Http.riskyRequest - { url = url - , headers = [ Http.header "Origin" Shared.clientOrigin ] - , method = "PUT" - , timeout = Nothing - , tracker = Nothing - , body = body - , expect = expect - } - - - -formatTime : Time.Posix -> String -formatTime ts = - DateFormat.format - [ DateFormat.monthNameFull - , DateFormat.text " " - , DateFormat.dayOfMonthSuffix - , DateFormat.text ", " - , DateFormat.yearNumber - ] - Time.utc - ts diff --git a/users/wpcarro/assessments/tt/data/accounts.csv b/users/wpcarro/assessments/tt/data/accounts.csv deleted file mode 100644 index f5fc77b6d..000000000 --- a/users/wpcarro/assessments/tt/data/accounts.csv +++ /dev/null @@ -1,2 +0,0 @@ -mimi,$2b$12$LynoGCNbe2RA1WWSiBEMVudJKs5dxnssY16rYmUyiwlSBIhHBOLbu,miriamwright@google.com,user, -wpcarro,$2b$12$3wbi4xfQmksLsu6GOKTbj.5WHywESATnXB4R8FJ55RSRLy6X9xA7u,wpcarro@google.com,admin, \ No newline at end of file diff --git a/users/wpcarro/assessments/tt/data/trips.csv b/users/wpcarro/assessments/tt/data/trips.csv deleted file mode 100644 index a583c750f..000000000 --- a/users/wpcarro/assessments/tt/data/trips.csv +++ /dev/null @@ -1,3 +0,0 @@ -mimi,Rome,2020-08-10,2020-08-12,Heading home before the upcoming trip with Panarea. -mimi,Panarea,2020-08-15,2020-08-28,Exciting upcoming trip with Matt and Sarah! -mimi,London,2020-08-30,2020-09-15,Heading back to London... \ No newline at end of file diff --git a/users/wpcarro/assessments/tt/populate.sqlite3 b/users/wpcarro/assessments/tt/populate.sqlite3 deleted file mode 100644 index e200d2b49..000000000 --- a/users/wpcarro/assessments/tt/populate.sqlite3 +++ /dev/null @@ -1,7 +0,0 @@ -PRAGMA foreign_keys = on; -.read src/init.sql -.mode csv -.import data/accounts.csv Accounts -.import data/trips.csv Trips -.mode column -.headers on \ No newline at end of file diff --git a/users/wpcarro/assessments/tt/shell.nix b/users/wpcarro/assessments/tt/shell.nix deleted file mode 100644 index bf8486ba1..000000000 --- a/users/wpcarro/assessments/tt/shell.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ pkgs, depot, ... }: - -pkgs.mkShell { - buildInputs = with pkgs; [ - (haskellPackages.ghcWithPackages (hpkgs: with hpkgs; [ - hpkgs.aeson - hpkgs.cryptonite - hpkgs.envy - hpkgs.hailgun - hpkgs.resource-pool - hpkgs.servant-server - hpkgs.sqlite-simple - hpkgs.uuid - hpkgs.wai-cors - hpkgs.warp - ])) - ]; -} diff --git a/users/wpcarro/assessments/tt/src/.ghci b/users/wpcarro/assessments/tt/src/.ghci deleted file mode 100644 index efc88e630..000000000 --- a/users/wpcarro/assessments/tt/src/.ghci +++ /dev/null @@ -1,2 +0,0 @@ -:set prompt "> " -:set -Wall diff --git a/users/wpcarro/assessments/tt/src/API.hs b/users/wpcarro/assessments/tt/src/API.hs deleted file mode 100644 index 471fa761e..000000000 --- a/users/wpcarro/assessments/tt/src/API.hs +++ /dev/null @@ -1,75 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE TypeOperators #-} --------------------------------------------------------------------------------- -module API where --------------------------------------------------------------------------------- -import Data.Text -import Servant.API -import Web.Cookie - -import qualified Types as T --------------------------------------------------------------------------------- - --- | Once authenticated, users receive a SessionCookie. -type SessionCookie = Header' '[Required] "Cookie" T.SessionCookie - -type API = - -- accounts: Create - "accounts" - :> Header "Cookie" T.SessionCookie - :> ReqBody '[JSON] T.CreateAccountRequest - :> Post '[JSON] NoContent - :<|> "verify" - :> ReqBody '[JSON] T.VerifyAccountRequest - :> Post '[JSON] NoContent - -- accounts: Read - -- accounts: Update - -- accounts: Delete - :<|> "accounts" - :> SessionCookie - :> QueryParam' '[Required] "username" Text - :> Delete '[JSON] NoContent - -- accounts: List - :<|> "accounts" - :> SessionCookie - :> Get '[JSON] [T.User] - - -- trips: Create - :<|> "trips" - :> SessionCookie - :> ReqBody '[JSON] T.Trip - :> Post '[JSON] NoContent - -- trips: Read - -- trips: Update - :<|> "trips" - :> SessionCookie - :> ReqBody '[JSON] T.UpdateTripRequest - :> Put '[JSON] NoContent - -- trips: Delete - :<|> "trips" - :> SessionCookie - :> ReqBody '[JSON] T.TripPK - :> Delete '[JSON] NoContent - -- trips: List - :<|> "trips" - :> SessionCookie - :> Get '[JSON] [T.Trip] - - -- Miscellaneous - :<|> "login" - :> ReqBody '[JSON] T.AccountCredentials - :> Post '[JSON] (Headers '[Header "Set-Cookie" SetCookie] T.Session) - :<|> "logout" - :> SessionCookie - :> Get '[JSON] (Headers '[Header "Set-Cookie" SetCookie] NoContent) - :<|> "unfreeze" - :> SessionCookie - :> ReqBody '[JSON] T.UnfreezeAccountRequest - :> Post '[JSON] NoContent - :<|> "invite" - :> SessionCookie - :> ReqBody '[JSON] T.InviteUserRequest - :> Post '[JSON] NoContent - :<|> "accept-invitation" - :> ReqBody '[JSON] T.AcceptInvitationRequest - :> Post '[JSON] NoContent diff --git a/users/wpcarro/assessments/tt/src/Accounts.hs b/users/wpcarro/assessments/tt/src/Accounts.hs deleted file mode 100644 index c7ab7a2f1..000000000 --- a/users/wpcarro/assessments/tt/src/Accounts.hs +++ /dev/null @@ -1,49 +0,0 @@ -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE OverloadedStrings #-} --------------------------------------------------------------------------------- -module Accounts where --------------------------------------------------------------------------------- -import Database.SQLite.Simple - -import qualified PendingAccounts -import qualified Types as T --------------------------------------------------------------------------------- - --- | Delete the account in PendingAccounts and create on in Accounts. -transferFromPending :: FilePath -> T.PendingAccount -> IO () -transferFromPending dbFile T.PendingAccount{..} = withConnection dbFile $ - \conn -> withTransaction conn $ do - PendingAccounts.delete dbFile pendingAccountUsername - execute conn "INSERT INTO Accounts (username,password,email,role) VALUES (?,?,?,?)" - ( pendingAccountUsername - , pendingAccountPassword - , pendingAccountEmail - , pendingAccountRole - ) - --- | Create a new account in the Accounts table. -create :: FilePath -> T.Username -> T.ClearTextPassword -> T.Email -> T.Role -> IO () -create dbFile username password email role = withConnection dbFile $ \conn -> do - hashed <- T.hashPassword password - execute conn "INSERT INTO Accounts (username,password,email,role) VALUES (?,?,?,?)" - (username, hashed, email, role) - --- | Delete `username` from `dbFile`. -delete :: FilePath -> T.Username -> IO () -delete dbFile username = withConnection dbFile $ \conn -> do - execute conn "DELETE FROM Accounts WHERE username = ?" - (Only username) - --- | Attempt to find `username` in the Account table of `dbFile`. -lookup :: FilePath -> T.Username -> IO (Maybe T.Account) -lookup dbFile username = withConnection dbFile $ \conn -> do - res <- query conn "SELECT username,password,email,role,profilePicture FROM Accounts WHERE username = ?" (Only username) - case res of - [x] -> pure (Just x) - _ -> pure Nothing - --- | Return a list of accounts with the sensitive data removed. -list :: FilePath -> IO [T.User] -list dbFile = withConnection dbFile $ \conn -> do - accounts <- query_ conn "SELECT username,password,email,role,profilePicture FROM Accounts" - pure $ T.userFromAccount <$> accounts diff --git a/users/wpcarro/assessments/tt/src/App.hs b/users/wpcarro/assessments/tt/src/App.hs deleted file mode 100644 index 742bc962d..000000000 --- a/users/wpcarro/assessments/tt/src/App.hs +++ /dev/null @@ -1,270 +0,0 @@ -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE NamedFieldPuns #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE TypeApplications #-} --------------------------------------------------------------------------------- -module App where --------------------------------------------------------------------------------- -import Control.Monad.IO.Class (liftIO) -import Data.String.Conversions (cs) -import Data.Text (Text) -import Servant -import API -import Utils -import Web.Cookie - -import qualified Network.Wai.Handler.Warp as Warp -import qualified Network.Wai.Middleware.Cors as Cors -import qualified System.Random as Random -import qualified Email as Email -import qualified Data.UUID as UUID -import qualified Types as T -import qualified Accounts as Accounts -import qualified Auth as Auth -import qualified Trips as Trips -import qualified Sessions as Sessions -import qualified Invitations as Invitations -import qualified LoginAttempts as LoginAttempts -import qualified PendingAccounts as PendingAccounts --------------------------------------------------------------------------------- - -err429 :: ServerError -err429 = ServerError - { errHTTPCode = 429 - , errReasonPhrase = "Too many requests" - , errBody = "" - , errHeaders = [] - } - --- | Send an email to recipient, `to`, with a secret code. -sendVerifyEmail :: T.Config - -> T.Username - -> T.Email - -> T.RegistrationSecret - -> IO (Either Email.SendError Email.SendSuccess) -sendVerifyEmail T.Config{..} (T.Username username) email (T.RegistrationSecret secretUUID) = do - Email.send mailgunAPIKey subject (cs body) email - where - subject = "Please confirm your account" - body = - let secret = secretUUID |> UUID.toString in - "To verify your account: POST /verify username=" ++ cs username ++ " secret=" ++ secret - --- | Send an invitation email to recipient, `to`, with a secret code. -sendInviteEmail :: T.Config - -> T.Email - -> T.InvitationSecret - -> IO (Either Email.SendError Email.SendSuccess) -sendInviteEmail T.Config{..} email@(T.Email to) (T.InvitationSecret secretUUID) = do - Email.send mailgunAPIKey subject (cs body) email - where - subject = "You've been invited!" - body = - let secret = secretUUID |> UUID.toString in - "To accept the invitation: POST /accept-invitation username= password= email=" ++ cs to ++ " secret=" ++ secret - -server :: T.Config -> Server API -server config@T.Config{..} = createAccount - :<|> verifyAccount - :<|> deleteAccount - :<|> listAccounts - :<|> createTrip - :<|> updateTrip - :<|> deleteTrip - :<|> listTrips - :<|> login - :<|> logout - :<|> unfreezeAccount - :<|> inviteUser - :<|> acceptInvitation - where - -- Admit Admins + whatever the predicate `p` passes. - adminsAnd cookie p = Auth.assert dbFile cookie (\acct@T.Account{..} -> accountRole == T.Admin || p acct) - -- Admit Admins only. - adminsOnly cookie = adminsAnd cookie (const True) - - -- TODO(wpcarro): Handle failed CONSTRAINTs instead of sending 500s - createAccount :: Maybe T.SessionCookie - -> T.CreateAccountRequest - -> Handler NoContent - createAccount mCookie T.CreateAccountRequest{..} = - case (mCookie, createAccountRequestRole) of - (_, T.RegularUser) -> - doCreateAccount - (Nothing, T.Manager) -> - throwError err401 { errBody = "Only admins can create Manager accounts" } - (Nothing, T.Admin) -> - throwError err401 { errBody = "Only admins can create Admin accounts" } - (Just cookie, _) -> - adminsAnd cookie (\T.Account{..} -> accountRole == T.Manager) doCreateAccount - where - doCreateAccount :: Handler NoContent - doCreateAccount = do - secretUUID <- liftIO $ T.RegistrationSecret <$> Random.randomIO - liftIO $ PendingAccounts.create dbFile - secretUUID - createAccountRequestUsername - createAccountRequestPassword - createAccountRequestRole - createAccountRequestEmail - res <- liftIO $ sendVerifyEmail config - createAccountRequestUsername - createAccountRequestEmail - secretUUID - case res of - Left _ -> undefined - Right _ -> pure NoContent - - verifyAccount :: T.VerifyAccountRequest -> Handler NoContent - verifyAccount T.VerifyAccountRequest{..} = do - mPendingAccount <- liftIO $ PendingAccounts.get dbFile verifyAccountRequestUsername - case mPendingAccount of - Nothing -> - throwError err401 { errBody = "Either your secret or your username (or both) is invalid" } - Just pendingAccount@T.PendingAccount{..} -> - if pendingAccountSecret == verifyAccountRequestSecret then do - liftIO $ Accounts.transferFromPending dbFile pendingAccount - pure NoContent - else - throwError err401 { errBody = "The secret you provided is invalid" } - - deleteAccount :: T.SessionCookie -> Text -> Handler NoContent - deleteAccount cookie username = adminsOnly cookie $ do - liftIO $ Accounts.delete dbFile (T.Username username) - pure NoContent - - listAccounts :: T.SessionCookie -> Handler [T.User] - listAccounts cookie = adminsOnly cookie $ do - liftIO $ Accounts.list dbFile - - createTrip :: T.SessionCookie -> T.Trip -> Handler NoContent - createTrip cookie trip@T.Trip{..} = - adminsAnd cookie (\T.Account{..} -> accountUsername == tripUsername) $ do - liftIO $ Trips.create dbFile trip - pure NoContent - - updateTrip :: T.SessionCookie -> T.UpdateTripRequest -> Handler NoContent - updateTrip cookie updates@T.UpdateTripRequest{..} = - adminsAnd cookie (\T.Account{..} -> accountUsername == T.tripPKUsername updateTripRequestTripPK) $ do - mTrip <- liftIO $ Trips.get dbFile updateTripRequestTripPK - case mTrip of - Nothing -> throwError err400 { errBody = "tripKey is invalid" } - Just trip@T.Trip{..} -> do - -- TODO(wpcarro): Prefer function in Trips module that does this in a - -- DB transaction. - liftIO $ Trips.delete dbFile updateTripRequestTripPK - liftIO $ Trips.create dbFile (T.updateTrip updates trip) - pure NoContent - - deleteTrip :: T.SessionCookie -> T.TripPK -> Handler NoContent - deleteTrip cookie tripPK@T.TripPK{..} = - adminsAnd cookie (\T.Account{..} -> accountUsername == tripPKUsername) $ do - liftIO $ Trips.delete dbFile tripPK - pure NoContent - - listTrips :: T.SessionCookie -> Handler [T.Trip] - listTrips cookie = do - mAccount <- liftIO $ Auth.accountFromCookie dbFile cookie - case mAccount of - Nothing -> throwError err401 { errBody = "Your session cookie is invalid. Try logging out and logging back in." } - Just T.Account{..} -> - case accountRole of - T.Admin -> liftIO $ Trips.listAll dbFile - _ -> liftIO $ Trips.list dbFile accountUsername - - login :: T.AccountCredentials - -> Handler (Headers '[Header "Set-Cookie" SetCookie] T.Session) - login (T.AccountCredentials username password) = do - mAccount <- liftIO $ Accounts.lookup dbFile username - case mAccount of - Just account@T.Account{..} -> do - mAttempts <- liftIO $ LoginAttempts.forUsername dbFile accountUsername - case mAttempts of - Nothing -> - if T.passwordsMatch password accountPassword then do - uuid <- liftIO $ Sessions.findOrCreate dbFile account - pure $ addHeader (Auth.mkCookie uuid) - T.Session{ sessionUsername = accountUsername - , sessionRole = accountRole - } - else do - liftIO $ LoginAttempts.increment dbFile username - throwError err401 { errBody = "Your credentials are invalid" } - Just attempts -> - if attempts >= 3 then - throwError err429 - else if T.passwordsMatch password accountPassword then do - uuid <- liftIO $ Sessions.findOrCreate dbFile account - pure $ addHeader (Auth.mkCookie uuid) - T.Session{ sessionUsername = accountUsername - , sessionRole = accountRole - } - else do - liftIO $ LoginAttempts.increment dbFile username - throwError err401 { errBody = "Your credentials are invalid" } - - -- In this branch, the user didn't supply a known username. - Nothing -> throwError err401 { errBody = "Your credentials are invalid" } - - logout :: T.SessionCookie - -> Handler (Headers '[Header "Set-Cookie" SetCookie] NoContent) - logout cookie = do - case Auth.uuidFromCookie cookie of - Nothing -> - pure $ addHeader Auth.emptyCookie NoContent - Just uuid -> do - liftIO $ Sessions.delete dbFile uuid - pure $ addHeader Auth.emptyCookie NoContent - - unfreezeAccount :: T.SessionCookie - -> T.UnfreezeAccountRequest - -> Handler NoContent - unfreezeAccount cookie T.UnfreezeAccountRequest{..} = - adminsAnd cookie (\T.Account{..} -> accountRole == T.Manager) $ do - liftIO $ LoginAttempts.reset dbFile unfreezeAccountRequestUsername - pure NoContent - - inviteUser :: T.SessionCookie - -> T.InviteUserRequest - -> Handler NoContent - inviteUser cookie T.InviteUserRequest{..} = adminsOnly cookie $ do - secretUUID <- liftIO $ T.InvitationSecret <$> Random.randomIO - liftIO $ Invitations.create dbFile - secretUUID - inviteUserRequestEmail - inviteUserRequestRole - res <- liftIO $ sendInviteEmail config inviteUserRequestEmail secretUUID - case res of - Left _ -> undefined - Right _ -> pure NoContent - - acceptInvitation :: T.AcceptInvitationRequest -> Handler NoContent - acceptInvitation T.AcceptInvitationRequest{..} = do - mInvitation <- liftIO $ Invitations.get dbFile acceptInvitationRequestEmail - case mInvitation of - Nothing -> throwError err404 { errBody = "No invitation for email" } - Just T.Invitation{..} -> - if invitationSecret == acceptInvitationRequestSecret then do - liftIO $ Accounts.create dbFile - acceptInvitationRequestUsername - acceptInvitationRequestPassword - invitationEmail - invitationRole - pure NoContent - else - throwError err401 { errBody = "You are not providing a valid secret" } - -run :: T.Config -> IO () -run config@T.Config{..} = - Warp.run 3000 (enforceCors $ serve (Proxy @ API) $ server config) - where - enforceCors = Cors.cors (const $ Just corsPolicy) - corsPolicy :: Cors.CorsResourcePolicy - corsPolicy = - Cors.simpleCorsResourcePolicy - { Cors.corsOrigins = Just ([cs configClient], True) - , Cors.corsMethods = Cors.simpleMethods ++ ["PUT", "PATCH", "DELETE", "OPTIONS"] - , Cors.corsRequestHeaders = Cors.simpleHeaders ++ ["Content-Type", "Authorization"] - } diff --git a/users/wpcarro/assessments/tt/src/Auth.hs b/users/wpcarro/assessments/tt/src/Auth.hs deleted file mode 100644 index f1bff2325..000000000 --- a/users/wpcarro/assessments/tt/src/Auth.hs +++ /dev/null @@ -1,64 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Auth where --------------------------------------------------------------------------------- -import Control.Monad.IO.Class (liftIO) -import Web.Cookie -import Servant - -import qualified Data.UUID as UUID -import qualified Sessions as Sessions -import qualified Accounts as Accounts -import qualified Types as T --------------------------------------------------------------------------------- - --- | Return the UUID from a Session cookie. -uuidFromCookie :: T.SessionCookie -> Maybe T.SessionUUID -uuidFromCookie (T.SessionCookie cookies) = do - auth <- lookup "auth" cookies - uuid <- UUID.fromASCIIBytes auth - pure $ T.SessionUUID uuid - --- | Attempt to return the account associated with `cookie`. -accountFromCookie :: FilePath -> T.SessionCookie -> IO (Maybe T.Account) -accountFromCookie dbFile cookie = - case uuidFromCookie cookie of - Nothing -> pure Nothing - Just uuid -> do - mSession <- Sessions.get dbFile uuid - case mSession of - Nothing -> pure Nothing - Just T.StoredSession{..} -> do - mAccount <- Accounts.lookup dbFile storedSessionUsername - case mAccount of - Nothing -> pure Nothing - Just x -> pure (Just x) - --- | Create a new session cookie. -mkCookie :: T.SessionUUID -> SetCookie -mkCookie (T.SessionUUID uuid) = - defaultSetCookie - { setCookieName = "auth" - , setCookieValue = UUID.toASCIIBytes uuid - } - --- | Use this to clear out the session cookie. -emptyCookie :: SetCookie -emptyCookie = - defaultSetCookie - { setCookieName = "auth" - , setCookieValue = "" - } - --- | Throw a 401 error if the `predicate` fails. -assert :: FilePath -> T.SessionCookie -> (T.Account -> Bool) -> Handler a -> Handler a -assert dbFile cookie predicate handler = do - mRole <- liftIO $ accountFromCookie dbFile cookie - case mRole of - Nothing -> throwError err401 { errBody = "Missing valid session cookie" } - Just account -> - if predicate account then - handler - else - throwError err401 { errBody = "You are not authorized to access this resource" } diff --git a/users/wpcarro/assessments/tt/src/Email.hs b/users/wpcarro/assessments/tt/src/Email.hs deleted file mode 100644 index 2dac0973b..000000000 --- a/users/wpcarro/assessments/tt/src/Email.hs +++ /dev/null @@ -1,46 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} --------------------------------------------------------------------------------- -module Email where --------------------------------------------------------------------------------- -import Data.Text -import Data.String.Conversions (cs) -import Utils - -import qualified Mail.Hailgun as MG -import qualified Types as T --------------------------------------------------------------------------------- - -newtype SendSuccess = SendSuccess MG.HailgunSendResponse - -data SendError - = MessageError MG.HailgunErrorMessage - | ResponseError MG.HailgunErrorResponse - --- | Attempt to send an email with `subject` and with message, `body`. -send :: Text - -> Text - -> Text - -> T.Email - -> IO (Either SendError SendSuccess) -send apiKey subject body (T.Email to) = do - case mkMsg of - Left e -> pure $ Left (MessageError e) - Right x -> do - res <- MG.sendEmail ctx x - case res of - Left e -> pure $ Left (ResponseError e) - Right y -> pure $ Right (SendSuccess y) - where - ctx = MG.HailgunContext { MG.hailgunDomain = "sandboxda5038873f924b50af2f82a0f05cffdf.mailgun.org" - , MG.hailgunApiKey = cs apiKey - , MG.hailgunProxy = Nothing - } - mkMsg = MG.hailgunMessage - subject - (body |> cs |> MG.TextOnly) - "mailgun@sandboxda5038873f924b50af2f82a0f05cffdf.mailgun.org" - (MG.MessageRecipients { MG.recipientsTo = [cs to] - , MG.recipientsCC = [] - , MG.recipientsBCC = [] - }) - [] diff --git a/users/wpcarro/assessments/tt/src/Invitations.hs b/users/wpcarro/assessments/tt/src/Invitations.hs deleted file mode 100644 index 0c700470f..000000000 --- a/users/wpcarro/assessments/tt/src/Invitations.hs +++ /dev/null @@ -1,21 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module Invitations where --------------------------------------------------------------------------------- -import Database.SQLite.Simple - -import qualified Types as T --------------------------------------------------------------------------------- - -create :: FilePath -> T.InvitationSecret -> T.Email -> T.Role -> IO () -create dbFile secret email role = withConnection dbFile $ \conn -> do - execute conn "INSERT INTO Invitations (email,role,secret) VALUES (?,?,?)" - (email, role, secret) - -get :: FilePath -> T.Email -> IO (Maybe T.Invitation) -get dbFile email = withConnection dbFile $ \conn -> do - res <- query conn "SELECT email,role,secret FROM Invitations WHERE email = ?" (Only email) - case res of - [x] -> pure (Just x) - _ -> pure Nothing diff --git a/users/wpcarro/assessments/tt/src/LoginAttempts.hs b/users/wpcarro/assessments/tt/src/LoginAttempts.hs deleted file mode 100644 index d78e12e3f..000000000 --- a/users/wpcarro/assessments/tt/src/LoginAttempts.hs +++ /dev/null @@ -1,30 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module LoginAttempts where --------------------------------------------------------------------------------- -import Database.SQLite.Simple - -import qualified Types as T --------------------------------------------------------------------------------- - -reset :: FilePath -> T.Username -> IO () -reset dbFile username = withConnection dbFile $ \conn -> - execute conn "UPDATE LoginAttempts SET numAttempts = 0 WHERE username = ?" - (Only username) - --- | Attempt to return the number of failed login attempts for --- `username`. Returns a Maybe in case `username` doesn't exist. -forUsername :: FilePath -> T.Username -> IO (Maybe Integer) -forUsername dbFile username = withConnection dbFile $ \conn -> do - res <- query conn "SELECT username,numAttempts FROM LoginAttempts WHERE username = ?" - (Only username) - case res of - [T.LoginAttempt{..}] -> pure (Just loginAttemptNumAttempts) - _ -> pure Nothing - --- | INSERT a failed login attempt for `username` or UPDATE an existing entry. -increment :: FilePath -> T.Username -> IO () -increment dbFile username = withConnection dbFile $ \conn -> - execute conn "INSERT INTO LoginAttempts (username,numAttempts) VALUES (?,?) ON CONFLICT (username) DO UPDATE SET numAttempts = numAttempts + 1" - (username, 1 :: Integer) diff --git a/users/wpcarro/assessments/tt/src/Main.hs b/users/wpcarro/assessments/tt/src/Main.hs deleted file mode 100644 index 9df423206..000000000 --- a/users/wpcarro/assessments/tt/src/Main.hs +++ /dev/null @@ -1,13 +0,0 @@ --------------------------------------------------------------------------------- -module Main where --------------------------------------------------------------------------------- -import qualified App -import qualified System.Envy as Envy --------------------------------------------------------------------------------- - -main :: IO () -main = do - mEnv <- Envy.decodeEnv - case mEnv of - Left err -> putStrLn err - Right env -> App.run env diff --git a/users/wpcarro/assessments/tt/src/PendingAccounts.hs b/users/wpcarro/assessments/tt/src/PendingAccounts.hs deleted file mode 100644 index a555185fa..000000000 --- a/users/wpcarro/assessments/tt/src/PendingAccounts.hs +++ /dev/null @@ -1,32 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} --------------------------------------------------------------------------------- -module PendingAccounts where --------------------------------------------------------------------------------- -import Database.SQLite.Simple - -import qualified Types as T --------------------------------------------------------------------------------- - -create :: FilePath - -> T.RegistrationSecret - -> T.Username - -> T.ClearTextPassword - -> T.Role - -> T.Email - -> IO () -create dbFile secret username password role email = withConnection dbFile $ \conn -> do - hashed <- T.hashPassword password - execute conn "INSERT INTO PendingAccounts (secret,username,password,role,email) VALUES (?,?,?,?,?)" - (secret, username, hashed, role, email) - -get :: FilePath -> T.Username -> IO (Maybe T.PendingAccount) -get dbFile username = withConnection dbFile $ \conn -> do - res <- query conn "SELECT secret,username,password,role,email FROM PendingAccounts WHERE username = ?" (Only username) - case res of - [x] -> pure (Just x) - _ -> pure Nothing - -delete :: FilePath -> T.Username -> IO () -delete dbFile username = withConnection dbFile $ \conn -> - execute conn "DELETE FROM PendingAccounts WHERE username = ?" (Only username) diff --git a/users/wpcarro/assessments/tt/src/Sessions.hs b/users/wpcarro/assessments/tt/src/Sessions.hs deleted file mode 100644 index 713059a38..000000000 --- a/users/wpcarro/assessments/tt/src/Sessions.hs +++ /dev/null @@ -1,74 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ScopedTypeVariables #-} --------------------------------------------------------------------------------- -module Sessions where --------------------------------------------------------------------------------- -import Database.SQLite.Simple - -import qualified Data.Time.Clock as Clock -import qualified Types as T -import qualified System.Random as Random --------------------------------------------------------------------------------- - --- | Return True if `session` was created at most three hours ago. -isValid :: T.StoredSession -> IO Bool -isValid session = do - t1 <- Clock.getCurrentTime - let t0 = T.storedSessionTsCreated session in - pure $ Clock.diffUTCTime t1 t0 <= 3 * 60 * 60 - --- | Lookup the session by UUID. -get :: FilePath -> T.SessionUUID -> IO (Maybe T.StoredSession) -get dbFile uuid = withConnection dbFile $ \conn -> do - res <- query conn "SELECT uuid,username,tsCreated FROM Sessions WHERE uuid = ?" (Only uuid) - case res of - [x] -> pure (Just x) - _ -> pure Nothing - --- | Lookup the session stored under `username` in `dbFile`. -find :: FilePath -> T.Username -> IO (Maybe T.StoredSession) -find dbFile username = withConnection dbFile $ \conn -> do - res <- query conn "SELECT uuid,username,tsCreated FROM Sessions WHERE username = ?" (Only username) - case res of - [x] -> pure (Just x) - _ -> pure Nothing - --- | Create a session under the `username` key in `dbFile`. -create :: FilePath -> T.Username -> IO T.SessionUUID -create dbFile username = withConnection dbFile $ \conn -> do - now <- Clock.getCurrentTime - uuid <- Random.randomIO - execute conn "INSERT INTO Sessions (uuid,username,tsCreated) VALUES (?,?,?)" - (T.SessionUUID uuid, username, now) - pure (T.SessionUUID uuid) - --- | Reset the tsCreated field to the current time to ensure the token is valid. -refresh :: FilePath -> T.SessionUUID -> IO () -refresh dbFile uuid = withConnection dbFile $ \conn -> do - now <- Clock.getCurrentTime - execute conn "UPDATE Sessions SET tsCreated = ? WHERE uuid = ?" - (now, uuid) - pure () - --- | Delete the session under `username` from `dbFile`. -delete :: FilePath -> T.SessionUUID -> IO () -delete dbFile uuid = withConnection dbFile $ \conn -> - execute conn "DELETE FROM Sessions WHERE uuid = ?" (Only uuid) - --- | Find or create a session in the Sessions table. If a session exists, --- refresh the token's validity. -findOrCreate :: FilePath -> T.Account -> IO T.SessionUUID -findOrCreate dbFile account = - let username = T.accountUsername account in do - mSession <- find dbFile username - case mSession of - Nothing -> create dbFile username - Just session -> - let uuid = T.storedSessionUUID session in do - refresh dbFile uuid - pure uuid - --- | Return a list of all sessions in the Sessions table. -list :: FilePath -> IO [T.StoredSession] -list dbFile = withConnection dbFile $ \conn -> - query_ conn "SELECT uuid,username,tsCreated FROM Sessions" diff --git a/users/wpcarro/assessments/tt/src/Trips.hs b/users/wpcarro/assessments/tt/src/Trips.hs deleted file mode 100644 index f90740363..000000000 --- a/users/wpcarro/assessments/tt/src/Trips.hs +++ /dev/null @@ -1,42 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} --------------------------------------------------------------------------------- -module Trips where --------------------------------------------------------------------------------- -import Database.SQLite.Simple -import Utils - -import qualified Types as T --------------------------------------------------------------------------------- - --- | Create a new `trip` in `dbFile`. -create :: FilePath -> T.Trip -> IO () -create dbFile trip = withConnection dbFile $ \conn -> - execute conn "INSERT INTO Trips (username,destination,startDate,endDate,comment) VALUES (?,?,?,?,?)" - (trip |> T.tripFields) - --- | Attempt to get the trip record from `dbFile` under `tripKey`. -get :: FilePath -> T.TripPK -> IO (Maybe T.Trip) -get dbFile tripKey = withConnection dbFile $ \conn -> do - res <- query conn "SELECT username,destination,startDate,endDate,comment FROM Trips WHERE username = ? AND destination = ? AND startDate = ? LIMIT 1" - (T.tripPKFields tripKey) - case res of - [x] -> pure (Just x) - _ -> pure Nothing - --- | Delete a trip from `dbFile` using its `tripKey` Primary Key. -delete :: FilePath -> T.TripPK -> IO () -delete dbFile tripKey = - withConnection dbFile $ \conn -> do - execute conn "DELETE FROM Trips WHERE username = ? AND destination = ? and startDate = ?" - (T.tripPKFields tripKey) - --- | Return a list of all of the trips in `dbFile`. -listAll :: FilePath -> IO [T.Trip] -listAll dbFile = withConnection dbFile $ \conn -> - query_ conn "SELECT username,destination,startDate,endDate,comment FROM Trips ORDER BY date(startDate) ASC" - --- | Return a list of all of the trips in `dbFile`. -list :: FilePath -> T.Username -> IO [T.Trip] -list dbFile username = withConnection dbFile $ \conn -> - query conn "SELECT username,destination,startDate,endDate,comment FROM Trips WHERE username = ? ORDER BY date(startDate) ASC" - (Only username) diff --git a/users/wpcarro/assessments/tt/src/Types.hs b/users/wpcarro/assessments/tt/src/Types.hs deleted file mode 100644 index 6b06a3969..000000000 --- a/users/wpcarro/assessments/tt/src/Types.hs +++ /dev/null @@ -1,544 +0,0 @@ -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE NamedFieldPuns #-} --------------------------------------------------------------------------------- -module Types where --------------------------------------------------------------------------------- -import Data.Aeson -import Utils -import Data.Text -import Data.Typeable -import Database.SQLite.Simple -import Database.SQLite.Simple.Ok -import Database.SQLite.Simple.FromField -import Database.SQLite.Simple.ToField -import GHC.Generics -import Web.Cookie -import Servant.API -import System.Envy (FromEnv, fromEnv, env) -import Crypto.Random.Types (MonadRandom) - -import qualified Data.Time.Calendar as Calendar -import qualified Crypto.KDF.BCrypt as BC -import qualified Data.Time.Clock as Clock -import qualified Data.ByteString.Char8 as B -import qualified Data.ByteString as BS -import qualified Data.Text.Encoding as TE -import qualified Data.Maybe as M -import qualified Data.UUID as UUID --------------------------------------------------------------------------------- - --- | Top-level application configuration. -data Config = Config - { mailgunAPIKey :: Text - , dbFile :: FilePath - , configClient :: Text - , configServer :: Text - } deriving (Eq, Show) - -instance FromEnv Config where - fromEnv _ = do - mailgunAPIKey <- env "MAILGUN_API_KEY" - dbFile <- env "DB_FILE" - configClient <- env "CLIENT" - configServer <- env "SERVER" - pure Config {..} - --- TODO(wpcarro): Properly handle NULL for columns like profilePicture. -forNewtype :: (Typeable b) => (Text -> b) -> FieldParser b -forNewtype wrapper y = - case fieldData y of - (SQLText x) -> Ok (wrapper x) - x -> returnError ConversionFailed y ("We expected SQLText, but we received: " ++ show x) - -newtype Username = Username Text - deriving (Eq, Show, Generic) - -instance ToJSON Username -instance FromJSON Username - -instance ToField Username where - toField (Username x) = SQLText x - -instance FromField Username where - fromField = forNewtype Username - -newtype HashedPassword = HashedPassword BS.ByteString - deriving (Eq, Show, Generic) - -instance ToField HashedPassword where - toField (HashedPassword x) = SQLText (TE.decodeUtf8 x) - -instance FromField HashedPassword where - fromField y = - case fieldData y of - (SQLText x) -> x |> TE.encodeUtf8 |> HashedPassword |> Ok - x -> returnError ConversionFailed y ("We expected SQLText, but we received: " ++ show x) - -newtype ClearTextPassword = ClearTextPassword Text - deriving (Eq, Show, Generic) - -instance ToJSON ClearTextPassword -instance FromJSON ClearTextPassword - -instance ToField ClearTextPassword where - toField (ClearTextPassword x) = SQLText x - -instance FromField ClearTextPassword where - fromField = forNewtype ClearTextPassword - -newtype Email = Email Text - deriving (Eq, Show, Generic) - -instance ToJSON Email -instance FromJSON Email - -instance ToField Email where - toField (Email x) = SQLText x - -instance FromField Email where - fromField = forNewtype Email - -data Role = RegularUser | Manager | Admin - deriving (Eq, Show, Generic) - -instance ToJSON Role where - toJSON RegularUser = "user" - toJSON Manager = "manager" - toJSON Admin = "admin" - -instance FromJSON Role where - parseJSON = withText "Role" $ \x -> - case x of - "user" -> pure RegularUser - "manager" -> pure Manager - "admin" -> pure Admin - _ -> fail "Expected \"user\" or \"manager\" or \"admin\"" - -instance ToField Role where - toField RegularUser = SQLText "user" - toField Manager = SQLText "manager" - toField Admin = SQLText "admin" - -instance FromField Role where - fromField y = - case fieldData y of - (SQLText "user") -> Ok RegularUser - (SQLText "manager") -> Ok Manager - (SQLText "admin") -> Ok Admin - x -> returnError ConversionFailed y ("We expected user, manager, admin, but we received: " ++ show x) - --- TODO(wpcarro): Prefer Data.ByteString instead of Text -newtype ProfilePicture = ProfilePicture Text - deriving (Eq, Show, Generic) - -instance ToJSON ProfilePicture -instance FromJSON ProfilePicture - -instance ToField ProfilePicture where - toField (ProfilePicture x) = SQLText x - -instance FromField ProfilePicture where - fromField = forNewtype ProfilePicture - -data Account = Account - { accountUsername :: Username - , accountPassword :: HashedPassword - , accountEmail :: Email - , accountRole :: Role - , accountProfilePicture :: Maybe ProfilePicture - } deriving (Eq, Show, Generic) - --- | Return a tuple with all of the fields for an Account record to use for SQL. -accountFields :: Account -> (Username, HashedPassword, Email, Role, Maybe ProfilePicture) -accountFields (Account {..}) - = ( accountUsername - , accountPassword - , accountEmail - , accountRole - , accountProfilePicture - ) - -instance FromRow Account where - fromRow = do - accountUsername <- field - accountPassword <- field - accountEmail <- field - accountRole <- field - accountProfilePicture <- field - pure Account{..} - -data Session = Session - { sessionUsername :: Username - , sessionRole :: Role - } deriving (Eq, Show) - -instance ToJSON Session where - toJSON (Session username role) = - object [ "username" .= username - , "role" .= role - ] - -newtype Comment = Comment Text - deriving (Eq, Show, Generic) - -instance ToJSON Comment -instance FromJSON Comment - -instance ToField Comment where - toField (Comment x) = SQLText x - -instance FromField Comment where - fromField = forNewtype Comment - -newtype Destination = Destination Text - deriving (Eq, Show, Generic) - -instance ToJSON Destination -instance FromJSON Destination - -instance ToField Destination where - toField (Destination x) = SQLText x - -instance FromField Destination where - fromField = forNewtype Destination - -newtype Year = Year Integer deriving (Eq, Show) -newtype Month = Month Integer deriving (Eq, Show) -newtype Day = Day Integer deriving (Eq, Show) -data Date = Date - { dateYear :: Year - , dateMonth :: Month - , dateDay :: Day - } deriving (Eq, Show) - -data Trip = Trip - { tripUsername :: Username - , tripDestination :: Destination - , tripStartDate :: Calendar.Day - , tripEndDate :: Calendar.Day - , tripComment :: Comment - } deriving (Eq, Show, Generic) - -instance FromRow Trip where - fromRow = do - tripUsername <- field - tripDestination <- field - tripStartDate <- field - tripEndDate <- field - tripComment <- field - pure Trip{..} - --- | The fields used as the Primary Key for a Trip entry. -data TripPK = TripPK - { tripPKUsername :: Username - , tripPKDestination :: Destination - , tripPKStartDate :: Calendar.Day - } deriving (Eq, Show, Generic) - -tripPKFields :: TripPK -> (Username, Destination, Calendar.Day) -tripPKFields (TripPK{..}) - = (tripPKUsername, tripPKDestination, tripPKStartDate) - -instance FromJSON TripPK where - parseJSON = withObject "TripPK" $ \x -> do - tripPKUsername <- x .: "username" - tripPKDestination <- x .: "destination" - tripPKStartDate <- x .: "startDate" - pure TripPK{..} - --- | Return the tuple representation of a Trip record for SQL. -tripFields :: Trip - -> (Username, Destination, Calendar.Day, Calendar.Day, Comment) -tripFields (Trip{..}) - = ( tripUsername - , tripDestination - , tripStartDate - , tripEndDate - , tripComment - ) - -instance ToJSON Trip where - toJSON (Trip username destination startDate endDate comment) = - object [ "username" .= username - , "destination" .= destination - , "startDate" .= startDate - , "endDate" .= endDate - , "comment" .= comment - ] - -instance FromJSON Trip where - parseJSON = withObject "Trip" $ \x -> do - tripUsername <- x .: "username" - tripDestination <- x .: "destination" - tripStartDate <- x .: "startDate" - tripEndDate <- x .: "endDate" - tripComment <- x .: "comment" - pure Trip{..} - --- | Users and Accounts both refer to the same underlying entities; however, --- Users model the user-facing Account details, hiding sensitive details like --- passwords and emails. -data User = User - { userUsername :: Username - , userProfilePicture :: Maybe ProfilePicture - , userRole :: Role - } deriving (Eq, Show, Generic) - -instance ToJSON User where - toJSON (User username profilePicture role) = - object [ "username" .= username - , "profilePicture" .= profilePicture - , "role" .= role - ] - -userFromAccount :: Account -> User -userFromAccount account = - User { userUsername = accountUsername account - , userProfilePicture = accountProfilePicture account - , userRole = accountRole account - } - --- | This is the data that a user needs to supply to authenticate with the --- application. -data AccountCredentials = AccountCredentials - { accountCredentialsUsername :: Username - , accountCredentialsPassword :: ClearTextPassword - } deriving (Eq, Show, Generic) - -instance FromJSON AccountCredentials where - parseJSON = withObject "AccountCredentials" $ \x -> do - accountCredentialsUsername <- x.: "username" - accountCredentialsPassword <- x.: "password" - pure AccountCredentials{..} - - --- | Hash password `x`. -hashPassword :: (MonadRandom m) => ClearTextPassword -> m HashedPassword -hashPassword (ClearTextPassword x) = do - hashed <- BC.hashPassword 12 (x |> unpack |> B.pack) - pure $ HashedPassword hashed - --- | Return True if the cleartext password matches the hashed password. -passwordsMatch :: ClearTextPassword -> HashedPassword -> Bool -passwordsMatch (ClearTextPassword clear) (HashedPassword hashed) = - BC.validatePassword (clear |> unpack |> B.pack) hashed - -data CreateAccountRequest = CreateAccountRequest - { createAccountRequestUsername :: Username - , createAccountRequestPassword :: ClearTextPassword - , createAccountRequestEmail :: Email - , createAccountRequestRole :: Role - } deriving (Eq, Show) - -instance FromJSON CreateAccountRequest where - parseJSON = withObject "CreateAccountRequest" $ \x -> do - createAccountRequestUsername <- x .: "username" - createAccountRequestPassword <- x .: "password" - createAccountRequestEmail <- x .: "email" - createAccountRequestRole <- x .: "role" - pure $ CreateAccountRequest{..} - -createAccountRequestFields :: CreateAccountRequest - -> (Username, ClearTextPassword, Email, Role) -createAccountRequestFields CreateAccountRequest{..} = - ( createAccountRequestUsername - , createAccountRequestPassword - , createAccountRequestEmail - , createAccountRequestRole - ) - -newtype SessionUUID = SessionUUID UUID.UUID - deriving (Eq, Show, Generic) - -instance FromField SessionUUID where - fromField y = - case fieldData y of - (SQLText x) -> - case UUID.fromText x of - Nothing -> returnError ConversionFailed y ("Could not convert to UUID: " ++ show x) - Just uuid -> Ok $ SessionUUID uuid - _ -> returnError ConversionFailed y "Expected SQLText for SessionUUID, but we received" - -instance ToField SessionUUID where - toField (SessionUUID uuid) = - uuid |> UUID.toText |> SQLText - -data StoredSession = StoredSession - { storedSessionUUID :: SessionUUID - , storedSessionUsername :: Username - , storedSessionTsCreated :: Clock.UTCTime - } deriving (Eq, Show, Generic) - -instance FromRow StoredSession where - fromRow = do - storedSessionUUID <- field - storedSessionUsername <- field - storedSessionTsCreated <- field - pure StoredSession {..} - -data LoginAttempt = LoginAttempt - { loginAttemptUsername :: Username - , loginAttemptNumAttempts :: Integer - } deriving (Eq, Show) - -instance FromRow LoginAttempt where - fromRow = do - loginAttemptUsername <- field - loginAttemptNumAttempts <- field - pure LoginAttempt {..} - -newtype SessionCookie = SessionCookie Cookies - -instance FromHttpApiData SessionCookie where - parseHeader x = - x |> parseCookies |> SessionCookie |> pure - parseQueryParam x = - x |> TE.encodeUtf8 |> parseCookies |> SessionCookie |> pure - -newtype RegistrationSecret = RegistrationSecret UUID.UUID - deriving (Eq, Show, Generic) - -instance FromHttpApiData RegistrationSecret where - parseQueryParam x = - case UUID.fromText x of - Nothing -> Left x - Just uuid -> Right (RegistrationSecret uuid) - -instance FromField RegistrationSecret where - fromField y = - case fieldData y of - (SQLText x) -> - case UUID.fromText x of - Nothing -> returnError ConversionFailed y ("Could not convert text to UUID: " ++ show x) - Just uuid -> Ok $ RegistrationSecret uuid - _ -> returnError ConversionFailed y "Field data is not SQLText, which is what we expect" - -instance ToField RegistrationSecret where - toField (RegistrationSecret secretUUID) = - secretUUID |> UUID.toText |> SQLText - -instance FromJSON RegistrationSecret - -data VerifyAccountRequest = VerifyAccountRequest - { verifyAccountRequestUsername :: Username - , verifyAccountRequestSecret :: RegistrationSecret - } deriving (Eq, Show) - -instance FromJSON VerifyAccountRequest where - parseJSON = withObject "VerifyAccountRequest" $ \x -> do - verifyAccountRequestUsername <- x .: "username" - verifyAccountRequestSecret <- x .: "secret" - pure VerifyAccountRequest{..} - -data PendingAccount = PendingAccount - { pendingAccountSecret :: RegistrationSecret - , pendingAccountUsername :: Username - , pendingAccountPassword :: HashedPassword - , pendingAccountRole :: Role - , pendingAccountEmail :: Email - } deriving (Eq, Show) - -instance FromRow PendingAccount where - fromRow = do - pendingAccountSecret <- field - pendingAccountUsername <- field - pendingAccountPassword <- field - pendingAccountRole <- field - pendingAccountEmail <- field - pure PendingAccount {..} - -data UpdateTripRequest = UpdateTripRequest - { updateTripRequestTripPK :: TripPK - , updateTripRequestDestination :: Maybe Destination - , updateTripRequestStartDate :: Maybe Calendar.Day - , updateTripRequestEndDate :: Maybe Calendar.Day - , updateTripRequestComment :: Maybe Comment - } deriving (Eq, Show) - -instance FromJSON UpdateTripRequest where - parseJSON = withObject "UpdateTripRequest" $ \x -> do - updateTripRequestTripPK <- x .: "tripKey" - -- the following four fields might not be present - updateTripRequestDestination <- x .:? "destination" - updateTripRequestStartDate <- x .:? "startDate" - updateTripRequestEndDate <- x .:? "endDate" - updateTripRequestComment <- x .:? "comment" - pure UpdateTripRequest{..} - --- | Apply the updates in the UpdateTripRequest to Trip. -updateTrip :: UpdateTripRequest -> Trip -> Trip -updateTrip UpdateTripRequest{..} Trip{..} = Trip - { tripUsername = tripUsername - , tripDestination = M.fromMaybe tripDestination updateTripRequestDestination - , tripStartDate = M.fromMaybe tripStartDate updateTripRequestStartDate - , tripEndDate = M.fromMaybe tripEndDate updateTripRequestEndDate - , tripComment = M.fromMaybe tripComment updateTripRequestComment - } - -data UnfreezeAccountRequest = UnfreezeAccountRequest - { unfreezeAccountRequestUsername :: Username - } deriving (Eq, Show) - -instance FromJSON UnfreezeAccountRequest where - parseJSON = withObject "UnfreezeAccountRequest" $ \x -> do - unfreezeAccountRequestUsername <- x .: "username" - pure UnfreezeAccountRequest{..} - -data InviteUserRequest = InviteUserRequest - { inviteUserRequestEmail :: Email - , inviteUserRequestRole :: Role - } deriving (Eq, Show) - -instance FromJSON InviteUserRequest where - parseJSON = withObject "InviteUserRequest" $ \x -> do - inviteUserRequestEmail <- x .: "email" - inviteUserRequestRole <- x .: "role" - pure InviteUserRequest{..} - -newtype InvitationSecret = InvitationSecret UUID.UUID - deriving (Eq, Show, Generic) - -instance ToJSON InvitationSecret -instance FromJSON InvitationSecret - -instance ToField InvitationSecret where - toField (InvitationSecret secretUUID) = - secretUUID |> UUID.toText |> SQLText - -instance FromField InvitationSecret where - fromField y = - case fieldData y of - (SQLText x) -> - case UUID.fromText x of - Nothing -> returnError ConversionFailed y ("Could not convert text to UUID: " ++ show x) - Just z -> Ok $ InvitationSecret z - _ -> returnError ConversionFailed y "Field data is not SQLText, which is what we expect" - -data Invitation = Invitation - { invitationEmail :: Email - , invitationRole :: Role - , invitationSecret :: InvitationSecret - } deriving (Eq, Show) - -instance FromRow Invitation where - fromRow = Invitation <$> field - <*> field - <*> field - -data AcceptInvitationRequest = AcceptInvitationRequest - { acceptInvitationRequestUsername :: Username - , acceptInvitationRequestPassword :: ClearTextPassword - , acceptInvitationRequestEmail :: Email - , acceptInvitationRequestSecret :: InvitationSecret - } deriving (Eq, Show) - -instance FromJSON AcceptInvitationRequest where - parseJSON = withObject "AcceptInvitationRequest" $ \x -> do - acceptInvitationRequestUsername <- x .: "username" - acceptInvitationRequestPassword <- x .: "password" - acceptInvitationRequestEmail <- x .: "email" - acceptInvitationRequestSecret <- x .: "secret" - pure AcceptInvitationRequest{..} diff --git a/users/wpcarro/assessments/tt/src/Utils.hs b/users/wpcarro/assessments/tt/src/Utils.hs deleted file mode 100644 index 48c33af07..000000000 --- a/users/wpcarro/assessments/tt/src/Utils.hs +++ /dev/null @@ -1,9 +0,0 @@ --------------------------------------------------------------------------------- -module Utils where --------------------------------------------------------------------------------- -import Data.Function ((&)) --------------------------------------------------------------------------------- - --- | Prefer this operator to the ampersand for stylistic reasons. -(|>) :: a -> (a -> b) -> b -(|>) = (&) diff --git a/users/wpcarro/assessments/tt/src/init.sql b/users/wpcarro/assessments/tt/src/init.sql deleted file mode 100644 index b42753ae5..000000000 --- a/users/wpcarro/assessments/tt/src/init.sql +++ /dev/null @@ -1,67 +0,0 @@ --- Run `.read init.sql` from within a SQLite3 REPL to initialize the tables we --- need for this application. This will erase all current entries, so use with --- caution. --- Make sure to set `PRAGMA foreign_keys = on;` when transacting with the --- database. - -BEGIN TRANSACTION; - -DROP TABLE IF EXISTS Accounts; -DROP TABLE IF EXISTS Trips; -DROP TABLE IF EXISTS Sessions; -DROP TABLE IF EXISTS LoginAttempts; -DROP TABLE IF EXISTS PendingAccounts; -DROP TABLE IF EXISTS Invitations; - -CREATE TABLE Accounts ( - username TEXT CHECK(LENGTH(username) > 0) NOT NULL, - password TEXT CHECK(LENGTH(password) > 0) NOT NULL, - email TEXT CHECK(LENGTH(email) > 0) NOT NULL UNIQUE, - role TEXT CHECK(role IN ('user', 'manager', 'admin')) NOT NULL, - profilePicture BLOB, - PRIMARY KEY (username) -); - -CREATE TABLE Trips ( - username TEXT NOT NULL, - destination TEXT CHECK(LENGTH(destination) > 0) NOT NULL, - startDate TEXT CHECK(LENGTH(startDate) == 10) NOT NULL, -- 'YYYY-MM-DD' - endDate TEXT CHECK(LENGTH(endDate) == 10) NOT NULL, -- 'YYYY-MM-DD' - comment TEXT NOT NULL, - PRIMARY KEY (username, destination, startDate), - FOREIGN KEY (username) REFERENCES Accounts ON DELETE CASCADE -); - -CREATE TABLE Sessions ( - uuid TEXT CHECK(LENGTH(uuid) == 36) NOT NULL, - username TEXT NOT NULL UNIQUE, - -- TODO(wpcarro): Add a LENGTH CHECK here - tsCreated TEXT NOT NULL, -- 'YYYY-MM-DD HH:MM:SS' - PRIMARY KEY (uuid), - FOREIGN KEY (username) REFERENCES Accounts ON DELETE CASCADE -); - -CREATE TABLE LoginAttempts ( - username TEXT NOT NULL UNIQUE, - numAttempts INTEGER NOT NULL, - PRIMARY KEY (username), - FOREIGN KEY (username) REFERENCES Accounts ON DELETE CASCADE -); - -CREATE TABLE PendingAccounts ( - secret TEXT CHECK(LENGTH(secret) == 36) NOT NULL, - username TEXT CHECK(LENGTH(username) > 0) NOT NULL, - password TEXT CHECK(LENGTH(password) > 0) NOT NULL, - role TEXT CHECK(role IN ('user', 'manager', 'admin')) NOT NULL, - email TEXT CHECK(LENGTH(email) > 0) NOT NULL UNIQUE, - PRIMARY KEY (username) -); - -CREATE TABLE Invitations ( - email TEXT CHECK(LENGTH(email) > 0) NOT NULL UNIQUE, - role TEXT CHECK(role IN ('user', 'manager', 'admin')) NOT NULL, - secret TEXT CHECK(LENGTH(secret) == 36) NOT NULL, - PRIMARY KEY (email) -); - -COMMIT; diff --git a/users/wpcarro/assessments/tt/tests/create-accounts.sh b/users/wpcarro/assessments/tt/tests/create-accounts.sh deleted file mode 100755 index 8c2a66bc8..000000000 --- a/users/wpcarro/assessments/tt/tests/create-accounts.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env sh - -# This script populates the Accounts table over HTTP. - -http POST :3000/accounts \ - username=mimi \ - password=testing \ - email=miriamwright@google.com \ - role=user - -http POST :3000/accounts \ - username=bill \ - password=testing \ - email=wpcarro@gmail.com \ - role=manager - -http POST :3000/accounts \ - username=wpcarro \ - password=testing \ - email=wpcarro@google.com \ - role=admin diff --git a/users/wpcarro/assessments/tt/todo.org b/users/wpcarro/assessments/tt/todo.org deleted file mode 100644 index 39592d048..000000000 --- a/users/wpcarro/assessments/tt/todo.org +++ /dev/null @@ -1,18 +0,0 @@ -* TODO Users must be able to create an account -* TODO Users must verify their account by email -* TODO Support federated login with Google -* TODO Users must be able to authenticate and login -* TODO Define three roles: user, manager, admin -* TODO Users can add trips -* TODO Users can edit trips -* TODO Users can delete trips -* TODO Users can filter trips -* TODO Support all actions via the REST API -* TODO Block users after three failed authentication attempts -* TODO Only admins and managers can unblock blocked login attempts -* TODO Add unit tests -* TODO Add E2E tests -* TODO Pull user profile pictures using Gravatar -* TODO Allow users to change their profile picture -* TODO Admins should be allowed to invite new users via email -* TODO Allow users to print their travel itineraries diff --git a/users/wpcarro/boilerplate/README.md b/users/wpcarro/boilerplate/README.md deleted file mode 100644 index aa72266a3..000000000 --- a/users/wpcarro/boilerplate/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# Boilerplate - -Storing some boilerplate code to help me reduce the time it takes me to develop -and deploy applications. - -## Usage - -Let's say that you would like to create a game for -`sandbox.wpcarro.dev/game`. We will create a new TypeScript project with the -following: - -```shell -$ cp -r typescript path/to/new-project -``` - -This initializes the project. To start developing, run: - -```shell -$ nix-shell -$ yarn run dev -``` diff --git a/users/wpcarro/boilerplate/clojure/.envrc b/users/wpcarro/boilerplate/clojure/.envrc deleted file mode 100644 index a4a62da52..000000000 --- a/users/wpcarro/boilerplate/clojure/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -use_nix diff --git a/users/wpcarro/boilerplate/clojure/.gitignore b/users/wpcarro/boilerplate/clojure/.gitignore deleted file mode 100644 index f24c5e393..000000000 --- a/users/wpcarro/boilerplate/clojure/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/.lein-repl-history -/target -/? -/.nrepl-port \ No newline at end of file diff --git a/users/wpcarro/boilerplate/clojure/README.md b/users/wpcarro/boilerplate/clojure/README.md deleted file mode 100644 index 53590850b..000000000 --- a/users/wpcarro/boilerplate/clojure/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Clojure Boilerplate - -This boilerplate uses `lein` to manage the project. - -## Files to change - -To use this boilerplate, run the following in a shell: - -```shell -$ cp -r . path/to/new-project -``` - -After running the above command, change the following files to remove the -placeholder values: - -- `README.md`: Change the title; change the description; drop "Files to change"; - keep "Getting started" -- `project.clj`: Change title -- `src/main.clj`: Change `:doc`; drop `main/foo` - -## Getting started - -From a shell, run: - -```shell -$ lein repl -``` - -From Emacs, navigate to a source code buffer and run: - -``` -M-x cider-jack-in -``` diff --git a/users/wpcarro/boilerplate/clojure/project.clj b/users/wpcarro/boilerplate/clojure/project.clj deleted file mode 100644 index 54e34eab7..000000000 --- a/users/wpcarro/boilerplate/clojure/project.clj +++ /dev/null @@ -1,2 +0,0 @@ -(defproject boilerplate "0.0.1" - :dependencies [[org.clojure/clojure "1.8.0"]]) diff --git a/users/wpcarro/boilerplate/clojure/shell.nix b/users/wpcarro/boilerplate/clojure/shell.nix deleted file mode 100644 index 8b92b592e..000000000 --- a/users/wpcarro/boilerplate/clojure/shell.nix +++ /dev/null @@ -1,7 +0,0 @@ -{ pkgs, ... }: - -pkgs.mkShell { - buildInputs = with pkgs; [ - leiningen - ]; -} diff --git a/users/wpcarro/boilerplate/clojure/src/main.clj b/users/wpcarro/boilerplate/clojure/src/main.clj deleted file mode 100644 index f6b60dba4..000000000 --- a/users/wpcarro/boilerplate/clojure/src/main.clj +++ /dev/null @@ -1,8 +0,0 @@ -(ns ^{:doc "Top-level module." - :author "William Carroll"} - main) - -(declare main) - -(defn foo [a b] - (+ a b)) diff --git a/users/wpcarro/boilerplate/elm/.envrc b/users/wpcarro/boilerplate/elm/.envrc deleted file mode 100644 index a4a62da52..000000000 --- a/users/wpcarro/boilerplate/elm/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -use_nix diff --git a/users/wpcarro/boilerplate/elm/.gitignore b/users/wpcarro/boilerplate/elm/.gitignore deleted file mode 100644 index 1cb4f3034..000000000 --- a/users/wpcarro/boilerplate/elm/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/elm-stuff -/Main.min.js -/output.css diff --git a/users/wpcarro/boilerplate/elm/README.md b/users/wpcarro/boilerplate/elm/README.md deleted file mode 100644 index 04804ad94..000000000 --- a/users/wpcarro/boilerplate/elm/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Elm - -Elm has one of the best developer experiences that I'm aware of. The error -messages are helpful and the entire experience is optimized to improve the ease -of writing web applications. - -## Developing - -If you're interested in contributing, the following will create an environment -in which you can develop: - -```shell -$ nix-shell -$ npx tailwindcss build index.css -o output.css -$ elm-live -- src/Main.elm --output=Main.min.js -``` - -You can now view your web client at `http://localhost:8000`! diff --git a/users/wpcarro/boilerplate/elm/elm.json b/users/wpcarro/boilerplate/elm/elm.json deleted file mode 100644 index a95f80408..000000000 --- a/users/wpcarro/boilerplate/elm/elm.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "type": "application", - "source-directories": [ - "src" - ], - "elm-version": "0.19.1", - "dependencies": { - "direct": { - "elm/browser": "1.0.2", - "elm/core": "1.0.5", - "elm/html": "1.0.0", - "elm/random": "1.0.0", - "elm/svg": "1.0.1", - "elm/time": "1.0.0", - "elm-community/list-extra": "8.2.3", - "elm-community/maybe-extra": "5.2.0", - "elm-community/random-extra": "3.1.0" - }, - "indirect": { - "elm/json": "1.1.3", - "elm/url": "1.0.0", - "elm/virtual-dom": "1.0.2", - "owanturist/elm-union-find": "1.0.0" - } - }, - "test-dependencies": { - "direct": {}, - "indirect": {} - } -} diff --git a/users/wpcarro/boilerplate/elm/index.css b/users/wpcarro/boilerplate/elm/index.css deleted file mode 100644 index b5c61c956..000000000 --- a/users/wpcarro/boilerplate/elm/index.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/users/wpcarro/boilerplate/elm/index.html b/users/wpcarro/boilerplate/elm/index.html deleted file mode 100644 index ce8f727b6..000000000 --- a/users/wpcarro/boilerplate/elm/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Elm SPA - - - - -
    - - - diff --git a/users/wpcarro/boilerplate/elm/shell.nix b/users/wpcarro/boilerplate/elm/shell.nix deleted file mode 100644 index afcc0f4d3..000000000 --- a/users/wpcarro/boilerplate/elm/shell.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ pkgs, ... }: - -pkgs.mkShell { - buildInputs = with pkgs.elmPackages; [ - elm - elm-format - elm-live - ]; -} diff --git a/users/wpcarro/boilerplate/elm/src/Landing.elm b/users/wpcarro/boilerplate/elm/src/Landing.elm deleted file mode 100644 index 00bb9e281..000000000 --- a/users/wpcarro/boilerplate/elm/src/Landing.elm +++ /dev/null @@ -1,13 +0,0 @@ -module Landing exposing (render) - -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import State - - -render : State.Model -> Html State.Msg -render model = - div [ class "pt-10 pb-20 px-10" ] - [ p [] [ text "Welcome to the landing page!" ] - ] diff --git a/users/wpcarro/boilerplate/elm/src/Login.elm b/users/wpcarro/boilerplate/elm/src/Login.elm deleted file mode 100644 index 27f1d811a..000000000 --- a/users/wpcarro/boilerplate/elm/src/Login.elm +++ /dev/null @@ -1,13 +0,0 @@ -module Login exposing (render) - -import Html exposing (..) -import Html.Attributes exposing (..) -import Html.Events exposing (..) -import State - - -render : State.Model -> Html State.Msg -render model = - div [ class "pt-10 pb-20 px-10" ] - [ p [] [ text "Please authenticate" ] - ] diff --git a/users/wpcarro/boilerplate/elm/src/Main.elm b/users/wpcarro/boilerplate/elm/src/Main.elm deleted file mode 100644 index 30006460c..000000000 --- a/users/wpcarro/boilerplate/elm/src/Main.elm +++ /dev/null @@ -1,31 +0,0 @@ -module Main exposing (main) - -import Browser -import Html exposing (..) -import Landing -import Login -import State - - -subscriptions : State.Model -> Sub State.Msg -subscriptions model = - Sub.none - - -view : State.Model -> Html State.Msg -view model = - case model.view of - State.Landing -> - Landing.render model - - State.Login -> - Login.render model - - -main = - Browser.element - { init = \() -> ( State.init, Cmd.none ) - , subscriptions = subscriptions - , update = State.update - , view = view - } diff --git a/users/wpcarro/boilerplate/elm/src/State.elm b/users/wpcarro/boilerplate/elm/src/State.elm deleted file mode 100644 index c1edae8bb..000000000 --- a/users/wpcarro/boilerplate/elm/src/State.elm +++ /dev/null @@ -1,43 +0,0 @@ -module State exposing (..) - - -type Msg - = DoNothing - | SetView View - - -type View - = Landing - | Login - - -type alias Model = - { isLoading : Bool - , view : View - } - - -{-| The initial state for the application. --} -init : Model -init = - { isLoading = False - , view = Landing - } - - -{-| Now that we have state, we need a function to change the state. --} -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = - case msg of - DoNothing -> - ( model, Cmd.none ) - - SetView x -> - ( { model - | view = x - , isLoading = True - } - , Cmd.none - ) diff --git a/users/wpcarro/boilerplate/typescript/.envrc b/users/wpcarro/boilerplate/typescript/.envrc deleted file mode 100644 index a4a62da52..000000000 --- a/users/wpcarro/boilerplate/typescript/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -use_nix diff --git a/users/wpcarro/boilerplate/typescript/.gitignore b/users/wpcarro/boilerplate/typescript/.gitignore deleted file mode 100644 index ebea22e07..000000000 --- a/users/wpcarro/boilerplate/typescript/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/.cache -/dist -/node_modules \ No newline at end of file diff --git a/users/wpcarro/boilerplate/typescript/README.md b/users/wpcarro/boilerplate/typescript/README.md deleted file mode 100644 index a54186a9f..000000000 --- a/users/wpcarro/boilerplate/typescript/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Frontend Boilerplate - -While many times I prefer using alt-languages like ReasonML, ClojureScript, or -Elm, sometimes I prefer to write an application using TypeScript. This directory -contains the necessary starter code to create these applications. - -- React: Maps application state to UI -- React-Router: Stateful routing for SPAs -- Redux: Application state management -- TypeScript: Type-safety -- TailwindCSS: Styling library using utility classes -- Prettier: Source code formatting -- Jest: Test runner - -## Developing - -```shell -$ nix-shell -$ yarn run dev -``` - -## Building - -```shell -$ nix-build -``` diff --git a/users/wpcarro/boilerplate/typescript/default.nix b/users/wpcarro/boilerplate/typescript/default.nix deleted file mode 100644 index b013cf07e..000000000 --- a/users/wpcarro/boilerplate/typescript/default.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ pkgs, ... }: - -pkgs.stdenv.mkDerivation { - name = "typescript"; - srcs = builtins.path { path = ./.; name = "typescript"; }; - buildInputs = with pkgs; [ - nodejs - # Exposes lscpu for parcel.js - util-linux - ]; - # parcel.js needs number of CPUs - PARCEL_WORKERS = "1"; - buildPhase = '' - export HOME="." - npx parcel build src/index.html --public-url ./ - ''; - installPhase = '' - mv dist $out - ''; - - # TODO(wpcarro): This doesn't build at all. - meta.ci.skip = true; -} diff --git a/users/wpcarro/boilerplate/typescript/package.json b/users/wpcarro/boilerplate/typescript/package.json deleted file mode 100644 index 104e7272d..000000000 --- a/users/wpcarro/boilerplate/typescript/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "tailwindcss", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "scripts": { - "dev": "parcel src/index.html & npx tsc --watch --noEmit", - "prettier": "prettier --ignore-path .gitignore --write \"**/*.{js,ts,jsx,tsx,html,css.json}\"" - }, - "devDependencies": { - "@types/node": "^13.9.3", - "parcel-bundler": "^1.12.4", - "prettier": "^2.0.2", - "tailwindcss": "^1.2.0", - "typescript": "^3.8.3" - }, - "dependencies": { - "@reduxjs/toolkit": "^1.2.5", - "@types/react-dom": "^16.9.5", - "@types/react-redux": "^7.1.7", - "@types/react-router-dom": "^5.1.3", - "react": "^16.13.1", - "react-dom": "^16.13.1", - "react-redux": "^7.2.0", - "react-router-dom": "^5.1.2" - } -} diff --git a/users/wpcarro/boilerplate/typescript/postcss.config.js b/users/wpcarro/boilerplate/typescript/postcss.config.js deleted file mode 100644 index d68fa6186..000000000 --- a/users/wpcarro/boilerplate/typescript/postcss.config.js +++ /dev/null @@ -1,7 +0,0 @@ -const tailwindcss = require('tailwindcss') - -module.exports = { - plugins: [ - tailwindcss('./tailwind.config.js') - ] -} diff --git a/users/wpcarro/boilerplate/typescript/shell.nix b/users/wpcarro/boilerplate/typescript/shell.nix deleted file mode 100644 index a3ae929ef..000000000 --- a/users/wpcarro/boilerplate/typescript/shell.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ pkgs, ... }: - -pkgs.mkShell { - buildInputs = with pkgs; [ - nodejs - yarn - ]; -} diff --git a/users/wpcarro/boilerplate/typescript/src/App.tsx b/users/wpcarro/boilerplate/typescript/src/App.tsx deleted file mode 100644 index 4fae1b36a..000000000 --- a/users/wpcarro/boilerplate/typescript/src/App.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React, { useEffect } from "react"; -import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; -import { useDispatch } from "react-redux"; -import { actions, useTypedSelector } from "./store"; -import { Link } from "react-router-dom"; - -const App: React.FC = () => { - const dispatch = useDispatch(); - const { isLoading } = useTypedSelector(state => ({ - isLoading: state.isLoading, - })); - - return ( - - - - -
    -

    Welcome to the home page. Loading: {isLoading ? "true" : "false"}

    - -
    -
    - -
    -

    Here is the about page.

    -
    -
    - -
    -

    Here is the contact page.

    -
    -
    -
    -
    - ); -}; - -export default App; diff --git a/users/wpcarro/boilerplate/typescript/src/index.css b/users/wpcarro/boilerplate/typescript/src/index.css deleted file mode 100644 index b5c61c956..000000000 --- a/users/wpcarro/boilerplate/typescript/src/index.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/users/wpcarro/boilerplate/typescript/src/index.html b/users/wpcarro/boilerplate/typescript/src/index.html deleted file mode 100644 index 91752af91..000000000 --- a/users/wpcarro/boilerplate/typescript/src/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - -
    - - - diff --git a/users/wpcarro/boilerplate/typescript/src/index.tsx b/users/wpcarro/boilerplate/typescript/src/index.tsx deleted file mode 100644 index dc28dc4a9..000000000 --- a/users/wpcarro/boilerplate/typescript/src/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import App from "./App"; -import { Provider } from "react-redux"; -import store from "./store"; - -ReactDOM.render( - - - , - document.getElementById("mount") -); diff --git a/users/wpcarro/boilerplate/typescript/src/store.ts b/users/wpcarro/boilerplate/typescript/src/store.ts deleted file mode 100644 index 03e980a49..000000000 --- a/users/wpcarro/boilerplate/typescript/src/store.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { createSlice, configureStore, PayloadAction } from "@reduxjs/toolkit"; -import { useSelector, TypedUseSelectorHook } from "react-redux"; - -export interface State { - isLoading: boolean; -} - -const initialState: State = { - isLoading: true, -}; - -export const { actions, reducer } = createSlice({ - name: "application", - initialState, - reducers: { - toggleIsLoading: state => ({ ...state, isLoading: !state.isLoading }), - } -}); - -/** - * Defining and consuming this allows us to avoid annotating State in all of our - * selectors. - */ -export const useTypedSelector: TypedUseSelectorHook = useSelector; - -export default configureStore({ reducer }); diff --git a/users/wpcarro/boilerplate/typescript/tailwind.config.js b/users/wpcarro/boilerplate/typescript/tailwind.config.js deleted file mode 100644 index af829e20f..000000000 --- a/users/wpcarro/boilerplate/typescript/tailwind.config.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - theme: { - extend: {}, - }, - variants: {}, - plugins: [], -} diff --git a/users/wpcarro/boilerplate/typescript/tsconfig.json b/users/wpcarro/boilerplate/typescript/tsconfig.json deleted file mode 100644 index 013f34fdf..000000000 --- a/users/wpcarro/boilerplate/typescript/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "esnext", - "moduleResolution": "node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react" - }, - "include": [ - "src/**/*" - ] -} diff --git a/users/wpcarro/boilerplate/typescript/yarn.lock b/users/wpcarro/boilerplate/typescript/yarn.lock deleted file mode 100644 index 0e16fe80a..000000000 --- a/users/wpcarro/boilerplate/typescript/yarn.lock +++ /dev/null @@ -1,5670 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - -"@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c" - integrity sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g== - dependencies: - browserslist "^4.9.1" - invariant "^2.2.4" - semver "^5.5.0" - -"@babel/core@^7.4.4": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" - integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helpers" "^7.9.0" - "@babel/parser" "^7.9.0" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.4.4", "@babel/generator@^7.9.0": - version "7.9.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.3.tgz#7c8b2956c6f68b3ab732bd16305916fbba521d94" - integrity sha512-RpxM252EYsz9qLUIq6F7YJyK1sv0wWDBFuztfDGWaQKzHjqDHysxSiRUpA/X9jmfqo+WzkAVKFaUily5h+gDCQ== - dependencies: - "@babel/types" "^7.9.0" - jsesc "^2.5.1" - lodash "^4.17.13" - source-map "^0.5.0" - -"@babel/helper-annotate-as-pure@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" - integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" - integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-builder-react-jsx-experimental@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx-experimental/-/helper-builder-react-jsx-experimental-7.9.0.tgz#066d80262ade488f9c1b1823ce5db88a4cedaa43" - integrity sha512-3xJEiyuYU4Q/Ar9BsHisgdxZsRlsShMe90URZ0e6przL26CCs8NJbDoxH94kKT17PcxlMhsCAwZd90evCo26VQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-module-imports" "^7.8.3" - "@babel/types" "^7.9.0" - -"@babel/helper-builder-react-jsx@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.9.0.tgz#16bf391990b57732700a3278d4d9a81231ea8d32" - integrity sha512-weiIo4gaoGgnhff54GQ3P5wsUQmnSwpkvU0r6ZHq6TzoSzKy4JxHEgnxNytaKbov2a9z/CVNyzliuCOUPEX3Jw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/types" "^7.9.0" - -"@babel/helper-compilation-targets@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" - integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== - dependencies: - "@babel/compat-data" "^7.8.6" - browserslist "^4.9.1" - invariant "^2.2.4" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" - integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-regex" "^7.8.3" - regexpu-core "^4.7.0" - -"@babel/helper-define-map@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" - integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/types" "^7.8.3" - lodash "^4.17.13" - -"@babel/helper-explode-assignable-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" - integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== - dependencies: - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" - integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-get-function-arity@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-hoist-variables@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" - integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-member-expression-to-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" - integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-imports@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" - integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-module-transforms@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" - integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-simple-access" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/template" "^7.8.6" - "@babel/types" "^7.9.0" - lodash "^4.17.13" - -"@babel/helper-optimise-call-expression@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" - integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" - integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== - -"@babel/helper-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" - integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== - dependencies: - lodash "^4.17.13" - -"@babel/helper-remap-async-to-generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" - integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-wrap-function" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" - integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/helper-simple-access@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" - integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== - dependencies: - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helper-split-export-declaration@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== - dependencies: - "@babel/types" "^7.8.3" - -"@babel/helper-validator-identifier@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" - integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== - -"@babel/helper-wrap-function@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" - integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.3" - "@babel/types" "^7.8.3" - -"@babel/helpers@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" - integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== - dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.9.0" - "@babel/types" "^7.9.0" - -"@babel/highlight@^7.8.3": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" - integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - chalk "^2.0.0" - js-tokens "^4.0.0" - -"@babel/parser@^7.4.4", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": - version "7.9.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.3.tgz#043a5fc2ad8b7ea9facddc4e802a1f0f25da7255" - integrity sha512-E6SpIDJZ0cZAKoCNk+qSDd0ChfTnpiJN9FfNf3RZ20dzwA2vL2oq5IX1XTVT+4vDmRlta2nGk5HGMMskJAR+4A== - -"@babel/plugin-proposal-async-generator-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" - integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-remap-async-to-generator" "^7.8.3" - "@babel/plugin-syntax-async-generators" "^7.8.0" - -"@babel/plugin-proposal-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" - integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - -"@babel/plugin-proposal-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" - integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" - -"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" - integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - -"@babel/plugin-proposal-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" - integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - -"@babel/plugin-proposal-object-rest-spread@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz#a28993699fc13df165995362693962ba6b061d6f" - integrity sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - -"@babel/plugin-proposal-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" - integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - -"@babel/plugin-proposal-optional-chaining@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" - integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - -"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" - integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.8" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-async-generators@^7.8.0": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-dynamic-import@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-flow@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.8.3.tgz#f2c883bd61a6316f2c89380ae5122f923ba4527f" - integrity sha512-innAx3bUbA0KSYj2E2MNFSn9hiCeowOFLxlsuhXzw8hMQnzkDomUr9QCD7E9VF60NmnG1sNTuuv6Qf4f8INYsg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-json-strings@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-jsx@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz#521b06c83c40480f1e58b4fd33b92eceb1d6ea94" - integrity sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" - integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-object-rest-spread@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-catch-binding@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-optional-chaining@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - -"@babel/plugin-syntax-top-level-await@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" - integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-arrow-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" - integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-async-to-generator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" - integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== - dependencies: - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-remap-async-to-generator" "^7.8.3" - -"@babel/plugin-transform-block-scoped-functions@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" - integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-block-scoping@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" - integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - lodash "^4.17.13" - -"@babel/plugin-transform-classes@^7.9.0": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz#8603fc3cc449e31fdbdbc257f67717536a11af8d" - integrity sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-define-map" "^7.8.3" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-optimise-call-expression" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.6" - "@babel/helper-split-export-declaration" "^7.8.3" - globals "^11.1.0" - -"@babel/plugin-transform-computed-properties@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" - integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-destructuring@^7.8.3": - version "7.8.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz#fadb2bc8e90ccaf5658de6f8d4d22ff6272a2f4b" - integrity sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" - integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-duplicate-keys@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" - integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-exponentiation-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" - integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-flow-strip-types@^7.4.4": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.9.0.tgz#8a3538aa40434e000b8f44a3c5c9ac7229bd2392" - integrity sha512-7Qfg0lKQhEHs93FChxVLAvhBshOPQDtJUTVHr/ZwQNRccCm4O9D79r9tVSoV8iNwjP1YgfD+e/fgHcPkN1qEQg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-flow" "^7.8.3" - -"@babel/plugin-transform-for-of@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" - integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" - integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== - dependencies: - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" - integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-member-expression-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" - integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-modules-amd@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4" - integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-commonjs@^7.4.4", "@babel/plugin-transform-modules-commonjs@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940" - integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-simple-access" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-systemjs@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90" - integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ== - dependencies: - "@babel/helper-hoist-variables" "^7.8.3" - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - babel-plugin-dynamic-import-node "^2.3.0" - -"@babel/plugin-transform-modules-umd@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" - integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== - dependencies: - "@babel/helper-module-transforms" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" - integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - -"@babel/plugin-transform-new-target@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" - integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-object-super@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" - integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-replace-supers" "^7.8.3" - -"@babel/plugin-transform-parameters@^7.8.7": - version "7.9.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz#3028d0cc20ddc733166c6e9c8534559cee09f54a" - integrity sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg== - dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-property-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" - integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-react-jsx@^7.0.0": - version "7.9.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.9.1.tgz#d03af29396a6dc51bfa24eefd8005a9fd381152a" - integrity sha512-+xIZ6fPoix7h57CNO/ZeYADchg1tFyX9NDsnmNFFua8e1JNPln156mzS+8AQe1On2X2GLlANHJWHIXbMCqWDkQ== - dependencies: - "@babel/helper-builder-react-jsx" "^7.9.0" - "@babel/helper-builder-react-jsx-experimental" "^7.9.0" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-syntax-jsx" "^7.8.3" - -"@babel/plugin-transform-regenerator@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" - integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== - dependencies: - regenerator-transform "^0.14.2" - -"@babel/plugin-transform-reserved-words@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" - integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-shorthand-properties@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" - integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" - integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-sticky-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" - integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/helper-regex" "^7.8.3" - -"@babel/plugin-transform-template-literals@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" - integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-typeof-symbol@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" - integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-transform-unicode-regex@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" - integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/preset-env@^7.4.4": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.0.tgz#a5fc42480e950ae8f5d9f8f2bbc03f52722df3a8" - integrity sha512-712DeRXT6dyKAM/FMbQTV/FvRCms2hPCx+3weRjZ8iQVQWZejWWk1wwG6ViWMyqb/ouBbGOl5b6aCk0+j1NmsQ== - dependencies: - "@babel/compat-data" "^7.9.0" - "@babel/helper-compilation-targets" "^7.8.7" - "@babel/helper-module-imports" "^7.8.3" - "@babel/helper-plugin-utils" "^7.8.3" - "@babel/plugin-proposal-async-generator-functions" "^7.8.3" - "@babel/plugin-proposal-dynamic-import" "^7.8.3" - "@babel/plugin-proposal-json-strings" "^7.8.3" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-proposal-numeric-separator" "^7.8.3" - "@babel/plugin-proposal-object-rest-spread" "^7.9.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" - "@babel/plugin-proposal-optional-chaining" "^7.9.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" - "@babel/plugin-syntax-json-strings" "^7.8.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" - "@babel/plugin-syntax-numeric-separator" "^7.8.0" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - "@babel/plugin-transform-arrow-functions" "^7.8.3" - "@babel/plugin-transform-async-to-generator" "^7.8.3" - "@babel/plugin-transform-block-scoped-functions" "^7.8.3" - "@babel/plugin-transform-block-scoping" "^7.8.3" - "@babel/plugin-transform-classes" "^7.9.0" - "@babel/plugin-transform-computed-properties" "^7.8.3" - "@babel/plugin-transform-destructuring" "^7.8.3" - "@babel/plugin-transform-dotall-regex" "^7.8.3" - "@babel/plugin-transform-duplicate-keys" "^7.8.3" - "@babel/plugin-transform-exponentiation-operator" "^7.8.3" - "@babel/plugin-transform-for-of" "^7.9.0" - "@babel/plugin-transform-function-name" "^7.8.3" - "@babel/plugin-transform-literals" "^7.8.3" - "@babel/plugin-transform-member-expression-literals" "^7.8.3" - "@babel/plugin-transform-modules-amd" "^7.9.0" - "@babel/plugin-transform-modules-commonjs" "^7.9.0" - "@babel/plugin-transform-modules-systemjs" "^7.9.0" - "@babel/plugin-transform-modules-umd" "^7.9.0" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" - "@babel/plugin-transform-new-target" "^7.8.3" - "@babel/plugin-transform-object-super" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.8.7" - "@babel/plugin-transform-property-literals" "^7.8.3" - "@babel/plugin-transform-regenerator" "^7.8.7" - "@babel/plugin-transform-reserved-words" "^7.8.3" - "@babel/plugin-transform-shorthand-properties" "^7.8.3" - "@babel/plugin-transform-spread" "^7.8.3" - "@babel/plugin-transform-sticky-regex" "^7.8.3" - "@babel/plugin-transform-template-literals" "^7.8.3" - "@babel/plugin-transform-typeof-symbol" "^7.8.4" - "@babel/plugin-transform-unicode-regex" "^7.8.3" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.9.0" - browserslist "^4.9.1" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/preset-modules@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" - integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - -"@babel/runtime@^7.1.2", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4": - version "7.9.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" - integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== - dependencies: - regenerator-runtime "^0.13.4" - -"@babel/template@^7.4.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/traverse@^7.4.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.0.tgz#d3882c2830e513f4fe4cec9fe76ea1cc78747892" - integrity sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.9.0" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.9.0" - "@babel/types" "^7.9.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.13" - -"@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0": - version "7.9.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.0.tgz#00b064c3df83ad32b2dbf5ff07312b15c7f1efb5" - integrity sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng== - dependencies: - "@babel/helper-validator-identifier" "^7.9.0" - lodash "^4.17.13" - to-fast-properties "^2.0.0" - -"@iarna/toml@^2.2.0": - version "2.2.3" - resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.3.tgz#f060bf6eaafae4d56a7dac618980838b0696e2ab" - integrity sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg== - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - -"@parcel/fs@^1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-1.11.0.tgz#fb8a2be038c454ad46a50dc0554c1805f13535cd" - integrity sha512-86RyEqULbbVoeo8OLcv+LQ1Vq2PKBAvWTU9fCgALxuCTbbs5Ppcvll4Vr+Ko1AnmMzja/k++SzNAwJfeQXVlpA== - dependencies: - "@parcel/utils" "^1.11.0" - mkdirp "^0.5.1" - rimraf "^2.6.2" - -"@parcel/logger@^1.11.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-1.11.1.tgz#c55b0744bcbe84ebc291155627f0ec406a23e2e6" - integrity sha512-9NF3M6UVeP2udOBDILuoEHd8VrF4vQqoWHEafymO1pfSoOMfxrSJZw1MfyAAIUN/IFp9qjcpDCUbDZB+ioVevA== - dependencies: - "@parcel/workers" "^1.11.0" - chalk "^2.1.0" - grapheme-breaker "^0.3.2" - ora "^2.1.0" - strip-ansi "^4.0.0" - -"@parcel/utils@^1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-1.11.0.tgz#539e08fff8af3b26eca11302be80b522674b51ea" - integrity sha512-cA3p4jTlaMeOtAKR/6AadanOPvKeg8VwgnHhOyfi0yClD0TZS/hi9xu12w4EzA/8NtHu0g6o4RDfcNjqN8l1AQ== - -"@parcel/watcher@^1.12.1": - version "1.12.1" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-1.12.1.tgz#b98b3df309fcab93451b5583fc38e40826696dad" - integrity sha512-od+uCtCxC/KoNQAIE1vWx1YTyKYY+7CTrxBJPRh3cDWw/C0tCtlBMVlrbplscGoEpt6B27KhJDCv82PBxOERNA== - dependencies: - "@parcel/utils" "^1.11.0" - chokidar "^2.1.5" - -"@parcel/workers@^1.11.0": - version "1.11.0" - resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-1.11.0.tgz#7b8dcf992806f4ad2b6cecf629839c41c2336c59" - integrity sha512-USSjRAAQYsZFlv43FUPdD+jEGML5/8oLF0rUzPQTtK4q9kvaXr49F5ZplyLz5lox78cLZ0TxN2bIDQ1xhOkulQ== - dependencies: - "@parcel/utils" "^1.11.0" - physical-cpu-count "^2.0.0" - -"@reduxjs/toolkit@^1.2.5": - version "1.2.5" - resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.2.5.tgz#149aa62da12a18a67a30495cb63fd897003f2272" - integrity sha512-/OWoW5mniUXAomw4+3ZhhWodcs1/SRvK2HKyxLXdW6vKgmJhiBiSHe/huHARlKWujEmGaJrkafx548GE494bCQ== - dependencies: - immer "^4.0.1" - redux "^4.0.0" - redux-devtools-extension "^2.13.8" - redux-immutable-state-invariant "^2.1.0" - redux-thunk "^2.3.0" - reselect "^4.0.0" - -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - -"@types/history@*": - version "4.7.5" - resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.5.tgz#527d20ef68571a4af02ed74350164e7a67544860" - integrity sha512-wLD/Aq2VggCJXSjxEwrMafIP51Z+13H78nXIX0ABEuIGhmB5sNGbR113MOKo+yfw+RDo1ZU3DM6yfnnRF/+ouw== - -"@types/hoist-non-react-statics@^3.3.0": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - -"@types/node@^13.9.3": - version "13.9.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.3.tgz#6356df2647de9eac569f9a52eda3480fa9e70b4d" - integrity sha512-01s+ac4qerwd6RHD+mVbOEsraDHSgUaefQlEdBbUolnQFjKwCr7luvAlEwW1RFojh67u0z4OUTjPn9LEl4zIkA== - -"@types/prop-types@*": - version "15.7.3" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" - integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== - -"@types/q@^1.5.1": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" - integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== - -"@types/react-dom@^16.9.5": - version "16.9.5" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.5.tgz#5de610b04a35d07ffd8f44edad93a71032d9aaa7" - integrity sha512-BX6RQ8s9D+2/gDhxrj8OW+YD4R+8hj7FEM/OJHGNR0KipE1h1mSsf39YeyC81qafkq+N3rU3h3RFbLSwE5VqUg== - dependencies: - "@types/react" "*" - -"@types/react-redux@^7.1.7": - version "7.1.7" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.7.tgz#12a0c529aba660696947384a059c5c6e08185c7a" - integrity sha512-U+WrzeFfI83+evZE2dkZ/oF/1vjIYgqrb5dGgedkqVV8HEfDFujNgWCwHL89TDuWKb47U0nTBT6PLGq4IIogWg== - dependencies: - "@types/hoist-non-react-statics" "^3.3.0" - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - redux "^4.0.0" - -"@types/react-router-dom@^5.1.3": - version "5.1.3" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.3.tgz#b5d28e7850bd274d944c0fbbe5d57e6b30d71196" - integrity sha512-pCq7AkOvjE65jkGS5fQwQhvUp4+4PVD9g39gXLZViP2UqFiFzsEpB3PKf0O6mdbKsewSK8N14/eegisa/0CwnA== - dependencies: - "@types/history" "*" - "@types/react" "*" - "@types/react-router" "*" - -"@types/react-router@*": - version "5.1.4" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.4.tgz#7d70bd905543cb6bcbdcc6bd98902332054f31a6" - integrity sha512-PZtnBuyfL07sqCJvGg3z+0+kt6fobc/xmle08jBiezLS8FrmGeiGkJnuxL/8Zgy9L83ypUhniV5atZn/L8n9MQ== - dependencies: - "@types/history" "*" - "@types/react" "*" - -"@types/react@*": - version "16.9.25" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.25.tgz#6ae2159b40138c792058a23c3c04fd3db49e929e" - integrity sha512-Dlj2V72cfYLPNscIG3/SMUOzhzj7GK3bpSrfefwt2YT9GLynvLCCZjbhyF6VsT0q0+aRACRX03TDJGb7cA0cqg== - dependencies: - "@types/prop-types" "*" - csstype "^2.2.0" - -abab@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" - integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== - -acorn-globals@^4.3.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== - dependencies: - acorn "^6.0.1" - acorn-walk "^6.0.1" - -acorn-node@^1.6.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" - integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== - dependencies: - acorn "^7.0.0" - acorn-walk "^7.0.0" - xtend "^4.0.2" - -acorn-walk@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== - -acorn-walk@^7.0.0: - version "7.1.1" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.1.1.tgz#345f0dffad5c735e7373d2fec9a1023e6a44b83e" - integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ== - -acorn@^6.0.1, acorn@^6.0.4: - version "6.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" - integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== - -acorn@^7.0.0, acorn@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" - integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== - -ajv@^6.5.5: - version "6.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" - integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -alphanum-sort@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" - integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== - -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - -ansi-styles@^3.2.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== - dependencies: - "@types/color-name" "^1.1.1" - color-convert "^2.0.1" - -ansi-to-html@^0.6.4: - version "0.6.14" - resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.14.tgz#65fe6d08bba5dd9db33f44a20aec331e0010dad8" - integrity sha512-7ZslfB1+EnFSDO5Ju+ue5Y6It19DRnZXWv8jrGHgIlPna5Mh4jz7BV5jCbQneXNFurQcKoolaaAjHtgSBfOIuA== - dependencies: - entities "^1.1.2" - -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - -asn1.js@^4.0.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" - integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert@^1.1.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" - integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== - dependencies: - object-assign "^4.1.1" - util "0.10.3" - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - -async-each@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" - integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== - -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - -autoprefixer@^9.4.5: - version "9.7.4" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.4.tgz#f8bf3e06707d047f0641d87aee8cfb174b2a5378" - integrity sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g== - dependencies: - browserslist "^4.8.3" - caniuse-lite "^1.0.30001020" - chalk "^2.4.2" - normalize-range "^0.1.2" - num2fraction "^1.2.2" - postcss "^7.0.26" - postcss-value-parser "^4.0.2" - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" - integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== - -babel-plugin-dynamic-import-node@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" - integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== - dependencies: - object.assign "^4.1.0" - -babel-runtime@^6.11.6, babel-runtime@^6.26.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-types@^6.15.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babylon-walk@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/babylon-walk/-/babylon-walk-1.0.2.tgz#3b15a5ddbb482a78b4ce9c01c8ba181702d9d6ce" - integrity sha1-OxWl3btIKni0zpwByLoYFwLZ1s4= - dependencies: - babel-runtime "^6.11.6" - babel-types "^6.15.0" - lodash.clone "^4.5.0" - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== - -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -binary-extensions@^1.0.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" - integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== - -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" - integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== - -boolbase@^1.0.0, boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -braces@^2.3.1, braces@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - -brfs@^1.2.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/brfs/-/brfs-1.6.1.tgz#b78ce2336d818e25eea04a0947cba6d4fb8849c3" - integrity sha512-OfZpABRQQf+Xsmju8XE9bDjs+uU4vLREGolP7bDgcpsI17QREyZ4Bl+2KLxxx1kCgA0fAIhKQBaBYh+PEcCqYQ== - dependencies: - quote-stream "^1.0.1" - resolve "^1.1.5" - static-module "^2.2.0" - through2 "^2.0.0" - -brorand@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -browserify-rsa@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" - integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= - dependencies: - bn.js "^4.1.1" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.2" - elliptic "^6.0.0" - inherits "^2.0.1" - parse-asn1 "^5.0.0" - -browserify-zlib@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" - integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== - dependencies: - pako "~1.0.5" - -browserslist@^4.0.0, browserslist@^4.1.0, browserslist@^4.8.3, browserslist@^4.9.1: - version "4.11.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.11.0.tgz#aef4357b10a8abda00f97aac7cd587b2082ba1ad" - integrity sha512-WqEC7Yr5wUH5sg6ruR++v2SGOQYpyUdYYd4tZoAq1F7y+QXoLoYGXVbxhtaIqWmAJjtNTRjVD3HuJc1OXTel2A== - dependencies: - caniuse-lite "^1.0.30001035" - electron-to-chromium "^1.3.380" - node-releases "^1.1.52" - pkg-up "^3.1.0" - -buffer-equal@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" - integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs= - -buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - -buffer@^4.3.0: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= - -bytes@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - -camelcase-css@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" - integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== - -camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -caniuse-api@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" - integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== - dependencies: - browserslist "^4.0.0" - caniuse-lite "^1.0.0" - lodash.memoize "^4.1.2" - lodash.uniq "^4.5.0" - -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001035: - version "1.0.30001036" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001036.tgz#930ea5272010d8bf190d859159d757c0b398caf0" - integrity sha512-jU8CIFIj2oR7r4W+5AKcsvWNVIb6Q6OZE3UsrXrZBHFtreT4YgTeOJtTucp+zSedEpTi3L5wASSP0LYIE3if6w== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chokidar@^2.1.5: - version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" - integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - -cli-spinners@^1.1.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.3.1.tgz#002c1990912d0d59580c93bd36c056de99e4259a" - integrity sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg== - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -clone@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" - integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= - -coa@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" - integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== - dependencies: - "@types/q" "^1.5.1" - chalk "^2.4.1" - q "^1.1.2" - -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - -color-convert@^1.9.0, color-convert@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -color-name@^1.0.0, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-string@^1.5.2: - version "1.5.3" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" - integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" - integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== - dependencies: - color-convert "^1.9.1" - color-string "^1.5.2" - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -command-exists@^1.2.6: - version "1.2.8" - resolved "https://registry.yarnpkg.com/command-exists/-/command-exists-1.2.8.tgz#715acefdd1223b9c9b37110a149c6392c2852291" - integrity sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw== - -commander@^2.11.0, commander@^2.19.0, commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -concat-stream@~1.6.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - -console-browserify@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" - integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== - -constants-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= - -convert-source-map@^1.5.1, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - -core-js-compat@^3.6.2: - version "3.6.4" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.4.tgz#938476569ebb6cda80d339bcf199fae4f16fff17" - integrity sha512-zAa3IZPvsJ0slViBQ2z+vgyyTuhd3MFn1rBQjZSKVEgB0UMYhUkCj9jJUVPgGTGqWvsBVmfnruXgTcNyTlEiSA== - dependencies: - browserslist "^4.8.3" - semver "7.0.0" - -core-js@^2.4.0, core-js@^2.6.5: - version "2.6.11" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" - integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== - -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -cosmiconfig@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - -create-ecdh@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" - integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-hash@^1.1.0, create-hash@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-spawn@^6.0.4: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - -css-color-names@0.0.4, css-color-names@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" - integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= - -css-declaration-sorter@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" - integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== - dependencies: - postcss "^7.0.1" - timsort "^0.3.0" - -css-modules-loader-core@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz#5908668294a1becd261ae0a4ce21b0b551f21d16" - integrity sha1-WQhmgpShvs0mGuCkziGwtVHyHRY= - dependencies: - icss-replace-symbols "1.1.0" - postcss "6.0.1" - postcss-modules-extract-imports "1.1.0" - postcss-modules-local-by-default "1.2.0" - postcss-modules-scope "1.1.0" - postcss-modules-values "1.3.0" - -css-select-base-adapter@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" - integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== - -css-select@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" - integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== - dependencies: - boolbase "^1.0.0" - css-what "^3.2.1" - domutils "^1.7.0" - nth-check "^1.0.2" - -css-selector-tokenizer@^0.7.0: - version "0.7.2" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.2.tgz#11e5e27c9a48d90284f22d45061c303d7a25ad87" - integrity sha512-yj856NGuAymN6r8bn8/Jl46pR+OC3eEvAhfGYDUe7YPtTPAYrSSw4oAniZ9Y8T5B92hjhwTBLUen0/vKPxf6pw== - dependencies: - cssesc "^3.0.0" - fastparse "^1.1.2" - regexpu-core "^4.6.0" - -css-tree@1.0.0-alpha.37: - version "1.0.0-alpha.37" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" - integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== - dependencies: - mdn-data "2.0.4" - source-map "^0.6.1" - -css-unit-converter@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/css-unit-converter/-/css-unit-converter-1.1.1.tgz#d9b9281adcfd8ced935bdbaba83786897f64e996" - integrity sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY= - -css-what@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1" - integrity sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw== - -cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - -cssnano-preset-default@^4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" - integrity sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA== - dependencies: - css-declaration-sorter "^4.0.1" - cssnano-util-raw-cache "^4.0.1" - postcss "^7.0.0" - postcss-calc "^7.0.1" - postcss-colormin "^4.0.3" - postcss-convert-values "^4.0.1" - postcss-discard-comments "^4.0.2" - postcss-discard-duplicates "^4.0.2" - postcss-discard-empty "^4.0.1" - postcss-discard-overridden "^4.0.1" - postcss-merge-longhand "^4.0.11" - postcss-merge-rules "^4.0.3" - postcss-minify-font-values "^4.0.2" - postcss-minify-gradients "^4.0.2" - postcss-minify-params "^4.0.2" - postcss-minify-selectors "^4.0.2" - postcss-normalize-charset "^4.0.1" - postcss-normalize-display-values "^4.0.2" - postcss-normalize-positions "^4.0.2" - postcss-normalize-repeat-style "^4.0.2" - postcss-normalize-string "^4.0.2" - postcss-normalize-timing-functions "^4.0.2" - postcss-normalize-unicode "^4.0.1" - postcss-normalize-url "^4.0.1" - postcss-normalize-whitespace "^4.0.2" - postcss-ordered-values "^4.1.2" - postcss-reduce-initial "^4.0.3" - postcss-reduce-transforms "^4.0.2" - postcss-svgo "^4.0.2" - postcss-unique-selectors "^4.0.1" - -cssnano-util-get-arguments@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" - integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= - -cssnano-util-get-match@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" - integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= - -cssnano-util-raw-cache@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" - integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== - dependencies: - postcss "^7.0.0" - -cssnano-util-same-parent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" - integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== - -cssnano@^4.0.0, cssnano@^4.1.10: - version "4.1.10" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" - integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== - dependencies: - cosmiconfig "^5.0.0" - cssnano-preset-default "^4.0.7" - is-resolvable "^1.0.0" - postcss "^7.0.0" - -csso@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.2.tgz#e5f81ab3a56b8eefb7f0092ce7279329f454de3d" - integrity sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg== - dependencies: - css-tree "1.0.0-alpha.37" - -cssom@0.3.x, cssom@^0.3.4: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^1.1.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" - integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== - dependencies: - cssom "0.3.x" - -csstype@^2.2.0: - version "2.6.9" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.9.tgz#05141d0cd557a56b8891394c1911c40c8a98d098" - integrity sha512-xz39Sb4+OaTsULgUERcCk+TJj8ylkL4aSVDQiX/ksxbELSqwkgt4d4RD7fovIdgJGSuNYqwZEiVjYY5l0ask+Q== - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -data-urls@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== - dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.0.0" - -deasync@^0.1.14: - version "0.1.19" - resolved "https://registry.yarnpkg.com/deasync/-/deasync-0.1.19.tgz#e7ea89fcc9ad483367e8a48fe78f508ca86286e8" - integrity sha512-oh3MRktfnPlLysCPpBpKZZzb4cUC/p0aA3SyRGp15lN30juJBTo/CiD0d4fR+f1kBtUQoJj1NE9RPNWQ7BQ9Mg== - dependencies: - bindings "^1.5.0" - node-addon-api "^1.7.1" - -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - -decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - -decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - -deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= - -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -detective@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" - integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== - dependencies: - acorn-node "^1.6.1" - defined "^1.0.0" - minimist "^1.1.1" - -diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - -dom-serializer@0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - -domain-browser@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" - integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== - -domelementtype@1, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.1.tgz#1f8bdfe91f5a78063274e803b4bdcedf6e94f94d" - integrity sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ== - -domexception@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== - dependencies: - webidl-conversions "^4.0.2" - -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - -domutils@^1.5.1, domutils@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - -dot-prop@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" - integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== - dependencies: - is-obj "^2.0.0" - -dotenv-expand@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" - integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== - -dotenv@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef" - integrity sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow== - -duplexer2@~0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= - dependencies: - readable-stream "^2.0.2" - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -electron-to-chromium@^1.3.380: - version "1.3.381" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.381.tgz#952678ff91a5f36175a3832358a6dd2de3bf62b7" - integrity sha512-JQBpVUr83l+QOqPQpj2SbOve1bBE4ACpmwcMNqWlZmfib7jccxJ02qFNichDpZ5LS4Zsqc985NIPKegBIZjK8Q== - -elliptic@^6.0.0: - version "6.5.2" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" - integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" - -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -entities@^1.1.1, entities@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - -entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" - integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== - -envinfo@^7.3.1: - version "7.5.0" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.5.0.tgz#91410bb6db262fb4f1409bd506e9ff57e91023f4" - integrity sha512-jDgnJaF/Btomk+m3PZDTTCb5XIIIX3zYItnCRfF73zVgvinLoRomuhi75Y4su0PtQxWz4v66XnLLckyvyJTOIQ== - -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: - version "1.17.5" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" - integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.1.5" - is-regex "^1.0.5" - object-inspect "^1.7.0" - object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimleft "^2.1.1" - string.prototype.trimright "^2.1.1" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -escodegen@^1.11.0, escodegen@^1.11.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" - integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== - dependencies: - esprima "^4.0.1" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -escodegen@~1.9.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.1.tgz#dbae17ef96c8e4bedb1356f4504fa4cc2f7cb7e2" - integrity sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q== - dependencies: - esprima "^3.1.3" - estraverse "^4.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - -esprima@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" - integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= - -esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -estraverse@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -events@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" - integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== - -evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -falafel@^2.1.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.2.4.tgz#b5d86c060c2412a43166243cb1bce44d1abd2819" - integrity sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ== - dependencies: - acorn "^7.1.1" - foreach "^2.0.5" - isarray "^2.0.1" - object-keys "^1.0.6" - -fast-deep-equal@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" - integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== - -fast-glob@^2.2.2: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - -fastparse@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -filesize@^3.6.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" - integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== - -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - -foreach@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -fs-extra@^8.0.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -fsevents@^1.2.7: - version "1.2.12" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.12.tgz#db7e0d8ec3b0b45724fd4d83d43554a8f1f0de5c" - integrity sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== - -get-caller-file@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-port@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" - integrity sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw= - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob-parent@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" - integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= - dependencies: - is-glob "^3.1.0" - path-dirname "^1.0.0" - -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - -glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - -graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -grapheme-breaker@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/grapheme-breaker/-/grapheme-breaker-0.3.2.tgz#5b9e6b78c3832452d2ba2bb1cb830f96276410ac" - integrity sha1-W55reMODJFLSuiuxy4MPlidkEKw= - dependencies: - brfs "^1.2.0" - unicode-trie "^0.3.1" - -gud@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" - integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - -has-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" - integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-symbols@^1.0.0, has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== - -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - -has@^1.0.0, has@^1.0.1, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hash-base@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hex-color-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" - integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== - -history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - -hmac-drbg@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -hsl-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" - integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= - -hsla-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" - integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= - -html-comment-regex@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" - integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== - -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== - dependencies: - whatwg-encoding "^1.0.1" - -html-tags@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-1.2.0.tgz#c78de65b5663aa597989dd2b7ab49200d7e4db98" - integrity sha1-x43mW1Zjqll5id0rerSSANfk25g= - -htmlnano@^0.2.2: - version "0.2.5" - resolved "https://registry.yarnpkg.com/htmlnano/-/htmlnano-0.2.5.tgz#134fd9548c7cbe51c8508ce434a3f9488cff1b0b" - integrity sha512-X1iPSwXG/iF9bVs+/obt2n6F64uH0ETkA8zp7qFDmLW9/+A6ueHGeb/+qD67T21qUY22owZPMdawljN50ajkqA== - dependencies: - cssnano "^4.1.10" - normalize-html-whitespace "^1.0.0" - posthtml "^0.12.0" - posthtml-render "^1.1.5" - purgecss "^1.4.0" - svgo "^1.3.2" - terser "^4.3.9" - uncss "^0.17.2" - -htmlparser2@^3.9.2: - version "3.10.1" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-browserify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" - integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -icss-replace-symbols@1.1.0, icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -immer@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/immer/-/immer-4.0.2.tgz#9ff0fcdf88e06f92618a5978ceecb5884e633559" - integrity sha512-Q/tm+yKqnKy4RIBmmtISBlhXuSDrB69e9EKTYiIenIKQkXBQir43w+kN/eGiax3wt1J0O1b2fYcNqLSbEcXA7w== - -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" - integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -invariant@^2.1.0, invariant@^2.2.2, invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - -is-absolute-url@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" - integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= - -is-absolute-url@^3.0.1: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" - integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== - -is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - -is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - -is-callable@^1.1.4, is-callable@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" - integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== - -is-color-stop@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" - integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= - dependencies: - css-color-names "^0.0.4" - hex-color-regex "^1.1.0" - hsl-regex "^1.0.0" - hsla-regex "^1.0.0" - rgb-regex "^1.0.1" - rgba-regex "^1.0.0" - -is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - -is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - -is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== - -is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - -is-extglob@^2.1.0, is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - -is-glob@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" - integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= - dependencies: - is-extglob "^2.1.0" - -is-glob@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== - dependencies: - is-extglob "^2.1.1" - -is-html@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-html/-/is-html-1.1.0.tgz#e04f1c18d39485111396f9a0273eab51af218464" - integrity sha1-4E8cGNOUhRETlvmgJz6rUa8hhGQ= - dependencies: - html-tags "^1.0.0" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-regex@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" - integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== - dependencies: - has "^1.0.3" - -is-resolvable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" - integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== - -is-svg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" - integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== - dependencies: - html-comment-regex "^1.1.0" - -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== - dependencies: - has-symbols "^1.0.1" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -is-url@^1.2.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" - integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - -is-wsl@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" - integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - -isarray@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.10.0, js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@^14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-14.1.0.tgz#916463b6094956b0a6c1782c94e380cd30e1981b" - integrity sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng== - dependencies: - abab "^2.0.0" - acorn "^6.0.4" - acorn-globals "^4.3.0" - array-equal "^1.0.0" - cssom "^0.3.4" - cssstyle "^1.1.1" - data-urls "^1.1.0" - domexception "^1.0.1" - escodegen "^1.11.0" - html-encoding-sniffer "^1.0.2" - nwsapi "^2.1.3" - parse5 "5.1.0" - pn "^1.1.0" - request "^2.88.0" - request-promise-native "^1.0.5" - saxes "^3.1.9" - symbol-tree "^3.2.2" - tough-cookie "^2.5.0" - w3c-hr-time "^1.0.1" - w3c-xmlserializer "^1.1.2" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^7.0.0" - ws "^6.1.2" - xml-name-validator "^3.0.0" - -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - -json5@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.2.tgz#43ef1f0af9835dd624751a6b7fa48874fb2d608e" - integrity sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ== - dependencies: - minimist "^1.2.5" - -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - -kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - -kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levenary@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" - integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== - dependencies: - leven "^3.1.0" - -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - -lodash.clone@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" - integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y= - -lodash.memoize@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" - integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= - -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - -lodash.toarray@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561" - integrity sha1-JMS/zWsvuji/0FlNsRedjptlZWE= - -lodash.uniq@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" - integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= - -lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.4: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== - -log-symbols@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -magic-string@^0.22.4: - version "0.22.5" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e" - integrity sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w== - dependencies: - vlq "^0.2.2" - -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -mdn-data@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" - integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== - -merge-source-map@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.4.tgz#a5de46538dae84d4114cc5ea02b4772a6346701f" - integrity sha1-pd5GU42uhNQRTMXqArR3KmNGcB8= - dependencies: - source-map "^0.5.6" - -merge2@^1.2.3: - version "1.3.0" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" - integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== - -micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - -mime-db@1.43.0: - version "1.43.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" - integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== - -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.26" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" - integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== - dependencies: - mime-db "1.43.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mini-create-react-context@^0.3.0: - version "0.3.2" - resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz#79fc598f283dd623da8e088b05db8cddab250189" - integrity sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw== - dependencies: - "@babel/runtime" "^7.4.0" - gud "^1.0.0" - tiny-warning "^1.0.2" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@^0.5.1, mkdirp@~0.5.1: - version "0.5.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" - integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== - dependencies: - minimist "^1.2.5" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -ms@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - -node-addon-api@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.1.tgz#cf813cd69bb8d9100f6bdca6755fc268f54ac492" - integrity sha512-2+DuKodWvwRTrCfKOeR24KIc5unKjOh8mz17NCzVnHWfjAdDqbfbjqh7gUT+BkXBRQM52+xCHciKWonJ3CbJMQ== - -node-emoji@^1.8.1: - version "1.10.0" - resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da" - integrity sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw== - dependencies: - lodash.toarray "^4.4.0" - -node-forge@^0.7.1: - version "0.7.6" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" - integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== - -node-libs-browser@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" - integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== - dependencies: - assert "^1.1.1" - browserify-zlib "^0.2.0" - buffer "^4.3.0" - console-browserify "^1.1.0" - constants-browserify "^1.0.0" - crypto-browserify "^3.11.0" - domain-browser "^1.1.1" - events "^3.0.0" - https-browserify "^1.0.0" - os-browserify "^0.3.0" - path-browserify "0.0.1" - process "^0.11.10" - punycode "^1.2.4" - querystring-es3 "^0.2.0" - readable-stream "^2.3.3" - stream-browserify "^2.0.1" - stream-http "^2.7.2" - string_decoder "^1.0.0" - timers-browserify "^2.0.4" - tty-browserify "0.0.0" - url "^0.11.0" - util "^0.11.0" - vm-browserify "^1.0.1" - -node-releases@^1.1.52: - version "1.1.52" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.52.tgz#bcffee3e0a758e92e44ecfaecd0a47554b0bcba9" - integrity sha512-snSiT1UypkgGt2wxPqS6ImEUICbNCMb31yaxWrOLXjhlt2z2/IBpaOxzONExqSm4y5oLnAqjjRWu+wsDzK5yNQ== - dependencies: - semver "^6.3.0" - -normalize-html-whitespace@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/normalize-html-whitespace/-/normalize-html-whitespace-1.0.0.tgz#5e3c8e192f1b06c3b9eee4b7e7f28854c7601e34" - integrity sha512-9ui7CGtOOlehQu0t/OhhlmDyc71mKVlv+4vF+me4iZLPrNtRL2xoquEdfZxasC/bdQi/Hr3iTrpyRKIG+ocabA== - -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - -normalize-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - -normalize-url@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - -normalize.css@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3" - integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg== - -nth-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - -num2fraction@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" - integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= - -nwsapi@^2.1.3: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" - integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== - -object-inspect@~1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.4.1.tgz#37ffb10e71adaf3748d05f713b4c9452f402cbc4" - integrity sha512-wqdhLpfCUbEsoEwl3FXwGyv8ief1k/1aUdIPCqVnupM6e8l63BEJdiF/0swtn04/8p05tG/T0FrpTlfwvljOdw== - -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.0.6, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - -object.getownpropertydescriptors@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" - integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - -object.values@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" - integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - -opn@^5.1.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" - integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== - dependencies: - is-wsl "^1.1.0" - -optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -ora@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/ora/-/ora-2.1.0.tgz#6caf2830eb924941861ec53a173799e008b51e5b" - integrity sha512-hNNlAd3gfv/iPmsNxYoAPLvxg7HuPozww7fFonMZvL84tP6Ox5igfk5j/+a9rtJJwqMgKK+JgWsAQik5o0HTLA== - dependencies: - chalk "^2.3.1" - cli-cursor "^2.1.0" - cli-spinners "^1.1.0" - log-symbols "^2.2.0" - strip-ansi "^4.0.0" - wcwidth "^1.0.1" - -os-browserify@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" - integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= - -p-limit@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" - integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== - dependencies: - p-try "^2.0.0" - -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - -pako@^0.2.5: - version "0.2.9" - resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" - integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU= - -pako@~1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - -parcel-bundler@^1.12.4: - version "1.12.4" - resolved "https://registry.yarnpkg.com/parcel-bundler/-/parcel-bundler-1.12.4.tgz#31223f4ab4d00323a109fce28d5e46775409a9ee" - integrity sha512-G+iZGGiPEXcRzw0fiRxWYCKxdt/F7l9a0xkiU4XbcVRJCSlBnioWEwJMutOCCpoQmaQtjB4RBHDGIHN85AIhLQ== - dependencies: - "@babel/code-frame" "^7.0.0" - "@babel/core" "^7.4.4" - "@babel/generator" "^7.4.4" - "@babel/parser" "^7.4.4" - "@babel/plugin-transform-flow-strip-types" "^7.4.4" - "@babel/plugin-transform-modules-commonjs" "^7.4.4" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/preset-env" "^7.4.4" - "@babel/runtime" "^7.4.4" - "@babel/template" "^7.4.4" - "@babel/traverse" "^7.4.4" - "@babel/types" "^7.4.4" - "@iarna/toml" "^2.2.0" - "@parcel/fs" "^1.11.0" - "@parcel/logger" "^1.11.1" - "@parcel/utils" "^1.11.0" - "@parcel/watcher" "^1.12.1" - "@parcel/workers" "^1.11.0" - ansi-to-html "^0.6.4" - babylon-walk "^1.0.2" - browserslist "^4.1.0" - chalk "^2.1.0" - clone "^2.1.1" - command-exists "^1.2.6" - commander "^2.11.0" - core-js "^2.6.5" - cross-spawn "^6.0.4" - css-modules-loader-core "^1.1.0" - cssnano "^4.0.0" - deasync "^0.1.14" - dotenv "^5.0.0" - dotenv-expand "^5.1.0" - envinfo "^7.3.1" - fast-glob "^2.2.2" - filesize "^3.6.0" - get-port "^3.2.0" - htmlnano "^0.2.2" - is-glob "^4.0.0" - is-url "^1.2.2" - js-yaml "^3.10.0" - json5 "^1.0.1" - micromatch "^3.0.4" - mkdirp "^0.5.1" - node-forge "^0.7.1" - node-libs-browser "^2.0.0" - opn "^5.1.0" - postcss "^7.0.11" - postcss-value-parser "^3.3.1" - posthtml "^0.11.2" - posthtml-parser "^0.4.0" - posthtml-render "^1.1.3" - resolve "^1.4.0" - semver "^5.4.1" - serialize-to-js "^3.0.0" - serve-static "^1.12.4" - source-map "0.6.1" - terser "^3.7.3" - v8-compile-cache "^2.0.0" - ws "^5.1.1" - -parse-asn1@^5.0.0: - version "5.1.5" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" - integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - -parse5@5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" - integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - -path-browserify@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" - integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== - -path-dirname@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" - integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= - -path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - -pbkdf2@^3.0.3: - version "3.0.17" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" - integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -physical-cpu-count@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/physical-cpu-count/-/physical-cpu-count-2.0.0.tgz#18de2f97e4bf7a9551ad7511942b5496f7aba660" - integrity sha1-GN4vl+S/epVRrXURlCtUlverpmA= - -pkg-up@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" - integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== - dependencies: - find-up "^3.0.0" - -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - -postcss-calc@^7.0.1: - version "7.0.2" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.2.tgz#504efcd008ca0273120568b0792b16cdcde8aac1" - integrity sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ== - dependencies: - postcss "^7.0.27" - postcss-selector-parser "^6.0.2" - postcss-value-parser "^4.0.2" - -postcss-colormin@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" - integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== - dependencies: - browserslist "^4.0.0" - color "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-convert-values@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" - integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-discard-comments@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" - integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== - dependencies: - postcss "^7.0.0" - -postcss-discard-duplicates@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" - integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== - dependencies: - postcss "^7.0.0" - -postcss-discard-empty@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" - integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== - dependencies: - postcss "^7.0.0" - -postcss-discard-overridden@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" - integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== - dependencies: - postcss "^7.0.0" - -postcss-functions@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-functions/-/postcss-functions-3.0.0.tgz#0e94d01444700a481de20de4d55fb2640564250e" - integrity sha1-DpTQFERwCkgd4g3k1V+yZAVkJQ4= - dependencies: - glob "^7.1.2" - object-assign "^4.1.1" - postcss "^6.0.9" - postcss-value-parser "^3.3.0" - -postcss-js@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-2.0.3.tgz#a96f0f23ff3d08cec7dc5b11bf11c5f8077cdab9" - integrity sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w== - dependencies: - camelcase-css "^2.0.1" - postcss "^7.0.18" - -postcss-merge-longhand@^4.0.11: - version "4.0.11" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" - integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== - dependencies: - css-color-names "0.0.4" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - stylehacks "^4.0.0" - -postcss-merge-rules@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" - integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - cssnano-util-same-parent "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - vendors "^1.0.0" - -postcss-minify-font-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" - integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-gradients@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" - integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - is-color-stop "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-minify-params@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" - integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== - dependencies: - alphanum-sort "^1.0.0" - browserslist "^4.0.0" - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - uniqs "^2.0.0" - -postcss-minify-selectors@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" - integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== - dependencies: - alphanum-sort "^1.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -postcss-modules-extract-imports@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz#b614c9720be6816eaee35fb3a5faa1dba6a05ddb" - integrity sha1-thTJcgvmgW6u41+zpfqh26agXds= - dependencies: - postcss "^6.0.1" - -postcss-modules-local-by-default@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" - integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk= - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-scope@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" - integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A= - dependencies: - css-selector-tokenizer "^0.7.0" - postcss "^6.0.1" - -postcss-modules-values@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" - integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA= - dependencies: - icss-replace-symbols "^1.1.0" - postcss "^6.0.1" - -postcss-nested@^4.1.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-4.2.1.tgz#4bc2e5b35e3b1e481ff81e23b700da7f82a8b248" - integrity sha512-AMayXX8tS0HCp4O4lolp4ygj9wBn32DJWXvG6gCv+ZvJrEa00GUxJcJEEzMh87BIe6FrWdYkpR2cuyqHKrxmXw== - dependencies: - postcss "^7.0.21" - postcss-selector-parser "^6.0.2" - -postcss-normalize-charset@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" - integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== - dependencies: - postcss "^7.0.0" - -postcss-normalize-display-values@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" - integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-positions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" - integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== - dependencies: - cssnano-util-get-arguments "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-repeat-style@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" - integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== - dependencies: - cssnano-util-get-arguments "^4.0.0" - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-string@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" - integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== - dependencies: - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-timing-functions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" - integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== - dependencies: - cssnano-util-get-match "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-unicode@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" - integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-url@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" - integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== - dependencies: - is-absolute-url "^2.0.0" - normalize-url "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-normalize-whitespace@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" - integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== - dependencies: - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-ordered-values@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" - integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== - dependencies: - cssnano-util-get-arguments "^4.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-reduce-initial@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" - integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== - dependencies: - browserslist "^4.0.0" - caniuse-api "^3.0.0" - has "^1.0.0" - postcss "^7.0.0" - -postcss-reduce-transforms@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" - integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== - dependencies: - cssnano-util-get-match "^4.0.0" - has "^1.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - -postcss-selector-parser@6.0.2, postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" - integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== - dependencies: - cssesc "^3.0.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-selector-parser@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" - integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== - dependencies: - dot-prop "^5.2.0" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss-svgo@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" - integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw== - dependencies: - is-svg "^3.0.0" - postcss "^7.0.0" - postcss-value-parser "^3.0.0" - svgo "^1.0.0" - -postcss-unique-selectors@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" - integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== - dependencies: - alphanum-sort "^1.0.0" - postcss "^7.0.0" - uniqs "^2.0.0" - -postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - -postcss-value-parser@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz#651ff4593aa9eda8d5d0d66593a2417aeaeb325d" - integrity sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg== - -postcss@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.1.tgz#000dbd1f8eef217aa368b9a212c5fc40b2a8f3f2" - integrity sha1-AA29H47vIXqjaLmiEsX8QLKo8/I= - dependencies: - chalk "^1.1.3" - source-map "^0.5.6" - supports-color "^3.2.3" - -postcss@^6.0.1, postcss@^6.0.9: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.11, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.18, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.27: - version "7.0.27" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9" - integrity sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -posthtml-parser@^0.4.0, posthtml-parser@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/posthtml-parser/-/posthtml-parser-0.4.2.tgz#a132bbdf0cd4bc199d34f322f5c1599385d7c6c1" - integrity sha512-BUIorsYJTvS9UhXxPTzupIztOMVNPa/HtAm9KHni9z6qEfiJ1bpOBL5DfUOL9XAc3XkLIEzBzpph+Zbm4AdRAg== - dependencies: - htmlparser2 "^3.9.2" - -posthtml-render@^1.1.3, posthtml-render@^1.1.5: - version "1.2.0" - resolved "https://registry.yarnpkg.com/posthtml-render/-/posthtml-render-1.2.0.tgz#3df0c800a8bbb95af583a94748520469477addf4" - integrity sha512-dQB+hoAKDtnI94RZm/wxBUH9My8OJcXd0uhWmGh2c7tVtQ85A+OS3yCN3LNbFtPz3bViwBJXAeoi+CBGMXM0DA== - -posthtml@^0.11.2: - version "0.11.6" - resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.11.6.tgz#e349d51af7929d0683b9d8c3abd8166beecc90a8" - integrity sha512-C2hrAPzmRdpuL3iH0TDdQ6XCc9M7Dcc3zEW5BLerY65G4tWWszwv6nG/ksi6ul5i2mx22ubdljgktXCtNkydkw== - dependencies: - posthtml-parser "^0.4.1" - posthtml-render "^1.1.5" - -posthtml@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/posthtml/-/posthtml-0.12.0.tgz#6e2a2fcd774eaed1a419a95c5cc3a92b676a40a6" - integrity sha512-aNUEP/SfKUXAt+ghG51LC5MmafChBZeslVe/SSdfKIgLGUVRE68mrMF4V8XbH07ZifM91tCSuxY3eHIFLlecQw== - dependencies: - posthtml-parser "^0.4.1" - posthtml-render "^1.1.5" - -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - -prettier@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.2.tgz#1ba8f3eb92231e769b7fcd7cb73ae1b6b74ade08" - integrity sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg== - -pretty-hrtime@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" - integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= - -private@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" - integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - -prop-types@^15.6.2, prop-types@^15.7.2: - version "15.7.2" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" - integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.8.1" - -psl@^1.1.28: - version "1.7.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c" - integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ== - -public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - -punycode@^1.2.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -purgecss@^1.4.0: - version "1.4.2" - resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-1.4.2.tgz#67ab50cb4f5c163fcefde56002467c974e577f41" - integrity sha512-hkOreFTgiyMHMmC2BxzdIw5DuC6kxAbP/gGOGd3MEsF3+5m69rIvUEPaxrnoUtfODTFKe9hcXjGwC6jcjoyhOw== - dependencies: - glob "^7.1.3" - postcss "^7.0.14" - postcss-selector-parser "^6.0.0" - yargs "^14.0.0" - -q@^1.1.2: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -querystring-es3@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= - -quote-stream@^1.0.1, quote-stream@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/quote-stream/-/quote-stream-1.0.2.tgz#84963f8c9c26b942e153feeb53aae74652b7e0b2" - integrity sha1-hJY/jJwmuULhU/7rU6rnRlK34LI= - dependencies: - buffer-equal "0.0.1" - minimist "^1.1.3" - through2 "^2.0.0" - -randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -react-dom@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f" - integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - scheduler "^0.19.1" - -react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.9.0: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -react-redux@^7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d" - integrity sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA== - dependencies: - "@babel/runtime" "^7.5.5" - hoist-non-react-statics "^3.3.0" - loose-envify "^1.4.0" - prop-types "^15.7.2" - react-is "^16.9.0" - -react-router-dom@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.1.2.tgz#06701b834352f44d37fbb6311f870f84c76b9c18" - integrity sha512-7BPHAaIwWpZS074UKaw1FjVdZBSVWEk8IuDXdB+OkLb8vd/WRQIpA4ag9WQk61aEfQs47wHyjWUoUGGZxpQXew== - dependencies: - "@babel/runtime" "^7.1.2" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.1.2" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-router@5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.1.2.tgz#6ea51d789cb36a6be1ba5f7c0d48dd9e817d3418" - integrity sha512-yjEuMFy1ONK246B+rsa0cUam5OeAQ8pyclRDgpxuSCrAlJ1qN9uZ5IgyKC7gQg0w8OM50NXHEegPh/ks9YuR2A== - dependencies: - "@babel/runtime" "^7.1.2" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - mini-create-react-context "^0.3.0" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react@^16.13.1: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" - integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.2" - -readable-stream@^2.0.2, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.3, readable-stream@~2.3.6: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readable-stream@^3.1.1: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readdirp@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" - integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== - dependencies: - graceful-fs "^4.1.11" - micromatch "^3.1.10" - readable-stream "^2.0.2" - -reduce-css-calc@^2.1.6: - version "2.1.7" - resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-2.1.7.tgz#1ace2e02c286d78abcd01fd92bfe8097ab0602c2" - integrity sha512-fDnlZ+AybAS3C7Q9xDq5y8A2z+lT63zLbynew/lur/IR24OQF5x98tfNwf79mzEdfywZ0a2wpM860FhFfMxZlA== - dependencies: - css-unit-converter "^1.1.1" - postcss-value-parser "^3.3.0" - -redux-devtools-extension@^2.13.8: - version "2.13.8" - resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1" - integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg== - -redux-immutable-state-invariant@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/redux-immutable-state-invariant/-/redux-immutable-state-invariant-2.1.0.tgz#308fd3cc7415a0e7f11f51ec997b6379c7055ce1" - integrity sha512-3czbDKs35FwiBRsx/3KabUk5zSOoTXC+cgVofGkpBNv3jQcqIe5JrHcF5AmVt7B/4hyJ8MijBIpCJ8cife6yJg== - dependencies: - invariant "^2.1.0" - json-stringify-safe "^5.0.1" - -redux-thunk@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" - integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== - -redux@^4.0.0: - version "4.0.5" - resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" - integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== - dependencies: - loose-envify "^1.4.0" - symbol-observable "^1.2.0" - -regenerate-unicode-properties@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" - integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== - dependencies: - regenerate "^1.4.0" - -regenerate@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" - integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== - -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - -regenerator-runtime@^0.13.4: - version "0.13.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" - integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== - -regenerator-transform@^0.14.2: - version "0.14.4" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" - integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== - dependencies: - "@babel/runtime" "^7.8.4" - private "^0.1.8" - -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - -regexpu-core@^4.6.0, regexpu-core@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" - integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== - dependencies: - regenerate "^1.4.0" - regenerate-unicode-properties "^8.2.0" - regjsgen "^0.5.1" - regjsparser "^0.6.4" - unicode-match-property-ecmascript "^1.0.4" - unicode-match-property-value-ecmascript "^1.2.0" - -regjsgen@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" - integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== - -regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== - dependencies: - jsesc "~0.5.0" - -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - -repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -request-promise-core@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" - integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== - dependencies: - lodash "^4.17.15" - -request-promise-native@^1.0.5: - version "1.0.8" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" - integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== - dependencies: - request-promise-core "1.1.3" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.88.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - -reselect@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7" - integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA== - -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - -resolve@^1.1.5, resolve@^1.14.2, resolve@^1.3.2, resolve@^1.4.0: - version "1.15.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" - integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== - dependencies: - path-parse "^1.0.6" - -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - -rgb-regex@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" - integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= - -rgba-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" - integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= - -rimraf@^2.6.2: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -sax@~1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - -saxes@^3.1.9: - version "3.1.11" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" - integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== - dependencies: - xmlchars "^2.1.1" - -scheduler@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" - integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - -semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - -semver@^5.4.1, semver@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -serialize-to-js@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/serialize-to-js/-/serialize-to-js-3.1.1.tgz#b3e77d0568ee4a60bfe66287f991e104d3a1a4ac" - integrity sha512-F+NGU0UHMBO4Q965tjw7rvieNVjlH6Lqi2emq/Lc9LUURYJbiCzmpi4Cy1OOjjVPtxu0c+NE85LU6968Wko5ZA== - -serve-static@^1.12.4: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -shallow-copy@~0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170" - integrity sha1-QV9CcC1z2BAzApLMXuhurhoRoXA= - -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - -signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= - -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - -source-map-support@~0.5.10, source-map-support@~0.5.12: - version "0.5.16" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" - integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= - -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.5.0, source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -stable@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" - integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== - -static-eval@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.5.tgz#f0782e66999c4b3651cda99d9ce59c507d188f71" - integrity sha512-nNbV6LbGtMBgv7e9LFkt5JV8RVlRsyJrphfAt9tOtBBW/SfnzZDf2KnS72an8e434A+9e/BmJuTxeGPvrAK7KA== - dependencies: - escodegen "^1.11.1" - -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - -static-module@^2.2.0: - version "2.2.5" - resolved "https://registry.yarnpkg.com/static-module/-/static-module-2.2.5.tgz#bd40abceae33da6b7afb84a0e4329ff8852bfbbf" - integrity sha512-D8vv82E/Kpmz3TXHKG8PPsCPg+RAX6cbCOyvjM6x04qZtQ47EtJFVwRsdov3n5d6/6ynrOY9XB4JkaZwB2xoRQ== - dependencies: - concat-stream "~1.6.0" - convert-source-map "^1.5.1" - duplexer2 "~0.1.4" - escodegen "~1.9.0" - falafel "^2.1.0" - has "^1.0.1" - magic-string "^0.22.4" - merge-source-map "1.0.4" - object-inspect "~1.4.0" - quote-stream "~1.0.2" - readable-stream "~2.3.3" - shallow-copy "~0.0.1" - static-eval "^2.0.0" - through2 "~2.0.3" - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - -stream-browserify@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" - integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-http@^2.7.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" - integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.3.6" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -string-width@^3.0.0, string-width@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - -string.prototype.trimleft@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" - integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== - dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" - -string.prototype.trimright@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" - integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== - dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" - -string_decoder@^1.0.0, string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - -stylehacks@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" - integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== - dependencies: - browserslist "^4.0.0" - postcss "^7.0.0" - postcss-selector-parser "^3.0.0" - -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -supports-color@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" - integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= - dependencies: - has-flag "^1.0.0" - -supports-color@^5.3.0, supports-color@^5.4.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" - integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== - dependencies: - has-flag "^4.0.0" - -svgo@^1.0.0, svgo@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" - integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== - dependencies: - chalk "^2.4.1" - coa "^2.0.2" - css-select "^2.0.0" - css-select-base-adapter "^0.1.1" - css-tree "1.0.0-alpha.37" - csso "^4.0.2" - js-yaml "^3.13.1" - mkdirp "~0.5.1" - object.values "^1.1.0" - sax "~1.2.4" - stable "^0.1.8" - unquote "~1.1.1" - util.promisify "~1.0.0" - -symbol-observable@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== - -symbol-tree@^3.2.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - -tailwindcss@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-1.2.0.tgz#5df317cebac4f3131f275d258a39da1ba3a0f291" - integrity sha512-CKvY0ytB3ze5qvynG7qv4XSpQtFNGPbu9pUn8qFdkqgD8Yo/vGss8mhzbqls44YCXTl4G62p3qVZBj45qrd6FQ== - dependencies: - autoprefixer "^9.4.5" - bytes "^3.0.0" - chalk "^3.0.0" - detective "^5.2.0" - fs-extra "^8.0.0" - lodash "^4.17.15" - node-emoji "^1.8.1" - normalize.css "^8.0.1" - postcss "^7.0.11" - postcss-functions "^3.0.0" - postcss-js "^2.0.0" - postcss-nested "^4.1.1" - postcss-selector-parser "^6.0.0" - pretty-hrtime "^1.0.3" - reduce-css-calc "^2.1.6" - resolve "^1.14.2" - -terser@^3.7.3: - version "3.17.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-3.17.0.tgz#f88ffbeda0deb5637f9d24b0da66f4e15ab10cb2" - integrity sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ== - dependencies: - commander "^2.19.0" - source-map "~0.6.1" - source-map-support "~0.5.10" - -terser@^4.3.9: - version "4.6.7" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.7.tgz#478d7f9394ec1907f0e488c5f6a6a9a2bad55e72" - integrity sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g== - dependencies: - commander "^2.20.0" - source-map "~0.6.1" - source-map-support "~0.5.12" - -through2@^2.0.0, through2@~2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -timers-browserify@^2.0.4: - version "2.0.11" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" - integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== - dependencies: - setimmediate "^1.0.4" - -timsort@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" - integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= - -tiny-inflate@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4" - integrity sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw== - -tiny-invariant@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" - integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== - -tiny-warning@^1.0.0, tiny-warning@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= - -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= - -to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -tough-cookie@^2.3.3, tough-cookie@^2.5.0, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" - -tty-browserify@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - dependencies: - prelude-ls "~1.1.2" - -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -typescript@^3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== - -uncss@^0.17.2: - version "0.17.3" - resolved "https://registry.yarnpkg.com/uncss/-/uncss-0.17.3.tgz#50fc1eb4ed573ffff763458d801cd86e4d69ea11" - integrity sha512-ksdDWl81YWvF/X14fOSw4iu8tESDHFIeyKIeDrK6GEVTQvqJc1WlOEXqostNwOCi3qAj++4EaLsdAgPmUbEyog== - dependencies: - commander "^2.20.0" - glob "^7.1.4" - is-absolute-url "^3.0.1" - is-html "^1.1.0" - jsdom "^14.1.0" - lodash "^4.17.15" - postcss "^7.0.17" - postcss-selector-parser "6.0.2" - request "^2.88.0" - -unicode-canonical-property-names-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" - integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== - -unicode-match-property-ecmascript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" - integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== - dependencies: - unicode-canonical-property-names-ecmascript "^1.0.4" - unicode-property-aliases-ecmascript "^1.0.4" - -unicode-match-property-value-ecmascript@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" - integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== - -unicode-property-aliases-ecmascript@^1.0.4: - version "1.1.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" - integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== - -unicode-trie@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/unicode-trie/-/unicode-trie-0.3.1.tgz#d671dddd89101a08bac37b6a5161010602052085" - integrity sha1-1nHd3YkQGgi6w3tqUWEBBgIFIIU= - dependencies: - pako "^0.2.5" - tiny-inflate "^1.0.0" - -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - -uniq@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" - integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= - -uniqs@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" - integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= - -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - -unquote@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" - integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= - -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - -upath@^1.1.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" - integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - -util.promisify@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.17.2" - has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" - -util@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= - dependencies: - inherits "2.0.1" - -util@^0.11.0: - version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" - integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== - dependencies: - inherits "2.0.3" - -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - -v8-compile-cache@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" - integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== - -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - -vendors@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" - integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -vlq@^0.2.2: - version "0.2.3" - resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26" - integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow== - -vm-browserify@^1.0.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" - integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== - -w3c-hr-time@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" - integrity sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg== - dependencies: - domexception "^1.0.1" - webidl-conversions "^4.0.2" - xml-name-validator "^3.0.0" - -wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-mimetype@^2.2.0, whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - -word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -ws@^5.1.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" - integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== - dependencies: - async-limiter "~1.0.0" - -ws@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" - integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== - dependencies: - async-limiter "~1.0.0" - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xmlchars@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - -xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== - -yargs-parser@^15.0.1: - version "15.0.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-15.0.1.tgz#54786af40b820dcb2fb8025b11b4d659d76323b3" - integrity sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs@^14.0.0: - version "14.2.3" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" - integrity sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg== - dependencies: - cliui "^5.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^15.0.1" diff --git a/users/wpcarro/buildHaskell/default.nix b/users/wpcarro/buildHaskell/default.nix deleted file mode 100644 index 2f0fd9e1c..000000000 --- a/users/wpcarro/buildHaskell/default.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ pkgs, ... }: - -{ - # Create a nix-shell for Haskell development. - shell = { deps }: - let - ghc = pkgs.haskellPackages.ghcWithPackages (hpkgs: deps hpkgs); - in - pkgs.mkShell { - buildInputs = [ ghc ]; - }; - - # Build a Haskell executable. This assumes a project directory with a - # top-level Main.hs. - # - `name`: You can find the result at ./result/$name - # - `srcs`: Will be passed to `srcs` field of `pkgs.stdenv.mkDerivation`. - # - `deps`: A function that accepts `hpkgs` and returns a list of Haskell - # - `ghcExtensions`: A list of strings representing the language extensions to - # use. - program = { name, srcs, deps, ghcExtensions }: - let - ghc = pkgs.haskellPackages.ghcWithPackages (hpkgs: deps hpkgs); - in - pkgs.stdenv.mkDerivation { - name = name; - buildInputs = [ ]; - srcs = srcs; - buildPhase = '' - ${ghc}/bin/ghc -Wall Main.hs ${pkgs.lib.concatMapStrings (x: "-X${x} ") ghcExtensions} - ''; - installPhase = '' - mkdir -p $out && mv Main $out/${name} - ''; - }; -} diff --git a/users/wpcarro/ci/pipelines/post-receive.nix b/users/wpcarro/ci/pipelines/post-receive.nix deleted file mode 100644 index 09b8990e1..000000000 --- a/users/wpcarro/ci/pipelines/post-receive.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ pkgs, depot, ... }: - -let - inherit (builtins) path toJSON; - - pipeline.steps = [ - { - key = "lint-secrets"; - command = "${pkgs.git-secrets}/bin/git-secrets --scan-history"; - label = ":broom: lint secrets"; - } - ]; -in -pkgs.writeText "pipeline.yaml" (toJSON pipeline) diff --git a/users/wpcarro/ci/secret-patterns.txt b/users/wpcarro/ci/secret-patterns.txt deleted file mode 100644 index cbf58a1e7..000000000 --- a/users/wpcarro/ci/secret-patterns.txt +++ /dev/null @@ -1,9 +0,0 @@ -(A3T[A-Z0-9]|AKIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASIA)[A-Z0-9]{16} -("|')?(AWS|aws|Aws)?_?(SECRET|secret|Secret)?_?(ACCESS|access|Access)?_?(KEY|key|Key)("|')?\s*(:|=>|=)\s*("|')?[A-Za-z0-9/\+=]{40}("|')? -("|')?(AWS|aws|Aws)?_?(ACCOUNT|account|Account)_?(ID|id|Id)?("|')?\s*(:|=>|=)\s*("|')?[0-9]{4}\-?[0-9]{4}\-?[0-9]{4}("|')? -AIza[0-9A-Za-z_-]{35} -[0-9]+-[0-9A-Za-z_]{32}\.apps\.googleusercontent\.com -(^|[^0-9A-Za-z/+])1/[0-9A-Za-z_-]{43} -(^|[^0-9A-Za-z/+])1/[0-9A-Za-z_-]{64} -ya29\.[0-9A-Za-z_-]+ -(sk|pk)_(test|live)_[a-zA-Z0-9]{99} diff --git a/users/wpcarro/common.nix b/users/wpcarro/common.nix deleted file mode 100644 index f7a03d676..000000000 --- a/users/wpcarro/common.nix +++ /dev/null @@ -1,83 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.users) wpcarro; -in -{ - programs = { - fish.enable = true; - - gnupg.agent.enable = true; - - ssh = { - startAgent = true; - extraConfig = '' - AddKeysToAgent yes - ''; - }; - - git = { - enable = true; - config = { - user.name = "William Carroll"; - user.email = "wpcarro@gmail.com"; - }; - }; - }; - - services = { - # Remodel the system clipboard as a list instead of a point. - clipmenu.enable = true; - - # TODO(wpcarro): broken in nixpkgs as of 2023-10-04 - locate.enable = false; - - depot.automatic-gc = { - enable = true; - interval = "1 hour"; - diskThreshold = 16; # GiB - maxFreed = 10; # GiB - preserveGenerations = "14d"; - }; - }; - - # Command-line tools I commonly used and want available on most (or all) of my - # machines. - shell-utils = with pkgs; [ - age - bat - coreutils - direnv - diskus - emacs - fd - fzf - git - gnupg - htop - jq - nmap - passage - python3 - rink - ripgrep - tldr - tokei - tree - vim - whois - # TODO(wpcarro): Debug this failing build. - # wpcarro.tools.simple_vim - xclip - zip - ] ++ - (if pkgs.stdenv.isLinux then [ - mkpasswd - sysz - # This depends on compiler-rt-libc-10.0.1, which is marked as broken on - # aarch64-darwin, but depot sets `allowBroken = true`, which means any - # build that depends on dig will fail on OSX (e.g. emacs). - # https://github.com/NixOS/nixpkgs/blob/e9b195248c6cd7961a453b10294aea9ab58e01b4/pkgs/development/compilers/llvm/10/compiler-rt/default.nix#L122 - dig - ] else [ ]); -} diff --git a/users/wpcarro/configs/.config/nixpkgs/config.nix b/users/wpcarro/configs/.config/nixpkgs/config.nix deleted file mode 100644 index 1dd1750ae..000000000 --- a/users/wpcarro/configs/.config/nixpkgs/config.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - allowUnfree = true; -} diff --git a/users/wpcarro/configs/.config/nvim/init.vim b/users/wpcarro/configs/.config/nvim/init.vim deleted file mode 100644 index 57cfe7ea6..000000000 --- a/users/wpcarro/configs/.config/nvim/init.vim +++ /dev/null @@ -1,668 +0,0 @@ -" -- BEGIN: Vundle config -- -set nocompatible " be iMproved, required -filetype off " required - -" set the runtime path to include Vundle and initialize -" share Vundle between vim and neovim -set rtp+=~/.vim/bundle/Vundle.vim -set rtp+=~/.config/nvim/bundle/Vundle.vim -call vundle#begin() -" alternatively, pass a path where Vundle should install plugins -"call vundle#begin('~/some/path/here') - -" let Vundle manage Vundle, required -Plugin 'VundleVim/Vundle.vim' - -" Rust IDE features -Plugin 'racer-rust/vim-racer' - -set hidden -let g:racer_experimental_completer = 1 -autocmd FileType rust nmap gd (rust-def) -autocmd FileType rust nmap gs (rust-def-split) -autocmd FileType rust nmap gx (rust-def-vertical) -autocmd FileType rust nmap gd (rust-doc) - -Plugin 'xolox/vim-misc' - -" The following are examples of different formats supported. -" Keep Plugin commands between vundle#begin/end. - -" Displays git information in airline. -Plugin 'tpope/vim-fugitive' - -" easier file navigation -Plugin 'tpope/vim-vinegar' - -" Displays git-tracked C*UD ops within gutter. -Plugin 'airblade/vim-gitgutter' - -" Fuzzy-finder -Plugin 'kien/ctrlp.vim' - -" Grep file contents -Plugin 'mileszs/ack.vim' - -" Syntax and other light-weight suppor for a variety of languages -Plugin 'sheerun/vim-polyglot' - -" Themes -Plugin 'deviantfero/wpgtk.vim' -Plugin 'rainglow/vim' - - -" Executes shell commands and pipes output into new Vim buffer. -Plugin 'sjl/clam.vim' - -" Multiple cursors for simultaneous edits. -" NOTE: use to run miltiple cursors not -Plugin 'terryma/vim-multiple-cursors' - -" Visualize buffers -Plugin 'vim-airline/vim-airline' -Plugin 'vim-airline/vim-airline-themes' - -" Visually align assignments -Plugin 'godlygeek/tabular' - -" Visually Highlight and comment code. -Plugin 'tpope/vim-commentary' - -" Macros for quotes, parens, etc. -Plugin 'tpope/vim-surround' - -" Allows Plugins to be repeated with `.` character -Plugin 'tpope/vim-repeat' - -" Pairs of mappings -Plugin 'tpope/vim-unimpaired' - -" LISPs support -Plugin 'guns/vim-sexp' -Plugin 'tpope/vim-sexp-mappings-for-regular-people' -let g:sexp_enable_insert_mode_mappings = 0 -let g:sexp_filetypes = '' - -" Seamlessly navigate Vim and Tmux with similar bindings. -Plugin 'christoomey/vim-tmux-navigator' - -" Async `:make` for code linting etc. -Plugin 'neomake/neomake' - -" Better buffer mgt than CtrlP -Plugin 'yegappan/mru' - -Plugin 'zanglg/nova.vim' - -" Emulates Emacs's Helm Swoop search -Plugin 'pelodelfuego/vim-swoop' - -" Transparent encryption + decryption -Plugin 'jamessan/vim-gnupg' - -" Javascript auto-formatting -" Plugin 'prettier/vim-prettier', { -" \ 'do': 'yarn install', - " \ 'for': ['javascript', 'typescript', 'css', 'less', 'scss', 'json', 'graphql', 'markdown'] } - -" Support Org mode -Plugin 'jceb/vim-orgmode' - -" Autocompletion -Plugin 'junegunn/fzf' - -" Text objects made easy -Plugin 'kana/vim-textobj-user' - -" Elixir text objects -Plugin 'andyl/vim-textobj-elixir' - -" Making HTML editing faster -Plugin 'mattn/emmet-vim' - -" Snippets for all languages -Plugin 'honza/vim-snippets' - -" Automatic bracket insertion -Plugin 'jiangmiao/auto-pairs' - -" Linting & error warnings -Plugin 'vim-syntastic/syntastic' - -" Angular.js support -Plugin 'burnettk/vim-angular' - -" Asynchronous Linting Engine -Plugin 'w0rp/ale' - -call vundle#end() " required -filetype plugin indent on " required -" Put your non-Plugin stuff after this line -" -- END: Vundle config -- - -" Changes to character. -let mapleader = " " - - -" Highlight column width -set textwidth=80 -set colorcolumn=+0 - -" autoreload a file when it changes on disk -set autoread - -" default to case-insensitive searching -set ignorecase - -" JSX configuration -let g:jsx_ext_required = 0 - - -autocmd FileType reason nnoremap gd :call LanguageClient_textDocument_definition() -autocmd FileType reason nnoremap gf :call LanguageClient_textDocument_formatting() -autocmd FileType reason nnoremap gh :call LanguageClient_textDocument_hover() -autocmd FileType reason nnoremap gr :call LanguageClient_textDocument_rename() - -" Replace with G for faster navigation -nnoremap G -onoremap G -vnoremap G - -" Mirror ZLE KBD -inoremap :echo "Working" - -" Syntastic configuration -set statusline+=%#warningmsg# -set statusline+=%{SyntasticStatuslineFlag()} -set statusline+=%* - -let g:syntastic_always_populate_loc_list = 1 -let g:syntastic_auto_loc_list = 1 -let g:syntastic_check_on_open = 1 -let g:syntastic_check_on_wq = 0 -" let g:syntastic_javascript_checkers = ['eslint'] -let g:syntastic_javascript_eslint_generic = 1 -" this is a hack to prevent a false negative -" https://github.com/vim-syntastic/syntastic/issues/1692 -" let g:syntastic_javascript_eslint_exec = '/bin/ls' -" let g:syntastic_javascript_eslint_exe = 'npx eslint' -" let g:syntastic_javascript_eslint_args = '-f compact' - -" javascript autocompletion -" autocmd FileType javascript setlocal omnifunc=javascriptcomplete#CompleteJS -" autocmd FileType javascript nnoremap gf :Prettier - -" Maximize the current window -" Similar to Tmux mapping alt-z in my tmux.conf -nnoremap t% :tab sp - -" Allow C-g to act like C-c the way it does in Emacs -cnoremap - -" Prettier configuration -" let g:prettier#exec_cmd_async = 1 -" force Prettier to run on files even without the @format pragma -" let g:prettier#autoformat = 0 - - -" Basic settings -" Thin cursor on INSERT mode -if has('nvim') - let $NVIM_TUI_ENABLE_CURSOR_SHAPE = 1 -endif - -set number -set nowrap -set tabstop=2 -set expandtab -set shiftwidth=2 -set background=dark - -syntax enable -colorscheme peacock - -" Vim in terminal cannot have a different font from the one set within your -" terminal. However, this setting will set the font for the GUI version. -if has('gui_running') - set guifont=Operator\ Mono:h12 -endif - -if has('termguicolors') - set termguicolors -endif - -if &term =~# '^screen' - let &t_8f = "\[38;2;%lu;%lu;%lum" - let &t_8b = "\[48;2;%lu;%lu;%lum" -endif - -set history=1000 -set undolevels=1000 - -set t_Co=255 - -" Support italics -highlight Comment cterm=italic - - -" quickly edit popular configuration files -nnoremap ev :vsplit $MYVIMRC -nnoremap ee :vsplit ~/.emacs.d/init.el -nnoremap ez :vsplit ~/.zshrc -nnoremap ea :vsplit ~/aliases.zsh -nnoremap ef :vsplit ~/functions.zsh -nnoremap el :vsplit ~/variables.zsh -nnoremap ex :vsplit ~/.Xresources - -" quickly source your vimrc -nnoremap sv :source $MYVIMRC - -" quickly edit your snippets -nnoremap es :vsplit:edit ~/.vim/bundle/vim-snippets/snippets/reason.snippets - - -" Auto resize window splits -autocmd VimResized * wincmd = - - -" Neomake Settings -autocmd! BufWritePost * Neomake - -" Elixir linting -let g:neomake_elixir_credo_maker = { - \ 'exe': 'mix', - \ 'args': ['credo', 'list', '%:p', '--format=oneline'], - \ 'errorformat': - \ '%W[F] %. %f:%l:%c %m,' . - \ '%W[F] %. %f:%l %m,' . - \ '%W[R] %. %f:%l:%c %m,' . - \ '%W[R] %. %f:%l %m,' . - \ '%I[C] %. %f:%l:%c %m,' . - \ '%I[C] %. %f:%l %m,' . - \ '%-Z%.%#' - \ } - - -let g:neomake_elixir_enabled_makers = ['mix', 'credo'] - -augroup my_error_signs - au! - autocmd ColorScheme * hi NeomakeErrorSign ctermfg=203 guifg=#ff5f5f - autocmd ColorScheme * hi NeomakeWarningSign ctermfg=209 guifg=#ffaf00 - autocmd ColorScheme * hi NeomakeInfoSign ctermfg=183 guifg=#dfafff - autocmd ColorScheme * hi NeomakeMessageSign ctermfg=27 guifg=#0087ff -augroup END - - -" templates -if has("autocmd") - autocmd BufNewFile *.c 0r ~/.config/nvim/templates/boilerplate.c - autocmd BufNewFile *.rs 0r ~/.config/nvim/templates/boilerplate.rs -endif - -let g:neomake_error_sign = { - \ 'text': '>>', - \ 'texthl': 'NeoMakeErrorSign', - \ } - -let g:neomake_warning_sign = { - \ 'text': '>>', - \ 'texthl': 'NeoMakeWarningSign', - \ } - -let g:neomake_info_sign = { - \ 'text': '>>', - \ 'texthl': 'NeoMakeInfoSign', - \ } - -let g:neomake_message_sign = { - \ 'text': '>>', - \ 'texthl': 'NeoMakeMessageSign', - \ } - -function! LocationPrevious() - try - lprev - catch /^Vim\%((\a\+)\)\=:E553/ - llast - endtry -endfunction - -function! LocationNext() - try - lnext - catch /^Vim\%((\a\+)\)\=:E553/ - lfirst - endtry -endfunction - -nnoremap [ :call LocationPrevious() -nnoremap ] :call LocationNext() - - -" Alchemist settings -let g:alchemist#elixir_erlang_src = '/usr/local/share/src' - - -" Airline Settings -" Enables the list of buffers. -let g:airline#extensions#tabline#enabled = 0 - -" Buffer numbers alongside files -let g:airline#extensions#tabline#buffer_nr_show = 0 - -" Shows the filename only. -let g:airline#extensions#tabline#fnamemod = ':t' - -" Allow glyphs in airline -let g:airline_powerline_fonts = 1 - -" Change Airline theme -let g:airline_theme = 'hybrid' - - -" Vim-Swoop Settings -" Edits colorscheme -let g:swoopHighlight = ["hi! link SwoopBufferLineHi Warning", "hi! link SwoopPatternHi Error"] - - -" Jump to buffers. -nmap :1b -nmap :2b -nmap :3b -nmap :4b -nmap :5b -nmap :6b -nmap :7b -nmap :8b -nmap :9b - - -" It's the twenty-first century...no swaps. -set noswapfile - - -" Allow visual tab completion in command mode -set wildmenu - - -" Show Vim commands as they're being input. -set showcmd - - -" Code folding -" set foldmethod=indent -" set foldnestmax=10 -" set nofoldenable -" set foldlevel=4 - - -" emulate ci" and ci' behavior -nnoremap ci( f(%ci( -nnoremap ci[ f[%ci[ - - -" extend functionality of & scrolling -nnoremap j -vnoremap j -nnoremap k -vnoremap k - - -" Opens all folds within the buffer -" nnoremap ZZ zR - -" Closes all folds within the buffer -" nnoremap zz zM - -" Opens all folds beneath the cursor -" NOTE: j is the character to go down -" nnoremap zJ zO - -" Opens single fold beneath the cursor -" NOTE: j is the character to go down -" nnoremap zj zo - -" Opens single fold beneath the cursor -" NOTE: k is the character to go down -" nnoremap zK zC - -" Opens single fold beneath the cursor -" NOTE: k is the character to go down -" nnoremap zk zc - - -" Save shortcut -nnoremap :w - - -" Switch to MRU'd buffer -nnoremap - - -" Alternative MRU to CtrlP MRU -nnoremap b :MRU - - -" Supports mouse interaction. -set mouse=a - - -" Highlights matches during a search. -set hlsearch - -" Clear highlight -noremap h :nohlsearch:echo - - -" backspace settings -set backspace=2 -set backspace=indent,eol,start - - -" Javascript specific variables -let g:javascript_plugin_jsdoc = 1 - -" GlobalListchars -set list -set listchars=tab:··,trail:·,nbsp:· - - -" Keeps everything concealed at all times. Even when cursor is on the word. -set conceallevel=1 -set concealcursor=nvic - - -" map jk to -inoremap jk - - -" Hybrid mode for Vim -inoremap I -inoremap A - -inoremap -inoremap - -inoremap -inoremap -inoremap -inoremap - -" temporarily disable in normal mode so it doesn't attempt to index all of -" Google3. -nnoremap :echo "You are attempting to index all of Google3. Aborting..." - -" tab maintenence -nnoremap :tabnew -nnoremap :tabclose -nnoremap :tabnext -nnoremap :tabprevious - -" Manage Vertical and Horizontal splits -nnoremap sl :vsl -nnoremap sh :vs -nnoremap sj :spj -nnoremap sk :sp - - -" Delete (i.e. "close") the currently opened buffer -" TODO: unless it's a split window, which should be :q -nnoremap q :bdelete - - -" Set CtrlP runtime path -set runtimepath^=~/.vim/bundle/ctrlp.vim - - -" Pane movement -let g:tmux_navigator_no_mappings = 1 - -nnoremap :TmuxNavigateLeft -nnoremap :TmuxNavigateDown -nnoremap :TmuxNavigateUp -nnoremap :TmuxNavigateRight -nnoremap :q - -" make Y do what is intuitive given: -" D: deletes until EOL -" C: changes until EOL -" Y: (should) yank until EOL -nnoremap Y y$ - - -" scrolling and maintaing mouse position -" nnoremap j -" nnoremap k - - -" remap redo key that is eclipsed by `rotate` currently -nnoremap U :redo - - -" Define highlighting groups -" NOTE: The ANSII aliases for colors will change when iTerm2 settings are -" changed. -highlight InterestingWord1 ctermbg=Magenta ctermfg=Black -highlight InterestingWord2 ctermbg=Blue ctermfg=Black - -" h1 highlighting -nnoremap 1 :execute '2match InterestingWord1 /\<\>/' -nnoremap x1 :execute '2match none' -vnoremap 1 :execute '2match InterestingWord1 /\<\>/' - -" h2 highlighting -nnoremap 2 :execute '3match InterestingWord2 /\<\>/' -nnoremap x2 :execute '3match none' - -"clear all highlighted groups -nnoremap xx :execute '2match none' :execute '3match none' hh - - -" pasteboard copy & paste -set clipboard+=unnamedplus - - -" Manage 80 char line limits -highlight OverLength1 ctermbg=Magenta ctermfg=Black -highlight OverLength2 ctermbg=LightMagenta ctermfg=Black -highlight OverLength3 ctermbg=White ctermfg=Black -" match OverLength3 /\%81v.\+/ -match OverLength2 /\%91v.\+/ -" match OverLength3 /\%101v.\+/ - -nnoremap w :w - - -" Resize split to 10,20,...,100 chars -" Uncomment the next lines for support at those sizes. -" These bindings interfere with the highlight groups, however. -" Increases the width of a vertical split. -" nnoremap 1 :vertical resize 10 -" nnoremap 2 :vertical resize 20 -nnoremap 3 :vertical resize 30 -nnoremap 4 :vertical resize 40 -nnoremap 5 :vertical resize 50 -nnoremap 6 :vertical resize 60 -nnoremap 7 :vertical resize 70 -nnoremap 8 :vertical resize 80 -nnoremap 9 :vertical resize 90 -nnoremap 0 :vertical resize 100 - - -" Increases the height of a horizontal split. -nnoremap v1 :resize 5 -nnoremap v2 :resize 10 -nnoremap v3 :resize 15 -nnoremap v4 :resize 20 -nnoremap v5 :resize 25 -nnoremap v6 :resize 30 -nnoremap v7 :resize 35 -nnoremap v8 :resize 40 -nnoremap v9 :resize 45 -nnoremap v0 :resize 50 - - -" BOL and EOL -nnoremap H ^ -vnoremap H ^ -nnoremap L $ -vnoremap L $ - - -" Search for visually selected text -vnoremap // y/"N - - -" trim trailing whitespace on save -" Are there any file type where I wouldn't want this? -autocmd BufWritePre *.{js,py,tpl,less,html,ex,exs,txt,hs,java,rs,ml} :%s/\s\+$//e - - -" Use .gitignore file to populate Ctrl-P -let g:ctrlp_user_command = ['.git', 'cd %s && git ls-files . -co --exclude-standard', 'find %s -type f'] - - -" Ignores dirs and files -let g:ctrlp_custom_ignore = { - \ 'dir': 'node_modules', - \ 'file': '\v\.(exe|dll|png|jpg|jpeg)$' -\} - - -" WIP: Run elixir tests on that line -" TODO: only register binding in *.exs? file extensions -nnoremap t :call ExTestToggle() - - -" Jumps from an Elixir module file to an Elixir test file. -fun! ExTestToggle() - if expand('%:e') == "ex" - - let test_file_name = expand('%:t:r') . "_test.exs" - let test_file_dir = substitute(expand('%:p:h'), "/lib/", "/test/", "") - let full_test_path = join([test_file_dir, test_file_name], "/") - - e `=full_test_path` - - elseif match(expand('%:t'), "_test.exs") != -1 - - let test_file_name = expand('%:t:r') - let offset_amt = strlen(test_file_name) - strlen("_test") - let module_file_name = strpart(test_file_name, 0, offset_amt) . ".ex" - let module_file_dir = substitute(expand('%:p:h'), "/test/", "/lib/", "") - let full_module_path = join([module_file_dir, module_file_name], "/") - - e `=full_module_path` - - endif -endfun - - -" Creates intermediate directories and file to match current buffer's filepath -fun! CreateNonExistingDirsAndFile() - ! echo "Creating directory..." && mkdir -p %:p:h && echo "Created directory." && echo "Creating file..." && touch %:t:p && echo "Created file." - - " Write the buffer to the recently created file. - w -endfun diff --git a/users/wpcarro/configs/.config/nvim/templates/boilerplate.c b/users/wpcarro/configs/.config/nvim/templates/boilerplate.c deleted file mode 100644 index 949743d72..000000000 --- a/users/wpcarro/configs/.config/nvim/templates/boilerplate.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main() { - printf("Hello, world!"); - return 0; -} diff --git a/users/wpcarro/configs/.config/nvim/templates/boilerplate.rs b/users/wpcarro/configs/.config/nvim/templates/boilerplate.rs deleted file mode 100644 index c83adbc69..000000000 --- a/users/wpcarro/configs/.config/nvim/templates/boilerplate.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - // The statements here will be executed when the compiled binary is called. - - println!("Hello, world!"); -} diff --git a/users/wpcarro/configs/.config/systemd/user/clipmenud.service b/users/wpcarro/configs/.config/systemd/user/clipmenud.service deleted file mode 100644 index fac317f3f..000000000 --- a/users/wpcarro/configs/.config/systemd/user/clipmenud.service +++ /dev/null @@ -1,18 +0,0 @@ -[Unit] -Description=Clipmenu daemon - -[Service] -ExecStart=clipmenud -Restart=always -RestartSec=500ms -Environment=DISPLAY=:0 - -MemoryDenyWriteExecute=yes -NoNewPrivileges=yes -ProtectControlGroups=yes -ProtectKernelTunables=yes -RestrictAddressFamilies= -RestrictRealtime=yes - -[Install] -WantedBy=default.target diff --git a/users/wpcarro/configs/.config/systemd/user/default.target.wants/clipmenud.service b/users/wpcarro/configs/.config/systemd/user/default.target.wants/clipmenud.service deleted file mode 120000 index 387f2023d..000000000 --- a/users/wpcarro/configs/.config/systemd/user/default.target.wants/clipmenud.service +++ /dev/null @@ -1 +0,0 @@ -/usr/local/google/home/wpcarro/.config/systemd/user/clipmenud.service \ No newline at end of file diff --git a/users/wpcarro/configs/.config/systemd/user/lieer-google.service b/users/wpcarro/configs/.config/systemd/user/lieer-google.service deleted file mode 100644 index 2f79ed6cc..000000000 --- a/users/wpcarro/configs/.config/systemd/user/lieer-google.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Lieer sync for account 'google' - -[Service] -Type=oneshot -ExecStart=/nix/store/n6c4pr4fyrsjfksspkapb7yqc6fzl166-corp-lieer/bin/gmi sync -WorkingDirectory=%h/mail/account.google diff --git a/users/wpcarro/configs/.config/systemd/user/lieer-google.timer b/users/wpcarro/configs/.config/systemd/user/lieer-google.timer deleted file mode 100644 index a073da25e..000000000 --- a/users/wpcarro/configs/.config/systemd/user/lieer-google.timer +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Run lieer sync for account 'google' - -[Timer] -OnActiveSec=1 -OnUnitActiveSec=120 - -[Install] -WantedBy=timers.target diff --git a/users/wpcarro/configs/.config/systemd/user/timers.target.wants/lieer-google.timer b/users/wpcarro/configs/.config/systemd/user/timers.target.wants/lieer-google.timer deleted file mode 120000 index e9f2cab3b..000000000 --- a/users/wpcarro/configs/.config/systemd/user/timers.target.wants/lieer-google.timer +++ /dev/null @@ -1 +0,0 @@ -/usr/local/google/home/wpcarro/.config/systemd/user/lieer-google.timer \ No newline at end of file diff --git a/users/wpcarro/configs/.gnupg/crls.d/DIR.txt b/users/wpcarro/configs/.gnupg/crls.d/DIR.txt deleted file mode 100644 index 2a29a47b8..000000000 --- a/users/wpcarro/configs/.gnupg/crls.d/DIR.txt +++ /dev/null @@ -1 +0,0 @@ -v:1: diff --git a/users/wpcarro/configs/.gnupg/exported/ownertrust.txt b/users/wpcarro/configs/.gnupg/exported/ownertrust.txt deleted file mode 100644 index 79b727914..000000000 --- a/users/wpcarro/configs/.gnupg/exported/ownertrust.txt +++ /dev/null @@ -1,3 +0,0 @@ -# List of assigned trustvalues, created Mon 29 Jul 2019 15:01:24 BST -# (Use "gpg --import-ownertrust" to restore them) -7E87921AAC9C514E9341C4F1C7A53CC58D3B1F8C:6: diff --git a/users/wpcarro/configs/.gnupg/exported/public.asc b/users/wpcarro/configs/.gnupg/exported/public.asc deleted file mode 100644 index 8b5547f4c..000000000 --- a/users/wpcarro/configs/.gnupg/exported/public.asc +++ /dev/null @@ -1,225 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -mQINBFk52cEBEADW2uF8AjpGxbd/yrtCguVzl7fWCCo/vZYGTomoHy7K3ru7bQEN -upIBj1ElcsLGxbNLqdEqb17blTOUpaLLxWhEUw38rTpRyepBH0y2u5INDiw9GlpU -uXKnkvaAF2f7DJH24jQA2mLI5Jcgc2M0Kzmuh1Q1foAy3frORBnYlrd9TlSPU7Og -Jj0T20jtZIsIORov2TFC2cEpwa+9jHkNaBK2Bdg5c0SyI2r3TSJq+L7X8Vkf3Hmb -NEWJj286+ElcFP/FyVgRCtSJPjBg/MF0ucukm96cel5qYfK5RkMA/HCyv6xI8iNn -eZj8sJnozDY4rMxFwNkTxIjwH9cCTW0CR9FMsc1wlIe6Zx0ic8Fu7PZCS5MjM8cQ -LnruOunVnb0YodQ+cLde6FlKu7kNUlLJrH5NnuFxjWPxzC63u+/K6CcRV9ilWe5r -so/ImtNfGO1JiCvisYeOqlTYBKceQgjvu5tZtLJoGxH0UzoJARLCLRwyHN8dGqgp -STRd0Ze6LtzYLG0uuedyPNXDKci7GyrVdAmxVIo+eLA1a7n3YCcluGKZlM0IBWx8 -fTKJ16ASTXpK7Hqr3XSf5V7tUcwxiFFtxh5C7kXglyd4QI6Jk6Xp8HlPLvYXNSNj -VYRMHi/ueFI92jlt3kCodD26btgIEfD3e3JxKfHhOtwSoA2i1Hr43qdvtQARAQAB -tCNXaWxsaWFtIENhcnJvbGwgPHdwY2Fycm9AZ21haWwuY29tPokCVAQTAQgAPhYh -BH6HkhqsnFFOk0HE8celPMWNOx+MBQJZOdnBAhsDBQkJZgGABQsJCAcCBhUICQoL -AgQWAgMBAh4BAheAAAoJEMelPMWNOx+MGm8P/RYqv5mnneRbyJ6CgisYn2iIBQvz -+rmpdGDfkFqsd2YqDoGjzEJLVkan+I1oLnKSv5QJqPw1gG7fSv6X7Trov9J+Cma3 -h1bSn2BBiq8L9paWTILYmsrBe7kU9bQjNKFu0qjfvPqkGX6HXO6c81N00Qgie574 -MCByWgPtJTcbPLJodIxu6+aibwNBc3XInL/d0ZbXLs8Fc0+z2/dO7cmzAdE77d5Q -QaG9fGyztiYlZoUS9g3xT4ZulpPqs9zFa04fPvOXWVl+RQjZOYVYW/T8aVRnXohz -3y7tnxOWs8cmCFd91DDR099DZXstAesWllPsdSld18aMjeM2XrzuaWVDYktaraiY -RUdz6ZRPcaCpsIA2RHn++xEg+3q6QRz1J4bsbqEOKys+KlQO9uIgPMIkiMaLFoe5 -nu63XI4EMezrti86ETUxFPFL107P9KZ0gitjUXP0KSbnGQ7jt5FmuZgSAkbCSlis -Ulm8PZ/cmKj9OZysezDKkXFGtyskAELkpToIy48GtyEVIMk+CXcgNydUXDiLnWI8 -VwgmR1Q+hClLYMPvrk7OR6zK8txXsglJItCRUF5fmAn4Q7loh6i/BCfQpHdylO7G -nn7BOEJ0CJ8Hrr4Y785dtswAX8hWMIuzS4mxAHCjqkkfsOObBfLi+XpkZ6lDkfrQ -jAt2KuAjQR58dHDSiQEzBBABCAAdFiEEDxGpiYeei7v9weI2RO9bXoYcCacFAlmu -vnAACgkQRO9bXoYcCacQ4AgAmjDO+8Sd8d+cezwIjZgq1nPPb+/K0KTGsALe7jdF -MDOKwwPKd75mKbAVyJRu8CMEfgFW04YKbkeVp9bLeD2lpMYsIgpNYy5bU6DNCgi5 -QO501sTqeaWc/rlm7Ng5AlF8GIK6FagrPS31eUexxJ62VFozi3EiibKYepgeIUHR -3ukw6+PWBkvOYSQjZ0Uc08nci8UsewDQaQvuDABR+6WbLDYX6PuyUEzV7MPbyzME -QOvGuYpgcAq5gGB6NNe9zFQK0xAQob1UhDlaa1p8VSZyH/RLnyYCdlq0Bmf95PNq -eE8YkmqFCPKNoWwzOa6pJOk/Y2mXhJm/eD4Avmlo122LN4kCMwQQAQgAHRYhBBP5 -Ly1Y78tmaShOtNywW0z4mvxmBQJZvs4vAAoJENywW0z4mvxmIAoQAMM6QLexK9fK -88EZxYC6x+qYkb3rzjaGyO3dzGhfRQTFJ8HtFrWTR5s/m+1ACKFnbf1xo7AWbsYq -jVIxXsqUt9a4jserpaczlzDQLojFCKSGFmfCVV40FwQHL3W+C40xLHLOq93bpHLD -knp38daRzSryW11ev9y0J3to0qX03WpgFKKwT3fQMT5+V4wZNuzOFmWGaPUsuCQh -SQj5VU+p9Q4soIIzu2gaal4vW3/qZgIlkAmkg0FV5iW7mwScWPcF/kPlkHFMj9pG -aTNVgegxtUQBJEXx+VF0vDiOtRnBjE2woVLq1FWGkn7feX4Jvnajqpf6A8dKeNcv -Egfm00HHhhR5f7LTOYTSXWCqhCmIBKGpYlZo/PDGHdlVoRSR5+qN/1kyP7WZg35u -+7XR0paCTR71RwO+oHZHiv97u6P/iPvVWE7aqCJe6kBW6Q8hB4zjLfH6AbjcIN/9 -Vy0k3ALBfNxatkJZAyl/PQpgSpfpAkbk5upBPvOKVGCWsYA5sYRH4MMiwrOuSgCh -nibnUT4jJjgU7hK7iOTJB1mbNEvyMSksgxtbdA4XWee4iv5qS3ZCX+1RUspZk3IS -8NePnaycg+OlI5gMbSEVEmLCat2V3l5KNZRFWpbmNTCo+Mi4t1i8kgJAHRtn0r6t -sIS9beklhQz1p7KZAphYWjl6kO9p80cnuQINBFk52cEBEAC8e3b6SN4t5I/RRmRt -/YbPFyC81yElaPzBM+OFsbRDr9MrtfeDUp/wgcihQIw01HUDlm4F2WjbGwth/8Zs -tEML3CFwtv4V+sYhKqfg+sS5YqzFrFWfZYod8ppFKNMaw9Pcjl70td2egcBDt1SR -51ni4SdhyMt/KOm4mym/Lf4UNyzlYwykbjtb3nsmvxYI/uVdceDv+7vZoW1rapSw -Zj4ZS8+jhgHrO2p5B5TCHdsDJEYQ2SOYeIm8tfqb4oQlTWwjG0frl5eOp/+9HfK1 -q7R049FMAzmd6fbm0jpzxDveDe58qWWq2aj+7HwTZhmvr9l7uFyR+3TL6s9hEALl -B3RGpOy5hGmvwLIAi4qylZuRJzW0tMveDcaDEdMhtyEKF9DYpk1Ug/01uG+PzK8e -TiFyTCN6OAawWIe7pIxRhlk4+CIqRPEprMTfDJxKEUS7RnUYZ76E94FSV9nEqIJj -UWFLq3aTMqSiSN5LAgT6AJKHrR2+cJVHM1cEILvCIugeuw1GUC+Bxs1qaxIpp4SS -xi9Givx8PkKuCukp1J4B8Alx0ZpRELsBEuhZdEN2LP+Hpz7uyD875r8BvEJ+hU20 -Qfnj2wHmKVF+6jBPwrpzZ/gbXuQzfstmrSJCY6p6izfcQSJmbSNpaTsrOvgmaUev -Wuss4bjuG4loSRwFb/7fsPsX9wARAQABiQI8BBgBCAAmFiEEfoeSGqycUU6TQcTx -x6U8xY07H4wFAlk52cECGwwFCQlmAYAACgkQx6U8xY07H4xvTg/+MbWyGFmLe9b8 -AMJtqwX+3EyP44Mo2CeafvmbPSqxoXh1NdOezlEESZU9fHMDY50IA2hpariO/Le3 -Ck8py5NAznCc4avS+gnahcPyhvUaMCskmN4UaRsohMvxKrdAGyRfXZcQqE5Tu6zM -6TxycQkT00qe+PTSQnV2dvGXE4iBFV5kj3NHV7RBC+7sDZ7cYuLHrw1gOaMWeCcF -oQ0l+DW3CNh3klFds/PIfPALjV25+niwOYcenxqp8GVjooWj7xkASkFyZAqusFTa -+/XY2y7+jvdSmm36gfWiPXWdpPiesekPK1NqPGdAtyv1/EKJd+7cYCbkSH6qPJpb -FnpfK/ItVm39OIe7OVUuZYd4lGeFvKK/nDqSQ+9STVar2+n8Wths4C8KJbLdZxGE -QYWKw5aL09tpQRy/skReAt9hVDq3qflODyuWPqS/oDbSGERA2NndkV3LIkU+ZCXI -xsin4IP8XzC8yJjv11PAzM8wmhlXWOdKDIZXMV/2wO+cyM/t9WtfeXUOuk2NyWO4 -nQ+gD3cDPTJS+t8ReKb/bEXSeHiRfgiYuZXcwT5vGmx4HiYgJ7d9i+8Ikcew75zw -EvR+OLXYVICsI9PiQPzqVBfp+2u5saEvmWORrNLLUBQt24R2CF4Y63pLumsCB3gv -n+cUG+sEsct2sSKhQEEU7Yra9tppHlO5Ag0EWT7OXAEQANUBV3/GFcAtsM9XiSGL -GuWs+S8np+A7WRIISsR5BU22u9XqF7P8/5o/ZJIvoNu9EwTkFZYP9pAxx7F+I/62 -x8YbXCU5byiOG0X/RKRafW1j9zJdZHK2jdga2pRUiCexpk43knTMyYUxyNlOFM+r -UKJlMErTaN8PJldD9f7qq+assxFN+rLW+tWwxtcL9WxdCIBBMKE7ldyaIRzKNMbZ -b+mckdP412Ht05sn2BijgHj/co07M0zw+MLWNc9c50wI+/CYBZXerDp7TZoB2HxD -JH9FqQ+ypjZQkNArieMj8IB6o8nZRbOqs+FO3LJf4A2WuHSLb187LpTLGoL/WaGG -YK5ZE/0DuR7lSZmVYt2qaKqzDUJbbETLNJlhEykKI0f4bkhjI9UPjxlFgarDuFOe -V7KkZXJoapda6lwy+W8GDAcrtMasMIgN5lMQdYJllIOJVs0wTJyMbLFN1hcr8oGc -09tLEPr0FO5lxygMHqcNiia1SO34IJF6HaRHZQeX6Hv2M+FHWpZ3fcu9dkY9i9JK -RM0W3x0OLFBNfCAvBVFxat9xmYYJuRqomPAFIlt3hik/Dl3dWOkPLdVoE97T/r1/ -5DDNBpaO/g7XU24bH6ja9/WO8T9g0L4nTLCtdKSaGFxwT0No7jmgTJxJQan7hHDZ -+0CHj8jCUsMNSK587HTWiZFZABEBAAGJBHIEGAEIACYWIQR+h5IarJxRTpNBxPHH -pTzFjTsfjAUCWT7OXAIbAgUJCWYBgAJACRDHpTzFjTsfjMF0IAQZAQgAHRYhBOpX -PxAcncyJjCSg9h7cm2rmkT65BQJZPs5cAAoJEB7cm2rmkT65H2sQAMlGuoA6pKlA -W9L+Mdn3aHaGHzxiLU0mxJZHLPxLru9YNkEF2uDiSzHRMSSbJCujF8O2Z8jg08f2 -+r/ZVHK1wWd/J7zikh/1pMVj9KVNG0JdyqiHuQ02i5vWdBg6lZZku4uUvU616Ynh -PMDVoEQ6QXQ24BhrSBH9B1tgSnIRc9EHzzW5lTF3+qttA1tJETJODzEZGmSlBene -kUxBZVuH7daEa1pRPGNVSa4TmCTkxgYZUIdnIDC7CeDREldAftCvEll37Ewy8QTi -goAPYYZQd9jJ7ywq1qWFiTt6n6IYvjfVm2ttO/3PBtla5FdCW3U0MZyxOiIIpHjh -IgVFWknvOEsKQhaN4rbq7YSMLLZW5Y0ukHk8c3OsRpO5Clc/yl0hHURGtjhvHgSg -kL8z80WhnP+XiMa/vaWIsats1/LGc+uvstmohI4np9+jF/6Byk9Y85ki1ilQszVP -/JEIj2IvH6/OsjcXlgAs8In7EBeixlERLneK9F0D+rb99m21rhkXmy/EQ75yeSV/ -z7sy9suK3SuULqYSuTKuw+mbAY3KOF3JLjQdW1NXCZhqRaxYF+5nMq1f6VDwGcpO -pPSF+9fY6/R5/cyEk8LOY4kS9O9rqc4PIi1ieYoyxezTBdX1aWpZEsAzVDWuJRCd -pwaKM8YF7ofZxEo5QAnfOO/gc1opPVIUMzAP/2md27adc9Qn0AkWf4Gbr5HSbArq -urGjqUa8HCUcishzW/TrWbDtuy0ZplvWv4z1KgqoAAr+U2rZwck8mk02UCmjpaDL -KliTiBAuRei6wgW0y7rLE0S1q9wjoJZemhVrI5C0hu7jIPzl1r/ZRNEqcKtsl6UG -+2zlo0loGiLt+G+p5KpcwuscYGEU0Ekasu+68sual5UUdRXpu8J9ePnqSIZUHanj -mrARW5iv17NGG3ZtGeX+rDZ2G23Ymnc/IOK1Qeyz07GE3OcxaikTk4EvNDJcl33E -uI7Dcauz+1msBxGwkib/BUx686ZI8e3Qa9cxzmzGBAwJGqtuOv0BrKbmT6dJ1FG2 -XtRCKsYDGttvoEM8fnhAeVXLIEidiMg3ri8cE/uhIKQlTCoel/hr6yM0BztxQRIk -PIkFDGSpOq6pknv0KgAxhymJlHmC002e3FAl+B+q71FUthwjs7h110CrI6yZTwbC -La9FZEODAFWkWLghV3iLP0D8HD+rsBxDttpJOC0lndsONIMkb2Xf4ue8pceUehEN -zf+mkS6B5ilfHOhrcY3vkfV/cuF2Zv1kBpjayCbanweeyEIok720eP4RoTu8NJGZ -gD0qLo2iJBW65FRr557CWET+X22k2vDO92PeB6MXdZ+PGNgPWw+SZfY5nUN6hsbm -73dNlPTad6zfMtHRuQINBFk+zuMBEADd0yUpELWiFKezO/GLaqBs5iI5fRvO97pk -5yhROIjaM4xz2tmZMvenO9AdVSchgh6w1CCNMvhbE9MkEakh8qN5hWl0XeN+UarF -XvIx1ARfzmI+Xwz40wNRNHkGMwZipvHQ0oFW2NI+qQaxu1QzX7eGIF1uQPhyw5wg -dQeO3fbAKR7G1YNOiBM5KyEPSFj29fSyPVjhqM5orHyrD3rtHir+978hA0W4yFY3 -0lY7OqaHs2crU4txy30bc2oYL93J5uMDeXmDg+K7NEGeih1vJnh3lF73yh3i6d+t -MxrMyzkhLf8GBD+38QqJ4npkcd4E66g0kB3Q1EYfh4R2eMkYCCcTuRuQVrtIyC81 -r490Kx3WFB2ioIOARk/0NUrnqO0tze4KuLKc4wVpKFCeRkBpN5ZxoF+NJ2DLodg8 -w5G5xkMluLpcUWU+D/LEf52Nu8JBro4BVOv8h+D3MwC8icaQaL4xTVqCBtOvhA3/ -0gxrEJ98g5jpR/Puspa/zQVpY2MP632m6Ctfw6mdHtcq3PKX2sJIF8UKLGhJsAYg -9bUSD4ka+IV1BLXY71b2DFZoTA9WaprG4GDTV4x3PcERq1/LSUBIKl9kHw9DvGzW -uBcQQOwUR564ghGPt4Lxq8fc5G03h2Oou6LZx1lfYHuwQs8iJtiX6EtkVhZxxQX5 -TClQMdVgEwARAQABiQI8BBgBCAAmFiEEfoeSGqycUU6TQcTxx6U8xY07H4wFAlk+ -zuMCGwwFCQlmAYAACgkQx6U8xY07H4yNohAApKlliONc+s6PMtwAOJ3j3NzOCPDy -MOiA24kKHMg4yCUiJDJ+xX2tQs6Jf99IcCIF625nnsUqyRDgdHyDeu4ZTneo1aFB -YMf4fgxqUkEiV7VNxvw2idDfW2Wy0fmyGCdS8UOw9UOjSMURNjfvY/pQlFNG+cWx -ZUfrU2HgXzdAchTlYQnpPwaDaMQE7xsV/Q+VVtWNe9gAuycrGNgPhh4zNAmjqiGN -a+YS0vW4v+TSaA7Y/jMTEJYEz9+60dYy4I64Wv1NWODT03KExQoINrROLwhn/wD8 -AZhyJKBNuAbSZpMXNMD+2QKtqeNxE7HbTQY7Bqx5feBvDkDgr7ox+KyzR3NuXOHQ -CSbmSEQPN3miiGglHGASctp3Fd93PhXzVtiiRAnqfBw7zGDSgdpaNC8z9DAG6iUY -ZtcNz5UoiCHSOqE1vxV38poWDtZLkKuQRXvXy/uNyPcPx2efaDNf/FxH3gM6L7+6 -gfJ9vDMKUI9Xa9A5u3BMR/1Xiehx/GL7kZ16fZDWhJH1iCUcPwu/wSPDCmzGaX3B -O/FT+H1m/Fql8oKWOy82K1zBVMx7cx+b+3/Qlkbx3wGPGtNLPH1m5QFKoPV7z2zP -tM9VziUSLPPlIEbsT3I4lXYdhFsHbGBk++ZbY9kRUTXkNRciqX2NFcFtNSo9RH8F -KOmVBBI+ZQ28HDGJAh8EKAEIAAkFAlm/5kACHQMACgkQx6U8xY07H4yS/xAAiHYW -T+wgYgFR0e0DYNOlz3KeYZwhORc5/ED07qCxUMFkChpBnXbKLzGViiKK3H9FyaFy -fOhuIqb0GgXX4TTYdHShvceBtMfTfeYMLXQC+WaJgIydbjRK978mDBgIDs96ylEj -ErtgP3J/GXTk616nv9VYYjGGNKQVJNxDGCRzfZks3m/gWH/whbctFQXaBOshstra -nGpoR6EEZERpDkDMdLqd1JEhCPK8YUSPwT0LKm2yQpeR3ly5phZiJC7uZVmq518P -f8UoHYhtb6P18kJeMVbrNpEzDTdGCZ6eKC3B+1tfoft8MXF3fEINFzZKqAXKqsHD -sQtVWPshg49J8HNpc0NbQi90+8ph4oVrWDHoDulhGg9xUTlY1fXUye1uDXhVn8gL -rAeLqz6WP2i7jPnNCJgTXw5+e2kAye0rCvKH0pw8a1Aq2iaxvxr0L1MzAgtKaTh/ -AU3K5j8r7YRUdOMUHMGS5CwwdhwNkABM2Sm7FmlZL/BNwmgxekhJSivLL3M6qPY3 -LjcxxJBfe4gk9RRX9/YCgSkKTwvx1Ko9368G4WcxYOSTP3eVol6o0yBqd0rV/P+l -CCgiAZ/ZoVOvi5jmTy2I9flafPzGp51EdH+RS/rGwW1feP5JMg+NULwc1y4kTru6 -pkHTUu3Ol+M2616HU32p8XJi4mDV5qMRWmLn+UCZAQ0EVKyAeQEIALyGS95q8aCp -8rjM35kpabNOhr9hAcdq0DrxwjOWZd5u569X1sS81VjPqoj1jpA+/GgheWeYrNxm -RbMT1fdtd22W5yiNd5TNXF+RMhZYvnT4Mxm3NNggZoriHsnrG4XbtLZZmMTXwF/6 -a/CsaCXYHp4J3YvYnDc/B0fssj37OXQH0SjpBQnU7U1m7mvLXfm7Mh+zi7VTSz45 -WcFyr7Lg1HRN6OzDtbBjn8kuWWMzYIlg+EUZPuHLHoCkjhN6g7AM5eDhQqXvzOcy -lSIk/TIPy7n8EeKrrgfijGQOJF6c6d5n0Hq+6lejT6uL3iHUOKtv8PYGr8vF01ao -vP/EOVTkYQEAEQEAAbQrR3JpZmZpbiBTbWl0aCA8Z3NtaXRoQHNlY3VyaXR5c2Nv -cmVjYXJkLmlvPokBNwQTAQgAIQUCWCuGZQIbAwULCQgHAgYVCAkKCwIEFgIDAQIe -AQIXgAAKCRBE71tehhwJp2lCCACiTsLoGbq44A11+k24oWItbJTrg5pISwKUwfwt -hvik0oQPWfQoz/sr0w/Ie0rUnCuSyOVUXuJZSgzFOjEcwmw1dDv0hsanyt+NZ3SC -r/hSasAOMIeXS7+hyL894E6NKIGDi25+Yhpj1AFneCu9cOoxlEXqynVaiBJbpHIw -atwB5i7ZvUz+krTBjf6wwgLzBi1EHw7IJYhgS1Ye9A/+h+iur7d/4/C6cC31IgBd -r8d8iNbMhqyk66+fhdZ5Vd2QO4DUq4CUgFoakO9X383Jf8azR0zXIPPphJ2QpQzD -sfriUT0J18bP546tknwOsNYlt1XPYwlLvXKljXr1YkRyTdPTtCdHcmlmZmluIFNt -aXRoIDx3aWxkZ3JpZmZpbjQ1QGdtYWlsLmNvbT6JATcEEwEIACEFAlSsgHkCGwMF -CwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQRO9bXoYcCaed+Qf+JSDZ3odMwlnr -bb2kwslduAt9VhRm+dfdIm25nAgxJUxIju8uIgE9v+8dRdGFwrV8pKBYYOCMi8MF -NYuu9zS66wXS4opd/DeYDj2yaN0wBYEfeXMCwVLVDHU7AHrsxQWRSxbcUOi2Mm2s -ig70ZSq2iNicX2f6eUSr/4CjocTP6jOqcHd6Di4odEy/hK6ukCCW8ia1Uujh7JYC -U7quHnuE1N184W2Jf6hUieFC2kE+Nmhix0LsYYe6c1InembHRZ85BpOsWWuE9cS6 -IuVO/jbNZcgS7NkuCHkG7CubPnSZX/EDwmyr9Pd57tr9BANuDNvTGgcbaXhJj5nl -Ix/usDsrRLQxR3JpZmZpbiBTbWl0aCAoS2V5YmFzZSkgPGdsaXR0ZXJzaGFya0Br -ZXliYXNlLmlvPokBNwQTAQgAIQUCWCuHlgIbAwULCQgHAgYVCAkKCwIEFgIDAQIe -AQIXgAAKCRBE71tehhwJpxWTB/0ehZJ1Bjkf7AvtWYn7PEwr1y9aAWHLhAxNNXOE -M5IhXjnpL5o3Pic8DonUrzDVxRsNxaGU8jvAvbQpWgtQXJFi0qgDxS6b1hf5CSlS -kcjqtkcMMqyi7XAydSyCXr5s0sZ2ZBn0tri0AKN7JW4Wd0aXJrP/RmmXNeTTARI/ -LGy5Em/PBFogDPTHRWwJQ5uCaddwev3pcOzNvrSvR0m1JXG+ZtP/Z+c4QQA3YGdT -TSxanK2w9NXTQVToJKO8Lig3ivYNgpbscE0ywrbXVfu3pzB1+9uTa3zd9MmQ0QL9 -mX3RiJeExNE+Vxj5jG+kE8GhcRxXKefXkg+UweaYfkcX8vEEuQENBFSsgHkBCADI -E/6vQg1OW9aGffzp3atrHtCjEHU6ZONE6unlez4CGHZXIZYTAbA0Nmgd3d3JA7wd -d0p48whI/tREFHlBD4lxQBN3wrpmDFVq0OiSLuMSAZaTXrX5ctY4CiHJVOIJUK16 -6zsoQFqvTBW7hYTsmFml1frOZrnyeYD9Hyj1Kkk1kaUkf+JrtnZzcftqD0hFzYHe -645YsLS2ub/ZoXrlV1hznDdIH64TYwlvabvBcZR6Exn6+hByMSbem1nNqB4PN2GV -/dO2OrkolThctGaxVoChDoauA+vfUQRWbpxzMJQHAJ3/PtKMKyMjv0+TTSIO1zsp -i2mayI7XUyXLu5fcTfQxABEBAAGJAR8EGAEIAAkFAlSsgHkCGwwACgkQRO9bXoYc -Cae2+Qf/QWJ+sVhFHNHUjPWSL1o+dSUMIv6qseCGyojGLZxAl9z6IKUng638XMrV -kgAy1aoy91N+HY0IPg45huTvU36uFoD2Hr9dd+ZVftO38jfviiowqu+iPt16sfZq -f9VUTDTJpsLzoxiwq+x5FbJYt2iqDqK30JyQD2EMn5Li0qtR1ohunxR2CE5byNRA -1ymk1BKMDb0tDHl87fCY5+bHZBrG0svqyDsxxK0T4bqRl0gSUfhVA67xcL1C7wG1 -MmtNZM+Ks9AepFlxmRDJnX0XNdaw7P6QtK4igLw5hSiFpVYmdfEyL9W0yn4No4Pj -rJnQvrCvIJqJ+1ANxY9H9ArCl3iF/5kCDQRZvrPlARAA1DjXoVu6jU9Rfojm7iFu -XJm2Suq7W3v4HjsycExn3ZBh2Lh5Jc7EdncPbP3UWnNBI5MlerHS5VMfC1OFzG/Z -IRXZyWIVOu1ajRH39i/8pIxOfcCQ1Y4msN0QntL79Z1qAtOdUGqppViiywgTA7XC -yGU8lvVEx7TlgXdmviRSI2Mm2McbeD/YLdTgqD8+8J00sIW5DUk1n/gUkyU2z4mk -4rwvGLJR2bGv1KIndZzfg7c+fNd2UsXjcJV8+eMRJCjE+xlrviBnJHnrNj75Ps9v -xX4WDX2PQZycS4NEictsFOmWmyiAHWcW8ZOrqsrDbd2QGUxjKrh6kdrZvVhCogsO -StwdVm39TfBykLt3K5jdhU5QK4AyNBbVoikoBtZFyVg2G6e0vbVAYF5NDoy+uDyM -jK9cHeJfMHRPCW+rBkaNh4+i0uj97SML9F1G1s3+dlPSNIofvJvZ69VxJi5w0OCT -vwdgmR/na7DQTBikZK+F0hoZRJAmKgxh0yUMzExYUq9rvdgNeEyIWs3nh6GVPs15 -iZfcRITiGFZsi/BWeSH/ce96qYG+c5UkN1QOvFqMZdneF/uUfUI/qOc3KGmhjW+f -lcO/qqtROO3UisckjvUZL1/80YQISMn96iJpG8mOUrDHiHndSMwErMyyxz3XXYzQ -ys7W2oihWL5iKU+SHmisNA0AEQEAAbQqSnVzdGluIERlTWFyaXMgKGh0dHA0MDIp -IDxqdXN0aW5AZGVtYXIuaXM+iQI+BBMBAgAoBQJZvrPlAhsDBQkDwmcABgsJCAcD -AgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDcsFtM+Jr8ZiuBD/9dOkCFWDZWAj1LKBc6 -nKci16H8tazePpvjYeZFxJw2w5NEGgwg1iGsdhKm60EOA8Okh8cEmmfq+AriFPEH -nAbnSePGNeXTRFy7njaApxnRQGaVTV+++B/J/zQTA+2iJXh4gWR2/ip6gmyAGQJK -u63jA/fwoeWqcQDI1FnHqpGEHb6BLeeyRA7iXd3TYTOYpuFJGx57yhZflFssbmwY -3MW3NyWdOYXkWiH1OfujYHuh5du5txiEMvN78q5F18byIaLSkoa3eOM6osGOn8kj -X3iJEAOk+HzMONQd2O59OWmozzyxHicr4rv7LIOeAvL9gi+gpEflT65/AJbgLa5N -JLcvQwAD/iRRv9fs7CSsOlwLyZEVGy0huZ2iyxSguBwkDsHd6yFAr90F8eehV4z6 -DlW3g5UREVQEcUIKW4FEg+E0XMe7tILOcqTzhsMrd3PwMmC/RDPoyOOhJLCLFAg9 -hN+xaFEr4cDUPT1PwudHqQ9u9uqyeH47O3Qi0KJ2IsrWgcjTy3z0setCZDh3APlv -Y9o+Go4ykvMNV/iHwnui/CS/sIX64VKrBq5L+0cq3PnbJfeqxi/Q7CRBko4Zf2h1 -A5SkSM3lwSuLk+zLNu+erS13EjwfainK4eOgFism7lN5CD4Z7VrKxtOTKjozidG0 -N3Ez7edUYQ28NGWJBIMEb6qn/7kCDQRZvrPlARAAoWI61RD8wjDINkiXAtX0jcoG -dvO9oMXvVFWqsGEGivqciifdA5VvB/9jK0YfFQbLvQtkfvcqITuGflBExCK47CDg -lv4AxI0xNkj1jKwgvm/tU6y+Oe1mrw+b64Z/V5naptNnIU4VgVSNsWvZkH2EKxgq -6k+fAoCCwxlctw2JMmbnmUNOiu2miwoiq/Agl8Jfd4xSrAGZn77ZHM+XNLgabKiJ -782E3alCFOXbIftOXIcxgOQWbiiPEUjzCJ5llMdjVnOkn7uP+ZXm3/h7IsrC9/GP -DqSsebGPbNuxgNrDj9HigYPNK6jjZ95bLImaADfd2h/OXA9FYz+HwJ2kBZRNGtDj -FxsmLvqNolu8WZKSjiw7SNK0Ya+55y8KU2iO/G3T5ilAB6nRPliP9aE6IIEzNWgK -9nNM92S34CZQMhOnVjRqH4WEi9i3j/rlSAX4mJLbe2pi6cueSBc53qisBs6H8p5Z -hqPQJfUlVeRxF4ZNKF7wt6dhQcEbi3/IxoABBizIt5DSBybOMLOAB65A5GQkPlJ7 -VyHhzlIoS5RqzwOqg6TCQ4UUtifQqtFXuwVHlHAPhi56U10IiCWJd4hy635Eei6C -WDmGr4+eXTK14h93f79JxIqqve5y7cZgcQ+dQPSBVl19FZnvQUA4/5E8UPI1X3cQ -o8I1542PpL74CcXBZ1kAEQEAAYkCJQQYAQIADwUCWb6z5QIbDAUJA8JnAAAKCRDc -sFtM+Jr8ZqSQEACFW1xrxu8mmXGXpLlXpGx9CFWBfJSFtWBYNjbLZ8Rcdu8FweBt -HVIAmdwYbBHYgT/xQd9Gxg+Z+JmnaAZFi88pN5Pmh2dy53nysLsjYZS8G7p2lKdu -alXrM90PxGpwugNNPVEr//+Bb6ahQgnJQLDY6wz3DuA3L1vk+sBN+00iuGbaW992 -kPRcz2KSDXY0jR3lh3938qBXJR6jbYN2YxHMhfCeK8y9hpNSP5UVUYlLeEjyEIT7 -HgbMwsX8WX8OvL+uacwSzwC1JE8Vn98pIEQgMveZn9ylwuJZp1zv5eSulDsDRWA8 -S8Agjb/fjdQGsck4REiahw3DIPqcIvUFr3yDybB8dTLp509UqK+HLw/bf8QMmpc8 -YazIquk0/HVm0tdijDCgAIw+Dh8LEP1gmCVxynlrHs9ItCjlipuTao8LopjwOiGE -9LnYy19ESF7kUbtyFenmp+FX0WAvlUfhrSfeeM+vR1yD8dJSa1XDI/WafkxBQRuV -sd3cfQIxDn7JGlhwytRkxl7oabxHokc3wCSzu5Sb4ok6A91HPbSNqJ2nKSkbAwQE -u6d5vx6SSO02stvyHPUFLM7zTTNa2B5Vrz9e7eItKEm6taXqzx1e7A8w+kOlP/0p -4oLlBDWgklpqVZcPWtFDsldyNZlxwo5xw9czlTZ+hVuaHdSqwP2NNQegYw== -=5XsB ------END PGP PUBLIC KEY BLOCK----- diff --git a/users/wpcarro/configs/.gnupg/pubring.kbx b/users/wpcarro/configs/.gnupg/pubring.kbx deleted file mode 100644 index 208fad71b..000000000 Binary files a/users/wpcarro/configs/.gnupg/pubring.kbx and /dev/null differ diff --git a/users/wpcarro/configs/.gnupg/trustdb.gpg b/users/wpcarro/configs/.gnupg/trustdb.gpg deleted file mode 100644 index 8781b2ad9..000000000 Binary files a/users/wpcarro/configs/.gnupg/trustdb.gpg and /dev/null differ diff --git a/users/wpcarro/configs/.sqliterc b/users/wpcarro/configs/.sqliterc deleted file mode 100644 index 7e8b3e3fb..000000000 --- a/users/wpcarro/configs/.sqliterc +++ /dev/null @@ -1,2 +0,0 @@ -.mode column -.headers on \ No newline at end of file diff --git a/users/wpcarro/configs/.xsecurelockrc b/users/wpcarro/configs/.xsecurelockrc deleted file mode 100644 index 101495c3e..000000000 --- a/users/wpcarro/configs/.xsecurelockrc +++ /dev/null @@ -1,5 +0,0 @@ -# Replace the gLinux penguin with a custom image. -XSECURELOCK_LOGO_IMAGE=~/.local/share/static/pickle-rick.jpg - -# Turn this off on laptop (not on desktop). -XSECURELOCK_BLANK_DPMS_STATE=on diff --git a/users/wpcarro/configs/default.nix b/users/wpcarro/configs/default.nix deleted file mode 100644 index 681f97605..000000000 --- a/users/wpcarro/configs/default.nix +++ /dev/null @@ -1,73 +0,0 @@ -{ pkgs, ... }: - -let - inherit (pkgs) writeShellScript; - inherit (pkgs.lib.strings) makeBinPath; -in -{ - install = writeShellScript "install-configs" '' - cd "$WPCARRO/configs" && ${pkgs.stow}/bin/stow --target="$HOME" . - ''; - - uninstall = writeShellScript "uninstall-configs" '' - cd "$WPCARRO/configs" && ${pkgs.stow}/bin/stow --delete --target="$HOME" . - ''; - - # Run this script to import all of the information exported by `export.sh`. - # Usage: import-gpg path/to/export.zip - import-gpg = writeShellScript "import-gpg" '' - set -euo pipefail - - if [ -z "''${1+x}" ]; then - echo "You must specify the path to export.zip. Exiting..." - exit 1 - fi - - PATH="${makeBinPath (with pkgs; [ busybox gnupg ])}" - destination="$(mktemp -d)" - - function cleanup() { - rm -rf "$destination" - } - trap cleanup EXIT - - unzip "$1" -d "$destination" >/dev/null - - gpg --import "$destination/public.asc" - gpg --import "$destination/secret.asc" - gpg --import-ownertrust "$destination/ownertrust.txt" - - # Run this at the end to output some verification - gpg --list-keys - gpg --list-secret-keys - ''; - - # Run this script to export all the information required to transport your GPG - # information to a zip file. - # Usage: export-gpg - export-gpg = writeShellScript "export-gpg" '' - set -euo pipefail - - PATH="${makeBinPath (with pkgs; [ busybox gnupg zip ])}" - output="$(pwd)/export.zip" - destination="$(mktemp -d)" - - function cleanup() { - rm -rf "$destination" - } - trap cleanup EXIT - - gpg --armor --export >"$destination/public.asc" - gpg --armor --export-secret-keys >"$destination/secret.asc" - gpg --armor --export-ownertrust >"$destination/ownertrust.txt" - - # Strangely enough this appears to be the only way to create a zip of a - # directory that doesn't contain the (noisy) full paths of each item from - # the source filesystem. (i.e. -j doesn't cooperate with -r). - pushd "$destination" - zip -r "$output" ./* - popd - - echo "$(realpath $output)" - ''; -} diff --git a/users/wpcarro/configs/install b/users/wpcarro/configs/install deleted file mode 100755 index a3f3ec328..000000000 --- a/users/wpcarro/configs/install +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -configs="$WPCARRO/configs" - -(cd "$configs" && stow --target="$HOME" .) diff --git a/users/wpcarro/configs/uninstall b/users/wpcarro/configs/uninstall deleted file mode 100755 index 9650479c4..000000000 --- a/users/wpcarro/configs/uninstall +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -configs="$WPCARRO/configs" - -(cd "$configs" && stow --delete --target="$HOME" .) diff --git a/users/wpcarro/dotfiles/config.fish b/users/wpcarro/dotfiles/config.fish deleted file mode 100644 index 3be8fefd9..000000000 --- a/users/wpcarro/dotfiles/config.fish +++ /dev/null @@ -1,44 +0,0 @@ -alias c 'xclip -selection clipboard -i' -alias p 'xclip -selection clipboard -o' -alias cat 'bat --theme="Monokai Extended Light"' -alias rgh 'rg --hidden' -alias fdh 'fd --hidden' -alias tpr 'tput reset' -alias ls 'exa --sort=type' -alias ll 'exa --long --sort=type' -alias la 'exa --long --all --sort=type' -alias gcan 'git commit --amend --no-edit' -alias gco 'git checkout' -alias gd 'git diff' -alias gds 'git diff --staged' -alias glp 'git log --pretty --oneline --graph' -alias gpf 'git push --force' -alias gsh 'git show HEAD' -alias gst 'git status' -alias gprom 'git pull --rebase origin main' -alias gfom 'git fetch origin main' -alias grh 'git reset --hard' -alias gproc 'git pull --rebase origin canon' -alias edit 'emacsclient -n' -alias h 'cd /hadrian' -alias d 'cd /depot' -alias hw 'cd /hadrian/users/wpcarro' -alias dw 'cd /depot/users/wpcarro' -alias sc 'systemctl' -alias ef 'edit ~/.config/fish/config.fish' -alias sf 'source ~/.config/fish/config.fish' -alias tf 'terraform' - -# environment variables -set -gx EDITOR "emacsclient" -set -gx ALTERNATE_EDITOR "emacs -q -nw" -set -gx VISUAL "emacsclient" - -# Use my custom fish prompt -source /depot/users/wpcarro/dotfiles/prompt.fish - -# Configure fuzzy history, file, directory searching -source (fzf-share)/key-bindings.fish && fzf_key_bindings - -# Install direnv -eval (direnv hook fish) diff --git a/users/wpcarro/dotfiles/default.nix b/users/wpcarro/dotfiles/default.nix deleted file mode 100644 index 8150f5370..000000000 --- a/users/wpcarro/dotfiles/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ ... }: - -{ - dunstrc = ./dunstrc; -} diff --git a/users/wpcarro/dotfiles/dunstrc b/users/wpcarro/dotfiles/dunstrc deleted file mode 100644 index a17533f07..000000000 --- a/users/wpcarro/dotfiles/dunstrc +++ /dev/null @@ -1,53 +0,0 @@ -[global] -font = JetBrains Mono -origin = top-right -markup = yes -plain_text = no -format = "%s\n%b" -sort = no -indicate_hidden = yes -alignment = center -bounce_freq = 0 -show_age_threshold = -1 -word_wrap = yes -ignore_newline = no -stack_duplicates = yes -hide_duplicate_count = yes -geometry = "300x50-15+49" -shrink = no -transparency = 5 -idle_threshold = 0 -monitor = 0 -follow = keyboard -sticky_history = yes -history_length = 15 -show_indicators = no -line_height = 3 -separator_height = 2 -padding = 6 -horizontal_padding = 6 -separator_color = frame -startup_notification = false -browser = xdg-open -icon_position = off -max_icon_size = 80 -frame_width = 3 -frame_color = "#8EC07C" - -[urgency_low] -frame_color = "#3B7C87" -foreground = "#3B7C87" -background = "#191311" -timeout = 4 - -[urgency_normal] -frame_color = "#5B8234" -foreground = "#5B8234" -background = "#191311" -timeout = 6 - -[urgency_critical] -frame_color = "#B7472A" -foreground = "#B7472A" -background = "#191311" -timeout = 8 \ No newline at end of file diff --git a/users/wpcarro/dotfiles/gitconfig b/users/wpcarro/dotfiles/gitconfig deleted file mode 100644 index f81c0c40f..000000000 --- a/users/wpcarro/dotfiles/gitconfig +++ /dev/null @@ -1,9 +0,0 @@ -[user] - name = "William Carroll" - email = "wpcarro@gmail.com" -[diff] - external = difft -[push] - default = current -[rebase] - autoStash = true diff --git a/users/wpcarro/dotfiles/prompt.fish b/users/wpcarro/dotfiles/prompt.fish deleted file mode 100644 index 58d22dab5..000000000 --- a/users/wpcarro/dotfiles/prompt.fish +++ /dev/null @@ -1,87 +0,0 @@ -# When the Emacs SSH client, Tramp, connects to a remote host that uses Fish, -# it's important to keep the shell prompt simple so that Tramp can parse it. -if test "$TERM" = "dumb" - function fish_prompt - echo "\$ " - end - function fish_right_prompt; end - function fish_greeting; end - function fish_title; end -else - function fish_prompt - # My custom prompt. - # - # Design objectives: - # - max-length <= 80 characters - # - minimal - # - no dependencies (well, you know what I mean) - # - # Components - # - ssh connection - # - user - # - host - # - git repo - # - git branch - # - lambda character as prompt - - # Cache status before we overwrite it. - set -l last_status $status - - # Colors - set -l color_inactive (set_color red --bold) - set -l color_active (set_color green --bold) - set -l color_normal (set_color normal) - - # SSH information - if set -q SSH_CLIENT; or set -q SSH_TTY - echo -en "$color_active \bssh ✓ [$color_normal$USER@"(hostname)"$color_active]$color_normal" - else - echo -en "$color_inactive \bssh ✗ [$color_normal$USER@"(hostname)"$color_inactive]$color_normal" - end - - # Separator - echo -n " " - - # Git information - set -l git_repo (git rev-parse --show-toplevel 2>/dev/null) - set -l git_status $status - - if [ (realpath .) = "/" ] - set -g dir_path (realpath .) - else if [ (realpath ..) = "/" ] - set -g dir_path (realpath .) - else - set -g dir_path (echo (basename (realpath ..))"/"(basename (realpath .))) - end - - if test $git_status -eq 0 - set -l git_repo_name (basename (git rev-parse --show-toplevel)) - set -l git_branch (git branch 2>/dev/null | grep '^\*' | cut -d' ' -f2-) - echo -en "$color_active \bgit ✓ [$color_normal$git_branch$color_active|$color_normal$git_repo_name$color_active|$color_normal$dir_path$color_active]$color_normal" - else - echo -en "$color_inactive \bgit ✗ [$color_normal$dir_path$color_inactive]$color_normal" - end - - # Newline - echo - - # Handle root vs non-root - if [ "$USER" = "root" ] - set -g prompt_sigil "#" - else - set -g prompt_sigil "λ" - end - - set -l time (date +"%T") - if test $last_status -eq 0 - set -l color_prompt (set_color white --bold) - echo -n "$time$color_prompt $prompt_sigil$color_normal " - else - set -l color_prompt (set_color red --bold) - echo -n "$time$color_prompt $prompt_sigil$color_normal " - end - end - function fish_right_prompt; end - function fish_greeting; end - function fish_title; end -end diff --git a/users/wpcarro/emacs/.emacs.d/init.el b/users/wpcarro/emacs/.emacs.d/init.el deleted file mode 100644 index 5db74d36c..000000000 --- a/users/wpcarro/emacs/.emacs.d/init.el +++ /dev/null @@ -1,15 +0,0 @@ -;; load order is intentional -(setq-default debug-on-error t) -(require 'wpc-package) -(require 'wpc-misc) -(require 'ssh) -(require 'keyboard) -(require 'email) -(require 'keybindings) -(require 'window-manager) -(require 'wpc-ui) -(require 'wpc-dired) -(require 'wpc-org) -(require 'wpc-company) -(require 'wpc-shell) -(require 'wpc-language-support) diff --git a/users/wpcarro/emacs/.emacs.d/opam-user-setup.el b/users/wpcarro/emacs/.emacs.d/opam-user-setup.el deleted file mode 100644 index a23addefa..000000000 --- a/users/wpcarro/emacs/.emacs.d/opam-user-setup.el +++ /dev/null @@ -1,145 +0,0 @@ -;; ## added by OPAM user-setup for emacs / base ## cfd3c9b7837c85cffd0c59de521990f0 ## you can edit, but keep this line -(provide 'opam-user-setup) - -;; Base configuration for OPAM - -(defun opam-shell-command-to-string (command) - "Similar to shell-command-to-string, but returns nil unless the process - returned 0, and ignores stderr (shell-command-to-string ignores return value)" - (let* ((return-value 0) - (return-string - (with-output-to-string - (setq return-value - (with-current-buffer standard-output - (process-file shell-file-name nil '(t nil) nil - shell-command-switch command)))))) - (if (= return-value 0) return-string nil))) - -(defun opam-update-env (switch) - "Update the environment to follow current OPAM switch configuration" - (interactive - (list - (let ((default - (car (split-string (opam-shell-command-to-string "opam switch show --safe"))))) - (completing-read - (concat "opam switch (" default "): ") - (split-string (opam-shell-command-to-string "opam switch list -s --safe") "\n") - nil t nil nil default)))) - (let* ((switch-arg (if (= 0 (length switch)) "" (concat "--switch " switch))) - (command (concat "opam config env --safe --sexp " switch-arg)) - (env (opam-shell-command-to-string command))) - (when (and env (not (string= env ""))) - (dolist (var (car (read-from-string env))) - (setenv (car var) (cadr var)) - (when (string= (car var) "PATH") - (setq exec-path (split-string (cadr var) path-separator))))))) - -(opam-update-env nil) - -(defvar opam-share - (let ((reply (opam-shell-command-to-string "opam config var share --safe"))) - (when reply (substring reply 0 -1)))) - -(add-to-list 'load-path (concat opam-share "/emacs/site-lisp")) -;; OPAM-installed tools automated detection and initialisation - -(defun opam-setup-tuareg () - (add-to-list 'load-path (concat opam-share "/tuareg") t) - (load "tuareg-site-file")) - -(defun opam-setup-add-ocaml-hook (h) - (add-hook 'tuareg-mode-hook h t) - (add-hook 'caml-mode-hook h t)) - -(defun opam-setup-complete () - (if (require 'company nil t) - (opam-setup-add-ocaml-hook - (lambda () - (company-mode) - (defalias 'auto-complete 'company-complete))) - (require 'auto-complete nil t))) - -(defun opam-setup-ocp-indent () - (opam-setup-complete) - (autoload 'ocp-setup-indent "ocp-indent" "Improved indentation for Tuareg mode") - (autoload 'ocp-indent-caml-mode-setup "ocp-indent" "Improved indentation for Caml mode") - (add-hook 'tuareg-mode-hook 'ocp-setup-indent t) - (add-hook 'caml-mode-hook 'ocp-indent-caml-mode-setup t)) - -(defun opam-setup-ocp-index () - (autoload 'ocp-index-mode "ocp-index" "OCaml code browsing, documentation and completion based on build artefacts") - (opam-setup-add-ocaml-hook 'ocp-index-mode)) - -(defun opam-setup-merlin () - (opam-setup-complete) - (require 'merlin) - (opam-setup-add-ocaml-hook 'merlin-mode) - - (defcustom ocp-index-use-auto-complete nil - "Use auto-complete with ocp-index (disabled by default by opam-user-setup because merlin is in use)" - :group 'ocp_index) - (defcustom merlin-ac-setup 'easy - "Use auto-complete with merlin (enabled by default by opam-user-setup)" - :group 'merlin-ac) - - ;; So you can do it on a mac, where `C-` and `C-` are used - ;; by spaces. - (define-key merlin-mode-map - (kbd "C-c ") 'merlin-type-enclosing-go-up) - (define-key merlin-mode-map - (kbd "C-c ") 'merlin-type-enclosing-go-down) - (set-face-background 'merlin-type-face "skyblue")) - -(defun opam-setup-utop () - (autoload 'utop "utop" "Toplevel for OCaml" t) - (autoload 'utop-minor-mode "utop" "Minor mode for utop" t) - (add-hook 'tuareg-mode-hook 'utop-minor-mode)) - -(defvar opam-tools - '(("tuareg" . opam-setup-tuareg) - ("ocp-indent" . opam-setup-ocp-indent) - ("ocp-index" . opam-setup-ocp-index) - ("merlin" . opam-setup-merlin) - ("utop" . opam-setup-utop))) - -(defun opam-detect-installed-tools () - (let* - ((command "opam list --installed --short --safe --color=never") - (names (mapcar 'car opam-tools)) - (command-string (mapconcat 'identity (cons command names) " ")) - (reply (opam-shell-command-to-string command-string))) - (when reply (split-string reply)))) - -(defvar opam-tools-installed (opam-detect-installed-tools)) - -(defun opam-auto-tools-setup () - (interactive) - (dolist (tool opam-tools) - (when (member (car tool) opam-tools-installed) - (funcall (symbol-function (cdr tool)))))) - -(opam-auto-tools-setup) -;; ## end of OPAM user-setup addition for emacs / base ## keep this line -;; ## added by OPAM user-setup for emacs / tuareg ## b10f42abebd2259b784b70d1a7f7e426 ## you can edit, but keep this line -;; Set to autoload tuareg from its original switch when not found in current -;; switch (don't load tuareg-site-file as it adds unwanted load-paths) -(defun opam-tuareg-autoload (fct file doc args) - (let ((load-path (cons "/home/wpcarro/.opam/default/share/emacs/site-lisp" load-path))) - (load file)) - (apply fct args)) -(when (not (member "tuareg" opam-tools-installed)) - (defun tuareg-mode (&rest args) - (opam-tuareg-autoload 'tuareg-mode "tuareg" "Major mode for editing OCaml code" args)) - (defun tuareg-run-ocaml (&rest args) - (opam-tuareg-autoload 'tuareg-run-ocaml "tuareg" "Run an OCaml toplevel process" args)) - (defun ocamldebug (&rest args) - (opam-tuareg-autoload 'ocamldebug "ocamldebug" "Run the OCaml debugger" args)) - (defalias 'run-ocaml 'tuareg-run-ocaml) - (defalias 'camldebug 'ocamldebug) - (add-to-list 'auto-mode-alist '("\\.ml[iylp]?\\'" . tuareg-mode)) - (add-to-list 'auto-mode-alist '("\\.eliomi?\\'" . tuareg-mode)) - (add-to-list 'interpreter-mode-alist '("ocamlrun" . tuareg-mode)) - (add-to-list 'interpreter-mode-alist '("ocaml" . tuareg-mode)) - (dolist (ext '(".cmo" ".cmx" ".cma" ".cmxa" ".cmxs" ".cmt" ".cmti" ".cmi" ".annot")) - (add-to-list 'completion-ignored-extensions ext))) -;; ## end of OPAM user-setup addition for emacs / tuareg ## keep this line diff --git a/users/wpcarro/emacs/.emacs.d/snippets/c-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/c-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/c-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/c-mode/stdio b/users/wpcarro/emacs/.emacs.d/snippets/c-mode/stdio deleted file mode 100644 index 52bc717e4..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/c-mode/stdio +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: -# key: sio -# -- -#include \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/c-mode/stdlib b/users/wpcarro/emacs/.emacs.d/snippets/c-mode/stdlib deleted file mode 100644 index 5d44e8ed7..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/c-mode/stdlib +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: -# key: slb -# -- -#include \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/c-mode/struct b/users/wpcarro/emacs/.emacs.d/snippets/c-mode/struct deleted file mode 100644 index 6e9282f83..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/c-mode/struct +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: struct -# key: struct -# -- -typedef struct $1 { - $2 -} $1_t; \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/elisp-module-docs b/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/elisp-module-docs deleted file mode 100644 index 8ea7b8f07..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/elisp-module-docs +++ /dev/null @@ -1,11 +0,0 @@ -# -*- mode: snippet -*- -# name: Elisp module docs -# key: emd -# -- -;;; `(-> (buffer-file-name) f-filename)` --- $2 -*- lexical-binding: t -*- -;; Author: William Carroll - -;;; Commentary: -;; $3 - -;;; Code: \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/function b/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/function deleted file mode 100644 index bfa888d52..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/function +++ /dev/null @@ -1,8 +0,0 @@ -# -*- mode: snippet -*- -# name: Function -# key: fn -# expand-env: ((yas-indent-line 'fixed)) -# -- -(defun $1 ($2) - "$3" - $4) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/generic-header b/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/generic-header deleted file mode 100644 index bf6e525f8..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/generic-header +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Header -# key: hdr -# -- -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; $1 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/library-header b/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/library-header deleted file mode 100644 index 0f0ad5c4f..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/library-header +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Library header -# key: lib -# -- -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/provide-footer b/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/provide-footer deleted file mode 100644 index 2a0bcc33f..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/emacs-lisp-mode/provide-footer +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: Provide footer -# key: elf -# -- -(provide '`(-> (buffer-file-name) f-filename f-no-ext)`) -;;; `(-> (buffer-file-name) f-filename)` ends here \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/derive-safe-copy b/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/derive-safe-copy deleted file mode 100644 index 95f7d9dee..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/derive-safe-copy +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Derive Safe Copy -# key: dsc -# -- -deriveSafeCopy 0 'base ''$1 \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/import-qualified b/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/import-qualified deleted file mode 100644 index 4c4db62a8..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/import-qualified +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Import qualified -# key: iq -# -- -import qualified $1 as $2 \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/instance-defn b/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/instance-defn deleted file mode 100644 index 10d194ce4..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/instance-defn +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: Instance -# key: inst -# -- -instance $1 where - $2 = $3 \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/language-extension b/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/language-extension deleted file mode 100644 index 9d6084acb..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/language-extension +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: language extension -# key: lang -# -- -{-# LANGUAGE $1 #-} \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/separator b/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/separator deleted file mode 100644 index 1ab0d762b..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/separator +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Separator -# key: - -# -- --------------------------------------------------------------------------------- \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/undefined b/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/undefined deleted file mode 100644 index 7609f801f..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/haskell-mode/undefined +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Undefiend -# key: nd -# -- -undefined \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/html-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/html-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/html-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/html-mode/index-boilerplate b/users/wpcarro/emacs/.emacs.d/snippets/html-mode/index-boilerplate deleted file mode 100644 index 3cea6ce00..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/html-mode/index-boilerplate +++ /dev/null @@ -1,18 +0,0 @@ -# -*- mode: snippet -*- -# name: HTML index.html starter -# key: html -# -- - - - - - - $1 - - - - - - - - \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/java-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/java-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/java-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/java-mode/public-static-void-main b/users/wpcarro/emacs/.emacs.d/snippets/java-mode/public-static-void-main deleted file mode 100644 index 1839a27eb..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/java-mode/public-static-void-main +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: public static void main -# key: psvm -# -- -public static void main(String[] args) { - $1 -} \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/defpackage b/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/defpackage deleted file mode 100644 index 7f110a971..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/defpackage +++ /dev/null @@ -1,9 +0,0 @@ -# -*- mode: snippet -*- -# name: Define package -# key: defp -# -- -(in-package #:cl-user) -(defpackage #:$1 - (:documentation "$2") - (:use #:cl)) -(in-package #:$1) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/function b/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/function deleted file mode 100644 index b1769cd3d..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/function +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Function -# key: fn -# -- -(defun $1 ($2) - "$3" - $4) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/typed-function b/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/typed-function deleted file mode 100644 index a3c236821..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/lisp-mode/typed-function +++ /dev/null @@ -1,8 +0,0 @@ -# -*- mode: snippet -*- -# name: Typed function -# key: tfn -# -- -(type $1 ($3) $4) -(defun $1 ($2) - "$5" - $6) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/nix-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/nix-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/nix-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/nix-mode/shell-nix b/users/wpcarro/emacs/.emacs.d/snippets/nix-mode/shell-nix deleted file mode 100644 index b5eb5a244..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/nix-mode/shell-nix +++ /dev/null @@ -1,12 +0,0 @@ -# -*- mode: snippet -*- -# name: shell.nix boilerplate -# key: import -# -- -{ pkgs, ... }: - -pkgs.stdenv.mkDerivation { - name = "$1"; - buildInputs = [ - $2 - ]; -} diff --git a/users/wpcarro/emacs/.emacs.d/snippets/org-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/org-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/org-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/org-mode/code-snippet b/users/wpcarro/emacs/.emacs.d/snippets/org-mode/code-snippet deleted file mode 100644 index 4215b1599..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/org-mode/code-snippet +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Code Snippet -# key: src -# -- -#+BEGIN_SRC $1 -$2 -#+END_SRC \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/org-mode/href b/users/wpcarro/emacs/.emacs.d/snippets/org-mode/href deleted file mode 100644 index ac65ea2e4..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/org-mode/href +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Org mode URL -# key: href -# -- -[[$1][$2]] \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/python-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/dunder-main b/users/wpcarro/emacs/.emacs.d/snippets/python-mode/dunder-main deleted file mode 100644 index 4dd22dc0b..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/dunder-main +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: Dunder main (__main__) -# key: mn -# -- -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/function b/users/wpcarro/emacs/.emacs.d/snippets/python-mode/function deleted file mode 100644 index 379ceda1a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/function +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: Function -# key: fn -# -- -def $1($2): - $3 \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/header b/users/wpcarro/emacs/.emacs.d/snippets/python-mode/header deleted file mode 100644 index db48adfec..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/header +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Header -# key: hdr -# -- -################################################################################ -# $1 -################################################################################ \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/init b/users/wpcarro/emacs/.emacs.d/snippets/python-mode/init deleted file mode 100644 index 5c407495f..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/init +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: dunder init -# key: ctor -# -- -def __init__(self$1): - $2 \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/shebang b/users/wpcarro/emacs/.emacs.d/snippets/python-mode/shebang deleted file mode 100644 index 0f45ae782..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/shebang +++ /dev/null @@ -1,6 +0,0 @@ -# -*- mode: snippet -*- -# name: shebang -# key: shb -# -- -#!/usr/bin/env python -# -*- coding: utf-8 -*- diff --git a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/utf-8 b/users/wpcarro/emacs/.emacs.d/snippets/python-mode/utf-8 deleted file mode 100644 index 3babc7303..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/python-mode/utf-8 +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: utf-8 -# key: utf -# -- -# -*- coding: utf-8 -*- \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/function b/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/function deleted file mode 100644 index 882c48ded..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/function +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Function -# key: fn -# -- -(define ($1) $2) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/lambda b/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/lambda deleted file mode 100644 index b9a684588..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/lambda +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Lambda function -# key: ld -# -- -(λ ($1) $2) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/lambda-symbol b/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/lambda-symbol deleted file mode 100644 index 254b9fd96..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/racket-mode/lambda-symbol +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Lambda symbol -# key: l -# -- -λ \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/function b/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/function deleted file mode 100644 index 6b4b6a5db..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/function +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Function -# key: fn -# -- -let $1 = (~$2:$3) => { - $4 -}; \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/switch b/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/switch deleted file mode 100644 index 40f34ff8d..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/reason-mode/switch +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Switch statement -# key: sw -# -- -switch ($1) { -| $2 => -} \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/action-extractor b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/action-extractor deleted file mode 100644 index 62834a29a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/action-extractor +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: exactness -# key: $x -# -- -$Exact<$Call> \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/console-log b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/console-log deleted file mode 100644 index 82ec3fd8e..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/console-log +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Console.log helper -# key: clg -# -- -console.log($1) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/const-defn b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/const-defn deleted file mode 100644 index 8e35e61fc..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/const-defn +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: const definition -# key: cn -# -- -const $1 = '$2' \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/const-function b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/const-function deleted file mode 100644 index 13f2018f2..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/const-function +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: const function -# key: cfn -# -- -const $1 = ($2) => { - $3 -} \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/destructure-const b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/destructure-const deleted file mode 100644 index 2a52c57c7..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/destructure-const +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Destructuring a const -# key: cds -# -- -const { $1 } = $2 \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/fat-arrow b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/fat-arrow deleted file mode 100644 index 187a2efc5..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/fat-arrow +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Fat arrow function -# key: fa -# -- -=> \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/fat-arrow-function b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/fat-arrow-function deleted file mode 100644 index 694914a83..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/fat-arrow-function +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Fat arrow function -# key: faf -# -- -() => { - $1 -} \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-destructured b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-destructured deleted file mode 100644 index ded3ce163..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-destructured +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Import destructured -# key: ids -# -- -import { $1 } from '$2' \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-react b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-react deleted file mode 100644 index 0463f5cd5..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-react +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Import React dependency (ES6) -# key: ir -# -- -import React from 'react' diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-type b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-type deleted file mode 100644 index fcd51f687..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-type +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: import type -# key: ixt -# -- -import type { $1 } from '$2' \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-x-from-y b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-x-from-y deleted file mode 100644 index 09fa6df50..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-x-from-y +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: import x from y -# key: ix -# -- -import $1 from '$2' \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-y b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-y deleted file mode 100644 index 9f550e300..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/import-y +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: import y -# key: iy -# -- -import '$1' \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/jest-describe-test b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/jest-describe-test deleted file mode 100644 index ed382d4f7..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/jest-describe-test +++ /dev/null @@ -1,10 +0,0 @@ -# -*- mode: snippet -*- -# name: Jest describe/test block -# key: dsc -# -- -describe('$1', () => { - test('$2', () => { - - expect($3).toEqual($4) - }) -}) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/jest-test b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/jest-test deleted file mode 100644 index 12ca2e786..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/jest-test +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Jest / Jasmine test -# key: tst -# -- -test('$1', () => { - expect($2).toBe($3) -}) \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/react-class-component b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/react-class-component deleted file mode 100644 index f2a93a31d..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/react-class-component +++ /dev/null @@ -1,11 +0,0 @@ -# -*- mode: snippet -*- -# name: React class extends -# key: clz -# -- -class $1 extends React.Component { - render() { - $2 - } -} - -export default $1 \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/redux-action b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/redux-action deleted file mode 100644 index 681c5d0df..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/redux-action +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: redux-action -# key: rax -# -- -export const ${1:$$(string-lower->caps yas-text)} = '`(downcase (functions-buffer-dirname))`/${1:$(string-caps->kebab yas-text)}' \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/typed-redux-action b/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/typed-redux-action deleted file mode 100644 index 53c6e5fc5..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rjsx-mode/typed-redux-action +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: typed-redux-action -# key: trax -# -- -export const ${1:$$(string-lower->caps yas-text)}: '`(downcase (functions-buffer-dirname))`/${1:$(string-caps->kebab yas-text)}' = '`(downcase (buffer-dirname))`/${1:$(string-caps->kebab yas-text)}' \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/for-loop b/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/for-loop deleted file mode 100644 index 4d8e0e3bb..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/for-loop +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: for-loop -# key: for -# -- -for $1 in $2 { - $3 -} \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/match b/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/match deleted file mode 100644 index bf0e876e2..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/rust-mode/match +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: match -# key: match -# -- -match $1 { - $2 => $3, -} \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/sh-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/sh-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/sh-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/sh-mode/function b/users/wpcarro/emacs/.emacs.d/snippets/sh-mode/function deleted file mode 100644 index efa946bb2..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/sh-mode/function +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Create function -# key: fn -# -- -$1() { - $2 -} \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/text-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/text-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/text-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/text-mode/check-mark b/users/wpcarro/emacs/.emacs.d/snippets/text-mode/check-mark deleted file mode 100644 index 797781968..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/text-mode/check-mark +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Unicode checkmark -# key: uck -# -- -✓ \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/text-mode/x-mark b/users/wpcarro/emacs/.emacs.d/snippets/text-mode/x-mark deleted file mode 100644 index bc3c356a6..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/text-mode/x-mark +++ /dev/null @@ -1,5 +0,0 @@ -# -*- mode: snippet -*- -# name: Unicode ex-mark -# key: ux -# -- -✗ \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/web-mode/.yas-parents b/users/wpcarro/emacs/.emacs.d/snippets/web-mode/.yas-parents deleted file mode 100644 index d58dacb7a..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/web-mode/.yas-parents +++ /dev/null @@ -1 +0,0 @@ -text-mode \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/web-mode/header b/users/wpcarro/emacs/.emacs.d/snippets/web-mode/header deleted file mode 100644 index ae59c7a50..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/web-mode/header +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: snippet -*- -# name: Header -# key: hdr -# -- -/******************************************************************************* - * $1 - ******************************************************************************/ \ No newline at end of file diff --git a/users/wpcarro/emacs/.emacs.d/snippets/web-mode/index-boilerplate b/users/wpcarro/emacs/.emacs.d/snippets/web-mode/index-boilerplate deleted file mode 100644 index b791cdf86..000000000 --- a/users/wpcarro/emacs/.emacs.d/snippets/web-mode/index-boilerplate +++ /dev/null @@ -1,18 +0,0 @@ -# -*- mode: snippet -*- -# name: HTML index.html starter -# key: html -# -- - - - - - - $1 - - - - - - - - diff --git a/users/wpcarro/emacs/.emacs.d/wpc/>.el b/users/wpcarro/emacs/.emacs.d/wpc/>.el deleted file mode 100644 index 6d5f86f8b..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/>.el +++ /dev/null @@ -1,28 +0,0 @@ -;;; >.el --- Small utility functions -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Originally I stored the `>>` macro in macros.el, but after setting up linting -;; for my Elisp in CI, `>>` failed because it didn't have the `macros-` -;; namespace. I created this module to establish a `>-` namespace under which I -;; can store some utilities that would be best kept without a cumbersome -;; namespace. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defmacro >-> (&rest forms) - "Compose a new, point-free function by composing FORMS together." - (let ((sym (gensym))) - `(lambda (,sym) - (->> ,sym ,@forms)))) - - -(provide '>) -;;; >.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/buffer.el b/users/wpcarro/emacs/.emacs.d/wpc/buffer.el deleted file mode 100644 index 0f86f7f81..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/buffer.el +++ /dev/null @@ -1,174 +0,0 @@ -;;; buffer.el --- Working with buffers -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Utilities for CRUDing buffers in Emacs. -;; -;; Many of these functions may seem unnecessary especially when you consider -;; there implementations. In general I believe that Elisp suffers from a -;; library disorganization problem. Providing simple wrapper functions that -;; rename functions or reorder parameters is worth the effort in my opinion if -;; it improves discoverability (via intuition) and improve composability. -;; -;; I support three ways for switching between what I'm calling "source code -;; buffers": -;; 1. Toggling previous: -;; 2. Using `ivy-read': b -;; TODO: These obscure evil KBDs. Maybe a hydra definition would be best? -;; 3. Cycling (forwards/backwards): C-f, C-b - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'prelude) -(require 'maybe) -(require 'set) -(require 'cycle) -(require 'struct) -(require 'ts) -(require 'general) -(require 'list) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst buffer-source-code-blacklist - (set-new 'dired-mode - 'erc-mode - 'vterm-mode - 'magit-status-mode - 'magit-process-mode - 'magit-log-mode - 'magit-diff-mode - 'org-mode - 'fundamental-mode) - "A blacklist of major-modes to ignore for listing source code buffers.") - -(defconst buffer-ivy-source-code-whitelist '("*scratch*" "*Messages*") - "A whitelist of buffers to include when listing source code buffers.") - -(defconst buffer-source-code-timeout 2 - "Number of seconds to wait before invalidating the cycle.") - -(cl-defstruct source-code-cycle cycle last-called) - -(defun buffer-emacs-generated? (name) - "Return t if buffer, NAME, is an Emacs-generated buffer. -Some buffers are Emacs-generated but are surrounded by whitespace." - (let ((trimmed (s-trim name))) - (and (s-starts-with? "*" trimmed)))) - -(defun buffer-find (buffer-or-name) - "Find a buffer by its BUFFER-OR-NAME." - (get-buffer buffer-or-name)) - -(defun buffer-major-mode (name) - "Return the active `major-mode' in buffer, NAME." - (with-current-buffer (buffer-find name) - major-mode)) - -(defun buffer-source-code-buffers () - "Return a list of source code buffers. -This will ignore Emacs-generated buffers, like *Messages*. It will also ignore - any buffer whose major mode is defined in `buffer-source-code-blacklist'." - (->> (buffer-list) - (list-map #'buffer-name) - (list-reject #'buffer-emacs-generated?) - (list-reject (lambda (name) - (set-contains? (buffer-major-mode name) - buffer-source-code-blacklist))))) - -(defvar buffer-source-code-cycle-state - (make-source-code-cycle - :cycle (cycle-from-list (buffer-source-code-buffers)) - :last-called (ts-now)) - "State used to manage cycling between source code buffers.") - -(defun buffer-exists? (name) - "Return t if buffer, NAME, exists." - (maybe-some? (buffer-find name))) - -(defun buffer-new (name) - "Return a newly created buffer NAME." - (generate-new-buffer name)) - -(defun buffer-find-or-create (name) - "Find or create buffer, NAME. -Return a reference to that buffer." - (let ((x (buffer-find name))) - (if (maybe-some? x) - x - (buffer-new name)))) - -;; TODO: Should this consume: `display-buffer' or `switch-to-buffer'? -(defun buffer-show (buffer-or-name) - "Display the BUFFER-OR-NAME, which is either a buffer reference or its name." - (display-buffer buffer-or-name)) - -;; TODO: Move this and `buffer-cycle-prev' into a separate module that -;; encapsulates all of this behavior. - -(defun buffer-cycle (cycle-fn) - "Using CYCLE-FN, move through `buffer-source-code-buffers'." - (let ((last-called (source-code-cycle-last-called - buffer-source-code-cycle-state)) - (cycle (source-code-cycle-cycle - buffer-source-code-cycle-state))) - (if (> (ts-diff (ts-now) last-called) - buffer-source-code-timeout) - (progn - (struct-set! source-code-cycle - cycle - (cycle-from-list (buffer-source-code-buffers)) - buffer-source-code-cycle-state) - (let ((cycle (source-code-cycle-cycle - buffer-source-code-cycle-state))) - (funcall cycle-fn cycle) - (switch-to-buffer (cycle-current cycle))) - (struct-set! source-code-cycle - last-called - (ts-now) - buffer-source-code-cycle-state)) - (progn - (funcall cycle-fn cycle) - (switch-to-buffer (cycle-current cycle)))))) - -(defun buffer-cycle-next () - "Cycle forward through the `buffer-source-code-buffers'." - (interactive) - (buffer-cycle #'cycle-next!)) - -(defun buffer-cycle-prev () - "Cycle backward through the `buffer-source-code-buffers'." - (interactive) - (buffer-cycle #'cycle-prev!)) - -(defun buffer-ivy-source-code () - "Use `ivy-read' to choose among all open source code buffers." - (interactive) - (ivy-read "Source code buffer: " - (-concat buffer-ivy-source-code-whitelist - (-drop 1 (buffer-source-code-buffers))) - :sort nil - :action #'switch-to-buffer)) - -(defun buffer-show-previous () - "Call `switch-to-buffer' on the previously visited buffer. -This function ignores Emacs-generated buffers, i.e. the ones that look like - this: *Buffer*. It also ignores buffers that are `dired-mode' or `erc-mode'. - This blacklist can easily be changed." - (interactive) - (let* ((xs (buffer-source-code-buffers)) - (candidate (list-get 1 xs))) - (prelude-assert (maybe-some? candidate)) - (switch-to-buffer candidate))) - -(provide 'buffer) -;;; buffer.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/clipboard.el b/users/wpcarro/emacs/.emacs.d/wpc/clipboard.el deleted file mode 100644 index ec2a46f54..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/clipboard.el +++ /dev/null @@ -1,40 +0,0 @@ -;;; clipboard.el --- Working with X11's pasteboard -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Simple functions for copying and pasting. -;; -;; Integrate with bburns/clipmon so that System Clipboard can integrate with -;; Emacs's kill-ring. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'cl-lib) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(cl-defun clipboard-copy (x &key (message "[clipboard.el] Copied!")) - "Copy string, X, to X11's clipboard and `message' MESSAGE." - (kill-new x) - (message message)) - -(cl-defun clipboard-paste (&key (message "[clipboard.el] Pasted!")) - "Paste contents of X11 clipboard and `message' MESSAGE." - (yank) - (message message)) - -(defun clipboard-contents () - "Return the contents of the clipboard as a string." - (substring-no-properties (current-kill 0))) - -(provide 'clipboard) -;;; clipboard.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/constants.el b/users/wpcarro/emacs/.emacs.d/wpc/constants.el deleted file mode 100644 index 48bcd9042..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/constants.el +++ /dev/null @@ -1,29 +0,0 @@ -;;; constants.el --- Constants for organizing my Elisp -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; This file contains constants that are shared across my configuration. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'maybe) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst constants-ci? (maybe-some? (getenv "CI")) - "Defined as t when Emacs is running in CI.") - -(defconst constants-osx? (eq system-type 'darwin) - "Defined as t when OSX is running.") - -(provide 'constants) -;;; constants.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/display.el b/users/wpcarro/emacs/.emacs.d/wpc/display.el deleted file mode 100644 index 69dae6939..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/display.el +++ /dev/null @@ -1,103 +0,0 @@ -;;; display.el --- Working with single or multiple displays -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Mostly wrappers around xrandr. -;; -;; Troubleshooting: -;; The following commands help me when I (infrequently) interact with xrandr. -;; - xrandr --listmonitors -;; - xrandr --query - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'prelude) -(require 'dash) -(require 's) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(cl-defmacro display-register (name &key - output - primary - coords - size - rate - dpi - rotate) - "Macro to define constants and two functions for {en,dis}abling a display. - -NAME - the human-readable identifier for the display -OUTPUT - the xrandr identifier for the display -PRIMARY - if true, send --primary flag to xrandr -COORDS - X and Y offsets -SIZE - the pixel resolution of the display (width height) -RATE - the refresh rate -DPI - the pixel density in dots per square inch -rotate - one of {normal,left,right,inverted} - -See the man-page for xrandr for more details." - `(progn - (defconst ,(intern (format "display-%s" name)) ,output - ,(format "The xrandr identifier for %s" name)) - (defconst ,(intern (format "display-%s-args" name)) - ,(replace-regexp-in-string - "\s+" " " - (s-format "--output ${output} ${primary-flag} --auto \ - --size ${size-x}x${size-y} --rate ${rate} --dpi ${dpi} \ - --rotate ${rotate} ${pos-flag}" - #'aget - `(("output" . ,output) - ("primary-flag" . ,(if primary "--primary" "--noprimary")) - ("pos-flag" . ,(if coords - (format "--pos %dx%d" - (car coords) - (cadr coords)) - "")) - ("size-x" . ,(car size)) - ("size-y" . ,(cadr size)) - ("rate" . ,rate) - ("dpi" . ,dpi) - ("rotate" . ,rotate)))) - ,(format "The arguments we pass to xrandr for display-%s." name)) - (defconst ,(intern (format "display-%s-command" name)) - (format "xrandr %s" ,(intern (format "display-%s-args" name))) - ,(format "The command we run to configure %s" name)) - (defun ,(intern (format "display-enable-%s" name)) () - ,(format "Attempt to enable my %s monitor" name) - (interactive) - (prelude-start-process - :name ,(format "display-enable-%s" name) - :command ,(intern (format "display-%s-command" name)))) - (defun ,(intern (format "display-disable-%s" name)) () - ,(format "Attempt to disable my %s monitor." name) - (interactive) - (prelude-start-process - :name ,(format "display-disable-%s" name) - :command ,(format - "xrandr --output %s --off" - output))))) - -(defmacro display-arrangement (name &key displays) - "Create a function, display-arrange-, to enable all your DISPLAYS." - `(defun ,(intern (format "display-arrange-%s" name)) () - (interactive) - (prelude-start-process - :name ,(format "display-configure-%s" name) - :command ,(format "xrandr %s" - (->> displays - (-map (lambda (x) - (eval (intern (format "display-%s-args" x))))) - (s-join " ")))))) - -(provide 'display) -;;; display.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/email.el b/users/wpcarro/emacs/.emacs.d/wpc/email.el deleted file mode 100644 index a83ca25e6..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/email.el +++ /dev/null @@ -1,76 +0,0 @@ -;;; email.el --- My email settings -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Attempting to configure to `notmuch' for my personal use. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'notmuch) -(require 'list) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(setq notmuch-saved-searches - '((:name "inbox" :query "tag:inbox" :key "i") - (:name "direct" - :query "tag:direct and tag:unread and not tag:sent" - :key "d") - (:name "action" :query "tag:action" :key "a") - (:name "review" :query "tag:review" :key "r") - (:name "waiting" :query "tag:waiting" :key "w") - (:name "broadcast" :query "tag:/broadcast\/.+/ and tag:unread" :key "b") - (:name "systems" :query "tag:/systems\/.+/ and tag:unread" :key "s") - (:name "sent" :query "tag:sent" :key "t") - (:name "drafts" :query "tag:draft" :key "D"))) - -;; Sort results from newest-to-oldest. -(setq notmuch-search-oldest-first nil) - -;; Discard noisy email signatures. -(setq notmuch-mua-cite-function #'message-cite-original-without-signature) - -;; By default, this is just '("-inbox") -(setq notmuch-archive-tags '("-inbox" "-unread" "+archive")) - -;; Show saved searches even when they're empty. -(setq notmuch-show-empty-saved-searches t) - -;; Currently the sendmail executable on my system is symlinked to msmtp. -(setq send-mail-function #'sendmail-send-it) - -;; I'm not sure if I need this or not. Copying it from tazjin@'s monorepo. -(setq notmuch-always-prompt-for-sender nil) - -;; Add the "User-Agent" header to my emails and ensure that it includes Emacs -;; and notmuch information. -(setq notmuch-mua-user-agent-function - (lambda () - (format "Emacs %s; notmuch.el %s" emacs-version notmuch-emacs-version))) - -;; I was informed that Gmail does this server-side -(setq notmuch-fcc-dirs nil) - -;; Ensure buffers are closed after sending mail. -(setq message-kill-buffer-on-exit t) - -;; Ensure sender is correctly passed to msmtp. -(setq mail-specify-envelope-from t - message-sendmail-envelope-from 'header - mail-envelope-from 'header) - -;; Assert that no two saved searches share share a KBD -(prelude-assert - (list-xs-distinct-by? (lambda (x) (plist-get x :key)) notmuch-saved-searches)) - -(provide 'email) -;;; email.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/fonts.el b/users/wpcarro/emacs/.emacs.d/wpc/fonts.el deleted file mode 100644 index 0f70f69c2..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/fonts.el +++ /dev/null @@ -1,99 +0,0 @@ -;;; fonts.el --- Font preferences -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Control my font preferences with ELisp. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'maybe) -(require 'cl-lib) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Constants -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgroup fonts nil - "Customize group for fonts configuration.") - -(defcustom fonts-size "10" - "My preferred default font-size." - :group 'fonts) - -(defcustom fonts-size-step 10 - "The amount (%) by which to increase or decrease a font." - :group 'fonts) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun fonts-set (font &optional size) - "Change the font to `FONT' with option integer, SIZE, in pixels." - (if (maybe-some? size) - (set-frame-font (string-format "%s %s" font size) nil t) - (set-frame-font font nil t))) - -(defun fonts-current () - "Return the currently enabled font." - (symbol-name (font-get (face-attribute 'default :font) :family))) - -(defun fonts-increase-size () - "Increase font size." - (interactive) - (->> (face-attribute 'default :height) - (+ fonts-size-step) - (set-face-attribute 'default (selected-frame) :height))) - -(defun fonts-decrease-size () - "Decrease font size." - (interactive) - (->> (face-attribute 'default :height) - (+ (- fonts-size-step)) - (set-face-attribute 'default (selected-frame) :height))) - -(defun fonts-reset-size () - "Restore font size to its default value." - (interactive) - (fonts-set (fonts-current) fonts-size)) - -(defun fonts-enable-ligatures () - "Call this function to enable ligatures." - (interactive) - (let ((alist '((33 . ".\\(?:\\(?:==\\|!!\\)\\|[!=]\\)") - (35 . ".\\(?:###\\|##\\|_(\\|[#(?[_{]\\)") ;; - (36 . ".\\(?:>\\)") - (37 . ".\\(?:\\(?:%%\\)\\|%\\)") - (38 . ".\\(?:\\(?:&&\\)\\|&\\)") - (42 . ".\\(?:\\(?:\\*\\*/\\)\\|\\(?:\\*[*/]\\)\\|[*/>]\\)") ;; - (43 . ".\\(?:\\(?:\\+\\+\\)\\|[+>]\\)") - (45 . ".\\(?:\\(?:-[>-]\\|<<\\|>>\\)\\|[<>}~-]\\)") - (46 . ".\\(?:\\(?:\\.[.<]\\)\\|[.=-]\\)") ;; - (47 . ".\\(?:\\(?:\\*\\*\\|//\\|==\\)\\|[*/=>]\\)") - (48 . ".\\(?:x[a-zA-Z]\\)") - (58 . ".\\(?:::\\|[:=]\\)") - (59 . ".\\(?:;;\\|;\\)") - (60 . ".\\(?:\\(?:!--\\)\\|\\(?:~~\\|->\\|\\$>\\|\\*>\\|\\+>\\|--\\|<[<=-]\\|=[<=>]\\||>\\)\\|[*$+~/<=>|-]\\)") - (61 . ".\\(?:\\(?:/=\\|:=\\|<<\\|=[=>]\\|>>\\)\\|[<=>~]\\)") - (62 . ".\\(?:\\(?:=>\\|>[=>-]\\)\\|[=>-]\\)") - (63 . ".\\(?:\\(\\?\\?\\)\\|[:=?]\\)") - (91 . ".\\(?:]\\)") - (92 . ".\\(?:\\(?:\\\\\\\\\\)\\|\\\\\\)") - (94 . ".\\(?:=\\)") - (119 . ".\\(?:ww\\)") - (123 . ".\\(?:-\\)") - (124 . ".\\(?:\\(?:|[=|]\\)\\|[=>|]\\)") - (126 . ".\\(?:~>\\|~~\\|[>=@~-]\\)")))) - (dolist (char-regexp alist) - (set-char-table-range composition-function-table (car char-regexp) - `([,(cdr char-regexp) 0 font-shape-gstring]))))) - -(provide 'fonts) -;;; fonts.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/ivy-helpers.el b/users/wpcarro/emacs/.emacs.d/wpc/ivy-helpers.el deleted file mode 100644 index 3303237d5..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/ivy-helpers.el +++ /dev/null @@ -1,67 +0,0 @@ -;;; ivy-helpers.el --- More interfaces to ivy -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Hopefully to improve my workflows. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'tuple) -(require 'string) -(require 'cl-lib) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(cl-defun ivy-helpers-kv (prompt kv f) - "PROMPT users with the keys in KV and return its corresponding value. - -Apply key and value from KV to F." - (ivy-read - prompt - kv - :require-match t - :action (lambda (entry) - (funcall f (car entry) (cdr entry))))) - -(defun ivy-helpers-do-run-external-command (cmd) - "Execute the specified CMD and notify the user when it finishes." - (message "Starting %s..." cmd) - (set-process-sentinel - (start-process-shell-command cmd nil cmd) - (lambda (process event) - (when (string= event "finished\n") - (message "%s process finished." process))))) - -(defun ivy-helpers-list-external-commands () - "Create a list of all external commands available on $PATH." - (cl-loop - for dir in (split-string (getenv "PATH") path-separator) - when (and (file-exists-p dir) (file-accessible-directory-p dir)) - for lsdir = (cl-loop for i in (directory-files dir t) - for bn = (file-name-nondirectory i) - when (and (not (s-contains? "-wrapped" i)) - (not (member bn completions)) - (not (file-directory-p i)) - (file-executable-p i)) - collect bn) - append lsdir into completions - finally return (sort completions 'string-lessp))) - -(defun ivy-helpers-run-external-command () - "Prompts the user with a list of all installed applications to launch." - (interactive) - (let ((external-commands-list (ivy-helpers-list-external-commands))) - (ivy-read "Command:" external-commands-list - :require-match t - :action #'ivy-helpers-do-run-external-command))) - -;;; Code: -(provide 'ivy-helpers) -;;; ivy-helpers.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/kbd.el b/users/wpcarro/emacs/.emacs.d/wpc/kbd.el deleted file mode 100644 index 7defc3d08..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/kbd.el +++ /dev/null @@ -1,85 +0,0 @@ -;;; kbd.el --- Elisp keybinding -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; In order to stay organized, I'm attempting to dedicate KBD prefixes to -;; specific functions. I'm hoping I can be more deliberate with my keybinding -;; choices this way. -;; -;; Terminology: -;; For a more thorough overview of the terminology refer to `keybindings.md' -;; file. Here's a brief overview: -;; - workspace: Anything concerning EXWM workspaces. -;; - x11: Anything concerning X11 applications. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'prelude) -(require 'al) -(require 'set) -(require 'string) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Constants -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst kbd-prefixes - '((workspace . "s") - (x11 . "C-s")) - "Mapping of functions to designated keybinding prefixes to stay organized.") - -;; Assert that no keybindings are colliding. -(prelude-assert - (= (al-count kbd-prefixes) - (->> kbd-prefixes - al-values - set-from-list - set-count))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun kbd-raw (f x) - "Return the string keybinding for function F and appendage X. -Values for F include: -- workspace -- x11" - (prelude-assert (al-has-key? f kbd-prefixes)) - (string-format - "%s-%s" - (al-get f kbd-prefixes) - x)) - -(defun kbd-for (f x) - "Return the `kbd' for function F and appendage X. -Values for F include: -- workspace -- x11" - (kbd (kbd-raw f x))) - -;; TODO: Prefer copying human-readable versions to the clipboard. Right now -;; this isn't too useful. -(defun kbd-copy-keycode () - "Copy the pressed key to the system clipboard." - (interactive) - (message "[kbd] Awaiting keypress...") - (let ((key (read-key))) - (clipboard-copy (string-format "%s" key)) - (message (string-format "[kbd] \"%s\" copied!" key)))) - -(defun kbd-print-keycode () - "Prints the pressed keybinding." - (interactive) - (message "[kbd] Awaiting keypress...") - (message (string-format "[kbd] keycode: %s" (read-key)))) - -(provide 'kbd) -;;; kbd.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/keybindings.el b/users/wpcarro/emacs/.emacs.d/wpc/keybindings.el deleted file mode 100644 index a55bf2733..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/keybindings.el +++ /dev/null @@ -1,495 +0,0 @@ -;;; keybindings.el --- Centralizing my keybindings -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; Attempting to centralize my keybindings to simplify my configuration. -;; -;; I have some expectations about my keybindings. Here are some of those -;; defined: -;; - In insert mode: -;; - C-a: beginning-of-line -;; - C-e: end-of-line -;; - C-b: backwards-char -;; - C-f: forwards-char - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'screen-brightness) -(require 'pulse-audio) -(require 'scrot) -(require 'ivy) -(require 'ivy-clipmenu) -(require 'ivy-helpers) -(require 'general) -(require 'exwm) -(require 'vterm-mgt) -(require 'buffer) -(require 'fonts) -(require 'bookmark) -(require 'tvl) -(require 'window-manager) - -;; Note: The following lines must be sorted this way. -(setq evil-want-integration t) -(setq evil-want-keybinding nil) -(general-evil-setup) -(require 'evil) -(require 'evil-collection) -(require 'evil-commentary) -(require 'evil-surround) -(require 'key-chord) -(require 'edebug) -(require 'avy) -(require 'passage) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Helper Functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun keybindings--window-vsplit-right () - "Split the window vertically and focus the right half." - (interactive) - (evil-window-vsplit) - (windmove-right)) - -(defun keybindings--window-split-down () - "Split the window horizontal and focus the bottom half." - (interactive) - (evil-window-split) - (windmove-down)) - -(defun keybindings--create-snippet () - "Create a window split and then opens the Yasnippet editor." - (interactive) - (evil-window-vsplit) - (call-interactively #'yas-new-snippet)) - -(defun keybindings--replace-under-point () - "Faster than typing %s//thing/g." - (interactive) - (let ((term (s-replace "/" "\\/" (symbol-to-string (symbol-at-point))))) - (save-excursion - (evil-ex (concat "%s/\\b" term "\\b/"))))) - -(defun keybindings--evil-ex-define-cmd-local (cmd f) - "Define CMD to F locally to a buffer." - (unless (local-variable-p 'evil-ex-commands) - (setq-local evil-ex-commands (copy-alist evil-ex-commands))) - (evil-ex-define-cmd cmd f)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; General Keybindings -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Ensure that evil's command mode behaves with readline bindings. -(general-define-key - :keymaps 'evil-ex-completion-map - "C-a" #'move-beginning-of-line - "C-e" #'move-end-of-line - "C-k" #'kill-line - "C-u" #'evil-delete-whole-line - "C-v" #'evil-paste-after - "C-d" #'delete-char - "C-f" #'forward-char - "M-b" #'backward-word - "M-f" #'forward-word - "M-d" #'kill-word - "M-DEL" #'backward-kill-word - "C-b" #'backward-char) - -(general-mmap - :keymaps 'override - "RET" #'evil-goto-line - "H" #'evil-first-non-blank - "L" #'evil-end-of-line - "_" #'ranger - "-" #'dired-jump - "sl" #'keybindings--window-vsplit-right - "sh" #'evil-window-vsplit - "sk" #'evil-window-split - "sj" #'keybindings--window-split-down) - -(general-nmap - :keymaps 'override - "gu" #'browse-url-at-point - "gd" #'xref-find-definitions - ;; Wrapping `xref-find-references' in the `let' binding to prevent xref from - ;; prompting. There are other ways to handle this variable, such as setting - ;; it globally with `setq' or buffer-locally with `setq-local'. For now, I - ;; prefer setting it with `let', which should bind it in the dynamic scope - ;; for the duration of the `xref-find-references' function call. - "gx" (lambda () - (interactive) - (let ((xref-prompt-for-identifier nil)) - (call-interactively #'xref-find-references)))) - -(general-unbind 'motion "M-." "C-p" "") -(general-unbind 'normal "s" "M-." "C-p" "C-n") -(general-unbind 'insert "C-v" "C-d" "C-a" "C-e" "C-n" "C-p" "C-k") - -(customize-set-variable 'evil-symbol-word-search t) -(evil-mode 1) -(evil-collection-init) -(evil-commentary-mode) -(global-evil-surround-mode 1) - -;; Ensure the Evil search results get centered vertically. -;; When Emacs is run from a terminal, this forces Emacs to redraw itself, which -;; is visually disruptive. -(when window-system - (progn - (defadvice isearch-update - (before advice-for-isearch-update activate) - (evil-scroll-line-to-center (line-number-at-pos))) - (defadvice evil-search-next - (after advice-for-evil-search-next activate) - (evil-scroll-line-to-center (line-number-at-pos))) - (defadvice evil-search-previous - (after advice-for-evil-search-previous activate) - (evil-scroll-line-to-center (line-number-at-pos))))) - -(general-define-key - :keymaps '(isearch-mode-map) - "C-p" #'isearch-ring-retreat - "C-n" #'isearch-ring-advance - "" #'isearch-ring-retreat - "" #'isearch-ring-advance) - -(general-define-key - :keymaps '(minibuffer-local-isearch-map) - "C-p" #'previous-line-or-history-element - "C-n" #'next-line-or-history-element - "" #'previous-line-or-history-element - "" #'next-line-or-history-element) - -(key-chord-mode 1) -(key-chord-define evil-insert-state-map "jk" 'evil-normal-state) - -;; This may be contraversial, but I never use the prefix key, and I'd prefer to -;; have to bound to the readline function that deletes the entire line. -(general-unbind "C-u") - -(defmacro keybindings-exwm (c fn) - "Bind C to FN using `exwm-input-set-key' with `kbd' applied to C." - `(exwm-input-set-key (kbd ,c) ,fn)) - -(keybindings-exwm "C-M-v" #'ivy-clipmenu-copy) -(keybindings-exwm "" #'screen-brightness-increase) -(keybindings-exwm "" #'screen-brightness-decrease) -(keybindings-exwm "" #'pulse-audio-toggle-mute) -(keybindings-exwm "" #'pulse-audio-decrease-volume) -(keybindings-exwm "" #'pulse-audio-increase-volume) -(keybindings-exwm "" #'pulse-audio-toggle-microphone) -(keybindings-exwm (kbd-raw 'x11 "s") #'scrot-select) -(keybindings-exwm "" #'window-manager-switch-to-exwm-buffer) -(keybindings-exwm (kbd-raw 'workspace "k") #'fonts-increase-size) -(keybindings-exwm (kbd-raw 'workspace "j") #'fonts-decrease-size) -(keybindings-exwm (kbd-raw 'workspace "0") #'fonts-reset-size) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Window sizing -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(keybindings-exwm "C-M-=" #'balance-windows) -(keybindings-exwm "C-M-j" #'shrink-window) -(keybindings-exwm "C-M-k" #'enlarge-window) -(keybindings-exwm "C-M-h" #'shrink-window-horizontally) -(keybindings-exwm "C-M-l" #'enlarge-window-horizontally) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Window Management -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(keybindings-exwm "M-h" #'windmove-left) -(keybindings-exwm "M-j" #'windmove-down) -(keybindings-exwm "M-k" #'windmove-up) -(keybindings-exwm "M-l" #'windmove-right) -(keybindings-exwm "M-\\" #'evil-window-vsplit) -(keybindings-exwm "M--" #'evil-window-split) -(keybindings-exwm "M-q" #'delete-window) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Miscellaneous -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(keybindings-exwm "M-:" #'eval-expression) -(keybindings-exwm "M-SPC" #'ivy-helpers-run-external-command) -(keybindings-exwm "M-x" #'counsel-M-x) -(keybindings-exwm "" #'window-manager-next-workspace) -(keybindings-exwm "" #'window-manager-prev-workspace) -(keybindings-exwm "C-S-f" #'window-manager-toggle-previous) -(keybindings-exwm "C-M-\\" #'passage-select) - -(defun keybindings-copy-emoji () - "Select an emoji from the completing-read menu." - (interactive) - (clipboard-copy (emojify-completing-read "Copy: "))) - -(keybindings-exwm "s-e" #'keybindings-copy-emoji) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Workspaces -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(keybindings-exwm (kbd-raw 'workspace "l") - (lambda () - (interactive) - (shell-command window-manager-screenlocker))) - -(general-define-key - :keymaps 'override - "M-q" #'delete-window - "" #'toggle-frame-fullscreen - "M-h" #'windmove-left - "M-l" #'windmove-right - "M-k" #'windmove-up - "M-j" #'windmove-down - "M-q" #'delete-window) - -;; Support pasting in M-:. -(general-define-key - :keymaps 'read-expression-map - "C-v" #'clipboard-yank - "C-S-v" #'clipboard-yank) - -(general-define-key - :prefix "" - :states '(normal) - "." #'ffap - "gn" #'notmuch - "i" #'counsel-semantic-or-imenu - "I" #'ibuffer - "hk" #'helpful-callable - "hf" #'helpful-function - "hm" #'helpful-macro - "hc" #'helpful-command - "hk" #'helpful-key - "hv" #'helpful-variable - "hp" #'helpful-at-point - "hi" #'info-apropos - "s" #'flyspell-mode - "S" #'sort-lines - "=" #'align - "p" #'flycheck-previous-error - "f" #'project-find-file - "n" #'flycheck-next-error - "N" #'smerge-next - "W" #'balance-windows - "gss" #'magit-status - "gsd" #'tvl-depot-status - "E" #'refine - "es" #'keybindings--create-snippet - "l" #'linum-mode - "B" #'magit-blame - "w" #'save-buffer - "r" #'keybindings--replace-under-point - "R" #'deadgrep) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Vterm -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Show or hide a vterm buffer. I'm intentionally not defining this in -;; vterm-mgt.el because it consumes `buffer-show-previous', and I'd like to -;; avoid bloating vterm-mgt.el with dependencies that others may not want. -(general-define-key (kbd-raw 'x11 "t") - (lambda () - (interactive) - (if (vterm-mgt--instance? (current-buffer)) - (switch-to-buffer (first (buffer-source-code-buffers))) - (call-interactively #'vterm-mgt-find-or-create)))) - -(general-define-key - :keymaps '(vterm-mode-map) - ;; For some reason vterm captures this KBD instead of EXWM - "C-S-f" nil - "s-x" #'vterm-mgt-select - "C-S-n" #'vterm-mgt-instantiate - "C-S-w" #'vterm-mgt-kill - "" #'vterm-mgt-next - "" #'vterm-mgt-prev - "" #'vterm-mgt-rename-buffer - ;; Without this, typing "+" is effectively no-op. Try for yourself: - ;; (vterm-send-key "") - "" "+" - "M--" #'evil-window-split - "M-\\" #'evil-window-vsplit) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; notmuch -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; evil-collection adds many KBDs to notmuch modes. Some of these I find -;; disruptive. -(general-define-key - :states '(normal) - :keymaps '(notmuch-show-mode-map) - "M-j" nil - "M-k" nil - "" #'notmuch-show-previous-thread-show - "" #'notmuch-show-next-thread-show - "e" #'notmuch-show-archive-message-then-next-or-next-thread) - -(add-hook 'notmuch-message-mode-hook - (lambda () - (keybindings--evil-ex-define-cmd-local "x" #'notmuch-mua-send-and-exit))) - -;; For now, I'm mimmicking Gmail KBDs that I have memorized and enjoy -(general-define-key - :states '(normal visual) - :keymaps '(notmuch-search-mode-map) - "M" (lambda () - (interactive) - (notmuch-search-tag '("-inbox" "+muted"))) - "mi" (lambda () - (interactive) - (notmuch-search-tag '("+inbox" "-action" "-review" "-waiting" "-muted"))) - "ma" (lambda () - (interactive) - (notmuch-search-tag '("-inbox" "+action" "-review" "-waiting"))) - "mr" (lambda () - (interactive) - (notmuch-search-tag '("-inbox" "-action" "+review" "-waiting"))) - "mw" (lambda () - (interactive) - (notmuch-search-tag '("-inbox" "-action" "-review" "+waiting"))) - "e" #'notmuch-search-archive-thread) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; magit -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(general-define-key - :states '(normal) - :keymaps '(magit-status-mode-map - magit-log-mode-map - magit-revision-mode-map) - "l" #'evil-forward-char - "L" #'magit-log) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Info-mode -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; NOTE: I find some of the following, existing KBDs useful: -;; M-x info-apropos -;; u Info-up -;; M-n clone-buffer -(general-define-key - :states '(normal) - :keymaps '(Info-mode-map) - "SPC" nil - "g SPC" #'Info-scroll-up - "RET" #'Info-follow-nearest-node - "" #'Info-next - "" #'Info-prev - "g l" #'Info-history-back - "g t" #'Info-toc) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ibuffer -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(general-define-key - :states '(normal) - :keymaps '(ibuffer-mode-map) - "M-j" nil - "K" #'ibuffer-do-delete) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; buffers -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(general-define-key - :states '(normal) - "C-f" #'buffer-cycle-next - "C-b" #'buffer-cycle-prev) - -(general-define-key - :prefix "" - :states '(normal) - "b" #'buffer-ivy-source-code - "" #'buffer-show-previous - "k" #'kill-buffer) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; edebug -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(general-define-key - :states '(normal) - :keymaps '(edebug-mode-map) - ;; this restores my ability to move-left while debugging - "h" nil) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; deadgrep -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(general-define-key - :states '(normal) - :keymaps '(deadgrep-mode-map) - "" #'deadgrep-forward - "" #'deadgrep-backward) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; bookmarks -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(bookmark-install-kbd - (make-bookmark :label "wpcarro" - :path (f-join tvl-depot-path "users/wpcarro") - :kbd "w")) - -(bookmark-install-kbd - (make-bookmark :label "depot" - :path tvl-depot-path - :kbd "d")) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; refine -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(general-define-key - :keymaps '(refine-mode-map) - :states '(normal) - "K" #'refine-delete - "q" #'kill-this-buffer) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; avy -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(global-set-key (kbd "C-;") #'avy-goto-char) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; ivy -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; restore the ability to paste in ivy -(general-define-key - :keymaps '(ivy-minibuffer-map) - "C-k" #'kill-line - "C-u" (lambda () (interactive) (kill-line 0)) - "C-v" #'clipboard-yank - "C-S-v" #'clipboard-yank) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Rust -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(general-define-key - :keymaps '(rust-mode-map) - :states '(normal) - "gd" #'lsp-find-definition - "gr" #'lsp-find-references) - -(general-define-key - :keymaps '(rust-mode-map) - "TAB" #'company-indent-or-complete-common) - -(provide 'keybindings) -;;; keybindings.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/keyboard.el b/users/wpcarro/emacs/.emacs.d/wpc/keyboard.el deleted file mode 100644 index 0ee00e1b8..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/keyboard.el +++ /dev/null @@ -1,138 +0,0 @@ -;;; keyboard.el --- Managing keyboard preferences with Elisp -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Setting key repeat and other values. -;; -;; Be wary of suspiciously round numbers. Especially those divisible by ten! - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'cl-lib) -(require 'prelude) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Constants -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO: Support clamping functions for repeat-{rate,delay} to ensure only valid -;; values are sent to xset. -(defcustom keyboard-repeat-rate 80 - "The number of key repeat signals sent per second.") - -(defcustom keyboard-repeat-delay 170 - "The number of milliseconds before autorepeat starts.") - -(defconst keyboard-repeat-rate-copy keyboard-repeat-rate - "Copy of `keyboard-repeat-rate' to support `keyboard-reset-key-repeat'.") - -(defconst keyboard-repeat-delay-copy keyboard-repeat-delay - "Copy of `keyboard-repeat-delay' to support `keyboard-reset-key-repeat'.") - -(defcustom keyboard-install-preferences? t - "When t, install keyboard preferences.") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun keyboard-message (x) - "Message X in a structured way." - (message (format "[keyboard.el] %s" x))) - -(cl-defun keyboard-set-key-repeat (&key - (rate keyboard-repeat-rate) - (delay keyboard-repeat-delay)) - "Use xset to set the key-repeat RATE and DELAY." - (prelude-start-process - :name "keyboard-set-key-repeat" - :command (format "xset r rate %s %s" delay rate))) - -;; NOTE: Settings like this are machine-dependent. For instance I only need to -;; do this on my laptop and other devices where I don't have access to my split -;; keyboard. -;; NOTE: Running keysym Caps_Lock is not idempotent. If this is called more -;; than once, xmodmap will start to error about non-existent Caps_Lock symbol. -;; For more information see here: -;; https://unix.stackexchange.com/questions/108207/how-to-map-caps-lock-as-the-compose-key-using-xmodmap-portably-and-idempotently -(defun keyboard-swap-caps-lock-and-escape () - "Swaps the caps lock and escape keys using xmodmap." - (interactive) - ;; TODO: Ensure these work once the tokenizing in prelude-start-process works - ;; as expected. - (start-process "keyboard-swap-caps-lock-and-escape" - nil "/usr/bin/xmodmap" "-e" "remove Lock = Caps_Lock") - (start-process "keyboard-swap-caps-lock-and-escape" - nil "/usr/bin/xmodmap" "-e" "keysym Caps_Lock = Escape")) - -(defun keyboard-inc-repeat-rate () - "Increment `keyboard-repeat-rate'." - (interactive) - (setq keyboard-repeat-rate (1+ keyboard-repeat-rate)) - (keyboard-set-key-repeat :rate keyboard-repeat-rate) - (keyboard-message - (format "Rate: %s" keyboard-repeat-rate))) - -(defun keyboard-dec-repeat-rate () - "Decrement `keyboard-repeat-rate'." - (interactive) - (setq keyboard-repeat-rate (1- keyboard-repeat-rate)) - (keyboard-set-key-repeat :rate keyboard-repeat-rate) - (keyboard-message - (format "Rate: %s" keyboard-repeat-rate))) - -(defun keyboard-inc-repeat-delay () - "Increment `keyboard-repeat-delay'." - (interactive) - (setq keyboard-repeat-delay (1+ keyboard-repeat-delay)) - (keyboard-set-key-repeat :delay keyboard-repeat-delay) - (keyboard-message - (format "Delay: %s" keyboard-repeat-delay))) - -(defun keyboard-dec-repeat-delay () - "Decrement `keyboard-repeat-delay'." - (interactive) - (setq keyboard-repeat-delay (1- keyboard-repeat-delay)) - (keyboard-set-key-repeat :delay keyboard-repeat-delay) - (keyboard-message - (format "Delay: %s" keyboard-repeat-delay))) - -(defun keyboard-print-key-repeat () - "Print the currently set values for key repeat." - (interactive) - (keyboard-message - (format "Rate: %s. Delay: %s" - keyboard-repeat-rate - keyboard-repeat-delay))) - -(defun keyboard-set-preferences () - "Reset the keyboard preferences to their default values. -NOTE: This function exists because occasionally I unplug and re-plug in a - keyboard and all of the preferences that I set using xset disappear." - (interactive) - (keyboard-swap-caps-lock-and-escape) - (keyboard-set-key-repeat :rate keyboard-repeat-rate - :delay keyboard-repeat-delay) - ;; TODO: Implement this message function as a macro that pulls the current - ;; file name. - (keyboard-message "Keyboard preferences set!")) - -(defun keyboard-reset-key-repeat () - "Set key repeat rate and delay to original values." - (interactive) - (keyboard-set-key-repeat :rate keyboard-repeat-rate-copy - :delay keyboard-repeat-delay-copy) - (keyboard-message "Key repeat preferences reset.")) - -(when keyboard-install-preferences? - (keyboard-set-preferences)) - -(provide 'keyboard) -;;; keyboard.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/modeline.el b/users/wpcarro/emacs/.emacs.d/wpc/modeline.el deleted file mode 100644 index df1cddec9..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/modeline.el +++ /dev/null @@ -1,68 +0,0 @@ -;;; modeline.el --- Customize my mode-line -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; Because I use EXWM, I treat my Emacs mode-line like my system bar: I need to -;; quickly check the system time, and I expect it to be at the bottom-right of -;; my Emacs frame. I used doom-modeline for awhile, which is an impressive -;; package, but it conditionally colorizes on the modeline for the active -;; buffer. So if my bottom-right window is inactive, I cannot see the time. -;; -;; My friend, @tazjin, has a modeline setup that I think is more compatible with -;; EXWM, so I'm going to base my setup off of his. - -;;; Code: - -(use-package telephone-line) - -(defun modeline-bottom-right-window? () - "Determines whether the last (i.e. -bottom-right) window of the -active frame is showing the buffer in which this function is - executed." - (let* ((frame (selected-frame)) - (right-windows (window-at-side-list frame 'right)) - (bottom-windows (window-at-side-list frame 'bottom)) - (last-window (car (seq-intersection right-windows bottom-windows)))) - (eq (current-buffer) (window-buffer last-window)))) - -(defun modeline-maybe-render-time () - "Conditionally renders the `mode-line-misc-info' string. - - The idea is to not display information like the current time, - load, battery levels on all buffers." - (when (modeline-bottom-right-window?) - (telephone-line-raw mode-line-misc-info t))) - -(defun modeline-setup () - "Render my custom modeline." - (telephone-line-defsegment telephone-line-last-window-segment () - (modeline-maybe-render-time)) - ;; Display the current EXWM workspace index in the mode-line - (telephone-line-defsegment telephone-line-exwm-workspace-index () - (when (modeline-bottom-right-window?) - (format "[%s]" exwm-workspace-current-index))) - ;; Define a highlight font for ~ important ~ information in the last - ;; window. - (defface special-highlight - '((t (:foreground "white" :background "#5f627f"))) "") - (add-to-list 'telephone-line-faces - '(highlight . (special-highlight . special-highlight))) - (setq telephone-line-lhs - '((nil . (telephone-line-position-segment)) - (accent . (telephone-line-buffer-segment)))) - (setq telephone-line-rhs - '((accent . (telephone-line-major-mode-segment)) - (nil . (telephone-line-last-window-segment - telephone-line-exwm-workspace-index)))) - (setq telephone-line-primary-left-separator 'telephone-line-tan-left - telephone-line-primary-right-separator 'telephone-line-tan-right - telephone-line-secondary-left-separator 'telephone-line-tan-hollow-left - telephone-line-secondary-right-separator 'telephone-line-tan-hollow-right) - (telephone-line-mode 1)) - -(provide 'modeline) -;;; modeline.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/prelude.el b/users/wpcarro/emacs/.emacs.d/wpc/prelude.el deleted file mode 100644 index 4a332cb8c..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/prelude.el +++ /dev/null @@ -1,144 +0,0 @@ -;;; prelude.el --- My attempt at augmenting Elisp stdlib -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Some of these ideas are scattered across other modules like `fs', -;; `string-functions', etc. I'd like to keep everything modular. I still don't -;; have an answer for which items belond in `misc'; I don't want that to become -;; a dumping grounds. Ideally this file will `require' all other modules and -;; define just a handful of functions. - -;; TODO: Consider removing all dependencies from prelude.el. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'dash) -(require 's) -(require 'f) -(require 'cl-lib) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Utilities -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun prelude-to-string (x) - "Convert X to a string." - (format "%s" x)) - -(defun prelude-inspect (&rest args) - "Message ARGS where ARGS are any type." - (->> args - (-map #'prelude-to-string) - (apply #'s-concat) - message)) - -(defmacro prelude-call-process-to-string (cmd &rest args) - "Return the string output of CMD called with ARGS." - `(with-temp-buffer - (call-process ,cmd nil (current-buffer) nil ,@args) - (buffer-string))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Assertions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO: Should I `throw' instead of `error' here? -(defmacro prelude-assert (x) - "Errors unless X is t. -These are strict assertions and purposely do not rely on truthiness." - (let ((as-string (prelude-to-string x))) - `(unless (equal t ,x) - (error (s-concat "Assertion failed: " ,as-string))))) - -(defmacro prelude-refute (x) - "Errors unless X is nil." - (let ((as-string (prelude-to-string x))) - `(unless (equal nil ,x) - (error (s-concat "Refutation failed: " ,as-string))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Adapter functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun prelude-identity (x) - "Return X unchanged." - x) - -(defun prelude-const (x) - "Return a variadic lambda that will return X." - (lambda (&rest _) x)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Miscellaneous -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO: Consider packaging these into a linum-color.el package. -;; TODO: Generate the color used here from the theme. -(defvar prelude--linum-safe? nil - "Flag indicating whether it is safe to work with function `linum-mode'.") - -(defvar prelude--linum-mru-color nil - "Stores the color most recently attempted to be applied.") - -(add-hook 'linum-mode-hook - (lambda () - (setq prelude--linum-safe? t) - (when (maybe-some? prelude--linum-mru-color) - (set-face-foreground 'linum prelude--linum-mru-color)))) - -(defun prelude-set-line-number-color (color) - "Safely set linum color to `COLOR'. - -If this is called before Emacs initializes, the color will be stored in -`prelude--linum-mru-color' and applied once initialization completes. - -Why is this safe? -If `(set-face-foreground 'linum)' is called before initialization completes, -Emacs will silently fail. Without this function, it is easy to introduce -difficult to troubleshoot bugs in your init files." - (if prelude--linum-safe? - (set-face-foreground 'linum color) - (setq prelude--linum-mru-color color))) - -(defun prelude-prompt (prompt) - "Read input from user with PROMPT." - (read-string prompt)) - -(cl-defun prelude-start-process (&key name command) - "Pass command string, COMMAND, and the function name, NAME. -This is a wrapper around `start-process' that has an API that resembles -`shell-command'." - ;; TODO: Fix the bug with tokenizing here, since it will split any whitespace - ;; character, even though it shouldn't in the case of quoted string in shell. - ;; e.g. - "xmodmap -e 'one two three'" => '("xmodmap" "-e" "'one two three'") - (prelude-refute (s-contains? "'" command)) - (let* ((tokens (s-split " " command)) - (program-name (nth 0 tokens)) - (program-args (cdr tokens))) - (apply #'start-process - `(,(format "*%s<%s>*" program-name name) - ,nil - ,program-name - ,@program-args)))) - -(defun prelude-executable-exists? (name) - "Return t if CLI tool NAME exists according to the variable `exec-path'." - (let ((file (locate-file name exec-path))) - (require 'maybe) - (if (maybe-some? file) - (f-exists? file) - nil))) - -(defmacro prelude-time (x) - "Print the time it takes to evaluate X." - `(benchmark 1 ',x)) - -(provide 'prelude) -;;; prelude.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/pulse-audio.el b/users/wpcarro/emacs/.emacs.d/wpc/pulse-audio.el deleted file mode 100644 index eaa610659..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/pulse-audio.el +++ /dev/null @@ -1,69 +0,0 @@ -;;; pulse-audio.el --- Control audio with Elisp -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Because everything in my configuration is turning into Elisp these days. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'prelude) -(require 'string) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Constants -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst pulse-audio--step-size 5 - "The size by which to increase or decrease the volume.") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun pulse-audio--message (x) - "Output X to *Messages*." - (message (string-format "[pulse-audio.el] %s" x))) - -(defun pulse-audio-toggle-mute () - "Mute the default sink." - (interactive) - (prelude-start-process - :name "pulse-audio-toggle-mute" - :command "pactl set-sink-mute @DEFAULT_SINK@ toggle") - (pulse-audio--message "Mute toggled.")) - -(defun pulse-audio-toggle-microphone () - "Mute the default sink." - (interactive) - (prelude-start-process - :name "pulse-audio-toggle-microphone" - :command "pactl set-source-mute @DEFAULT_SOURCE@ toggle") - (pulse-audio--message "Microphone toggled.")) - -(defun pulse-audio-decrease-volume () - "Low the volume output of the default sink." - (interactive) - (prelude-start-process - :name "pulse-audio-decrease-volume" - :command (string-format "pactl set-sink-volume @DEFAULT_SINK@ -%s%%" - pulse-audio--step-size)) - (pulse-audio--message "Volume decreased.")) - -(defun pulse-audio-increase-volume () - "Raise the volume output of the default sink." - (interactive) - (prelude-start-process - :name "pulse-audio-increase-volume" - :command (string-format "pactl set-sink-volume @DEFAULT_SINK@ +%s%%" - pulse-audio--step-size)) - (pulse-audio--message "Volume increased.")) - -(provide 'pulse-audio) -;;; pulse-audio.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/region.el b/users/wpcarro/emacs/.emacs.d/wpc/region.el deleted file mode 100644 index 0b692981f..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/region.el +++ /dev/null @@ -1,23 +0,0 @@ -;;; region.el --- Functions for working with regions -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Sometimes Emacs's function names and argument ordering is great; other times, -;; it isn't. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun region-to-string () - "Return the string in the active region." - (buffer-substring-no-properties (region-beginning) - (region-end))) - -(provide 'region) -;;; region.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/screen-brightness.el b/users/wpcarro/emacs/.emacs.d/wpc/screen-brightness.el deleted file mode 100644 index 851be9f99..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/screen-brightness.el +++ /dev/null @@ -1,57 +0,0 @@ -;;; screen-brightness.el --- Control laptop screen brightness -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Control your laptop's screen brightness. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'prelude) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Constants -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgroup screen-brightness nil "Configuration for screen-brightness.") - -(defcustom screen-brightness-increase-cmd - "light -A 3" - "The shell command to run to increase screen brightness." - :group 'screen-brightness - :type 'string) - -(defcustom screen-brightness-decrease-cmd - "light -U 3" - "The shell command to run to decrease screen brightness." - :group 'screen-brightness - :type 'string) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun screen-brightness-increase () - "Increase the screen brightness." - (interactive) - (prelude-start-process - :name "screen-brightness-increase" - :command screen-brightness-increase-cmd) - (message "[screen-brightness.el] Increased screen brightness.")) - -(defun screen-brightness-decrease () - "Decrease the screen brightness." - (interactive) - (prelude-start-process - :name "screen-brightness-decrease" - :command screen-brightness-decrease-cmd) - (message "[screen-brightness.el] Decreased screen brightness.")) - -(provide 'screen-brightness) -;;; screen-brightness.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/scrot.el b/users/wpcarro/emacs/.emacs.d/wpc/scrot.el deleted file mode 100644 index 08994fea5..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/scrot.el +++ /dev/null @@ -1,54 +0,0 @@ -;;; scrot.el --- Screenshot functions -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; scrot is a Linux utility for taking screenshots. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'f) -(require 'string) -(require 'ts) -(require 'clipboard) -(require 'kbd) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst scrot-screenshot-directory "~/Downloads" - "The default directory for screenshot outputs.") - -(defconst scrot-output-format "screenshot_%H:%M:%S_%Y-%m-%d.png" - "The format string for the output screenshot file. -See scrot's man page for more information.") - -(defun scrot--copy-image (path) - "Use xclip to copy the image at PATH to the clipboard. -This currently only works for PNG files because that's what I'm outputting" - (call-process "xclip" nil nil nil - "-selection" "clipboard" "-t" "image/png" path) - (message (string-format "[scrot.el] Image copied to clipboard!"))) - -(defun scrot-select () - "Click-and-drag to screenshot a region. -The output path is copied to the user's clipboard." - (interactive) - (let ((screenshot-path (f-join scrot-screenshot-directory - (ts-format scrot-output-format (ts-now))))) - (make-process - :name "scrot-select" - :command `("scrot" "--select" ,screenshot-path) - :sentinel (lambda (proc _err) - (when (= 0 (process-exit-status proc)) - (scrot--copy-image screenshot-path)))))) - -(provide 'scrot) -;;; scrot.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/ssh.el b/users/wpcarro/emacs/.emacs.d/wpc/ssh.el deleted file mode 100644 index 1179e9036..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/ssh.el +++ /dev/null @@ -1,67 +0,0 @@ -;;; ssh.el --- When working remotely -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Configuration to make remote work easier. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'tramp) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO: Is "ssh" preferable to "scp"? -(setq tramp-default-method "ssh") - -;; Taken from: https://superuser.com/questions/179313/tramp-waiting-for-prompts-from-remote-shell -(setq tramp-shell-prompt-pattern "^[^$>\n]*[#$%>] *\\(\[[0-9;]*[a-zA-Z] *\\)*") - -;; Sets the value of the TERM variable to "dumb" when logging into the remote -;; host. This allows me to check for the value of "dumb" in my shell's init file -;; and control the startup accordingly. You can see in the (shamefully large) -;; commit, 0b4ef0e, that I added a check like this to my ~/.zshrc. I've since -;; switched from z-shell to fish. I don't currently have this check in -;; config.fish, but I may need to add it one day soon. -(setq tramp-terminal-type "dumb") - -;; Maximizes the tramp debugging noisiness while I'm still learning about tramp. -(setq tramp-verbose 10) - -;; As confusing as this may seem, this forces Tramp to use *my* .ssh/config -;; options, which enable ControlMaster. In other words, disabling this actually -;; enables ControlMaster. -(setq tramp-use-ssh-controlmaster-options nil) - -(defcustom ssh-hosts '("wpcarro@wpcarro.dev" - "foundation" - "edge") - "List of hosts to which I commonly connect.") - -(defun ssh-sudo-buffer () - "Open the current buffer with sudo rights." - (interactive) - (with-current-buffer (current-buffer) - (if (s-starts-with? "/ssh:" buffer-file-name) - (pcase (s-split ":" buffer-file-name) - (`(,one ,two ,three) (find-file (format "/ssh:%s|sudo:%s:%s" two two three)))) - (find-file - (s-join ":" (-insert-at 2 "|sudo" (s-split ":" buffer-file-name)))) - (find-file (format "/sudo::%s" buffer-file-name))))) - -(defun ssh-cd-home () - "Prompt for an SSH host and open a dired buffer for wpcarro on that machine." - (interactive) - (let ((machine (completing-read "Machine: " ssh-hosts))) - (find-file (format "/ssh:%s:~" machine)))) - -(provide 'ssh) -;;; ssh.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/window-manager.el b/users/wpcarro/emacs/.emacs.d/wpc/window-manager.el deleted file mode 100644 index 94fb99d42..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/window-manager.el +++ /dev/null @@ -1,228 +0,0 @@ -;;; window-manager.el --- Functions augmenting my usage of EXWM -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; I switched to EXWM from i3, and I haven't looked back. One day I may write a -;; poem declaring my love for Emacs and EXWM. For now, I haven't the time. - -;; Wist List: -;; - TODO: Consider supporting MRU cache of worksapces. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'alert) -(require 'cycle) -(require 'dash) -(require 'kbd) -(require 's) -(require 'exwm) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Variables -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgroup window-manager nil - "Customization options for `window-manager'.") - -(cl-defstruct window-manager-named-workspace - label kbd display) - -(defcustom window-manager-named-workspaces nil - "List of `window-manager-named-workspace' structs." - :group 'window-manager - :type (list 'window-manager-named-workspace)) - -(defcustom window-manager-screenlocker "xsecurelock" - "Reference to a screen-locking executable." - :group 'window-manager - :type 'string) - -(defvar window-manager--workspaces nil - "Cycle of the my EXWM workspaces.") - -(defconst window-manager--modes - (cycle-from-list (list #'window-manager--char-mode - #'window-manager--line-mode)) - "Functions to switch exwm modes.") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun window-manager--alert (x) - "Message X with a structured format." - (alert (s-concat "[exwm] " x))) - -(cl-defun window-manager-init (&key init-hook) - "Call `exwm-enable' alongside other bootstrapping functions." - (require 'exwm-config) - (require 'exwm-randr) - (setq exwm-randr-workspace-monitor-plist - (->> window-manager-named-workspaces - (-map-indexed (lambda (i x) - (list i (window-manager-named-workspace-display x)))) - -flatten)) - (setq exwm-workspace-number (length window-manager-named-workspaces)) - (setq exwm-input-simulation-keys - '(([?\C-b] . [left]) - ([?\M-b] . [C-left]) - ([?\C-f] . [right]) - ([?\M-f] . [C-right]) - ([?\C-p] . [up]) - ([?\C-n] . [down]) - ([?\C-a] . [home]) - ([?\C-e] . [end]) - ([?\C-d] . [delete]) - ([?\C-c] . [C-c]))) - ;; Install workspace KBDs - (progn - (->> window-manager-named-workspaces - (list-map #'window-manager--register-kbd)) - (window-manager--alert "Registered workspace KBDs!")) - ;; Ensure exwm apps open in char-mode. - (add-hook 'exwm-manage-finish-hook #'window-manager--char-mode) - (add-hook 'exwm-init-hook init-hook) - (setq window-manager--workspaces - (cycle-from-list window-manager-named-workspaces)) - (exwm-randr-enable) - (exwm-enable)) - -(defun window-manager-next-workspace () - "Cycle forwards to the next workspace." - (interactive) - (window-manager--change-workspace (cycle-next! window-manager--workspaces))) - -(defun window-manager-prev-workspace () - "Cycle backwards to the previous workspace." - (interactive) - (window-manager--change-workspace (cycle-prev! window-manager--workspaces))) - -;; Here is the code required to toggle EXWM's modes. -(defun window-manager--line-mode () - "Switch exwm to line-mode." - (call-interactively #'exwm-input-grab-keyboard) - (window-manager--alert "Switched to line-mode")) - -(defun window-manager--char-mode () - "Switch exwm to char-mode." - (call-interactively #'exwm-input-release-keyboard) - (window-manager--alert "Switched to char-mode")) - -(defun window-manager-toggle-mode () - "Switch between line- and char- mode." - (interactive) - (with-current-buffer (window-buffer) - (when (eq major-mode 'exwm-mode) - (funcall (cycle-next! window-manager--modes))))) - -(defun window-manager--label->index (label workspaces) - "Return the index of the workspace in WORKSPACES named LABEL." - (let ((index (-elem-index label (-map #'window-manager-named-workspace-label - workspaces)))) - (if index index (error (format "No workspace found for label: %s" label))))) - -(defun window-manager--register-kbd (workspace) - "Registers a keybinding for WORKSPACE struct. -Currently using super- as the prefix for switching workspaces." - (let ((handler (lambda () - (interactive) - (window-manager--switch - (window-manager-named-workspace-label workspace)))) - (key (window-manager-named-workspace-kbd workspace))) - (exwm-input-set-key - (kbd-for 'workspace key) - handler))) - -(defun window-manager--change-workspace (workspace) - "Switch EXWM workspaces to the WORKSPACE struct." - (exwm-workspace-switch - (window-manager--label->index - (window-manager-named-workspace-label workspace) - window-manager-named-workspaces)) - (window-manager--alert - (format "Switched to: %s" - (window-manager-named-workspace-label workspace)))) - -(defun window-manager--switch (label) - "Switch to a named workspaces using LABEL." - (cycle-focus! (lambda (x) - (equal label - (window-manager-named-workspace-label x))) - window-manager--workspaces) - (window-manager--change-workspace (cycle-current window-manager--workspaces))) - -(defun window-manager-toggle-previous () - "Focus the previously active EXWM workspace." - (interactive) - (window-manager--change-workspace - (cycle-focus-previous! window-manager--workspaces))) - -(defun window-manager--exwm-buffer? (x) - "Return t if buffer X is an EXWM buffer." - (equal 'exwm-mode (buffer-local-value 'major-mode x))) - -(defun window-manager--application-name (buffer) - "Return the name of the application running in the EXWM BUFFER. -This function asssumes that BUFFER passes the `window-manager--exwm-buffer?' -predicate." - (with-current-buffer buffer exwm-class-name)) - -;; TODO: Support disambiguating between two or more instances of the same -;; application. For instance if two `exwm-class-name' values are -;; "Google-chrome", find a encode this information in the `buffer-alist'. -(defun window-manager-switch-to-exwm-buffer () - "Use `completing-read' to focus an EXWM buffer." - (interactive) - (let* ((buffer-alist (->> (buffer-list) - (-filter #'window-manager--exwm-buffer?) - (-map - (lambda (buffer) - (cons (window-manager--application-name buffer) - buffer))))) - (label (completing-read "Switch to EXWM buffer: " buffer-alist))) - (exwm-workspace-switch-to-buffer - (al-get label buffer-alist)))) - -(defun window-manager-current-workspace () - "Output the label of the currently active workspace." - (->> window-manager--workspaces - cycle-current - window-manager-named-workspace-label)) - -(defun window-manager-workspace-move () - "Prompt the user to move the current workspace to another." - (interactive) - (exwm-workspace-move - exwm-workspace--current - (window-manager--label->index - (completing-read "Move current workspace to: " - (->> window-manager-named-workspaces - (-map #'window-manager-named-workspace-label)) - nil - t) - window-manager-named-workspaces))) - -(defun window-manager-move-window () - "Prompt the user to move the current window to another workspace." - (interactive) - (let ((window (get-buffer-window)) - (dest (completing-read "Move current window to: " - (->> window-manager-named-workspaces - (-map #'window-manager-named-workspace-label)) - nil - t))) - (exwm-workspace-move-window - (exwm-workspace--workspace-from-frame-or-index - (window-manager--label->index dest window-manager-named-workspaces)) - (exwm--buffer->id window)) - (window-manager--switch dest))) - -(provide 'window-manager) -;;; window-manager.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-clojure.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-clojure.el deleted file mode 100644 index 5582641b3..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-clojure.el +++ /dev/null @@ -1,71 +0,0 @@ -;;; wpc-clojure.el --- My Clojure preferences -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; Hosting my Clojure tooling preferences - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'general) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(use-package clojure-mode - :config - ;; from Ryan Schmukler: - (setq cljr-magic-require-namespaces - '(("io" . "clojure.java.io") - ("sh" . "clojure.java.shell") - ("jdbc" . "clojure.java.jdbc") - ("set" . "clojure.set") - ("time" . "java-time") - ("str" . "cuerdas.core") - ("path" . "pathetic.core") - ("walk" . "clojure.walk") - ("zip" . "clojure.zip") - ("async" . "clojure.core.async") - ("component" . "com.stuartsierra.component") - ("http" . "clj-http.client") - ("url" . "cemerick.url") - ("sql" . "honeysql.core") - ("csv" . "clojure.data.csv") - ("json" . "cheshire.core") - ("s" . "clojure.spec.alpha") - ("fs" . "me.raynes.fs") - ("ig" . "integrant.core") - ("cp" . "com.climate.claypoole") - ("re-frame" . "re-frame.core") - ("rf" . "re-frame.core") - ("re" . "reagent.core") - ("reagent" . "reagent.core") - ("u.core" . "utopia.core") - ("gen" . "clojure.spec.gen.alpha")))) - -(use-package cider - :config - (general-define-key - :keymaps 'cider-repl-mode-map - "C-l" #'cider-repl-clear-buffer - "C-u" #'kill-whole-line - "" #'cider-repl-previous-input - "" #'cider-repl-next-input) - (general-define-key - :keymaps 'clojure-mode-map - :states '(normal) - :prefix "" - "x" #'cider-eval-defun-at-point - "X" #'cider-eval-buffer - "d" #'cider-symbol-at-point) - (setq cider-prompt-for-symbol nil)) - -(provide 'wpc-clojure) -;;; wpc-clojure.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-company.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-company.el deleted file mode 100644 index 89fde4b6a..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-company.el +++ /dev/null @@ -1,41 +0,0 @@ -;;; wpc-company.el --- Autocompletion package, company, preferences -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; Hosts my company mode preferences - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'general) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; autocompletion client -(use-package company - :config - (general-define-key - :keymaps 'company-active-map - "C-j" #'company-select-next - "C-n" #'company-select-next - "C-k" #'company-select-previous - "C-p" #'company-select-previous - "C-d" #'company-show-doc-buffer) - (setq company-tooltip-align-annotations t) - (setq company-idle-delay 0) - (setq company-show-numbers t) - (setq company-minimum-prefix-length 2) - (setq company-dabbrev-downcase nil - company-dabbrev-ignore-case t) - (global-company-mode)) - -(provide 'wpc-company) -;;; wpc-company.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-dired.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-dired.el deleted file mode 100644 index 7c22a4657..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-dired.el +++ /dev/null @@ -1,51 +0,0 @@ -;;; wpc-dired.el --- My dired preferences -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; File management in Emacs, if learned and configured properly, should be -;; capable to reduce my dependency on the terminal. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'macros) -(require 'general) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(progn - (require 'dired) - (setq dired-recursive-copies 'always - dired-recursive-deletes 'top) - (setq dired-listing-switches "-la --group-directories-first") - (general-define-key - :keymaps 'dired-mode-map - :states '(normal) - ;; Overriding some KBDs defined in the evil-collection module. - "o" #'dired-find-file-other-window - "" nil ;; This unblocks some of my leader-prefixed KBDs. - "s" nil ;; This unblocks my window-splitting KBDs. - "c" #'find-file - "f" #'project-find-file - "-" (lambda () (interactive) (find-alternate-file ".."))) - (general-add-hook 'dired-mode-hook - (list (macros-enable dired-hide-details-mode) - #'auto-revert-mode))) - -(progn - (require 'locate) - (general-define-key - :keymaps 'locate-mode-map - :states 'normal - "o" #'dired-find-file-other-window)) - -(provide 'wpc-dired) -;;; wpc-dired.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-dotnet.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-dotnet.el deleted file mode 100644 index 03fc430e4..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-dotnet.el +++ /dev/null @@ -1,16 +0,0 @@ -;;; wpc-dotnet.el --- C# and company -*- lexical-binding: t -*- - -;; Author: William Carroll - -;;; Commentary: -;; Windows things v0v. - -;;; Code: - -(require 'macros) - -(use-package csharp-mode) -(macros-support-file-extension "csproj" xml-mode) - -(provide 'wpc-dotnet) -;;; wpc-dotnet.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-elixir.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-elixir.el deleted file mode 100644 index 69259274c..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-elixir.el +++ /dev/null @@ -1,27 +0,0 @@ -;;; wpc-elixir.el --- Elixir / Erland configuration -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; My preferences for working with Elixir / Erlang projects - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'macros) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(use-package elixir-mode - :config - (macros-add-hook-before-save 'elixir-mode-hook #'elixir-format)) - -(provide 'wpc-elixir) -;;; wpc-elixir.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-flycheck.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-flycheck.el deleted file mode 100644 index c32c5daef..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-flycheck.el +++ /dev/null @@ -1,17 +0,0 @@ -;;; wpc-flycheck.el --- My flycheck configuration -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Hosts my Flycheck preferences - -;;; Code: - -(use-package flycheck - :config - (global-flycheck-mode)) - -(provide 'wpc-flycheck) -;;; wpc-flycheck.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-golang.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-golang.el deleted file mode 100644 index 47198c8e0..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-golang.el +++ /dev/null @@ -1,42 +0,0 @@ -;;; wpc-golang.el --- Tooling preferences for Go -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Tooling support for golang development. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'prelude) -(require 'macros) -(require 'general) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO: Support jumping to go source code for fmt.Println, etc. - -(use-package go-mode - :config - (setq gofmt-command "goimports") - ;; TODO: Consider configuring `xref-find-definitions' to use `godef-jump' - ;; instead of shadowing the KBD here. - (general-define-key - :states '(normal) - :keymaps '(go-mode-map) - "M-." #'godef-jump) - ;; Support calling M-x `compile'. - (add-hook 'go-mode-hook (lambda () - (setq-local tab-width 2) - (setq-local compile-command "go build -v"))) - (macros-add-hook-before-save 'go-mode-hook #'gofmt-before-save)) - -(provide 'wpc-golang) -;;; wpc-golang.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-haskell.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-haskell.el deleted file mode 100644 index 536790e36..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-haskell.el +++ /dev/null @@ -1,53 +0,0 @@ -;;; wpc-haskell.el --- My Haskell preferences -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Hosts my Haskell development preferences - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'macros) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; font-locking, glyph support, etc -(use-package haskell-mode - :config - (macros-add-hook-before-save 'haskell-mode #'haskell-align-imports)) - -;; Test toggling -(defun wpc-haskell-module->test () - "Jump from a module to a test." - (let ((filename (->> buffer-file-name - (s-replace "/src/" "/test/") - (s-replace ".hs" "Test.hs") - find-file))) - (make-directory (f-dirname filename) t) - (find-file filename))) - -(defun wpc-haskell-test->module () - "Jump from a test to a module." - (let ((filename (->> buffer-file-name - (s-replace "/test/" "/src/") - (s-replace "Test.hs" ".hs")))) - (make-directory (f-dirname filename) t) - (find-file filename))) - -(defun wpc-haskell-test<->module () - "Toggle between test and module in Haskell." - (interactive) - (if (s-contains? "/src/" buffer-file-name) - (wpc-haskell-module->test) - (wpc-haskell-test->module))) - -(provide 'wpc-haskell) -;;; wpc-haskell.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-javascript.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-javascript.el deleted file mode 100644 index 9e137ad88..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-javascript.el +++ /dev/null @@ -1,93 +0,0 @@ -;;; wpc-javascript.el --- My Javascript preferences -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; This module hosts my Javascript tooling preferences. This also includes -;; tooling for TypeScript and other frontend tooling. Perhaps this module will -;; change names to more accurately reflect that. -;; -;; Depends -;; - yarn global add prettier - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'general) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; Constants -(defconst wpc-javascript--js-hooks - '(js-mode-hook - web-mode-hook - typescript-mode-hook - js2-mode-hook - rjsx-mode-hook) - "All of the commonly used hooks for Javascript buffers.") - -(defconst wpc-javascript--frontend-hooks - (-insert-at 0 'css-mode-hook wpc-javascript--js-hooks) - "All of the commonly user hooks for frontend development.") - -;; frontend indentation settings -(setq typescript-indent-level 2 - js-indent-level 2 - css-indent-offset 2) - -(use-package web-mode - :mode "\\.html\\'" - :config - (setq web-mode-css-indent-offset 2) - (setq web-mode-code-indent-offset 2) - (setq web-mode-markup-indent-offset 2)) - -;; JSX highlighting -(use-package rjsx-mode - :config - (general-unbind rjsx-mode-map "<" ">" "C-d") - (general-nmap - :keymaps 'rjsx-mode-map - "K" #'flow-minor-type-at-pos) - (setq js2-mode-show-parse-errors nil - js2-mode-show-strict-warnings nil)) - -(progn - (defun wpc-javascript-tide-setup () - (interactive) - (tide-setup) - (flycheck-mode 1) - (setq flycheck-check-syntax-automatically '(save mode-enabled)) - (eldoc-mode 1) - (tide-hl-identifier-mode 1) - (company-mode 1)) - (use-package tide - :config - (add-hook 'typescript-mode-hook #'wpc-javascript-tide-setup)) - (require 'web-mode) - (add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode)) - (add-hook 'web-mode-hook - (lambda () - (when (string-equal "tsx" (f-ext buffer-file-name)) - (wpc-javascript-tide-setup)))) - (flycheck-add-mode 'typescript-tslint 'web-mode)) - -;; JS autoformatting -(use-package prettier-js - :config - (general-add-hook wpc-javascript--frontend-hooks #'prettier-js-mode)) - -;; Support Elm -(use-package elm-mode - :config - (add-hook 'elm-mode-hook #'elm-format-on-save-mode)) - -(provide 'wpc-javascript) -;;; wpc-javascript.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-language-support.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-language-support.el deleted file mode 100644 index 8363e3c08..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-language-support.el +++ /dev/null @@ -1,36 +0,0 @@ -;;; wpc-language-support.el --- Support for miscellaneous programming languages -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; I defined this module to declutter my init.el. -;; -;; When a particular programming-language's configuration gets too complicated, -;; I break it out into a dedicated module. Everything else gets dumped in -;; "Miscellaneous Configuration". - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dedicated Modules -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'wpc-lisp) -(require 'wpc-haskell) -(require 'wpc-elixir) -(require 'wpc-nix) -(require 'wpc-rust) -(require 'wpc-clojure) -(require 'wpc-prolog) -(require 'wpc-dotnet) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Miscellaneous Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(use-package terraform-mode) - -(provide 'wpc-language-support) -;;; wpc-language-support.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-lisp.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-lisp.el deleted file mode 100644 index 599d42620..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-lisp.el +++ /dev/null @@ -1,123 +0,0 @@ -;;; wpc-lisp.el --- Generic LISP preferences -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; parent (up) -;; child (down) -;; prev-sibling (left) -;; next-sibling (right) - -;;; Code: - -;; TODO: Consider having a separate module for each LISP dialect. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'general) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst wpc-lisp--hooks - '(lisp-mode-hook - emacs-lisp-mode-hook - clojure-mode-hook - clojurescript-mode-hook - racket-mode-hook) - "List of LISP modes.") - -(use-package sly - :config - (setq inferior-lisp-program "sbcl") - (general-define-key - :keymaps 'sly-mode-map - :states '(normal) - :prefix "" - "x" #'sly-eval-defun - "X" #'sly-eval-buffer - "d" #'sly-describe-symbol)) - -(use-package rainbow-delimiters - :config - (general-add-hook wpc-lisp--hooks #'rainbow-delimiters-mode)) - -(use-package racket-mode - :config - (general-define-key - :keymaps 'racket-mode-map - :states 'normal - :prefix "" - "x" #'racket-send-definition - "X" #'racket-run - "d" #'racket-describe) - (setq racket-program "~/.nix-profile/bin/racket")) - -(use-package lispyville - :init - (defconst wpc-lisp--lispyville-key-themes - '(c-w - operators - text-objects - prettify - commentary - slurp/barf-cp - wrap - additional - additional-insert - additional-wrap - escape) - "All available key-themes in Lispyville.") - :config - (general-add-hook wpc-lisp--hooks #'lispyville-mode) - (lispyville-set-key-theme wpc-lisp--lispyville-key-themes) - (progn - (general-define-key - :keymaps 'lispyville-mode-map - :states 'motion - ;; first unbind - "M-h" nil - "M-l" nil) - (general-define-key - :keymaps 'lispyville-mode-map - :states 'normal - ;; first unbind - "M-j" nil - "M-k" nil - ;; second rebind - "C-s-h" #'lispyville-drag-backward - "C-s-l" #'lispyville-drag-forward - "C-s-e" #'lispyville-end-of-defun - "C-s-a" #'lispyville-beginning-of-defun))) - -;; Elisp -(use-package elisp-slime-nav - :config - (general-add-hook 'emacs-lisp-mode #'ielm-mode)) - -(defun wpc-lisp-copy-elisp-eval-output () - "Copy the output of the elisp evaluation" - (interactive) - (call-interactively 'eval-last-sexp) - (clipboard-copy (current-message) - :message (format "%s - copied!" (current-message)))) - -(general-define-key - :keymaps 'emacs-lisp-mode-map - :prefix "" - :states 'normal - "c" #'wpc-lisp-copy-elisp-eval-output - "x" #'eval-defun - "X" #'eval-buffer - "d" (lambda () - (interactive) - (with-current-buffer (current-buffer) - (helpful-function (symbol-at-point))))) - -(provide 'wpc-lisp) -;;; wpc-lisp.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-misc.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-misc.el deleted file mode 100644 index 36fbf8b12..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-misc.el +++ /dev/null @@ -1,330 +0,0 @@ -;;; wpc-misc.el --- Hosting miscellaneous configuration -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; This is the home of any configuration that couldn't find a better home. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'project) -(require 'f) -(require 'dash) -(require 'tvl) -(require 'region) -(require 'general) -(require 'constants) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(setq display-time-string-forms - '((format-time-string "%H:%M %a %b %d"))) -(display-time-mode 1) - -;; Remove the boilerplate in the *scratch* buffer -(setq initial-scratch-message "") - -;; disable custom variable entries from being written to ~/.emacs.d/init.el -(setq custom-file (f-join user-emacs-directory "custom.el")) -(load custom-file 'noerror) - -;; integrate Emacs with X11 clipboard -(customize-set-variable 'select-enable-primary t) -(customize-set-variable 'select-enable-clipboard t) -(customize-set-variable 'evil-visual-update-x-selection-p nil) -(general-def 'insert - "s-v" #'clipboard-yank - "C-S-v" #'clipboard-yank) - -;; transparently edit compressed files -(auto-compression-mode t) - -;; autowrap when over the fill-column -(setq-default auto-fill-function #'do-auto-fill) - -;; link to Emacs source code -;; TODO: Update this link. -(setq find-function-C-source-directory - "~/Dropbox/programming/emacs/src") - -;; change emacs prompts from "yes or no" -> "y or n" -(fset 'yes-or-no-p 'y-or-n-p) - -;; open photos in Emacs -(auto-image-file-mode 1) - -;; disable line-wrapping -(setq-default truncate-lines 1) - -;; shell file indentation -(setq sh-basic-offset 2) -(setq sh-indentation 2) - -(use-package vterm - :config - (general-define-key - :keymaps '(vterm-mode-map) - :states '(insert) - "C-S-v" #'vterm-yank) - (general-define-key - :keymaps '(vterm-mode-map) - :states '(normal) - "K" #'evil-scroll-line-up - "J" #'evil-scroll-line-down - "C-b" #'evil-scroll-page-up - "C-f" #'evil-scroll-page-down)) - -;; Use en Emacs buffer as a REST client. -;; For more information: http://emacsrocks.com/e15.html -(use-package restclient) - -;; Run `package-lint' before publishing to MELPA. -(use-package package-lint) - -;; Parser combinators in Elisp. -(use-package parsec) - -;; disable company mode when editing markdown -;; TODO: move this out of wpc-misc.el and into a later file to call -;; `(disable company-mode)' -(use-package markdown-mode - :config - ;; TODO: Add assertion that pandoc is installed and it is accessible from - ;; Emacs. - (setq markdown-command "pandoc") - (setq markdown-split-window-direction 'right) - ;; (add-hook 'markdown-mode-hook #'markdown-live-preview-mode) - ;; Use mode-specific syntax highlighting for code blocks. - (setq markdown-fontify-code-blocks-natively t) - ;; Prevent Emacs from adding a space after the leading 3x-backticks. - (setq markdown-spaces-after-code-fence 0)) - -(use-package alert) - -(use-package refine) - -;; Required by some google-emacs package commands. -(use-package deferred) - -;; git integration -(use-package magit - :config - (add-hook 'git-commit-setup-hook - (lambda () - (company-mode -1) - (flyspell-mode 1))) - (setq magit-display-buffer-function - #'magit-display-buffer-same-window-except-diff-v1)) - -(use-package magit-popup) - -;; http -(use-package request) - -;; TVL depot stuff -(use-package tvl) - -;; perl-compatible regular expressions -(use-package pcre2el) - -;; alternative to help -(use-package helpful) - -;; If called from an existing helpful-mode buffer, reuse that buffer; otherwise, -;; call `pop-to-buffer'. -(setq helpful-switch-buffer-function - (lambda (buffer-or-name) - (if (eq major-mode 'helpful-mode) - (switch-to-buffer buffer-or-name) - (pop-to-buffer buffer-or-name)))) - -;; Emacs integration with direnv -(use-package direnv - :config - (direnv-mode)) - -;; Superior Elisp library for working with dates and times. -;; TODO: Put this where my other installations for dash.el, s.el, a.el, and -;; other utility Elisp libraries are located. -(use-package ts) - -;; persist history etc b/w Emacs sessions -(setq desktop-save 'if-exists) -(desktop-save-mode 1) -(setq desktop-globals-to-save - (append '((extended-command-history . 30) - (file-name-history . 100) - (grep-history . 30) - (compile-history . 30) - (minibuffer-history . 50) - (query-replace-history . 60) - (read-expression-history . 60) - (regexp-history . 60) - (regexp-search-ring . 20) - (search-ring . 20) - (shell-command-history . 50) - tags-file-name - register-alist))) - -;; configure ibuffer -(setq ibuffer-default-sorting-mode 'major-mode) - -;; Emacs autosave, backup, interlocking files -(setq auto-save-default nil - make-backup-files nil - create-lockfiles nil) - -;; ensure code wraps at 80 characters by default -(setq-default fill-column 80) - -;; render tabs 2x-chars wide -(setq tab-width 2) - -(put 'narrow-to-region 'disabled nil) - -;; trim whitespace on save -(add-hook 'before-save-hook #'delete-trailing-whitespace) - -;; call `git secret hide` after saving secrets.json -(add-hook 'after-save-hook - (lambda () - (when (f-equal? (buffer-file-name) - (f-join tvl-depot-path - "users" - "wpcarro" - "secrets.json")) - (shell-command "git secret hide")))) - -;; use tabs instead of spaces -(setq-default indent-tabs-mode nil) - -;; prefer shorter tab-widths (e.g. writing Go code) -(setq-default tab-width 2) - -;; automatically follow symlinks -(setq vc-follow-symlinks t) - -;; fullscreen settings -(setq ns-use-native-fullscreen nil) - -(use-package yasnippet - :config - (unless constants-ci? - (setq yas-snippet-dirs (list (f-join user-emacs-directory "snippets"))) - (yas-global-mode 1))) - -(use-package projectile - :config - (projectile-mode t)) - -;; TODO(wpcarro): Consider replacing this with a TVL version if it exists. -(defun wpc-misc--depot-find (dir) - "Find the default.nix nearest to DIR." - ;; I use 'vc only at the root of my monorepo because 'transient doesn't use my - ;; .gitignore, which slows things down. Ideally, I could write a version that - ;; behaves like 'transient but also respects my monorepo's .gitignore and any - ;; ancestor .gitignore files. - (if (f-equal? tvl-depot-path dir) - (cons 'vc dir) - (when (f-ancestor-of? tvl-depot-path dir) - (if (f-exists? (f-join dir "default.nix")) - (cons 'transient dir) - (wpc-misc--depot-find (f-parent dir)))))) - -(add-to-list 'project-find-functions #'wpc-misc--depot-find) - -(defun wpc-misc-pkill (name) - "Call the pkill executable using NAME as its argument." - (interactive "sProcess name: ") - (call-process "pkill" nil nil nil name)) - -(use-package deadgrep - :config - (general-define-key - :keymaps 'deadgrep-mode-map - :states 'normal - "o" #'deadgrep-visit-result-other-window) - (setq-default deadgrep--context '(0 . 3)) - (defun wpc-misc-deadgrep-region () - "Run a ripgrep search on the active region." - (interactive) - (deadgrep (region-to-string))) - (defun wpc-misc-deadgrep-dwim () - "If a region is active, use that as the search, otherwise don't." - (interactive) - (with-current-buffer (current-buffer) - (if (region-active-p) - (setq deadgrep--additional-flags '("--multiline")) - (wpc-misc-deadgrep-region) - (call-interactively #'deadgrep)))) - (advice-add 'deadgrep--arguments - :filter-return - (lambda (args) - (push "--hidden" args) - (push "--follow" args)))) - -;; TODO: Do I need this when I have swiper? -(use-package counsel) - -(use-package counsel-projectile) - -;; search Google, Stackoverflow from within Emacs -(use-package engine-mode - :config - (defengine google - "http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s" - :keybinding "g") - (defengine stack-overflow - "https://stackoverflow.com/search?q=%s" - :keybinding "s")) - -;; EGlot (another LSP client) -(use-package eglot) - -;; Microsoft's Debug Adapter Protocol (DAP) -(use-package dap-mode - :after lsp-mode - :config - (dap-mode 1) - (dap-ui-mode 1)) - -;; Microsoft's Language Server Protocol (LSP) -(use-package lsp-ui - :config - (add-hook 'lsp-mode-hook #'lsp-ui-mode)) - -;; Wilfred/suggest.el - Tool for discovering functions basesd on declaring your -;; desired inputs and outputs. -(use-package suggest) - -;; Malabarba/paradox - Enhances the `list-packages' view. -(use-package paradox - :config - (paradox-enable)) - -;; render emojis in Emacs 🕺 -(use-package emojify - :config - (add-hook 'after-init-hook #'global-emojify-mode) - ;; Disable the default styles of: - ;; - ascii :P (When this is enabled, the vim command, :x, renders as 😶) - ;; - github :smile: - (setq emojify-emoji-styles '(unicode))) - -;; Always auto-close parantheses and other pairs -(electric-pair-mode) - -;; Start the Emacs server -(when (not (server-running-p)) - (server-start)) - -(provide 'wpc-misc) -;;; wpc-misc.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-nix.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-nix.el deleted file mode 100644 index e9dc20369..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-nix.el +++ /dev/null @@ -1,37 +0,0 @@ -;;; wpc-nix.el --- Nix support -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; Configuration to support working with Nix. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'tvl) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(use-package nix-mode - :mode "\\.nix\\'") - -(defun wpc-nix-rebuild-emacs () - "Use nix-env to rebuild wpcarros-emacs." - (interactive) - (let* ((pname (format "nix-env -iA users.wpcarro.emacs.nixos")) - (bname (format "*%s*" pname))) - (start-process pname bname - "nix-env" - "-f" tvl-depot-path - "-iA" "users.wpcarro.emacs.nixos") - (display-buffer bname))) - -(provide 'wpc-nix) -;;; wpc-nix.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-org.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-org.el deleted file mode 100644 index 229177220..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-org.el +++ /dev/null @@ -1,39 +0,0 @@ -;;; wpc-org.el --- My org preferences -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.1")) - -;;; Commentary: -;; Hosts my org mode preferences - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'f) -(require 'macros) -(require 'general) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(use-package org - :config - (evil-set-initial-state 'org-mode 'normal) - (general-add-hook 'org-mode-hook - (list (macros-disable linum-mode) - (macros-disable company-mode))) - (setq org-startup-folded nil) - (setq org-todo-keywords '((sequence "TODO" "BLOCKED" "DONE"))) - (general-unbind 'normal org-mode-map "M-h" "M-j" "M-k" "M-l")) - -(use-package org-bullets - :config - (general-add-hook 'org-mode-hook (macros-enable org-bullets-mode))) - -(provide 'wpc-org) -;;; wpc-org.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-package.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-package.el deleted file mode 100644 index 9c57bb427..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-package.el +++ /dev/null @@ -1,32 +0,0 @@ -;;; wpc-package.el --- My package configuration -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.1")) - -;;; Commentary: -;; This module hosts all of the settings required to work with ELPA, -;; MELPA, QUELPA, and co. - -;;; Code: - -(require 'package) - -;; Even though we're packaging our Emacs with Nix, having MELPA registered is -;; helpful to ad-hoc test out packages before declaratively adding them to -;; emacs/default.nix. -(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) -(package-initialize) - -(unless (package-installed-p 'use-package) - ;; TODO: Consider removing this to improve initialization speed. - (package-refresh-contents) - (package-install 'use-package)) -(eval-when-compile - (require 'use-package)) -;; TODO: Consider removing this, since I'm requiring general.el in individual -;; modules. -(use-package general) - -(provide 'wpc-package) -;;; wpc-package.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-prolog.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-prolog.el deleted file mode 100644 index 6779431c1..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-prolog.el +++ /dev/null @@ -1,19 +0,0 @@ -;;; wpc-prolog.el --- For Prologging things -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Code configuring my Prolog work. - -;;; Code: - -(require 'macros) - -;; TODO: Notice that the .pl extension conflicts with Perl files. This may -;; become a problem should I start working with Perl. -(macros-support-file-extension "pl" prolog-mode) - -(provide 'wpc-prolog) -;;; wpc-prolog.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-python.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-python.el deleted file mode 100644 index 9ffb7c4c8..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-python.el +++ /dev/null @@ -1,24 +0,0 @@ -;;; wpc-python.el --- Python configuration -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; My Python configuration settings -;; -;; Depends -;; - `apti yapf` - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(use-package py-yapf - :config - (add-hook 'python-mode-hook #'py-yapf-enable-on-save)) - -(provide 'wpc-python) -;;; wpc-python.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-rust.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-rust.el deleted file mode 100644 index b609efb43..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-rust.el +++ /dev/null @@ -1,30 +0,0 @@ -;;; wpc-rust.el --- Support Rust language -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Supports my Rust work. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'lsp) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(use-package rust-mode - :config - (setq lsp-rust-server #'rust-analyzer) - (setq rust-format-show-buffer nil) - (setq rust-format-on-save t) - (add-hook 'rust-mode-hook #'lsp)) - -(provide 'wpc-rust) -;;; wpc-rust.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-shell.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-shell.el deleted file mode 100644 index f4229ed32..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-shell.el +++ /dev/null @@ -1,31 +0,0 @@ -;;; wpc-shell.el --- POSIX Shell scripting support -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Helpers for my shell scripting. Includes bash, zsh, etc. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'zle) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Code -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(use-package flymake-shellcheck - :commands flymake-shellcheck-load - :init - (add-hook 'sh-mode-hook #'flymake-shellcheck-load) - (add-hook 'sh-mode-hook #'zle-minor-mode)) - -(use-package fish-mode) - -(provide 'wpc-shell) -;;; wpc-shell.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-ui.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-ui.el deleted file mode 100644 index a2f533cec..000000000 --- a/users/wpcarro/emacs/.emacs.d/wpc/wpc-ui.el +++ /dev/null @@ -1,186 +0,0 @@ -;;; wpc-ui.el --- Any related to the UI/UX goes here -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Hosts font settings, scrolling, color schemes. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require '>) -(require 'al) -(require 'constants) -(require 'dash) -(require 'fonts) -(require 'general) -(require 'modeline) -(require 'prelude) -(require 'theme) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; line height -(setq-default line-spacing 0) - -(when window-system - (setq frame-title-format '(buffer-file-name "%f" ("%b")))) - -;; Ensure that buffers update when their contents change on disk. -(global-auto-revert-mode t) - -;; smooth scrolling settings -(setq scroll-step 1 - scroll-conservatively 10000) - -;; clean up modeline -(use-package diminish - :config - (diminish 'emacs-lisp-mode "elisp") - (diminish 'evil-commentary-mode) - (diminish 'flycheck-mode) - (diminish 'auto-revert-mode) - (diminish 'which-key-mode) - (diminish 'yas-minor-mode) - (diminish 'lispyville-mode) - (diminish 'undo-tree-mode) - (diminish 'company-mode) - (diminish 'projectile-mode) - (diminish 'eldoc-mode) - ;; This is how to diminish `auto-fill-mode'. - (diminish 'auto-fill-function) - (diminish 'counsel-mode) - (diminish 'ivy-mode)) - -;; TODO: Further customize `mode-line-format' variable. -(delete 'mode-line-modes mode-line-format) -(delete '(vc-mode vc-mode) mode-line-format) - -;; disable startup screen -(setq inhibit-startup-screen t) - -;; disable toolbar -(tool-bar-mode -1) - -;; premium Emacs themes -(use-package doom-themes - :config - (setq doom-themes-enable-bold t - doom-themes-enable-italic t) - (doom-themes-visual-bell-config) - (doom-themes-org-config)) - -;; kbd discovery -(use-package which-key - :config - (setq which-key-idle-delay 0.25) - (which-key-mode)) - -;; completion framework -(use-package ivy - :config - (counsel-mode t) - (ivy-mode t) - ;; Remove preceding "^" from ivy prompts - (setq ivy-initial-inputs-alist nil) - ;; prefer using `helpful' variants - (progn - (setq counsel-describe-function-function #'helpful-callable) - (setq counsel-describe-variable-function #'helpful-variable)) - (general-define-key - :keymaps '(ivy-minibuffer-map ivy-switch-buffer-map) - ;; prev - "C-k" #'ivy-previous-line - "" #'ivy-previous-line - ;; next - "C-j" #'ivy-next-line - "" #'ivy-next-line)) - -(use-package ivy-prescient - :config - (ivy-prescient-mode 1) - (unless constants-ci? - (prescient-persist-mode 1))) - -;; all-the-icons -(use-package all-the-icons - :config - (unless (or constants-ci? - (f-exists? "~/.local/share/fonts/all-the-icons.ttf") - (f-exists? "~/Library/Fonts/all-the-icons.ttf")) - (all-the-icons-install-fonts t))) - -;; icons for Ivy -(use-package all-the-icons-ivy - :after (ivy all-the-icons) - :config - (all-the-icons-ivy-setup)) - -;; disable menubar -(menu-bar-mode -1) - -;; reduce noisiness of auto-revert-mode -(setq auto-revert-verbose nil) - -;; highlight lines that are over 80 characters long -(use-package whitespace - :config - ;; TODO: This should change depending on the language and project. For - ;; example, Google Java projects prefer 100 character width instead of 80 - ;; character width. - (setq whitespace-line-column 80) - (setq whitespace-style '(face lines-tail tabs)) - (global-whitespace-mode t)) - -;; dirname/filename instead of filename -(setq uniquify-buffer-name-style 'forward) - -;; highlight matching parens, brackets, etc -(show-paren-mode 1) - -;; hide the scroll-bars in the GUI -(scroll-bar-mode -1) - -;; TODO: Learn how to properly integrate this with dunst or another system-level -;; notification program. -;; GUI alerts in emacs -(use-package alert - :commands (alert) - :config - (setq alert-default-style 'notifier)) - -(display-battery-mode 1) - -(setq theme-whitelist - (->> (custom-available-themes) - (list-map #'symbol-name) - (list-filter (>-> (s-starts-with? "doom-"))) - (list-map #'intern) - cycle-from-list)) -(setq theme-linum-color-override "da5478") -(add-hook 'theme-after-change - (lambda () (prelude-set-line-number-color "#da5478"))) -(theme-whitelist-set 'doom-flatwhite) - -(when window-system - ;; On OSX, JetBrainsMono is installed as "JetBrains Mono", and I'm - ;; not sure how to change that. - (let ((font (if constants-osx? "JetBrains Mono" "JetBrainsMono"))) - (fonts-set font) - ;; Some themes (e.g. doom-acario-*) change the font for comments. This - ;; should prevent that. - (set-face-attribute font-lock-comment-face nil - :family font - :slant 'normal))) - -(modeline-setup) - -(provide 'wpc-ui) -;;; wpc-ui.el ends here diff --git a/users/wpcarro/emacs/AppIcon.icns b/users/wpcarro/emacs/AppIcon.icns deleted file mode 100644 index b3be251cc..000000000 Binary files a/users/wpcarro/emacs/AppIcon.icns and /dev/null differ diff --git a/users/wpcarro/emacs/README.md b/users/wpcarro/emacs/README.md deleted file mode 100644 index 16f4fc31f..000000000 --- a/users/wpcarro/emacs/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Emacs - -Emacs is one of a handful software projects that I highly value. I consider it -as central to my workflow as `git` and `nix`. - -## Installing - -If you already have `depot` on your local file system, run the following from -the top-level `depot` directory: - -```shell -$ nix-env -iA users.wpcarro.emacs.nixos -``` - -Test edit (from depot). diff --git a/users/wpcarro/emacs/ci.el b/users/wpcarro/emacs/ci.el deleted file mode 100644 index 9dfaf3056..000000000 --- a/users/wpcarro/emacs/ci.el +++ /dev/null @@ -1,44 +0,0 @@ -;; This script initializes Emacs and exits with either a zero or non-zero status -;; depending on whether or not Emacs initialized without logging warnings or -;; encountering errors. -;; -;; This script reads the location of init.el as the last argument in `argv'. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'prelude) -(require 'f) -(require 'dash) -(require 'buffer) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Script -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defvar init-el-path (-last-item argv) - "Path to the init.el file that this script attempts to load.") - -(prelude-assert (f-exists? init-el-path)) - -(condition-case err - (load init-el-path) - (error - (message "Encountered an error while attempting to load init.el: %s" err) - (kill-emacs 1))) - -(when (buffer-exists? "*Errors*") - (progn - (with-current-buffer "*Errors*" - (message "Encountered errors in *Errors* buffer: %s" (buffer-string))) - (kill-emacs 1))) - -(when (buffer-exists? "*Warnings*") - (progn - (with-current-buffer "*Warnings*" - (message "Encountered warnings in *Warnings* buffer: %s" (buffer-string))) - (kill-emacs 1))) - -(message "Successfully initialized Emacs without errors or warnings!") -(kill-emacs 0) diff --git a/users/wpcarro/emacs/default.nix b/users/wpcarro/emacs/default.nix deleted file mode 100644 index 92deeb39a..000000000 --- a/users/wpcarro/emacs/default.nix +++ /dev/null @@ -1,266 +0,0 @@ -# My Emacs distribution, which is supporting the following platforms: -# - Linux -# - Darwin -# -# USAGE: -# $ nix-build -A users.wpcarro.emacs.osx -o /Applications/BillsEmacs.app -{ depot, pkgs, lib, ... }: - -# TODO(wpcarro): See if it's possible to expose emacsclient on PATH, so that I -# don't need to depend on wpcarros-emacs and emacs in my NixOS configurations. -let - inherit (depot.third_party.nixpkgs) emacsPackagesFor emacs; - inherit (depot.users) wpcarro; - inherit (lib) mapAttrsToList; - inherit (lib.strings) concatStringsSep makeBinPath; - inherit (pkgs) runCommand writeShellScriptBin; - - emacsBinPath = makeBinPath ( - wpcarro.common.shell-utils ++ - # Rust dependencies - (with pkgs; [ - cargo - rust-analyzer - rustc - rustfmt - ]) ++ - # Misc dependencies - (with pkgs; [ - ispell - nix - rust-analyzer - rustc - rustfmt - xorg.xset - ] ++ - (if pkgs.stdenv.isLinux then [ - scrot - ] else [ ])) - ); - - emacsWithPackages = (emacsPackagesFor emacs).emacsWithPackages; - - wpcarrosEmacs = emacsWithPackages (epkgs: - (with wpcarro.emacs.pkgs; [ - al - bookmark - cycle - list - macros - maybe - passage - set - string - struct - symbol - theme - tuple - vterm-mgt - zle - ]) ++ - - (with epkgs.tvlPackages; [ - tvl - ]) ++ - - (with epkgs.elpaPackages; [ - exwm - ]) ++ - - (with epkgs.melpaPackages; [ - alert - all-the-icons - all-the-icons-ivy - avy - base16-theme - cider - clojure-mode - company - counsel - counsel-projectile - csharp-mode - dap-mode - dash - deadgrep - deferred - diminish - direnv - dockerfile-mode - # TODO(wpcarro): broken since channel bump cl/10204 - # doom-themes - elisp-slime-nav - elixir-mode - elm-mode - emojify - engine-mode - evil - evil-collection - evil-commentary - evil-surround - f - fish-mode - flycheck - flymake-shellcheck - general - go-mode - haskell-mode - helpful - ivy - ivy-clipmenu - ivy-prescient - key-chord - lispyville - lsp-ui - magit - magit-popup - markdown-mode - nix-mode - notmuch - org-bullets - package-lint - paradox - parsec - pcre2el - prettier-js - projectile - py-yapf - racket-mode - rainbow-delimiters - reason-mode - refine - request - restclient - rjsx-mode - rust-mode - sly - suggest - telephone-line - terraform-mode - tide - ts - tuareg - vterm - web-mode - which-key - yaml-mode - yasnippet - ]) ++ - - [ - epkgs.eglot # from elpa devel - ]); - - loadPath = concatStringsSep ":" [ - ./.emacs.d/wpc - # TODO(wpcarro): Explain why the trailing ":" is needed. - "${wpcarrosEmacs.deps}/share/emacs/site-lisp:" - ]; - - # Transform an attrset into "export k=v" statements. - makeEnvVars = env: concatStringsSep "\n" - (mapAttrsToList (k: v: "export ${k}=\"${v}\"") env); - - withEmacsPath = { emacsBin, env ? { }, load ? [ ] }: - writeShellScriptBin "wpcarros-emacs" '' - export XMODIFIERS=emacs - export PATH="${emacsBinPath}:$PATH" - export EMACSLOADPATH="${loadPath}" - ${makeEnvVars env} - exec ${emacsBin} \ - --debug-init \ - --no-init-file \ - --no-site-file \ - --no-site-lisp \ - --load ${./.emacs.d/init.el} \ - ${concatStringsSep "\n " (map (el: "--load ${el} \\") load)} - "$@" - ''; - - # I can't figure out how to augment LSEnvironment.PATH such that it inherits - # the default $PATH and adds the things that I need as well, so let's - # hardcode the desired outcome in the meantime. - osxDefaultPath = builtins.concatStringsSep ":" [ - "/Users/bill/.nix-profile/bin" - "/nix/var/nix/profiles/default/bin" - "/opt/homebrew/bin" - "/opt/homebrew/sbin" - "/usr/local/bin" - "/usr/bin" - "/bin" - "/usr/sbin" - "/sbin" - "/opt/X11/bin" - ]; - - infoPlist = pkgs.writeText "Info.plist" (pkgs.lib.generators.toPlist { } { - LSEnvironment = { - PATH = "${emacsBinPath}:${osxDefaultPath}"; - }; - CFBundleExecutable = "BillsEmacs"; - CFBundleDisplayName = "BillsEmacs"; - CFBundleIconFile = "AppIcon"; - CFBundleIconName = "AppIcon"; - }); - - versionPlist = pkgs.writeText "version.plist" (pkgs.lib.generators.toPlist { } { - ProjectName = "OSXPlatformSupport"; - }); -in -{ - # TODO(wpcarro): Support this with base.overrideAttrs or something similar. - nixos = { load ? [ ] }: withEmacsPath { - inherit load; - emacsBin = "${wpcarrosEmacs}/bin/emacs"; - }; - - # To install GUI: - # $ nix-build -A users.wpcarro.emacs.osx -o /Applications/BillsEmacs.app - osx = pkgs.stdenv.mkDerivation { - pname = "bills-emacs"; - version = "0.0.1"; - src = ./.; - dontFixup = true; - installPhase = '' - runHook preInstall - APP="$out" - mkdir -p "$APP/Contents/MacOS" - mkdir -p "$APP/Contents/Resources" - cp ${infoPlist} "$APP/Contents/Info.plist" - cp ${versionPlist} "$APP/Contents/version.plist" - cp ${./AppIcon.icns} "$APP/Contents/Resources/AppIcon.icns" - echo "APPL????" > "$APP/Contents/PkgInfo" - cat << EOF > "$APP/Contents/MacOS/BillsEmacs" - #!${pkgs.stdenvNoCC.shell} - export EMACSLOADPATH="${loadPath}" - exec ${wpcarrosEmacs}/bin/emacs \ - --debug-init \ - --no-init-file \ - --no-site-file \ - --no-site-lisp \ - --load ${./.emacs.d/init.el} - EOF - chmod +x "$APP/Contents/MacOS/BillsEmacs" - runHook postInstall - ''; - meta.platforms = [ "aarch64-darwin" ]; - }; - - # Script that asserts my Emacs can initialize without warnings or errors. - check = runCommand "check-emacs" { } '' - # Even though Buildkite defines this, I'd still like still be able to test - # this locally without depending on my ability to remember to set CI=true. - export CI=true - export PATH="${emacsBinPath}:$PATH" - export EMACSLOADPATH="${loadPath}" - ${wpcarrosEmacs}/bin/emacs \ - --no-site-file \ - --no-site-lisp \ - --no-init-file \ - --script ${./ci.el} \ - ${./.emacs.d/init.el} && \ - touch $out - ''; - - # TODO(wpcarro): commented out because of doom-themes breakage; cl/10204 - # meta.ci.targets = [ "check" ]; -} diff --git a/users/wpcarro/emacs/elisp-conventions.md b/users/wpcarro/emacs/elisp-conventions.md deleted file mode 100644 index 0e39c3069..000000000 --- a/users/wpcarro/emacs/elisp-conventions.md +++ /dev/null @@ -1,20 +0,0 @@ -# Elisp Conventions - -Some of this aligns with existing style guides. Some of it does not. - -In general, prefer functions with fixed arities instead of variadic -alternatives. - -- Namespace functions with `namespace/function-name` -- Use `ensure`, `assert`, `refute` whenever possible. -- When talking about encoding and decoding, let's use the words "encoding" and - "decoding" rather than the myriad of other variants that appear like: - - `marshalling` and `unmarshalling` - - `parse` and `deparse`, `serialize`, `stringify` - - `unpickle` and `pickle` (Python) - - `from-string` and `to-string` - - TODO: Add more examples of these; there should be close to a dozen. -- Annotate assertions with `!` endings. -- Prefer the Scheme style of `predicate?` -- Variadic functions *should* encode this by appending * onto their - name. E.g. `maybe/nil?*` diff --git a/users/wpcarro/emacs/keybindings.md b/users/wpcarro/emacs/keybindings.md deleted file mode 100644 index 96ba7c964..000000000 --- a/users/wpcarro/emacs/keybindings.md +++ /dev/null @@ -1,47 +0,0 @@ -# Keybindings - -Since I'm using Emacs to manage most of my workflow, all of the keybindings -should be defined herein and -- in order to scale -- order must be imposed. This -can help avoid KBD collisions and improve my ability to remember each KBD. - -See `kbd.el` for the programmatic encoding of these principles. - -## Troubleshooting - -When in doubt, use Emacs's `read-key` and `read-event` to learn what signal -you're sending Emacs. - -### Super- - -- EXWM X11 windows are not processing `s-`. -- EXWM X11 windows are not processing ``. - -### Super-Ctrl- - -I'm reserving `C-s-` for opening X11 applications. - -- `terminator`: `t` -- `google-chrome`: `c` - -## Emacs nouns - -Most of my keybindings should be organized according to their function, which in -turn should be related to the following Emacs nouns. - -- `workspace`: As defined by EXWM. -- `frame`: What non-Emacs users would call a "window". Currently my workflow - doesn't use or rely on Emacs frames. -- `window`: A vertical or horizontal split within an Emacs frame. -- `buffer`: Anything storing text in memory. - -## Prefixes and their meanings - -TODO: Have a system for leader-prefixed KBDs, chords, and prefixed chords. - -- `s-`: Switching between named workspaces. Right now, super is too overloaded - and would benefit from having more deliberate keybindings. -- `C-M-`: Window sizing -- `M-{h,j,k,l}`: Window traversing -- `M-{\,-}`: Window splitting -- `M-q`: Window deletion -- `-q`: Window deletion diff --git a/users/wpcarro/emacs/pkgs/al/al.el b/users/wpcarro/emacs/pkgs/al/al.el deleted file mode 100644 index 4c37526c6..000000000 --- a/users/wpcarro/emacs/pkgs/al/al.el +++ /dev/null @@ -1,227 +0,0 @@ -;;; al.el --- Interface for working with associative lists -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; Firstly, a rant: -;; In most cases, I find Elisp's APIs to be confusing. There's a mixture of -;; overloaded functions that leak the implementation details (TODO: provide an -;; example of this.) of the abstract data type, which I find privileges those -;; "insiders" who spend disproportionately large amounts of time in Elisp land, -;; and other functions with little-to-no pattern about the order in which -;; arguments should be applied. In theory, however, most of these APIs could -;; and should be much simpler. This module represents a step in that direction. -;; -;; I'm modelling these APIs after Elixir's APIs. -;; -;; On my wishlist is to create protocols that will allow generic interfaces like -;; Enum protocols, etc. Would be nice to abstract over... -;; - associative lists (i.e. alists) -;; - property lists (i.e. plists) -;; - hash tables -;; ...with some dictionary or map-like interface. This will probably end up -;; being quite similar to the kv.el project but with differences at the API -;; layer. -;; -;; Similar libraries: -;; - map.el: Comes bundled with recent versions of Emacs. -;; - asoc.el: Helpers for working with alists. asoc.el is similar to alist.el -;; because it uses the "!" convention for signalling that a function mutates -;; the underlying data structure. -;; - ht.el: Hash table library. -;; - kv.el: Library for dealing with key-value collections. Note that map.el -;; has a similar typeclass because it works with lists, hash-tables, or -;; arrays. -;; - a.el: Clojure-inspired way of working with key-value data structures in -;; Elisp. Works with alists, hash-tables, and sometimes vectors. -;; -;; Some API design principles: -;; - The "noun" (i.e. alist) of the "verb" (i.e. function) comes last to improve -;; composability with the threading macro (i.e. `->>') and to improve consumers' -;; intuition with the APIs. Learn this once, know it always. -;; -;; - Every function avoids mutating the alist unless it ends with !. -;; -;; - CRUD operations will be named according to the following table: -;; - "create" *and* "set" -;; - "read" *and* "get" -;; - "update" -;; - "delete" *and* "remove" -;; -;; For better or worse, all of this code expects alists in the form of: -;; ((first-name . "William") (last-name . "Carroll")) -;; -;; Special thanks to github.com/alphapapa/emacs-package-dev-handbook for some of -;; the idiomatic ways to update alists. -;; -;; TODO: Include a section that compares alist.el to a.el from -;; github.com/plexus/a.el. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies: -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'dash) -(require 'list) -(require 'map) - -;; TODO: Support function aliases for: -;; - create/set -;; - read/get -;; - update -;; - delete/remove - -;; Support mutative variants of functions with an ! appendage to their name. - -;; Ensure that the same message about only updating the first occurrence of a -;; key is consistent throughout documentation using string interpolation or some -;; other mechanism. - -;; TODO: Consider wrapping all of this with `(cl-defstruct alist xs)'. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO: Support a variadic version of this to easily construct alists. -(defun al-new () - "Return a new, empty alist." - '()) - -;; Create -;; TODO: See if this mutates. -(defun al-set (k v xs) - "Set K to V in XS." - (if (al-has-key? k xs) - (progn - ;; Note: this is intentional `alist-get' and not `al-get'. - (setf (alist-get k xs) v) - xs) - (list-cons `(,k . ,v) xs))) - -(defun al-set! (k v xs) - "Set K to V in XS mutatively. -Note that this doesn't append to the alist in the way that most alists handle - writing. If the k already exists in XS, it is overwritten." - (map-delete xs k) - (map-put! xs k v)) - -;; Read -(defun al-get (k xs &optional default) - "Return the value at K in XS; otherwise, return nil or DEFAULT (if set). -Returns the first occurrence of K in XS since alists support multiple entries." - (if (not (al-has-key? k xs)) - default - (cdr (assoc k xs)))) - -(defun al-get-entry (k xs) - "Return the first key-value pair at K in XS." - (assoc k xs)) - -;; Update -;; TODO: Add warning about only the first occurrence being updated in the -;; documentation. -(defun al-update (k f xs) - "Apply F to the value stored at K in XS. -If `K' is not in `XS', this function errors. Use `al-upsert' if you're -interested in inserting a value when a key doesn't already exist." - (if (not (al-has-key? k xs)) - (error "Refusing to update: key does not exist in alist") - (al-set k (funcall f (al-get k xs)) xs))) - -(defun al-update! (k f xs) - "Call F on the entry at K in XS. -Mutative variant of `al-update'." - (al-set! k (funcall f (al-get k xs))xs)) - -;; TODO: Support this. -(defun al-upsert (k v f xs) - "If K exists in `XS' call `F' on the value otherwise insert `V'." - (if (al-has-key? k xs) - (al-update k f xs) - (al-set k v xs))) - -;; Delete -;; TODO: Make sure `delete' and `remove' behave as advertised in the Elisp docs. -(defun al-delete (k xs) - "Deletes the entry of K from XS. -This only removes the first occurrence of K, since alists support multiple - key-value entries. See `al-delete-all' and `al-dedupe'." - (remove (assoc k xs) xs)) - -(defun al-delete! (k xs) - "Delete the entry of K from XS. -Mutative variant of `al-delete'." - (delete (assoc k xs) xs)) - -;; Additions to the CRUD API -;; TODO: Implement this function. -(defun al-dedupe-keys (xs) - "Remove the entries in XS where the keys are `equal'.") - -(defun al-dedupe-entries (xs) - "Remove the entries in XS where the key-value pair are `equal'." - (delete-dups xs)) - -(defun al-keys (xs) - "Return a list of the keys in XS." - (mapcar 'car xs)) - -(defun al-values (xs) - "Return a list of the values in XS." - (mapcar 'cdr xs)) - -(defun al-has-key? (k xs) - "Return t if XS has a key `equal' to K." - (not (eq nil (assoc k xs)))) - -(defun al-has-value? (v xs) - "Return t if XS has a value of V." - (not (eq nil (rassoc v xs)))) - -(defun al-count (xs) - "Return the number of entries in XS." - (length xs)) - -;; TODO: Should I support `al-find-key' and `al-find-value' variants? -(defun al-find (p xs) - "Find an element in XS. - -Apply a predicate fn, P, to each key and value in XS and return the key of the -first element that returns t." - (let ((result (list-find (lambda (x) (funcall p (car x) (cdr x))) xs))) - (if result - (car result) - nil))) - -(defun al-map-keys (f xs) - "Call F on the values in XS, returning a new alist." - (list-map (lambda (x) - `(,(funcall f (car x)) . ,(cdr x))) - xs)) - -(defun al-map-values (f xs) - "Call F on the values in XS, returning a new alist." - (list-map (lambda (x) - `(,(car x) . ,(funcall f (cdr x)))) - xs)) - -(defun al-reduce (acc f xs) - "Return a new alist by calling F on k v and ACC from XS. -F should return a tuple. See tuple.el for more information." - (->> (al-keys xs) - (list-reduce acc - (lambda (k acc) - (funcall f k (al-get k xs) acc))))) - -(defun al-merge (a b) - "Return a new alist with a merge of alists, A and B. -In this case, the last writer wins, which is B." - (al-reduce a #'al-set b)) - -(provide 'al) -;;; al.el ends here diff --git a/users/wpcarro/emacs/pkgs/al/default.nix b/users/wpcarro/emacs/pkgs/al/default.nix deleted file mode 100644 index 0a32930e2..000000000 --- a/users/wpcarro/emacs/pkgs/al/default.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ pkgs, depot, ... }: - -let - al = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "al"; - version = "1.0.0"; - src = ./al.el; - packageRequires = - (with emacsPackages; [ - dash - ]) ++ - (with depot.users.wpcarro.emacs.pkgs; [ - list - ]); - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ al ]); -in -al.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/al/tests.el b/users/wpcarro/emacs/pkgs/al/tests.el deleted file mode 100644 index 04fe4dcbb..000000000 --- a/users/wpcarro/emacs/pkgs/al/tests.el +++ /dev/null @@ -1,53 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'al) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest al-has-key? () - (should (al-has-key? 'fname '((fname . "William")))) - (should (not (al-has-key? 'lname '((fname . "William")))))) - -(ert-deftest al-get () - (let ((xs (->> (al-new) - (al-set 'fname "John") - (al-set 'employed? nil)))) - (should (string= "John" (al-get 'fname xs))) - (should (string= "Cleese" (al-get 'lname xs "Cleese"))) - ;; Test that the value of nil is returned even when a default is defined, - ;; which could be a subtle bug in the typical Elisp pattern of supporting - ;; defaults with: (or foo default). - (should (eq nil (al-get 'employed? xs))) - (should (eq nil (al-get 'employed? xs "default"))))) - -(ert-deftest al-has-value? () - (should (al-has-value? "William" '((fname . "William")))) - (should (not (al-has-key? "John" '((fname . "William")))))) - -(ert-deftest al-map-keys () - (should - (equal '((2 . one) - (3 . two)) - (al-map-keys #'1+ - '((1 . one) - (2 . two)))))) - -(ert-deftest al-map-values () - (should (equal '((one . 2) - (two . 3)) - (al-map-values #'1+ - '((one . 1) - (two . 2)))))) - -(ert-deftest al-delete () - (let ((person (->> (al-new) - (al-set "fname" "John") - (al-set "lname" "Cleese") - (al-set "age" 82)))) - (should (al-has-key? "age" person)) - (should (not (al-has-key? "age" (al-delete "age" person)))))) diff --git a/users/wpcarro/emacs/pkgs/bag/bag.el b/users/wpcarro/emacs/pkgs/bag/bag.el deleted file mode 100644 index 502f56725..000000000 --- a/users/wpcarro/emacs/pkgs/bag/bag.el +++ /dev/null @@ -1,78 +0,0 @@ -;;; bag.el --- Working with bags (aka multi-sets) -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; What is a bag? A bag should be thought of as a frequency table. It's a way -;; to convert a list of something into a set that allows duplicates. Isn't -;; allowing duplicates the whole thing with Sets? Kind of. But the interface -;; of Sets is something that bags resemble, so multi-set isn't as bad of a name -;; as it may first seem. -;; -;; If you've used Python's collections.Counter, the concept of a bag should be -;; familiar already. -;; -;; Interface: -;; - add :: x -> Bag(x) -> Bag(x) -;; - remove :: x -> Bag(x) -> Bag(x) -;; - union :: Bag(x) -> Bag(x) -> Bag(x) -;; - difference :: Bag(x) -> Bag(x) -> Bag(x) - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'al) -(require 'list) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(cl-defstruct bag xs) - -(defun bag-new () - "Create an empty bag." - (make-bag :xs (al-new))) - -(defun bag-from-list (xs) - "Map a list of `XS' into a bag." - (->> xs - (list-reduce (bag-new) #'bag-add))) - -(defun bag-add (x xs) - "Add X to XS." - (if (bag-contains? x xs) - (struct-update - bag xs (lambda (xs) (al-update x (lambda (x) (+ 1 x)) xs)) xs) - (struct-update bag xs (lambda (xs) (al-set x 1 xs)) xs))) - -(defun bag-remove (x xs) - "Remove X from XS. -This is a no-op is X doesn't exist in XS." - (when (bag-contains? x xs) - (struct-update bag xs (lambda (xs) (al-delete x xs)) xs))) - -(defun bag-count (x xs) - "Return the number of occurrences of X in XS." - (al-get x (bag-xs xs) 0)) - -(defun bag-total (xs) - "Return the total number of elements in XS." - (->> (bag-xs xs) - (al-reduce 0 (lambda (_key v acc) (+ acc v))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Predicates -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun bag-contains? (x xs) - "Return t if XS has X." - (al-has-key? x (bag-xs xs))) - -(provide 'bag) -;;; bag.el ends here diff --git a/users/wpcarro/emacs/pkgs/bag/default.nix b/users/wpcarro/emacs/pkgs/bag/default.nix deleted file mode 100644 index 3ff32e173..000000000 --- a/users/wpcarro/emacs/pkgs/bag/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ pkgs, depot, ... }: - -let - bag = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "bag"; - version = "1.0.0"; - src = ./bag.el; - packageRequires = - (with depot.users.wpcarro.emacs.pkgs; [ - al - list - ]); - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ bag ]); -in -bag.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/bag/tests.el b/users/wpcarro/emacs/pkgs/bag/tests.el deleted file mode 100644 index 4970f7081..000000000 --- a/users/wpcarro/emacs/pkgs/bag/tests.el +++ /dev/null @@ -1,32 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'bag) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(setq fixture (bag-from-list '(1 1 1 2 2 3))) - -(ert-deftest bag-add () - (should (not (bag-contains? 4 fixture))) - (should (bag-contains? 4 (bag-add 4 fixture)))) - -(ert-deftest bag-remove () - (should (bag-contains? 1 fixture)) - (should (not (bag-contains? 3 (bag-remove 3 fixture))))) - -(ert-deftest bag-count () - (should (= 3 (bag-count 1 fixture))) - (should (= 2 (bag-count 2 fixture))) - (should (= 1 (bag-count 3 fixture)))) - -(ert-deftest bag-total () - (should (= 6 (bag-total fixture)))) - -(ert-deftest bag-contains? () - (should (bag-contains? 1 fixture)) - (should (not (bag-contains? 4 fixture)))) diff --git a/users/wpcarro/emacs/pkgs/bookmark/bookmark.el b/users/wpcarro/emacs/pkgs/bookmark/bookmark.el deleted file mode 100644 index ab9169a07..000000000 --- a/users/wpcarro/emacs/pkgs/bookmark/bookmark.el +++ /dev/null @@ -1,50 +0,0 @@ -;;; bookmark.el --- Saved files and directories on my filesystem -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; A more opinionated version of Emacs's builtin `jump-to-register'. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'project) -(require 'general) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(cl-defstruct bookmark label path kbd) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; API -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun bookmark-open (b) - "Open bookmark, B, as either a project directory or a regular directory." - (with-temp-buffer - (cd (bookmark-path b)) - (call-interactively #'project-find-file))) - -(defun bookmark-install-kbd (b) - "Define two functions to explore B and assign them to keybindings." - (eval `(defun ,(intern (format "bookmark-visit-%s" (bookmark-label b))) () - (interactive) - (find-file ,(bookmark-path b)))) - (eval `(defun ,(intern (format "bookmark-browse-%s" (bookmark-label b))) () - (interactive) - (bookmark-open ,b))) - (general-define-key - :prefix "" - :states '(motion) - (format "J%s" (bookmark-kbd b)) `,(intern (format "bookmark-visit-%s" (bookmark-label b))) - (format "j%s" (bookmark-kbd b)) `,(intern (format "bookmark-browse-%s" (bookmark-label b))))) - -(provide 'bookmark) -;;; bookmark.el ends here diff --git a/users/wpcarro/emacs/pkgs/bookmark/default.nix b/users/wpcarro/emacs/pkgs/bookmark/default.nix deleted file mode 100644 index 882481701..000000000 --- a/users/wpcarro/emacs/pkgs/bookmark/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ pkgs, depot, ... }: - -pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "bookmark"; - version = "1.0.0"; - src = ./bookmark.el; - packageRequires = (with pkgs.emacsPackages; [ - general - ]); - }) -{ } diff --git a/users/wpcarro/emacs/pkgs/bytes/bytes.el b/users/wpcarro/emacs/pkgs/bytes/bytes.el deleted file mode 100644 index b0d64795a..000000000 --- a/users/wpcarro/emacs/pkgs/bytes/bytes.el +++ /dev/null @@ -1,94 +0,0 @@ -;;; bytes.el --- Working with byte values -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Functions to help with human-readable representations of byte values. -;; -;; Usage: -;; See the test cases for example usage. Or better yet, I should use a type of -;; structured documentation that would allow me to expose a view into the test -;; suite here. Is this currently possible in Elisp? -;; -;; API: -;; - serialize :: Integer -> String -;; -;; Wish list: -;; - Rounding: e.g. (bytes (* 1024 1.7)) => "2KB" - -;;; Code: - -;; TODO: Support -ibabyte variants like Gibibyte (GiB). - -;; Ranges: -;; B: [ 0, 1e3) -;; KB: [ 1e3, 1e6) -;; MB: [ 1e6, 1e6) -;; GB: [ 1e9, 1e12) -;; TB: [1e12, 1e15) -;; PB: [1e15, 1e18) -;; -;; Note: I'm currently not support exabytes because that causes the integer to -;; overflow. I imagine a larger integer type may exist, but for now, I'll -;; treat this as a YAGNI. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'tuple) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Constants -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst bytes-kb (expt 2 10) - "Number of bytes in a kilobyte.") - -(defconst bytes-mb (expt 2 20) - "Number of bytes in a megabytes.") - -(defconst bytes-gb (expt 2 30) - "Number of bytes in a gigabyte.") - -(defconst bytes-tb (expt 2 40) - "Number of bytes in a terabyte.") - -(defconst bytes-pb (expt 2 50) - "Number of bytes in a petabyte.") - -(defconst bytes-eb (expt 2 60) - "Number of bytes in an exabyte.") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun bytes-classify (x) - "Return unit that closest fits byte count, X." - (cond - ((and (>= x 0) (< x bytes-kb)) 'byte) - ((and (>= x bytes-kb) (< x bytes-mb)) 'kilobyte) - ((and (>= x bytes-mb) (< x bytes-gb)) 'megabyte) - ((and (>= x bytes-gb) (< x bytes-tb)) 'gigabyte) - ((and (>= x bytes-tb) (< x bytes-pb)) 'terabyte) - ((and (>= x bytes-pb) (< x bytes-eb)) 'petabyte))) - -(defun bytes-to-string (x) - "Convert integer X into a human-readable string." - (let ((base-and-unit - (pcase (bytes-classify x) - ('byte (tuple-from 1 "B")) - ('kilobyte (tuple-from bytes-kb "KB")) - ('megabyte (tuple-from bytes-mb "MB")) - ('gigabyte (tuple-from bytes-gb "GB")) - ('terabyte (tuple-from bytes-tb "TB")) - ('petabyte (tuple-from bytes-pb "PB"))))) - (format "%d%s" - (round x (tuple-first base-and-unit)) - (tuple-second base-and-unit)))) - -(provide 'bytes) -;;; bytes.el ends here diff --git a/users/wpcarro/emacs/pkgs/bytes/default.nix b/users/wpcarro/emacs/pkgs/bytes/default.nix deleted file mode 100644 index c32207d70..000000000 --- a/users/wpcarro/emacs/pkgs/bytes/default.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ pkgs, depot, ... }: - -let - bytes = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "bytes"; - version = "1.0.0"; - src = ./bytes.el; - packageRequires = - (with depot.users.wpcarro.emacs.pkgs; [ - tuple - ]); - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ bytes ]); -in -bytes.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/bytes/tests.el b/users/wpcarro/emacs/pkgs/bytes/tests.el deleted file mode 100644 index 9b71a466c..000000000 --- a/users/wpcarro/emacs/pkgs/bytes/tests.el +++ /dev/null @@ -1,18 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'bytes) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest bytes-to-string () - (should (equal "1000B" (bytes-to-string 1000))) - (should (equal "2KB" (bytes-to-string (* 2 bytes-kb)))) - (should (equal "17MB" (bytes-to-string (* 17 bytes-mb)))) - (should (equal "419GB" (bytes-to-string (* 419 bytes-gb)))) - (should (equal "999TB" (bytes-to-string (* 999 bytes-tb)))) - (should (equal "2PB" (bytes-to-string (* 2 bytes-pb))))) diff --git a/users/wpcarro/emacs/pkgs/cycle/README.md b/users/wpcarro/emacs/pkgs/cycle/README.md deleted file mode 100644 index 416900d25..000000000 --- a/users/wpcarro/emacs/pkgs/cycle/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# cycle.el - -[![Build status](https://badge.buildkite.com/016bff4b8ae2704a3bbbb0a250784e6692007c582983b6dea7.svg?branch=refs/heads/canon)](https://buildkite.com/tvl/depot) - -Cycle data structure exposing mutable and (coming soon!) immutable APIs. - -[![asciicast](https://asciinema.org/a/FvFujpRpYjV9qCSGvk3uobOpV.svg)](https://asciinema.org/a/FvFujpRpYjV9qCSGvk3uobOpV) diff --git a/users/wpcarro/emacs/pkgs/cycle/cycle.el b/users/wpcarro/emacs/pkgs/cycle/cycle.el deleted file mode 100644 index 2f5b252a0..000000000 --- a/users/wpcarro/emacs/pkgs/cycle/cycle.el +++ /dev/null @@ -1,194 +0,0 @@ -;;; cycle.el --- Simple module for working with cycles -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Something like this may already exist, but I'm having trouble finding it, and -;; I think writing my own is a nice exercise for learning more Elisp. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'dash) -(require 'struct) -(require 'cl-lib) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Wish list -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; - TODO: Provide immutable variant. -;; - TODO: Replace mutable consumption with immutable variant. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; `current-index' tracks the current index -;; `xs' is the original list -(cl-defstruct cycle current-index previous-index xs) - -(defun cycle-from-list (xs) - "Create a cycle from a list of `XS'." - (if (= 0 (length xs)) - (make-cycle :current-index nil - :previous-index nil - :xs xs) - (make-cycle :current-index 0 - :previous-index nil - :xs xs))) - -(defun cycle-new (&rest xs) - "Create a cycle with XS as the values." - (cycle-from-list xs)) - -(defun cycle-to-list (xs) - "Return the list representation of a cycle, XS." - (cycle-xs xs)) - -(defun cycle-previous-focus (cycle) - "Return the previously focused entry in CYCLE." - (let ((i (cycle-previous-index cycle))) - (when i (nth i (cycle-xs cycle))))) - -(defun cycle-focus-previous! (xs) - "Jump to the item in XS that was most recently focused; return the cycle. -This will error when previous-index is nil. This function mutates the -underlying struct." - (let ((i (cycle-previous-index xs))) - (if i - (progn (cycle-jump! i xs) (cycle-current xs)) - (error "Cannot focus the previous element since cycle-previous-index is nil")))) - -(defun cycle-next! (xs) - "Return the next value in `XS' and update `current-index'." - (let* ((current-index (cycle-current-index xs)) - (next-index (cycle--next-index-> 0 (cycle-count xs) current-index))) - (struct-set! cycle previous-index current-index xs) - (struct-set! cycle current-index next-index xs) - (nth next-index (cycle-xs xs)))) - -(defun cycle-prev! (xs) - "Return the previous value in `XS' and update `current-index'." - (let* ((current-index (cycle-current-index xs)) - (next-index (cycle--next-index<- 0 (cycle-count xs) current-index))) - (struct-set! cycle previous-index current-index xs) - (struct-set! cycle current-index next-index xs) - (nth next-index (cycle-xs xs)))) - -(defun cycle-current (cycle) - "Return the current value in `CYCLE'." - (nth (cycle-current-index cycle) (cycle-xs cycle))) - -(defun cycle-count (cycle) - "Return the length of `xs' in `CYCLE'." - (length (cycle-xs cycle))) - -(defun cycle-jump! (i xs) - "Jump to the I index of XS." - (let ((current-index (cycle-current-index xs)) - (next-index (mod i (cycle-count xs)))) - (struct-set! cycle previous-index current-index xs) - (struct-set! cycle current-index next-index xs)) - xs) - -(defun cycle-focus! (p cycle) - "Focus the element in CYCLE for which predicate, P, is t." - (let ((i (->> cycle - cycle-xs - (-find-index p)))) - (if i - (cycle-jump! i cycle) - (error "No element in cycle matches predicate")))) - -(defun cycle-focus-item! (x xs) - "Focus item, X, in cycle XS. -ITEM is the first item in XS that t for `equal'." - (cycle-focus! (lambda (y) (equal x y)) xs)) - -(defun cycle-append! (x xs) - "Add X to the left of the focused element in XS. -If there is no currently focused item, add X to the beginning of XS." - (if (cycle-empty? xs) - (progn - (struct-set! cycle xs (list x) xs) - (struct-set! cycle current-index 0 xs) - (struct-set! cycle previous-index nil xs)) - (let ((curr-i (cycle-current-index xs)) - (prev-i (cycle-previous-index xs))) - (if curr-i - (progn - (struct-set! cycle xs (-insert-at curr-i x (cycle-xs xs)) xs) - (when (and prev-i (>= prev-i curr-i)) - (struct-set! cycle previous-index (1+ prev-i) xs)) - (when curr-i (struct-set! cycle current-index (1+ curr-i) xs))) - (progn - (struct-set! cycle xs (cons x (cycle-xs xs)) xs) - (when prev-i (struct-set! cycle previous-index (1+ prev-i) xs)))) - xs))) - -(defun cycle-remove! (x xs) - "Attempt to remove X from XS. - -X is found using `equal'. - -If X is the currently focused value, after it's deleted, current-index will be - nil. If X is the previously value, after it's deleted, previous-index will be - nil." - (let ((curr-i (cycle-current-index xs)) - (prev-i (cycle-previous-index xs)) - (rm-i (-elem-index x (cycle-xs xs)))) - (struct-set! cycle xs (-remove-at rm-i (cycle-xs xs)) xs) - (when prev-i - (when (> prev-i rm-i) (struct-set! cycle previous-index (1- prev-i) xs)) - (when (= prev-i rm-i) (struct-set! cycle previous-index nil xs))) - (when curr-i - (when (> curr-i rm-i) (struct-set! cycle current-index (1- curr-i) xs)) - (when (= curr-i rm-i) (struct-set! cycle current-index nil xs))) - xs)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Predicates -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun cycle-contains? (x xs) - "Return t if cycle, XS, has member X." - (not (null (-contains? (cycle-xs xs) x)))) - -(defun cycle-empty? (xs) - "Return t if cycle XS has no elements." - (= 0 (length (cycle-xs xs)))) - -(defun cycle-focused? (xs) - "Return t if cycle XS has a non-nil value for current-index." - (not (null (cycle-current-index xs)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Helper Functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun cycle--next-index<- (lo hi x) - "Return the next index in a cycle when moving downwards. -- `LO' is the lower bound. -- `HI' is the upper bound. -- `X' is the current index." - (if (< (- x 1) lo) - (- hi 1) - (- x 1))) - -(defun cycle--next-index-> (lo hi x) - "Return the next index in a cycle when moving upwards. -- `LO' is the lower bound. -- `HI' is the upper bound. -- `X' is the current index." - (if (>= (+ 1 x) hi) - lo - (+ 1 x))) - -(provide 'cycle) -;;; cycle.el ends here diff --git a/users/wpcarro/emacs/pkgs/cycle/default.nix b/users/wpcarro/emacs/pkgs/cycle/default.nix deleted file mode 100644 index d42f918b8..000000000 --- a/users/wpcarro/emacs/pkgs/cycle/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ pkgs, depot, ... }: - -let - cycle = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "cycle"; - version = "1.0.0"; - src = ./cycle.el; - packageRequires = - (with emacsPackages; [ - dash - ]) ++ - (with depot.users.wpcarro.emacs.pkgs; [ - struct - ]); - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ - epkgs.dash - cycle - ]); -in -cycle.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; - passthru.meta.ci.extraSteps.github = depot.tools.releases.filteredGitPush { - filter = ":/users/wpcarro/emacs/pkgs/cycle"; - remote = "git@github.com:wpcarro/cycle.el.git"; - ref = "refs/heads/canon"; - }; -}) diff --git a/users/wpcarro/emacs/pkgs/cycle/tests.el b/users/wpcarro/emacs/pkgs/cycle/tests.el deleted file mode 100644 index 29c0e2a0d..000000000 --- a/users/wpcarro/emacs/pkgs/cycle/tests.el +++ /dev/null @@ -1,79 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'cycle) -(require 'dash) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(setq xs (cycle-new 1 2 3)) - -(ert-deftest cycle-initializes-properly () - (should (= 3 (cycle-count xs))) - (should (null (cycle-previous-focus xs))) - (should (cycle-contains? 1 xs)) - (should (cycle-contains? 2 xs)) - (should (cycle-contains? 3 xs))) - -(ert-deftest cycle-contains? () - ;; Returns t or nil - (should (eq t (cycle-contains? 1 xs))) - (should (eq t (cycle-contains? 2 xs))) - (should (eq t (cycle-contains? 3 xs))) - (should (eq nil (cycle-contains? 4 xs)))) - -(ert-deftest cycle-empty? () - (should (eq t (cycle-empty? (cycle-new)))) - (should (eq nil (cycle-empty? xs)))) - -(ert-deftest cycle-current () - (should (= 1 (cycle-current xs)))) - -(ert-deftest cycle-next! () - (let ((xs (cycle-from-list '(1 2 3)))) - (should (= 2 (cycle-next! xs))))) - -(ert-deftest cycle-prev! () - (let ((xs (cycle-from-list '(1 2 3)))) - (cycle-next! xs) - (should (= 1 (cycle-prev! xs))))) - -(ert-deftest cycle-previous-focus () - (let ((xs (cycle-from-list '(1 2 3)))) - (cycle-focus-item! 2 xs) - (cycle-next! xs) - (should (= 2 (cycle-previous-focus xs))))) - -(ert-deftest cycle-jump! () - (let ((xs (cycle-from-list '(1 2 3)))) - (should (= 1 (->> xs (cycle-jump! 0) cycle-current))) - (should (= 2 (->> xs (cycle-jump! 1) cycle-current))) - (should (= 3 (->> xs (cycle-jump! 2) cycle-current))))) - -(ert-deftest cycle-focus-previous! () - (let ((xs (cycle-from-list '(1 2 3)))) - (cycle-focus-item! 2 xs) - (cycle-next! xs) - (should (= 2 (cycle-previous-focus xs))) - (should (= 2 (cycle-focus-previous! xs))))) - -(ert-deftest cycle-append! () - (let ((xs (cycle-from-list '(1 2 3)))) - (cycle-focus-item! 2 xs) - (cycle-append! 4 xs) - (should (equal '(1 4 2 3) (cycle-xs xs))))) - -(ert-deftest cycle-remove! () - (let ((xs (cycle-from-list '(1 2 3)))) - (should (equal '(1 2) (cycle-xs (cycle-remove! 3 xs)))))) - -(ert-deftest cycle-misc () - (cycle-focus-item! 3 xs) - (cycle-focus-item! 2 xs) - (cycle-remove! 1 xs) - (should (= 2 (cycle-current xs))) - (should (= 3 (cycle-previous-focus xs)))) diff --git a/users/wpcarro/emacs/pkgs/fs/default.nix b/users/wpcarro/emacs/pkgs/fs/default.nix deleted file mode 100644 index b92e9e605..000000000 --- a/users/wpcarro/emacs/pkgs/fs/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ pkgs, depot, ... }: - -let - fs = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "fs"; - version = "1.0.0"; - src = ./fs.el; - packageRequires = - (with emacsPackages; [ - dash - f - s - ]); - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ - fs - ]); -in -fs.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/fs/fs.el b/users/wpcarro/emacs/pkgs/fs/fs.el deleted file mode 100644 index 125c1f100..000000000 --- a/users/wpcarro/emacs/pkgs/fs/fs.el +++ /dev/null @@ -1,47 +0,0 @@ -;;; fs.el --- Make working with the filesystem easier -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.1")) - -;;; Commentary: -;; Ergonomic alternatives for working with the filesystem. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'dash) -(require 'f) -(require 's) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun fs-ensure-file (path) - "Ensure that a file and its directories in `PATH' exist. -Will error for inputs with a trailing slash." - (when (s-ends-with? "/" path) - (error (format "Input path has trailing slash: %s" path))) - (->> path - f-dirname - fs-ensure-dir) - (f-touch path)) - -(defun fs-ensure-dir (path) - "Ensure that a directory and its ancestor directories in `PATH' exist." - (->> path - f-split - (apply #'f-mkdir))) - -(defun fs-ls (dir &optional full-path?) - "List the files in `DIR' one-level deep. -Should behave similarly in spirit to the Unix command, ls. -If `FULL-PATH?' is set, return the full-path of the files." - (-drop 2 (directory-files dir full-path?))) - -(provide 'fs) -;;; fs.el ends here diff --git a/users/wpcarro/emacs/pkgs/fs/tests.el b/users/wpcarro/emacs/pkgs/fs/tests.el deleted file mode 100644 index adef11a60..000000000 --- a/users/wpcarro/emacs/pkgs/fs/tests.el +++ /dev/null @@ -1,26 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'fs) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest fs-test-ensure-file () - (let ((file "/tmp/file/a/b/c/file.txt")) - ;; Ensure this file doesn't exist first to prevent false-positives. - (f-delete file t) - (fs-ensure-file file) - (should (and (f-exists? file) - (f-file? file))))) - -(ert-deftest fs-test-ensure-dir () - (let ((dir "/tmp/dir/a/b/c")) - ;; Ensure the directory doesn't exist. - (f-delete dir t) - (fs-ensure-dir dir) - (should (and (f-exists? dir) - (f-dir? dir))))) diff --git a/users/wpcarro/emacs/pkgs/list/README.md b/users/wpcarro/emacs/pkgs/list/README.md deleted file mode 100644 index 7afa8494f..000000000 --- a/users/wpcarro/emacs/pkgs/list/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# list.el - -Functions for working with lists in Elisp. - -## Wish List - -Here are some additional functions that I'd like to support. - -- **TODO**: delete_at/2 -- **TODO**: flatten/1 -- **TODO**: flatten/2 -- **TODO**: foldl/3 -- **TODO**: foldr/3 -- **TODO**: insert_at/3 -- **TODO**: pop_at/3 -- **TODO**: replace_at/3 -- **TODO**: starts_with?/2 -- **TODO**: update_at/3 -- **TODO**: zip/1 diff --git a/users/wpcarro/emacs/pkgs/list/default.nix b/users/wpcarro/emacs/pkgs/list/default.nix deleted file mode 100644 index 3f220f631..000000000 --- a/users/wpcarro/emacs/pkgs/list/default.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ pkgs, depot, ... }: - -let - list = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "list"; - version = "1.0.0"; - src = ./list.el; - packageRequires = - (with depot.users.wpcarro.emacs.pkgs; [ - maybe - set - ]); - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ list ]); -in -list.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/list/list.el b/users/wpcarro/emacs/pkgs/list/list.el deleted file mode 100644 index 18be5f0a7..000000000 --- a/users/wpcarro/emacs/pkgs/list/list.el +++ /dev/null @@ -1,219 +0,0 @@ -;;; list.el --- Functions for working with lists -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Since I prefer having the `list-' namespace, I wrote this module to wrap many -;; of the functions that are defined in the the global namespace in Elisp. I -;; sometimes forget the names of these functions, so it's nice for them to be -;; organized like this. -;; -;; Motivation: -;; Here are some examples of function names where I prefer more modern -;; alternatives: -;; - `car': Return the first element (i.e. "head") of a linked list -;; - `cdr': Return the tail of a linked list - -;; As are most APIs for standard libraries that I write, this is influenced by -;; Elixir's standard library. -;; -;; Similar libraries: -;; - dash.el: Excellent and widely adopted library for working with lists. -;; - list-utils.el: Utility library that covers things that dash.el may not -;; cover. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'maybe) -(require 'set) -(require 'set) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun list-new () - "Return a new, empty list." - '()) - -(defun list-concat (&rest lists) - "Joins `LISTS' into on list." - (apply #'append lists)) - -(defun list-duplicate (n x) - "Duplicates the given element, X, N times in a list." - (list-map (lambda (_) x) (number-sequence 1 n))) - -(defun list-join (joint xs) - "Join a list of strings, XS, with JOINT." - (if (list-empty? xs) - "" - (list-reduce (list-first xs) - (lambda (x acc) - (format "%s%s%s" acc joint x)) - (list-tail xs)))) - -(defun list-length (xs) - "Return the number of elements in `XS'." - (length xs)) - -(defun list-get (i xs) - "Return the value in `XS' at `I', or nil." - (nth i xs)) - -(defun list-first (xs &optional default) - "Alias for `list-head' for `XS'." - (if (list-empty? xs) - default - (car xs))) - -(defun list-last (xs &optional default) - "Returns the last element in XS or DEFAULT if empty." - (if (list-empty? xs) - default - (nth (- (length xs) 1) xs))) - -(defun list-tail (xs) - "Return the tail of `XS'." - (cdr xs)) - -(defun list-reverse (xs) - "Reverses `XS'." - (reverse xs)) - -(defun list-cons (x xs) - "Add `X' to the head of `XS'." - (cons x xs)) - -(defun list-delete (x xs) - "Deletes the given element, X, from XS. -Returns a new list without X. If X occurs more than once, only the first - occurrence is removed." - (let ((deleted? nil)) - (list-reject (lambda (y) - (if deleted? nil - (when (equal x y) - (setq deleted? t) t))) - xs))) - -(defun list-filter (p xs) - "Return a subset of XS where predicate P returned t." - (list--assert-instance xs) - (seq-filter p xs)) - -(defun list-map (f xs) - "Call `F' on each element of `XS'." - (list--assert-instance xs) - (seq-map f xs)) - -(defun list-reduce (acc f xs) - "Return over `XS' calling `F' on an element in `XS'and `ACC'." - (list--assert-instance xs) - (seq-reduce (lambda (acc x) (funcall f x acc)) xs acc)) - -(defun list-map-indexed (f xs) - "Call `F' on each element of `XS' along with its index." - (list-reverse - (cdr - (list-reduce '(0 . nil) - (lambda (x acc) - (let ((i (car acc)) - (result (cdr acc))) - `(,(+ 1 i) . ,(cons (funcall f x i) result)))) - xs)))) - -(defun list-reject (p xs) - "Return a subset of XS where predicate of P return nil." - (list-filter (lambda (x) (not (funcall p x))) xs)) - -(defun list-find (p xs) - "Return the first x in XS that passes P or nil." - (list--assert-instance xs) - (seq-find p xs)) - -(defun list-dedupe-adjacent (xs) - "Return XS without adjacent duplicates." - (list-reverse - (list-reduce (list (list-first xs)) - (lambda (x acc) - (if (equal x (list-first acc)) - acc - (list-cons x acc))) - xs))) - -(defun list-chunk (n xs) - "Chunk XS into lists of size N." - (if (> n (length xs)) - (list xs) - (let* ((xs (list-reduce '(:curr () :result ()) - (lambda (x acc) - (let ((curr (plist-get acc :curr)) - (result (plist-get acc :result))) - (if (= (- n 1) (length curr)) - `(:curr () :result ,(list-cons (list-reverse (list-cons x curr)) result)) - `(:curr ,(list-cons x curr) :result - ,result)))) xs)) - (curr (plist-get xs :curr)) - (result (plist-get xs :result))) - (list-reverse (if curr (list-cons curr result) result))))) - -(defun list-wrap (xs) - "Wraps XS in a list if it is not a list already." - (if (list-instance? xs) - xs - (list xs))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Predicates -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun list-instance? (xs) - "Return t if `XS' is a list. -Be leery of using this with things like alists. Many data structures in Elisp - are implemented using linked lists." - (listp xs)) - -(defun list-empty? (xs) - "Return t if XS are empty." - (= 0 (list-length xs))) - -(defun list-all? (p xs) - "Return t if all `XS' pass the predicate, `P'." - (if (list-empty? xs) - t - (and (maybe-some? (funcall p (car xs))) - (list-all? p (cdr xs))))) - -(defun list-any? (p xs) - "Return t if any `XS' pass the predicate, `P'." - (if (list-empty? xs) - nil - (or (maybe-some? (funcall p (car xs))) - (list-any? p (cdr xs))))) - -(defun list-contains? (x xs) - "Return t if X is in XS using `equal'." - (list--assert-instance xs) - (maybe-some? (seq-contains-p xs x))) - -(defun list-xs-distinct-by? (f xs) - "Return t if all elements in XS are distinct after applying F to each." - (= (length xs) - (set-count (set-from-list (list-map f xs))))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Helpers -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun list--assert-instance (xs) - (unless (list-instance? xs) - (error (format "Assertion failed: argument is not a list: %s" xs)))) - -(provide 'list) -;;; list.el ends here diff --git a/users/wpcarro/emacs/pkgs/list/tests.el b/users/wpcarro/emacs/pkgs/list/tests.el deleted file mode 100644 index 4b4579688..000000000 --- a/users/wpcarro/emacs/pkgs/list/tests.el +++ /dev/null @@ -1,107 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'list) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(setq xs '(1 2 3 4 5)) - -(ert-deftest list-length () - (should (= 0 (list-length '()))) - (should (= 5 (list-length xs)))) - -(ert-deftest list-reduce () - (should (= 16 (list-reduce 1 (lambda (x acc) (+ x acc)) xs)))) - -(ert-deftest list-map () - (should - (equal '(2 4 6 8 10) - (list-map (lambda (x) (* x 2)) xs)))) - -(ert-deftest list-xs-distinct-by? () - (should - (equal t (list-xs-distinct-by? - (lambda (x) (plist-get x :kbd)) - '((:kbd "C-a" :name "foo") - (:kbd "C-b" :name "foo")))))) - -(ert-deftest list-dedupe-adjacent () - (should (equal '(1 2 3 4 3 5) - (list-dedupe-adjacent '(1 1 1 2 2 3 4 4 3 5 5))))) - -(ert-deftest list-contains? () - ;; Assert returns t or nil - (should (equal t (list-contains? 1 xs))) - (should (equal nil (list-contains? 100 xs)))) - -(ert-deftest list-join () - (should (equal "foo-bar-baz" - (list-join "-" '("foo" "bar" "baz"))))) - -(ert-deftest list-chunk () - (should (equal '((1 2 3 4 5 6)) - (list-chunk 7 '(1 2 3 4 5 6)))) - (should (equal '((1) (2) (3) (4) (5) (6)) - (list-chunk 1 '(1 2 3 4 5 6)))) - (should (equal '((1 2 3) (4 5 6)) - (list-chunk 3 '(1 2 3 4 5 6)))) - (should (equal '((1 2) (3 4) (5 6)) - (list-chunk 2 '(1 2 3 4 5 6))))) - -(ert-deftest list-find () - (should (equal 2 (list-find (lambda (x) (= 2 x)) '(1 2 3 4))))) - -(ert-deftest list-all? () - (should (equal t (list-all? (lambda (x) (= 2 x)) nil))) - (should (null (list-all? (lambda (x) (= 2 x)) '(1 2 3)))) - (should (equal t (list-all? (lambda (x) (= 2 x)) '(2 2 2 2))))) - -(ert-deftest list-any? () - (should (null (list-any? (lambda (x) (= 2 x)) nil))) - (should (equal t (list-any? (lambda (x) (= 2 x)) '(1 2 3)))) - (should (null (list-any? (lambda (x) (= 4 x)) '(1 2 3))))) - -(ert-deftest list-duplicate () - (should (equal '() (list-duplicate 0 "hello"))) - (should (equal '("hi") (list-duplicate 1 "hi"))) - (should (equal '("bye" "bye") (list-duplicate 2 "bye"))) - (should (equal '((1 2) (1 2) (1 2)) (list-duplicate 3 '(1 2))))) - -(ert-deftest list-first () - (should (null (list-first '()))) - (should (equal 1 (list-first '() 1))) - (should (equal 1 (list-first '(1)))) - (should (equal 1 (list-first '(1) 2))) - (should (equal 1 (list-first '(1 2 3))))) - -(ert-deftest list-last () - (should (null (list-last '()))) - (should (equal 1 (list-last '() 1))) - (should (equal 1 (list-last '(1)))) - (should (equal 1 (list-last '(1) 2))) - (should (equal 3 (list-last '(1 2 3))))) - -(ert-deftest list-wrap () - (should (equal '("hello") (list-wrap "hello"))) - (should (equal '(1 2 3) (list-wrap '(1 2 3)))) - (should (equal '() (list-wrap nil)))) - -(ert-deftest list-delete () - (should (equal '(b c) (list-delete 'a '(a b c)))) - (should (equal '(a b c) (list-delete 'd '(a b c)))) - (should (equal '(a b c) (list-delete 'b '(a b b c)))) - (should (equal '() (list-delete 'b '())))) - -(ert-deftest list-concat () - (should (equal '(1 2 3 4 5) (list-concat '(1) '(2 3) '(4 5)))) - (should (equal '(1 2 3) (list-concat '() '(1 2 3))))) - -;; TODO(wpcarro): Supoprt this. -;; (ert-deftest list-zip () -;; (should (equal '((1 3 5) (2 4 6)) (list-zip '(1 2) '(3 4) '(5 6)))) -;; (should (equal '((1 3 5)) (list-zip '(1 2) '(3) '(5 6))))) diff --git a/users/wpcarro/emacs/pkgs/macros/default.nix b/users/wpcarro/emacs/pkgs/macros/default.nix deleted file mode 100644 index d2811ed39..000000000 --- a/users/wpcarro/emacs/pkgs/macros/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ pkgs, depot, ... }: - -pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "macros"; - version = "1.0.0"; - src = ./macros.el; - }) -{ } diff --git a/users/wpcarro/emacs/pkgs/macros/macros.el b/users/wpcarro/emacs/pkgs/macros/macros.el deleted file mode 100644 index 3642686ee..000000000 --- a/users/wpcarro/emacs/pkgs/macros/macros.el +++ /dev/null @@ -1,45 +0,0 @@ -;;; macros.el --- Helpful variables for making my ELisp life more enjoyable -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; This file contains helpful variables that I use in my ELisp development. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defmacro macros-enable (mode) - "Helper for enabling `MODE'. -Useful in `add-hook' calls. Some modes, like `linum-mode' need to be called as -`(linum-mode 1)', so `(add-hook mode #'linum-mode)' won't work." - `#'(lambda nil (,mode 1))) - -(defmacro macros-disable (mode) - "Helper for disabling `MODE'. -Useful in `add-hook' calls." - `#'(lambda nil (,mode -1))) - -(defmacro macros-add-hook-before-save (mode f) - "Register a hook, `F', for a mode, `MODE' more conveniently. -Usage: (macros-add-hook-before-save 'reason-mode-hook #'refmt-before-save)" - `(add-hook ,mode - (lambda () - (add-hook 'before-save-hook ,f)))) - -(defmacro macros-comment (&rest _) - "Empty comment s-expresion where `BODY' is ignored." - `nil) - -(defmacro macros-support-file-extension (ext mode) - "Register MODE to automatically load with files ending with EXT extension. -Usage: (macros-support-file-extension \"pb\" protobuf-mode)" - (let ((extension (format "\\.%s\\'" ext))) - `(add-to-list 'auto-mode-alist '(,extension . ,mode)))) - -(provide 'macros) -;;; macros.el ends here diff --git a/users/wpcarro/emacs/pkgs/math/default.nix b/users/wpcarro/emacs/pkgs/math/default.nix deleted file mode 100644 index 1db5c847e..000000000 --- a/users/wpcarro/emacs/pkgs/math/default.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ pkgs, depot, ... }: - -let - math = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "math"; - version = "1.0.0"; - src = ./math.el; - packageRequires = - (with emacsPackages; [ - dash - ]) ++ - (with depot.users.wpcarro.emacs.pkgs; [ - maybe - ]); - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ - math - ]); -in -math.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/math/math.el b/users/wpcarro/emacs/pkgs/math/math.el deleted file mode 100644 index dbc527928..000000000 --- a/users/wpcarro/emacs/pkgs/math/math.el +++ /dev/null @@ -1,63 +0,0 @@ -;;; math.el --- Math stuffs -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Containing some useful mathematical functions. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'dash) -(require 'maybe) -(require 'cl-lib) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Constants -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defconst math-pi pi - "The number pi.") - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; TODO: Support all three arguments. -;; Int -> Int -> Int -> Boolean -(cl-defun math-triangle-of-power (&key base power result) - (cond - ((-all? #'maybe-some? (list base power result)) - (error "All three arguments should not be set")) - ((-all? #'maybe-some? (list power result)) - (message "power and result")) - ((-all? #'maybe-some? (list base result)) - (log result base)) - ((-all? #'maybe-some? (list base power)) - (expt base power)) - (t - (error "Two of the three arguments must be set")))) - -(defun math-mod (x y) - "Return X mod Y." - (mod x y)) - -(defun math-exp (x y) - "Return X raised to the Y." - (expt x y)) - -(defun math-round (x) - "Round X to nearest ones digit." - (round x)) - -(defun math-floor (x) - "Floor value X." - (floor x)) - -(provide 'math) -;;; math.el ends here diff --git a/users/wpcarro/emacs/pkgs/math/tests.el b/users/wpcarro/emacs/pkgs/math/tests.el deleted file mode 100644 index ef3430c91..000000000 --- a/users/wpcarro/emacs/pkgs/math/tests.el +++ /dev/null @@ -1,25 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'math) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest math-mod () - (should (= 0 (math-mod 9 3))) - (should (= 4 (math-mod 9 5)))) - -(ert-deftest math-exp () - (should (= 9 (math-exp 3 2))) - (should (= 8 (math-exp 2 3)))) - -(ert-deftest math-round () - (should (= 10 (math-round 9.5))) - (should (= 9 (math-round 9.45)))) - -(ert-deftest math-floor () - (should (= 9 (math-floor 9.5)))) diff --git a/users/wpcarro/emacs/pkgs/maybe/default.nix b/users/wpcarro/emacs/pkgs/maybe/default.nix deleted file mode 100644 index f0abf4c53..000000000 --- a/users/wpcarro/emacs/pkgs/maybe/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ pkgs, depot, ... }: - -let - maybe = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "maybe"; - version = "1.0.0"; - src = ./maybe.el; - packageRequires = [ ]; - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ - maybe - ]); -in -maybe.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/maybe/maybe.el b/users/wpcarro/emacs/pkgs/maybe/maybe.el deleted file mode 100644 index 581568d8c..000000000 --- a/users/wpcarro/emacs/pkgs/maybe/maybe.el +++ /dev/null @@ -1,54 +0,0 @@ -;;; maybe.el --- Library for dealing with nil values -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Inspired by Elm's Maybe library. -;; -;; For now, a Nothing value will be defined exclusively as a nil value. I'm -;; uninterested in supported falsiness in this module even at risk of going -;; against the LISP grain. -;; -;; I'm avoiding introducing a struct to handle the creation of Just and Nothing -;; variants of Maybe. Perhaps this is a mistake in which case this file would -;; be more aptly named nil.el. I may change that. Because of this limitation, -;; functions in Elm's Maybe library like andThen, which is the monadic bind for -;; the Maybe type, doesn't have a home here since we cannot compose multiple -;; Nothing or Just values without a struct or some other construct. -;; -;; Possible names for the variants of a Maybe. -;; None | Some -;; Nothing | Something -;; None | Just -;; Nil | Set -;; -;; NOTE: In Elisp, values like '() (i.e. the empty list) are aliases for nil. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun maybe-nil? (x) - "Return t if X is nil." - (null x)) - -(defun maybe-some? (x) - "Return t when X is non-nil." - (not (maybe-nil? x))) - -(defun maybe-default (default x) - "Return DEFAULT when X is nil." - (if (maybe-nil? x) default x)) - -(defun maybe-map (f x) - "Apply F to X if X is not nil." - (if (maybe-some? x) - (funcall f x) - x)) - -(provide 'maybe) -;;; maybe.el ends here diff --git a/users/wpcarro/emacs/pkgs/maybe/tests.el b/users/wpcarro/emacs/pkgs/maybe/tests.el deleted file mode 100644 index c0463cc65..000000000 --- a/users/wpcarro/emacs/pkgs/maybe/tests.el +++ /dev/null @@ -1,25 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'maybe) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest maybe-nil? () - (should (maybe-nil? nil)) - (should (not (maybe-nil? t)))) - -(ert-deftest maybe-some? () - (should (maybe-some? '(1 2 3))) - (should (not (maybe-some? nil)))) - -(ert-deftest maybe-default () - (should (string= "some" (maybe-default "some" nil))) - (should (= 10 (maybe-default 1 10)))) - -(ert-deftest maybe-map () - (should (eq nil (maybe-map (lambda (x) (* x 2)) nil))) - (should (= 4 (maybe-map (lambda (x) (* x 2)) 2)))) diff --git a/users/wpcarro/emacs/pkgs/passage/README.md b/users/wpcarro/emacs/pkgs/passage/README.md deleted file mode 100644 index 51f7bd6ef..000000000 --- a/users/wpcarro/emacs/pkgs/passage/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# passage.el - -Emacs support for `passage`. - -## Alternative Packages - -If you're looking for more feature-complete, configurable alternatives, -check-out the following packages: - -- `ivy-pass.el` -- `password-store.el` -- `pass.el` diff --git a/users/wpcarro/emacs/pkgs/passage/default.nix b/users/wpcarro/emacs/pkgs/passage/default.nix deleted file mode 100644 index ac87f193b..000000000 --- a/users/wpcarro/emacs/pkgs/passage/default.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ pkgs, depot, ... }: - -pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "passage"; - version = "1.0.0"; - src = ./passage.el; - packageRequires = (with emacsPackages; [ dash f s ]); - } - ) -{ } diff --git a/users/wpcarro/emacs/pkgs/passage/passage.el b/users/wpcarro/emacs/pkgs/passage/passage.el deleted file mode 100644 index 4a43920e0..000000000 --- a/users/wpcarro/emacs/pkgs/passage/passage.el +++ /dev/null @@ -1,65 +0,0 @@ -;;; passage.el --- Emacs passage support -*- lexical-binding: t; -*- - -;; Copyright (C) 2022-2023 William Carroll - -;; Author: William Carroll -;; Version: 1.0.0 - -;; This file is not part of GNU Emacs. - -;; This program is free software: you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, either version 3 of the License, or -;; (at your option) any later version. - -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. - -;; You should have received a copy of the GNU General Public License -;; along with this program. If not, see . - -;;; Commentary: - -;; This package provides functions for working with passage. - -;;; Code: - -(require 'dash) -(require 'f) -(require 's) - -(defgroup passage nil - "Customization options for `passage'." - :prefix "passage-" - :group 'vterm) - -(defcustom passage-store - "~/.passage/store" - "Path to the passage store directory." - :type 'string - :group 'passage) - -(defcustom passage-executable - (or (executable-find "passage") - "/nix/store/jgffkfdiiwiqa4zqpxn3691mx9xc6axa-passage-unstable-2022-05-01/bin/passage") - "Path to passage executable." - :type 'string - :group 'passage) - -(defun passage-select () - "Select an entry and copy its password to the kill ring." - (interactive) - (let ((key (completing-read "Copy password of entry: " - (-map (lambda (x) - (f-no-ext (f-relative x passage-store))) - (f-files passage-store nil t))))) - (kill-new - (s-trim-right - (shell-command-to-string - (format "%s show %s | head -1" passage-executable key)))) - (message "[passage.el] Copied \"%s\"!" key))) - -(provide 'passage) -;;; passage.el ends here diff --git a/users/wpcarro/emacs/pkgs/set/default.nix b/users/wpcarro/emacs/pkgs/set/default.nix deleted file mode 100644 index feb9ac272..000000000 --- a/users/wpcarro/emacs/pkgs/set/default.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ pkgs, depot, ... }: - -let - set = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "set"; - version = "1.0.0"; - src = ./set.el; - packageRequires = - (with emacsPackages; [ - dash - ht - ]) ++ - (with depot.users.wpcarro.emacs.pkgs; [ - struct - ]); - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ - epkgs.dash - set - ]); -in -set.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/set/set.el b/users/wpcarro/emacs/pkgs/set/set.el deleted file mode 100644 index 2d6e14917..000000000 --- a/users/wpcarro/emacs/pkgs/set/set.el +++ /dev/null @@ -1,116 +0,0 @@ -;;; set.el --- Working with mathematical sets -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; The set data structure is a collection that deduplicates its elements. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'cl-lib) -(require 'dash) -(require 'ht) ;; friendlier API for hash-tables -(require 'struct) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Wish List -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;; - TODO: Support enum protocol for set. -;; - TODO: Prefer a different hash-table library that doesn't rely on mutative -;; code. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(cl-defstruct set xs) - -(defun set-from-list (xs) - "Create a new set from the list XS." - (make-set :xs (->> xs - (-map (lambda (x) (cons x nil))) - ht-from-alist))) - -(defun set-new (&rest args) - "Create a new set from ARGS." - (set-from-list args)) - -(defun set-to-list (xs) - "Map set XS into a list." - (->> xs - set-xs - ht-keys)) - -(defun set-add (x xs) - "Add X to set XS." - (struct-update set - xs - (lambda (table) - (let ((table-copy (ht-copy table))) - (ht-set table-copy x nil) - table-copy)) - xs)) - -;; TODO: Ensure all `*/reduce' functions share the same API. -(defun set-reduce (acc f xs) - "Return a new set by calling F on each element of XS and ACC." - (->> xs - set-to-list - (-reduce-from (lambda (acc x) (funcall f x acc)) acc))) - -(defun set-intersection (a b) - "Return the set intersection between A and B." - (set-reduce (set-new) - (lambda (x acc) - (if (set-contains? x b) - (set-add x acc) - acc)) - a)) - -(defun set-count (xs) - "Return the number of elements in XS." - (->> xs - set-xs - ht-size)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Predicates -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun set-empty? (xs) - "Return t if XS has no elements in it." - (= 0 (set-count xs))) - -(defun set-contains? (x xs) - "Return t if set XS has X." - (ht-contains? (set-xs xs) x)) - -;; TODO: Prefer using `ht.el' functions for this. -(defun set-equal? (a b) - "Return t if A and B share the name members." - (ht-equal? (set-xs a) - (set-xs b))) - -(defun set-distinct? (a b) - "Return t if A and B have no shared members." - (set-empty? (set-intersection a b))) - -(defun set-superset? (a b) - "Return t if A has all of the members of B." - (->> b - set-to-list - (-all? (lambda (x) (set-contains? x a))))) - -(defun set-subset? (a b) - "Return t if each member of set A is present in set B." - (set-superset? b a)) - -(provide 'set) -;;; set.el ends here diff --git a/users/wpcarro/emacs/pkgs/set/tests.el b/users/wpcarro/emacs/pkgs/set/tests.el deleted file mode 100644 index 7f5c2ae3f..000000000 --- a/users/wpcarro/emacs/pkgs/set/tests.el +++ /dev/null @@ -1,69 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'dash) -(require 'set) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest set-from-list () - (should (equal '(1 2 3) - (->> '(1 2 3 1 2 3) - set-from-list - set-to-list)))) - -(ert-deftest set-distinct? () - (should (set-distinct? (set-new 'one 'two 'three) - (set-new 'a 'b 'c))) - (should (not - (set-distinct? (set-new 1 2 3) - (set-new 3 4 5)))) - (should (not - (set-distinct? (set-new 1 2 3) - (set-new 1 2 3))))) - -(ert-deftest set-equal? () - (should (not (set-equal? (set-new 'a 'b 'c) - (set-new 'x 'y 'z)))) - (should (not (set-equal? (set-new 'a 'b 'c) - (set-new 'a 'b)))) - (should (set-equal? (set-new 'a 'b 'c) - (set-new 'a 'b 'c)))) - -(ert-deftest set-intersection () - (should (set-equal? (set-new 2 3) - (set-intersection (set-new 1 2 3) - (set-new 2 3 4))))) - -(ert-deftest set-to/from-list () - (should (equal '(1 2 3) - (->> '(1 1 2 2 3 3) - set-from-list - set-to-list)))) - -(ert-deftest set-subset? () - (should (not (set-subset? (set-new "black" "grey") - (set-new "red" "green" "blue")))) - (should (set-subset? (set-new "red") - (set-new "red" "green" "blue")))) - -(ert-deftest set-superset? () - (let ((primary-colors (set-new "red" "green" "blue"))) - (should (not (set-superset? primary-colors - (set-new "black" "grey")))) - (should (set-superset? primary-colors - (set-new "red" "green" "blue"))) - (should (set-superset? primary-colors - (set-new "red" "blue"))))) - -(ert-deftest set-empty? () - (should (set-empty? (set-new))) - (should (not (set-empty? (set-new 1 2 3))))) - -(ert-deftest set-count () - (should (= 0 (set-count (set-new)))) - (should (= 2 (set-count (set-new 1 1 2 2))))) diff --git a/users/wpcarro/emacs/pkgs/string/default.nix b/users/wpcarro/emacs/pkgs/string/default.nix deleted file mode 100644 index 0ae53b208..000000000 --- a/users/wpcarro/emacs/pkgs/string/default.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ pkgs, depot, ... }: - -let - string = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "string"; - version = "1.0.0"; - src = ./string.el; - packageRequires = [ - emacsPackages.dash - emacsPackages.s - ]; - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ - string - ]); -in -string.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/string/string.el b/users/wpcarro/emacs/pkgs/string/string.el deleted file mode 100644 index 30da1805e..000000000 --- a/users/wpcarro/emacs/pkgs/string/string.el +++ /dev/null @@ -1,98 +0,0 @@ -;;; string.el --- Library for working with strings -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Library for working with strings. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 's) -(require 'dash) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun string-split (y x) - "Map string X into a list of strings that were separated by Y." - (s-split y x)) - -(defun string-format (x &rest args) - "Format template string X with ARGS." - (apply #'format (cons x args))) - -(defun string-concat (&rest strings) - "Joins `STRINGS' into onto string." - (apply #'s-concat strings)) - -(defun string-to-symbol (string) - "Maps `STRING' to a symbol." - (intern string)) - -(defun string-from-symbol (symbol) - "Maps `SYMBOL' into a string." - (symbol-name symbol)) - -(defun string-prepend (prefix x) - "Prepend `PREFIX' onto `X'." - (s-concat prefix x)) - -(defun string-append (postfix x) - "Appen `POSTFIX' onto `X'." - (s-concat x postfix)) - -(defun string-surround (s x) - "Surrounds `X' one each side with `S'." - (->> x - (string-prepend s) - (string-append s))) - -;; TODO: Define a macro for defining a function and a test. - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Casing -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun string-caps->kebab (x) - "Change the casing of `X' from CAP_CASE to kebab-case." - (->> x - s-downcase - (s-replace "_" "-"))) - -(defun string-kebab->caps (x) - "Change the casing of X from CAP_CASE to kebab-case." - (->> x - s-upcase - (s-replace "-" "_"))) - -(defun string-lower->caps (x) - "Change the casing of X from lowercase to CAPS_CASE." - (->> x - s-upcase - (s-replace " " "_"))) - -(defun string-lower->kebab (x) - "Change the casing of `X' from lowercase to kebab-case." - (s-replace " " "-" x)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Predicates -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun string-instance? (x) - "Return t if X is a string." - (stringp x)) - -(defun string-contains? (c x) - "Return t if X is in C." - (s-contains? c x)) - -(provide 'string) -;;; string.el ends here diff --git a/users/wpcarro/emacs/pkgs/string/tests.el b/users/wpcarro/emacs/pkgs/string/tests.el deleted file mode 100644 index 351e30546..000000000 --- a/users/wpcarro/emacs/pkgs/string/tests.el +++ /dev/null @@ -1,22 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'string) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest string-caps->kebab () - (should (string= "foo-bar-baz" (string-caps->kebab "FOO_BAR_BAZ")))) - -(ert-deftest string-kebab->caps () - (should (string= "FOO_BAR_BAZ" (string-kebab->caps "foo-bar-baz")))) - -(ert-deftest string-lower->caps () - (should (string= "FOO_BAR_BAZ" (string-lower->caps "foo bar baz")))) - -(ert-deftest string-lower->kebab () - (should (string= "foo-bar-baz" (string-lower->kebab "foo bar baz")))) diff --git a/users/wpcarro/emacs/pkgs/struct/README.md b/users/wpcarro/emacs/pkgs/struct/README.md deleted file mode 100644 index 34dac6614..000000000 --- a/users/wpcarro/emacs/pkgs/struct/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# struct.el - -[![Build status](https://badge.buildkite.com/016bff4b8ae2704a3bbbb0a250784e6692007c582983b6dea7.svg?branch=refs/heads/canon)](https://buildkite.com/tvl/depot) - -Provides new macros exposing immutable and mutable interfaces for working with -structs in Elisp. diff --git a/users/wpcarro/emacs/pkgs/struct/default.nix b/users/wpcarro/emacs/pkgs/struct/default.nix deleted file mode 100644 index e3037bfbf..000000000 --- a/users/wpcarro/emacs/pkgs/struct/default.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ pkgs, depot, ... }: - -let - struct = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "struct"; - version = "1.0.0"; - src = ./struct.el; - packageRequires = [ ]; - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ - struct - ]); -in -struct.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; - passthru.meta.ci.extraSteps.github = depot.tools.releases.filteredGitPush { - filter = ":/users/wpcarro/emacs/pkgs/struct"; - remote = "git@github.com:wpcarro/struct.el.git"; - ref = "refs/heads/canon"; - }; -}) diff --git a/users/wpcarro/emacs/pkgs/struct/struct.el b/users/wpcarro/emacs/pkgs/struct/struct.el deleted file mode 100644 index 5d6572bf6..000000000 --- a/users/wpcarro/emacs/pkgs/struct/struct.el +++ /dev/null @@ -1,65 +0,0 @@ -;;; struct.el --- Helpers for working with structs -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 1.0.0 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; Provides new macros for working with structs. Also provides adapter -;; interfaces to existing struct macros, that should have more intuitive -;; interfaces. -;; -;; Sometimes `setf' just isn't enough. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defmacro struct-update (type field f xs) - "Apply F to FIELD in XS, which is a struct of TYPE. -This is immutable." - (let ((copier (struct--copier-for type)) - (accessor (struct--accessor-for type field))) - `(let ((copy (,copier ,xs))) - (setf (,accessor copy) (funcall ,f (,accessor copy))) - copy))) - -(defmacro struct-update! (type field f xs) - "Mutably apply F to FIELD in XS." - (let ((accessor (struct--accessor-for type field))) - `(progn - (setf (,accessor ,xs) (funcall ,f (,accessor ,xs))) - ,xs))) - -(defmacro struct-set (type field x xs) - "Immutably set FIELD in XS (struct TYPE) to X." - (let ((copier (struct--copier-for type)) - (accessor (struct--accessor-for type field))) - `(let ((copy (,copier ,xs))) - (setf (,accessor copy) ,x) - copy))) - -(defmacro struct-set! (type field x xs) - "Set FIELD in XS (struct TYPE) to X mutably. -This is an adapter interface to `setf'." - (let ((accessor (struct--accessor-for type field))) - `(progn - (setf (,accessor ,xs) ,x) - ,xs))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Helper Functions -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun struct--copier-for (type) - (intern (format "copy-%s" (symbol-name type)))) - -(defun struct--accessor-for (type field) - (intern (format "%s-%s" - (symbol-name type) - (symbol-name field)))) - -(provide 'struct) -;;; struct.el ends here diff --git a/users/wpcarro/emacs/pkgs/struct/tests.el b/users/wpcarro/emacs/pkgs/struct/tests.el deleted file mode 100644 index a7ddb52c4..000000000 --- a/users/wpcarro/emacs/pkgs/struct/tests.el +++ /dev/null @@ -1,44 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'struct) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(cl-defstruct dummy name age) - -(ert-deftest struct-update () - (let* ((test (make-dummy :name "Roofus" :age 19)) - (result (struct-update dummy name #'upcase test))) - ;; test - (should (string= "Roofus" (dummy-name test))) - (should (= 19 (dummy-age test))) - ;; result - (should (string= "ROOFUS" (dummy-name result))) - (should (= 19 (dummy-age result))))) - -(ert-deftest struct-update! () - (let ((test (make-dummy :name "Roofus" :age 19))) - (struct-update! dummy name #'upcase test) - (should (string= "ROOFUS" (dummy-name test))) - (should (= 19 (dummy-age test))))) - -(ert-deftest struct-set () - (let* ((test (make-dummy :name "Roofus" :age 19)) - (result (struct-set dummy name "Shoofus" test))) - ;; test - (should (string= "Roofus" (dummy-name test))) - (should (= 19 (dummy-age test))) - ;; result - (should (string= "Shoofus" (dummy-name result))) - (should (= 19 (dummy-age result))))) - -(ert-deftest struct-set! () - (let ((test (make-dummy :name "Roofus" :age 19))) - (struct-set! dummy name "Doofus" test) - (should (string= "Doofus" (dummy-name test))) - (should (= 19 (dummy-age test))))) diff --git a/users/wpcarro/emacs/pkgs/symbol/default.nix b/users/wpcarro/emacs/pkgs/symbol/default.nix deleted file mode 100644 index c10b69166..000000000 --- a/users/wpcarro/emacs/pkgs/symbol/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ pkgs, depot, ... }: - -let - symbol = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "symbol"; - version = "1.0.0"; - src = ./symbol.el; - packageRequires = [ ]; - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ - symbol - ]); -in -symbol.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/symbol/symbol.el b/users/wpcarro/emacs/pkgs/symbol/symbol.el deleted file mode 100644 index 4b1635183..000000000 --- a/users/wpcarro/emacs/pkgs/symbol/symbol.el +++ /dev/null @@ -1,38 +0,0 @@ -;;; symbol.el --- Library for working with symbols -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; Library for working with symbols. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun symbol-to-string (symbol) - "Map `SYMBOL' into a string." - (symbol-name symbol)) - -(defun symbol-from-string (string) - "Map `STRING' into a symbol." - (intern string)) - -(defun symbol-as-string (f x) - "Treat the symbol, X, as a string while applying F to it. -Coerce back to a symbol on the way out." - (symbol-from-string (funcall f (symbol-to-string x)))) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Predicates -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun symbol-instance? (x) - "Return t if X is a symbol." - (symbolp x)) - -(provide 'symbol) -;;; symbol.el ends here diff --git a/users/wpcarro/emacs/pkgs/symbol/tests.el b/users/wpcarro/emacs/pkgs/symbol/tests.el deleted file mode 100644 index b10362b16..000000000 --- a/users/wpcarro/emacs/pkgs/symbol/tests.el +++ /dev/null @@ -1,22 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'symbol) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest symbol-to-string () - (should (string= "foo" (symbol-to-string 'foo)))) - -(ert-deftest symbol-from-string () - (should (eq 'foo (symbol-from-string "foo")))) - -(ert-deftest symbol-as-string () - (should (eq 'foo-hook - (symbol-as-string - (lambda (x) (format "%s-hook" x)) - 'foo)))) diff --git a/users/wpcarro/emacs/pkgs/theme/default.nix b/users/wpcarro/emacs/pkgs/theme/default.nix deleted file mode 100644 index aea639436..000000000 --- a/users/wpcarro/emacs/pkgs/theme/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ pkgs, depot, ... }: - -pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "theme"; - version = "1.0.0"; - src = ./theme.el; - packageRequires = - (with depot.users.wpcarro.emacs.pkgs; [ - cycle - ]); - }) -{ } diff --git a/users/wpcarro/emacs/pkgs/theme/theme.el b/users/wpcarro/emacs/pkgs/theme/theme.el deleted file mode 100644 index 32f2c89a4..000000000 --- a/users/wpcarro/emacs/pkgs/theme/theme.el +++ /dev/null @@ -1,78 +0,0 @@ -;;; theme.el --- Colors and stuff -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24.3")) - -;;; Commentary: -;; -;; Cycle through a whitelist of themes. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'cycle) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgroup theme nil - "Customization options for `theme'." - :group 'theme) - -(defcustom theme-whitelist - (cycle-from-list (custom-available-themes)) - "The whitelist of themes through which to cycle." - :type '(cycle symbol) - :group 'theme) - -(defcustom theme-after-change - nil - "Hook invoked after a new theme is loaded" - :type 'hook - :group 'theme) - -(defun theme-whitelist-set (theme) - "Focus the THEME in the `theme-whitelist' cycle." - (cycle-focus! (lambda (x) (equal x theme)) theme-whitelist) - (theme--set (cycle-current theme-whitelist))) - -(defun theme-select () - "Load a theme using `completing-read'." - (interactive) - (let ((theme (completing-read "Theme: " (cycle-to-list theme-whitelist)))) - (theme--disable-all) - (theme--set (intern theme)))) - -(defun theme-next () - "Disable the currently active theme and load the next theme." - (interactive) - (disable-theme (cycle-current theme-whitelist)) - (theme--set (cycle-next! theme-whitelist)) - (message (format "Active theme: %s" (cycle-current theme-whitelist)))) - -(defun theme-prev () - "Disable the currently active theme and load the previous theme." - (interactive) - (disable-theme (cycle-current theme-whitelist)) - (theme--set (cycle-prev! theme-whitelist)) - (message (format "Active theme: %s" (cycle-current theme-whitelist)))) - -(defun theme--disable-all () - "Disable all currently enabled themes." - (interactive) - (dolist (x custom-enabled-themes) - (disable-theme x))) - -(defun theme--set (theme) - "Call `load-theme' with `THEME', ensuring that the line numbers are bright. -There is no hook that I'm aware of to handle this more elegantly." - (load-theme theme t) - (run-hooks 'theme-after-change)) - -(provide 'theme) -;;; theme.el ends here diff --git a/users/wpcarro/emacs/pkgs/tuple/default.nix b/users/wpcarro/emacs/pkgs/tuple/default.nix deleted file mode 100644 index 0626370e4..000000000 --- a/users/wpcarro/emacs/pkgs/tuple/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ pkgs, depot, ... }: - -pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "tuple"; - version = "1.0.0"; - src = ./tuple.el; - }) -{ } diff --git a/users/wpcarro/emacs/pkgs/tuple/tuple.el b/users/wpcarro/emacs/pkgs/tuple/tuple.el deleted file mode 100644 index 848c6fa48..000000000 --- a/users/wpcarro/emacs/pkgs/tuple/tuple.el +++ /dev/null @@ -1,93 +0,0 @@ -;;; tuple.el --- Tuple API for Elisp -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; Work with cons cells with two elements with a familiar API for those who have -;; worked with tuples before. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(cl-defstruct tuple first second) - -;; Create -(defun tuple-new () - "Return an empty tuple." - (make-tuple :first nil - :second nil)) - -(defun tuple-from (a b) - "Return a new tuple from A and B." - (make-tuple :first a - :second b)) - -(defun tuple-from-dotted (dp) - "Convert dotted pair, DP, into a tuple." - (tuple-from (car dp) (cdr dp))) - -;; Read -(defun tuple-first (pair) - "Return the first element of PAIR." - (tuple-first pair)) - -(defun tuple-second (pair) - "Return the second element of PAIR." - (tuple-second pair)) - -;; Update -(defun tuple-map-each (f g pair) - "Apply F to first, G to second in PAIR." - (->> pair - (tuple-map-first f) - (tuple-map-second g))) - -(defun tuple-map (f pair) - "Apply F to PAIR." - (let ((pair-copy (copy-tuple pair))) - (funcall f pair-copy))) - -(defun tuple-map-first (f pair) - "Apply function F to the first element of PAIR." - (let ((pair-copy (copy-tuple pair))) - (setf (tuple-first pair-copy) (funcall f (tuple-first pair-copy))) - pair-copy)) - -(defun tuple-map-second (f pair) - "Apply function F to the second element of PAIR." - (let ((pair-copy (copy-tuple pair))) - (setf (tuple-second pair-copy) (funcall f (tuple-second pair-copy))) - pair-copy)) - -(defun tuple-set-first (a pair) - "Return a new tuple with the first element set as A in PAIR." - (tuple-map-first (lambda (_) a) pair)) - -(defun tuple-set-second (b pair) - "Return a new tuple with the second element set as B in PAIR." - (tuple-map-second (lambda (_) b) pair)) - -;; Delete -(defun tuple-delete-first (pair) - "Return PAIR with the first element set to nil." - (tuple-set-first nil pair)) - -(defun tuple-delete-second (pair) - "Return PAIR with the second element set to nil." - (tuple-set-second nil pair)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Predicates -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun tuple-instance? (x) - "Return t if X is a tuple." - (tuple-p x)) - -(provide 'tuple) -;;; tuple.el ends here diff --git a/users/wpcarro/emacs/pkgs/vector/default.nix b/users/wpcarro/emacs/pkgs/vector/default.nix deleted file mode 100644 index 23932935a..000000000 --- a/users/wpcarro/emacs/pkgs/vector/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ pkgs, depot, ... }: - -let - vector = pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "vector"; - version = "1.0.0"; - src = ./vector.el; - }) - { }; - - emacs = (pkgs.emacsPackagesFor pkgs.emacs).emacsWithPackages (epkgs: [ vector ]); -in -vector.overrideAttrs (_old: { - doCheck = true; - checkPhase = '' - ${emacs}/bin/emacs -batch \ - -l ert -l ${./tests.el} -f ert-run-tests-batch-and-exit - ''; -}) diff --git a/users/wpcarro/emacs/pkgs/vector/tests.el b/users/wpcarro/emacs/pkgs/vector/tests.el deleted file mode 100644 index ffa983188..000000000 --- a/users/wpcarro/emacs/pkgs/vector/tests.el +++ /dev/null @@ -1,20 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'ert) -(require 'vector) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Tests -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(ert-deftest vector-misc-tests () - (let ((xs [1 2 3]) - (ys [1 2 3])) - (should (= 1 (vector-get 0 ys))) - (vector-set 0 4 ys) - (should (= 1 (vector-get 0 ys))) - (should (= 1 (vector-get 0 xs))) - (vector-set! 0 4 xs) - (should (= 4 (vector-get 0 xs))))) diff --git a/users/wpcarro/emacs/pkgs/vector/vector.el b/users/wpcarro/emacs/pkgs/vector/vector.el deleted file mode 100644 index 87f38d7d9..000000000 --- a/users/wpcarro/emacs/pkgs/vector/vector.el +++ /dev/null @@ -1,58 +0,0 @@ -;;; vector.el --- Working with Elisp's Vector data type -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; It might be best to think of Elisp vectors as tuples in languages like -;; Haskell or Erlang. -;; -;; Not surprisingly, this API is modelled after Elixir's Tuple API. -;; -;; Some Elisp trivia: -;; - "Array": Usually means vector or string. -;; - "Sequence": Usually means list or "array" (see above). -;; -;; It might be a good idea to think of Array and Sequence as typeclasses in -;; Elisp. This is perhaps more similar to Elixir's notion of the Enum protocol. -;; -;; Intentionally not supporting a to-list function, because tuples can contain -;; heterogenous types whereas lists should contain homogenous types. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Library -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defun vector-concat (&rest args) - "Return a new vector composed of all vectors in `ARGS'." - (apply #'vconcat args)) - -(defun vector-prepend (x xs) - "Add `X' to the beginning of `XS'." - (vector-concat `[,x] xs)) - -(defun vector-append (x xs) - "Add `X' to the end of `XS'." - (vector-concat xs `[,x])) - -(defun vector-get (i xs) - "Return the value in `XS' at index, `I'." - (aref xs i)) - -(defun vector-set (i v xs) - "Set index `I' to value `V' in `XS'. -Returns a copy of `XS' with the updates." - (let ((copy (vconcat [] xs))) - (aset copy i v) - copy)) - -(defun vector-set! (i v xs) - "Set index `I' to value `V' in `XS'. -This function mutates XS." - (aset xs i v)) - -(provide 'vector) -;;; vector.el ends here diff --git a/users/wpcarro/emacs/pkgs/vterm-mgt/README.md b/users/wpcarro/emacs/pkgs/vterm-mgt/README.md deleted file mode 100644 index b85582692..000000000 --- a/users/wpcarro/emacs/pkgs/vterm-mgt/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# vterm-mgt.el - -[![Build status](https://badge.buildkite.com/016bff4b8ae2704a3bbbb0a250784e6692007c582983b6dea7.svg?branch=refs/heads/canon)](https://buildkite.com/tvl/depot) - -[emacs-libvterm](https://github.com/akermu/emacs-libvterm) is a feature-complete -terminal emulator inside Emacs based on libvterm. - -`vterm-mgt.el`, adds functionality on top of `vterm` to allow you to: - -* find-or-create `vterm` instances -* fuzzily switch between existing `vterm` buffers -* cycle through existing `vterm` instances -* easily rename `vterm` buffers - -## Alternatives to vterm-mgt.el - -* [multi-vterm](https://github.com/suonlight/multi-vterm) diff --git a/users/wpcarro/emacs/pkgs/vterm-mgt/default.nix b/users/wpcarro/emacs/pkgs/vterm-mgt/default.nix deleted file mode 100644 index 88eb55020..000000000 --- a/users/wpcarro/emacs/pkgs/vterm-mgt/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ pkgs, depot, ... }: - -pkgs.emacsPackages.trivialBuild { - pname = "vterm-mgt"; - version = "1.0.0"; - src = ./vterm-mgt.el; - packageRequires = - (with pkgs.emacsPackages; [ - vterm - ]) ++ - (with depot.users.wpcarro.emacs.pkgs; [ - cycle - ]); - passthru.meta.ci.extraSteps.github = depot.tools.releases.filteredGitPush { - filter = ":/users/wpcarro/emacs/pkgs/vterm-mgt"; - remote = "git@github.com:wpcarro/vterm-mgt.el.git"; - ref = "refs/heads/canon"; - }; -} diff --git a/users/wpcarro/emacs/pkgs/vterm-mgt/vterm-mgt.el b/users/wpcarro/emacs/pkgs/vterm-mgt/vterm-mgt.el deleted file mode 100644 index c082e54a5..000000000 --- a/users/wpcarro/emacs/pkgs/vterm-mgt/vterm-mgt.el +++ /dev/null @@ -1,140 +0,0 @@ -;;; vterm-mgt.el --- Help me manage my vterm instances -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "25.1")) - -;;; Commentary: -;; Supporting functions to instantiate vterm buffers, kill existing vterm -;; buffers, rename vterm buffers, cycle forwards and backwards through vterm -;; buffers. -;; -;; Many of the functions defined herein are intended to be bound to -;; `vterm-mode-map'. Some assertions are made to guard against calling -;; functions that are intended to be called from outside of a vterm buffer. -;; These assertions shouldn't error when the functions are bound to -;; `vterm-mode-map'. If for some reason, you'd like to bind these functions to -;; a separate keymap, caveat emptor. - -;;; Code: - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'cycle) -(require 'vterm) -(require 'seq) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(defgroup vterm-mgt nil - "Customization options for `vterm-mgt'." - :group 'vterm) - -(defcustom vterm-mgt-scroll-on-focus nil - "When t, call `end-of-buffer' after focusing a vterm instance." - :type '(boolean) - :group 'vterm-mgt) - -(defconst vterm-mgt--instances (cycle-new) - "A cycle tracking all of my vterm instances.") - -(defun vterm-mgt--instance? (b) - "Return t if the buffer B is a vterm instance." - (equal 'vterm-mode (buffer-local-value 'major-mode b))) - -(defun vterm-mgt--assert-vterm-buffer () - "Error when the `current-buffer' is not a vterm buffer." - (unless (vterm-mgt--instance? (current-buffer)) - (error "Current buffer is not a vterm buffer"))) - -(defun vterm-mgt-next () - "Replace the current buffer with the next item in `vterm-mgt--instances'. -This function should be called from a buffer running vterm." - (interactive) - (vterm-mgt--assert-vterm-buffer) - (vterm-mgt-reconcile-state) - (cycle-focus-item! (current-buffer) vterm-mgt--instances) - (switch-to-buffer (cycle-next! vterm-mgt--instances)) - (when vterm-mgt-scroll-on-focus (end-of-buffer))) - -(defun vterm-mgt-prev () - "Replace the current buffer with the previous item in `vterm-mgt--instances'. -This function should be called from a buffer running vterm." - (interactive) - (vterm-mgt--assert-vterm-buffer) - (vterm-mgt-reconcile-state) - (cycle-focus-item! (current-buffer) vterm-mgt--instances) - (switch-to-buffer (cycle-prev! vterm-mgt--instances)) - (when vterm-mgt-scroll-on-focus (end-of-buffer))) - -(defun vterm-mgt-instantiate () - "Create a new vterm instance. - -Prefer calling this function instead of `vterm'. This function ensures that the - newly created instance is added to `vterm-mgt--instances'. - -If however you must call `vterm', if you'd like to cycle through vterm - instances, make sure you call `vterm-mgt-reconcile-state' to allow vterm-mgt - to collect any untracked vterm instances." - (interactive) - (vterm-mgt-reconcile-state) - (let ((buffer (vterm t))) - (cycle-append! buffer vterm-mgt--instances) - (cycle-focus-item! buffer vterm-mgt--instances))) - -(defun vterm-mgt-kill () - "Kill the current buffer and remove it from `vterm-mgt--instances'. -This function should be called from a buffer running vterm." - (interactive) - (vterm-mgt--assert-vterm-buffer) - (let* ((buffer (current-buffer))) - (when (kill-buffer buffer) - (vterm-mgt-reconcile-state)))) - -(defun vterm-mgt-find-or-create () - "Call `switch-to-buffer' on a focused vterm instance if there is one. - -When `cycle-focused?' returns nil, focus the first item in the cycle. When -there are no items in the cycle, call `vterm-mgt-instantiate' to create a vterm -instance." - (interactive) - (vterm-mgt-reconcile-state) - (if (cycle-empty? vterm-mgt--instances) - (vterm-mgt-instantiate) - (if (cycle-focused? vterm-mgt--instances) - (switch-to-buffer (cycle-current vterm-mgt--instances)) - (progn - (cycle-jump! 0 vterm-mgt--instances) - (switch-to-buffer (cycle-current vterm-mgt--instances)))))) - -(defun vterm-mgt-rename-buffer (name) - "Rename the current buffer ensuring that its NAME is wrapped in *vterm<...>*. -This function should be called from a buffer running vterm." - (interactive "SRename vterm buffer: ") - (vterm-mgt--assert-vterm-buffer) - (rename-buffer (format "*vterm<%s>*" name))) - -(defun vterm-mgt-reconcile-state () - "Fill `vterm-mgt--instances' with the existing vterm buffers. - -If for whatever reason, the state of `vterm-mgt--instances' is corrupted and - misaligns with the state of vterm buffers in Emacs, use this function to - restore the state." - (interactive) - (setq vterm-mgt--instances - (cycle-from-list (seq-filter #'vterm-mgt--instance? (buffer-list))))) - -(defun vterm-mgt-select () - "Select a vterm instance by name from the list in `vterm-mgt--instances'." - (interactive) - (vterm-mgt-reconcile-state) - (switch-to-buffer - (completing-read "Switch to vterm: " - (seq-map #'buffer-name (cycle-to-list vterm-mgt--instances))))) - -(provide 'vterm-mgt) -;;; vterm-mgt.el ends here diff --git a/users/wpcarro/emacs/pkgs/zle/default.nix b/users/wpcarro/emacs/pkgs/zle/default.nix deleted file mode 100644 index 9d4820a94..000000000 --- a/users/wpcarro/emacs/pkgs/zle/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ pkgs, ... }: - -pkgs.callPackage - ({ emacsPackages }: - emacsPackages.trivialBuild { - pname = "zle"; - version = "1.0.0"; - src = ./zle.el; - }) -{ } diff --git a/users/wpcarro/emacs/pkgs/zle/zle.el b/users/wpcarro/emacs/pkgs/zle/zle.el deleted file mode 100644 index 21a6e35f1..000000000 --- a/users/wpcarro/emacs/pkgs/zle/zle.el +++ /dev/null @@ -1,90 +0,0 @@ -;;; zle.el --- Functions to mimmick my ZLE KBDs -*- lexical-binding: t -*- - -;; Author: William Carroll -;; Version: 0.0.1 -;; Package-Requires: ((emacs "24")) - -;;; Commentary: -;; This is primarily for personal use. The keybindings that I choose are those -;; that feel slightly mnemonic while also not shadowing important bindings. -;; It's quite possible that our tastes will differ here. -;; -;; All of these keybindings are intended to shave off milliseconds off your -;; typing. I don't expect these numbers to sum up to a meaningful amount. The -;; primary reason that I wrote this, is that it introduces a small amount of -;; structural editing to my workflow. I've been using these exact keybindings -;; on the command line, and I find them subtely delightful to use. So much so -;; that I decided to bring them to my Emacs configuration. -;; -;; ZLE is the Z-shell line editor. I have some KBDs and functions that I often -;; want in Emacs. -;; -;; Usage: -;; Consider running `(zle-minor-mode)' to run this globally. Depending on your -;; configuration, it could be non-disruptive, disruptive, or extremely -;; disruptive. - -;;; Code: - -;; subshell (C-j) -(defun zle-subshell () - "Insert the characters necessary to create a subshell." - (interactive) - (insert-char ?$) - (insert-char ?\() - (save-excursion - (insert-char ?\)))) - -;; variable (C-v) -(defun zle-variable () - "Insert the characters to reference a variable." - (interactive) - (insert-char ?$) - (insert-char ?{) - (save-excursion - (insert-char ?}))) - -;; 2x dash (C-M--) -(defun zle-dash-dash () - "Insert the characters for flags with 2x dashes." - (interactive) - (insert-char ? ) - (insert-char ?-) - (insert-char ?-)) - -;; 1x quotes (M-') -(defun zle-single-quote () - "Insert the characters to quickly create single quotes." - (interactive) - (insert-char ? ) - (insert-char ?') - (save-excursion - (insert-char ?'))) - -;; 2x quotes (M-") -(defun zle-double-quote () - "Insert the characters to quickly create double quotes." - (interactive) - (insert-char ? ) - (insert-char ?\") - (save-excursion - (insert-char ?\"))) - -(defvar zle-kbds - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-j") #'zle-subshell) - (define-key map (kbd "C-v") #'zle-variable) - (define-key map (kbd "C-M--") #'zle-dash-dash) - (define-key map (kbd "M-'") #'zle-single-quote) - (define-key map (kbd "M-\"") #'zle-double-quote) - map) - "Keybindings shaving milliseconds off of typing.") - -(define-minor-mode zle-minor-mode - "A minor mode mirroring my ZLE keybindings." - :init-value nil - :lighter " zle" - :keymap zle-kbds) - -(provide 'zle) -;;; zle.el ends here diff --git a/users/wpcarro/emacs/snippets.md b/users/wpcarro/emacs/snippets.md deleted file mode 100644 index 2081b5617..000000000 --- a/users/wpcarro/emacs/snippets.md +++ /dev/null @@ -1,22 +0,0 @@ -# Snippets - -Specifying snippets that I plan on defining for most of the programming -languages with which I work. I hope this will serve as a checklist of language -constructs I should support when adopting a new language. - -## Shared language features - -These are language features that should be available across most of the -languages that I'm hoping to support. - -- `ld`: anonymous functions (i.e. lambdas) -- `fn`: named function definition -- `var`: variable definition - -## Miscellaneous other language KBDs - -Some of this is related to language tool must-haves, which may need to be a -separate document. - -- `d`: Show documentation -- `x`: Evaluate expression (works mostly for LISPs) diff --git a/users/wpcarro/emacs/workspace.josh b/users/wpcarro/emacs/workspace.josh deleted file mode 100644 index e69de29bb..000000000 diff --git a/users/wpcarro/go/.envrc b/users/wpcarro/go/.envrc deleted file mode 100644 index a4a62da52..000000000 --- a/users/wpcarro/go/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -use_nix diff --git a/users/wpcarro/go/actors.go b/users/wpcarro/go/actors.go deleted file mode 100644 index 1409db185..000000000 --- a/users/wpcarro/go/actors.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" -) - -// Call function `f` in a go-routine, passing a reference to a newly created -// channel, `c`, as its only argument. Return a reference to `c` to the caller -// of `act`. When `f` halts, close the channel. -func act(f func(chan interface{})) chan interface{} { - c := make(chan interface{}) - - go func() { - defer close(c) - f(c) - }() - - return c -} - -func prompt(msg string) string { - reader := bufio.NewReader(os.Stdin) - fmt.Print(msg) - text, _ := reader.ReadString('\n') - // TODO: Trim trailing newline from the rhs of text. - return text -} - -func main() { - c := act(func(c chan interface{}) { - for { - x := <-c - fmt.Printf("[A] Received value: %v\n", x) - - } - }) - - for { - x := prompt("[B] Enter a value: ") - c <- x - } - os.Exit(0) -} diff --git a/users/wpcarro/go/atomic-counters.go b/users/wpcarro/go/atomic-counters.go deleted file mode 100644 index 6cbcd2ee4..000000000 --- a/users/wpcarro/go/atomic-counters.go +++ /dev/null @@ -1,26 +0,0 @@ -// Attempting to apply some of the lessons I learned here: -// https://gobyexample.com/atomic-counters -package main - -import ( - "fmt" - "sync" - "sync/atomic" -) - -func main() { - var count uint64 - var wg sync.WaitGroup - - for i := 0; i < 50; i += 1 { - wg.Add(1) - go func() { - defer wg.Done() - for j := 0; j < 1000; j += 1 { - atomic.AddUint64(&count, 1) - } - }() - } - wg.Wait() - fmt.Println("Count: ", count) -} diff --git a/users/wpcarro/go/channels.go b/users/wpcarro/go/channels.go deleted file mode 100644 index cba8abfc9..000000000 --- a/users/wpcarro/go/channels.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "fmt" - "math/rand" - "sync" - "sync/atomic" -) - -type readMsg struct { - key int - sender chan int -} - -type writeMsg struct { - key int - value int - sender chan bool -} - -func main() { - fmt.Println("Hello, go.") - - var readOps uint64 - var writeOps uint64 - var wg sync.WaitGroup - - reads := make(chan readMsg) - writes := make(chan writeMsg) - - go func() { - state := make(map[int]int) - for { - select { - case msg := <-reads: - msg.sender <- state[msg.key] - case msg := <-writes: - state[msg.key] = msg.value - msg.sender <- true - } - } - }() - - // Reads - for i := 0; i < 100; i += 1 { - go func() { - wg.Add(1) - defer wg.Done() - for j := 0; j < 100; j += 1 { - msg := readMsg{ - key: rand.Intn(5), - sender: make(chan int)} - reads <- msg - val := <-msg.sender - fmt.Printf("Received %d.\n", val) - atomic.AddUint64(&readOps, 1) - } - }() - } - - // Writes - for i := 0; i < 100; i += 1 { - go func() { - wg.Add(1) - defer wg.Done() - for j := 0; j < 100; j += 1 { - msg := writeMsg{ - key: rand.Intn(5), - value: rand.Intn(10), - sender: make(chan bool)} - writes <- msg - <-msg.sender - fmt.Printf("Set %d as %d in state\n", msg.key, msg.value) - atomic.AddUint64(&writeOps, 1) - } - }() - } - - wg.Wait() - fmt.Printf("Read ops: %d\tWrite ops: %d\n", atomic.LoadUint64(&readOps), atomic.LoadUint64(&writeOps)) -} diff --git a/users/wpcarro/go/mutex.go b/users/wpcarro/go/mutex.go deleted file mode 100644 index 5cea20754..000000000 --- a/users/wpcarro/go/mutex.go +++ /dev/null @@ -1,53 +0,0 @@ -package main - -import ( - "fmt" - "math/rand" - "sync" - "sync/atomic" - "time" -) - -func main() { - state := make(map[int]int) - mux := &sync.Mutex{} - - var readOps uint64 - var writeOps uint64 - - // Read from state - for i := 0; i < 1000; i += 1 { - for j := 0; j < 100; j += 1 { - go func() { - key := rand.Intn(5) - mux.Lock() - fmt.Printf("state[%d] = %d\n", key, state[key]) - mux.Unlock() - atomic.AddUint64(&readOps, 1) - time.Sleep(time.Millisecond) - }() - } - } - - // Write to state - for i := 0; i < 10; i += 1 { - for j := 0; j < 100; j += 1 { - go func() { - key := rand.Intn(5) - mux.Lock() - state[key] += 1 - mux.Unlock() - fmt.Printf("Wrote to state[%d].\n", key) - atomic.AddUint64(&writeOps, 1) - time.Sleep(time.Millisecond) - }() - } - } - - time.Sleep(time.Millisecond) - - mux.Lock() - fmt.Printf("State: %v\n", state) - mux.Unlock() - fmt.Printf("Reads: %d\tWrites: %d\n", atomic.LoadUint64(&readOps), atomic.LoadUint64(&writeOps)) -} diff --git a/users/wpcarro/go/shell.nix b/users/wpcarro/go/shell.nix deleted file mode 100644 index f777c13fe..000000000 --- a/users/wpcarro/go/shell.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ pkgs, ... }: - -pkgs.mkShell { - buildInputs = with pkgs; [ - go - goimports - godef - ]; -} diff --git a/users/wpcarro/go/waitgroups.go b/users/wpcarro/go/waitgroups.go deleted file mode 100644 index 816321b87..000000000 --- a/users/wpcarro/go/waitgroups.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "fmt" - "sync" - "time" -) - -func saySomething(x string, wg *sync.WaitGroup) { - defer wg.Done() - fmt.Println(x) - time.Sleep(time.Second) - fmt.Printf("Finished saying \"%s\"\n", x) -} - -func main() { - var wg sync.WaitGroup - var things = [5]string{"chicken", "panini", "cheeseburger", "rice", "bread"} - for i := 0; i < 5; i += 1 { - wg.Add(1) - go saySomething(things[i], &wg) - } - wg.Wait() -} diff --git a/users/wpcarro/gopkgs/kv/default.nix b/users/wpcarro/gopkgs/kv/default.nix deleted file mode 100644 index 72aae7827..000000000 --- a/users/wpcarro/gopkgs/kv/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ depot, ... }: - -depot.nix.buildGo.package { - name = "kv"; - srcs = [ - ./kv.go - ]; -} diff --git a/users/wpcarro/gopkgs/kv/kv.go b/users/wpcarro/gopkgs/kv/kv.go deleted file mode 100644 index 040cc63e0..000000000 --- a/users/wpcarro/gopkgs/kv/kv.go +++ /dev/null @@ -1,39 +0,0 @@ -// Supporting reading and writing key-value pairs to disk. -package kv - -import ( - "encoding/json" - "io/ioutil" - "log" - "path" -) - -// Return the decoded store from disk. -func getStore(storePath string) map[string]interface{} { - b, err := ioutil.ReadFile(path.Join(storePath, "kv.json")) - if err != nil { - log.Fatal("Could not read store: ", err) - } - var state map[string]interface{} - err = json.Unmarshal(b, &state) - if err != nil { - log.Fatal("Could not decode store as JSON: ", err) - } - return state -} - -// Set `key` to `value` in the store. -func Set(storePath string, key string, value interface{}) error { - state := getStore(storePath) - state[key] = value - b, err := json.Marshal(state) - if err != nil { - log.Fatal("Could not encode state as JSON: ", err) - } - return ioutil.WriteFile(path.Join(storePath, "kv.json"), b, 0644) -} - -// Get `key` from the store. -func Get(storePath string, key string) interface{} { - return getStore(path.Join(storePath, "kv.json"))[key] -} diff --git a/users/wpcarro/gopkgs/utils/default.nix b/users/wpcarro/gopkgs/utils/default.nix deleted file mode 100644 index 25321f50a..000000000 --- a/users/wpcarro/gopkgs/utils/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ depot, ... }: - -depot.nix.buildGo.package { - name = "utils"; - srcs = [ - ./utils.go - ]; -} diff --git a/users/wpcarro/gopkgs/utils/utils.go b/users/wpcarro/gopkgs/utils/utils.go deleted file mode 100644 index 7d662d086..000000000 --- a/users/wpcarro/gopkgs/utils/utils.go +++ /dev/null @@ -1,131 +0,0 @@ -// Some utility functions to tidy up my Golang. -package utils - -import ( - "fmt" - "io/ioutil" - "log" - "net/http" - "net/http/httputil" - "os" - "os/user" - "path/filepath" -) - -// Return the absolute path to the current uesr's home directory. -func HomeDir() string { - user, err := user.Current() - if err != nil { - log.Fatal(err) - } - return user.HomeDir -} - -// Returns true if `info` is a symlink. -func IsSymlink(info os.FileMode) bool { - return info&os.ModeSymlink != 0 -} - -// Return true if `path` exists and false otherwise. -func FileExists(path string) bool { - if _, err := os.Stat(path); os.IsNotExist(err) { - return false - } else { - return true - } -} - -// Return the absolute file path of `file` using the following resolution -// strategy: -// - Traverse and search upwards until you reach the user's home directory -// - Return the first path in `backupPaths` that exists -// - Fail -func Resolve(fileName string, backupPaths []string) string { - // TODO(wpcarro): Drop hardcoding when whoami behaves as expected. - boundary := "/home" - cwd := "." - files, _ := ioutil.ReadDir(cwd) - - for { - fullCwd, _ := filepath.Abs(cwd) - if fullCwd == boundary { - break - } - for _, file := range files { - if file.Name() == fileName { - path, _ := filepath.Abs(cwd + "/" + file.Name()) - return path - } - } - cwd += "/.." - files, _ = ioutil.ReadDir(cwd) - } - - // TODO(wpcarro): Support expanding these paths to allow the consumer to - // pass in relative paths, and paths with "~" in them. - for _, backup := range backupPaths { - if FileExists(backup) { - return backup - } - } - log.Fatal("Cannot find a run.json to use.") - // This code should be unreachable. - return "" -} - -// Call log.Fatal with `err` when it's not nil. -func FailOn(err error) { - if err != nil { - log.Fatal(err) - } -} - -// Prints the verbose form of an HTTP request. -func DebugRequest(req *http.Request) { - bytes, _ := httputil.DumpRequest(req, true) - fmt.Println(string(bytes)) -} - -// Prints out the verbose form of an HTTP response. -func DebugResponse(res *http.Response) { - bytes, _ := httputil.DumpResponse(res, true) - fmt.Println(string(bytes)) -} - -// Make a simple GET request to `url`. Fail if anything returns an error. I'd -// like to accumulate a library of these, so that I can write scrappy Go -// quickly. For now, this function just returns the body of the response back as -// a string. -func SimpleGet(url string, headers map[string]string, debug bool) string { - client := &http.Client{} - req, err := http.NewRequest("GET", url, nil) - if err != nil { - log.Fatal(err) - } - for k, v := range headers { - req.Header.Add(k, v) - } - - res, err := client.Do(req) - if err != nil { - log.Fatal(err) - } - defer res.Body.Close() - - if debug { - DebugRequest(req) - DebugResponse(res) - } - - if res.StatusCode == http.StatusOK { - bytes, err := ioutil.ReadAll(res.Body) - if err != nil { - log.Fatal(err) - } - return string(bytes) - } else { - log.Println(res) - log.Fatalf("HTTP status code of response not OK: %v\n", res.StatusCode) - return "" - } -} diff --git a/users/wpcarro/haskell-file/.envrc b/users/wpcarro/haskell-file/.envrc deleted file mode 100644 index a4a62da52..000000000 --- a/users/wpcarro/haskell-file/.envrc +++ /dev/null @@ -1,2 +0,0 @@ -source_up -use_nix diff --git a/users/wpcarro/haskell-file/README.md b/users/wpcarro/haskell-file/README.md deleted file mode 100644 index 3f3ac1474..000000000 --- a/users/wpcarro/haskell-file/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# haskell-file - -This is a half-baked project. I'd like to write a library whose API closely -resembles some of the more modern filesystem APIs to which I am accustomed: -notably f.el for Elisp. - -I expect more development to come. diff --git a/users/wpcarro/haskell-file/f-todo.org b/users/wpcarro/haskell-file/f-todo.org deleted file mode 100644 index 6dd43a962..000000000 --- a/users/wpcarro/haskell-file/f-todo.org +++ /dev/null @@ -1,67 +0,0 @@ -* Paths -** TODO f-join (&rest args) -** TODO f-split (path) -** TODO f-expand (path &optional dir) -** TODO f-filename (path) -** TODO f-dirname (path) -** TODO f-common-parent (paths) -** TODO f-ext (path) -** TODO f-no-ext (path) -** TODO f-swap-ext (path ext) -** TODO f-base (path) -** TODO f-relative (path &optional dir) -** TODO f-short (path) -** TODO f-long (path) -** TODO f-canonical (path) -** TODO f-slash (path) -** TODO f-full (path) -** TODO f-uniquify (paths) -** TODO f-uniquify-alist (paths) -* I/O -** TODO f-read-bytes (path) -** TODO f-write-bytes (data path) -** TODO f-read-text (path &optional coding) -** TODO f-write-text(text coding path) -** TODO f-append-text(text coding path) -** TODO f-append-bytes(text coding path) -** TODO Destructive -** TODO f-mkdir (&rest dirs) -** TODO f-delete (path &optional force) -** TODO f-symlink (source path) -** TODO f-move (from to) -** TODO f-copy (from to) -** TODO f-copy-contenst (from to) -** TODO f-touch (path) -** TODO Predicates -** TODO f-exists? (path) -** TODO f-directory? (path) -** TODO f-file? (path) -** TODO f-symlink? (path) -** TODO f-readable? (path) -** TODO f-writable? (path) -** TODO f-executable? (path) -** TODO f-absolute? (path) -** TODO f-relative? (path) -** TODO f-root? (path) -** TODO f-ext? (path ext) -** TODO f-same? (path-a path-b) -** TODO f-parent-of? (path-a path-b) -** TODO f-child-of? (path-a path-b) -** TODO f-ancestor-of? (path-a path-b) -** TODO f-descendant-of? (path-a path-b) -** TODO f-hidden? (path) -** TODO f-empty? (path) -** TODO Stats -** TODO f-size (path) -** f-depth (path) - -* Misc -** TODO f-this-file () -** TODO f-path-separator () -** TODO f-glob (pattern &optional path) -** TODO f-entries (path &optional fn recursive) -** TODO f-directories (path &optional fn recursive) -** TODO f-files (path &optional fn recursive) -** TODO f-root () -** TODO f-traverse-upwards (fn &optional path) -** TODO f-with-sandbox (path-or-paths &rest body) diff --git a/users/wpcarro/haskell-file/f.hs b/users/wpcarro/haskell-file/f.hs deleted file mode 100644 index 295575f3f..000000000 --- a/users/wpcarro/haskell-file/f.hs +++ /dev/null @@ -1,64 +0,0 @@ -module F - ( join - , split - ) where - --------------------------------------------------------------------------------- --- Dependencies --------------------------------------------------------------------------------- - -import Data.List (span) -import System.FilePath (FilePath, pathSeparator) -import System.FilePath.Posix (FilePath) -import qualified System.FilePath.Posix as F - --- TODO: Move this to a misc.hs, prelude.hs, operators.hs; somewhere. -(|>) :: a -> (a -> b) -> b -(|>) a f = f a -infixl 1 |> - --- TODO: Move this to a test_utils.hs or elsewhere. -simpleAssert :: (Eq a) => a -> a -> () -simpleAssert x y = - if x == y then - () - else - error "Assertion error" - --------------------------------------------------------------------------------- --- Library --------------------------------------------------------------------------------- - -join :: [FilePath] -> FilePath -join = F.joinPath - --- | Split path and return list containing parts. -split :: FilePath -> [String] -split = splitJoin . span (/= pathSeparator) - where - splitJoin :: (String, String) -> [String] - splitJoin ([], []) = [] - splitJoin (a, []) = [a] - splitJoin (a, [_]) = [a] - splitJoin (a, _:b) = a : split b - --------------------------------------------------------------------------------- --- Tests --------------------------------------------------------------------------------- - -expected :: [([FilePath], FilePath)] -expected = [ (["path"], "path") - , (["/path"], "/path") - , (["path", "to", "file"], "path/to/file") - , (["/path", "to", "file"], "/path/to/file") - , (["/"], "/") - ] - -runTests :: [()] -runTests = - fmap (\(input, expected) -> simpleAssert (join input) expected) expected - -main :: IO () -main = do - print runTests - pure () diff --git a/users/wpcarro/haskell-file/shell.nix b/users/wpcarro/haskell-file/shell.nix deleted file mode 100644 index 0c6a298bf..000000000 --- a/users/wpcarro/haskell-file/shell.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ depot, ... }: - -depot.users.wpcarro.buildHaskell.shell { - deps = hpkgs: [ ]; -} diff --git a/users/wpcarro/haskell-file/tests.hs b/users/wpcarro/haskell-file/tests.hs deleted file mode 100644 index e3967b77d..000000000 --- a/users/wpcarro/haskell-file/tests.hs +++ /dev/null @@ -1,39 +0,0 @@ -module FTest where --------------------------------------------------------------------------------- -import Test.Tasty -import Test.Tasty.Hedgehog -import Hedgehog --------------------------------------------------------------------------------- -import qualified Hedgehog as H -import qualified Hedgehog.Gen as Gen -import qualified Hedgehog.Range as Range --------------------------------------------------------------------------------- -import Data.List (intercalate) -import System.FilePath (pathSeparator) --------------------------------------------------------------------------------- -import F --------------------------------------------------------------------------------- -main :: IO () -main - = defaultMain - . localOption (HedgehogTestLimit $ Just 50) - $ testGroup "f functions" - [ test_split - ] --------------------------------------------------------------------------------- -test_split :: TestTree -test_split - = testGroup "split function" - [ testProperty "splits parts properly" splitSuccess - ] -splitSuccess :: Property -splitSuccess = property $ do - -- separator - -- <- H.forAll - -- $ Gen.element ['/', '\\'] - parts - <- H.forAll - . Gen.list (Range.linear 0 10) - $ Gen.list (Range.linear 1 10) Gen.alphaNum - let path = intercalate [pathSeparator] parts - F.split path === parts diff --git a/users/wpcarro/keys.nix b/users/wpcarro/keys.nix deleted file mode 100644 index 531d110f7..000000000 --- a/users/wpcarro/keys.nix +++ /dev/null @@ -1,20 +0,0 @@ -# wpcarro's public SSH keys -{ ... }: - -rec { - ava = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB/5Fuo7wi8rNXVXgNaCK2X6ePCh9LQs/9h7Tj6UeXrl wpcarro@ava"; - iphone = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEU1tsRQ/cMxi9Hd7Xo+YpiWB5i6qx24EJLCEFBK4q4W wpcarro@iphone"; - kyoko = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBFILKdkNqfTP5WeoQAV6K3MdTzsDW65ToXGc6KlQ9yl wpcarro@kyoko"; - marcus = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJkNQJBXekuSzZJ8+gxT+V1+eXTm3hYsfigllr/ARXkf wpcarro@gmail.com"; - nathan = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP2NjuP722VUgpSu5bVUPTfdVNPO8fSW0Jlas8L4up13 bill@nathan"; - tarasco = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOh+wG4f7tI0IwGyF2sLi5mPlh3JKE7KqV2ab0tlcL36 wpcarro@tarasco"; - - all = [ - ava - iphone - kyoko - marcus - nathan - tarasco - ]; -} diff --git a/users/wpcarro/lib/default.nix b/users/wpcarro/lib/default.nix deleted file mode 100644 index 6354877dd..000000000 --- a/users/wpcarro/lib/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ depot, ... }: - -{ - usermod = name: depot.path.origSrc + ("/users/wpcarro/nixos/modules/${name}"); -} diff --git a/users/wpcarro/lisp/README.md b/users/wpcarro/lisp/README.md deleted file mode 100644 index 9f8693fa6..000000000 --- a/users/wpcarro/lisp/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Common Lisp - -Things that I like about Common Lisp: -- It's an S-expression based language. -- It has a powerful macro system -- It has a unique way of handling-errors -- It is highly introspectible -- The tooling integration with Emacs is the best I have ever seen for any language - -Things that I don't like about Common Lisp: -- I find its standard libraries difficult to use and -- compared to modern - libraries -- like Golang's or Elixir's standard libraries, Common Lisp's - libraries are clunky - -As such, I would like to modernize CL's libraries to resemble other libraries -with which I am more familiar and, therefore, productive. diff --git a/users/wpcarro/lisp/prelude.lisp b/users/wpcarro/lisp/prelude.lisp deleted file mode 100644 index 3522567ea..000000000 --- a/users/wpcarro/lisp/prelude.lisp +++ /dev/null @@ -1,14 +0,0 @@ -(in-package #:cl-user) -(defpackage #:prelude - (:documentation "Supporting miscellaneous utility functions and macros.") - (:use #:cl) - (:shadow #:type) - (:export #:type #:comment)) -(in-package #:prelude) - -;; TODO: Add documentation to these macros. - -(defmacro type (name in out) - `(declaim (ftype (function ,in ,out) ,name))) - -(defmacro comment (&rest _forms) nil) diff --git a/users/wpcarro/lisp/prelude.nix b/users/wpcarro/lisp/prelude.nix deleted file mode 100644 index 5fe5d628e..000000000 --- a/users/wpcarro/lisp/prelude.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ depot, ... }: - -depot.nix.buildLisp.library { - name = "prelude"; - srcs = [ - ./prelude.lisp - ]; -} diff --git a/users/wpcarro/nixos/ava/ava.el b/users/wpcarro/nixos/ava/ava.el deleted file mode 100644 index b0b13746b..000000000 --- a/users/wpcarro/nixos/ava/ava.el +++ /dev/null @@ -1,61 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'bookmark) -(require 'display) -(require 'window-manager) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(bookmark-install-kbd - (make-bookmark :label "hadrian" - :path "/hadrian" - :kbd "h")) - -(setq initial-buffer-choice "/hadrian") - -(add-to-list 'ssh-hosts "wpcarro@tarasco") - -(display-register primary - :output "HDMI-1" - :primary t - :coords (0 0) - :size (2560 1440) - :rate 30.0 - :dpi 96 - :rotate normal) - -(display-register secondary - :output "HDMI-2" - :primary nil - :coords (2561 0) - :size (2560 1440) - :rate 30.0 - :dpi 96 - :rotate normal) - -(display-arrangement main :displays (primary secondary)) - -(setq window-manager-named-workspaces - (list (make-window-manager-named-workspace - :label "Web Browsing" - :kbd "c" - :display display-secondary) - (make-window-manager-named-workspace - :label "Coding I" - :kbd "1" - :display display-primary) - (make-window-manager-named-workspace - :label "Coding II" - :kbd "2" - :display display-primary) - (make-window-manager-named-workspace - :label "Chatting" - :kbd "h" - :display display-secondary))) - -;; I *think* this needs to be the last statement in this file. -(window-manager-init :init-hook #'display-arrange-main) diff --git a/users/wpcarro/nixos/ava/default.nix b/users/wpcarro/nixos/ava/default.nix deleted file mode 100644 index 457947607..000000000 --- a/users/wpcarro/nixos/ava/default.nix +++ /dev/null @@ -1,146 +0,0 @@ -{ depot, pkgs, lib, ... }: -{ ... }: - -let - inherit (depot.users) wpcarro; - inherit (depot.users.wpcarro.lib) usermod; - - wpcarrosEmacs = wpcarro.emacs.nixos { - load = [ ./ava.el ]; - }; - - quasselClient = pkgs.quassel.override { - client = true; - enableDaemon = false; - monolithic = false; - }; -in -{ - imports = [ - (usermod "hardware/nopn.nix") - ]; - - # Use the TVL binary cache - tvl.cache.enable = true; - - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = true; - - # Support IP forwarding to use this device as a Tailscale exit node. - boot.kernel.sysctl."net.ipv4.ip_forward" = true; - boot.kernel.sysctl."net.ipv6.conf.all.forwarding" = true; - # Additionall exit node settings that Tailscale recommends. - networking.firewall.checkReversePath = "loose"; - - time.timeZone = "America/Los_Angeles"; - - networking = { - # The global useDHCP flag is deprecated, therefore explicitly set to false - # here. Per-interface useDHCP will be mandatory in the future, so this - # generated config replicates the default behaviour. - useDHCP = false; - hostName = "ava"; - networkmanager.enable = true; - interfaces.enp1s0.useDHCP = true; - interfaces.enp3s0.useDHCP = true; - interfaces.wlp2s0.useDHCP = true; - }; - - services = wpcarro.common.services // { - # Check the amount of available memory and free swap a few times per second - # and kill the largest process if both are below 10%. - earlyoom.enable = true; - - tailscale.enable = true; - - openssh.enable = true; - - printing = { - enable = true; - drivers = with pkgs; [ gutenprint ]; - }; - - xserver = { - enable = true; - xkb.layout = "us"; - xkb.options = "caps:escape"; - displayManager = { - # Give EXWM permission to control the session (from tazjin's setup). - sessionCommands = "${pkgs.xorg.xhost}/bin/xhost +SI:localhost:$USER"; - lightdm.enable = true; - }; - windowManager.session = lib.singleton { - name = "exwm"; - start = "${wpcarrosEmacs}/bin/wpcarros-emacs"; - }; - }; - }; - - users.mutableUsers = true; - users.users.root.openssh.authorizedKeys.keys = with wpcarro.keys; [ - iphone - nathan - tarasco - ]; - users.users.wpcarro = { - initialPassword = "password"; - isNormalUser = true; - extraGroups = [ - "networkmanager" - "wheel" - "docker" - ]; - shell = pkgs.fish; - openssh.authorizedKeys.keys = with wpcarro.keys; [ - iphone - nathan - tarasco - ]; - }; - users.extraGroups.vboxusers.members = [ "wpcarro" ]; - - security.sudo.wheelNeedsPassword = false; - - fonts = { - packages = with pkgs; [ - jetbrains-mono - ]; - - fontconfig = { - defaultFonts = { - monospace = [ "JetBrains Mono" ]; - }; - }; - }; - - programs = wpcarro.common.programs // { - mosh.enable = true; - }; - - virtualisation.docker.enable = true; - virtualisation.virtualbox.host.enable = true; - - environment.variables = { - EDITOR = "emacsclient"; - ALTERNATE_EDITOR = "emacs -q -nw"; - VISUAL = "emacsclient"; - }; - - environment.systemPackages = - wpcarro.common.shell-utils ++ - (with pkgs; [ - alacritty - ec2-api-tools - firefox - google-chrome - httpie - pavucontrol - quasselClient - remmina - tdesktop - wpcarrosEmacs - xsecurelock - ]); - - system.stateVersion = "21.11"; -} diff --git a/users/wpcarro/nixos/default.nix b/users/wpcarro/nixos/default.nix deleted file mode 100644 index 9c8a7e5a7..000000000 --- a/users/wpcarro/nixos/default.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ depot, pkgs, ... }: - -let - inherit (depot.users.wpcarro.nixos) - ava - kyoko - marcus - tarasco; - - systemFor = sys: (depot.ops.nixos.nixosFor sys).system; -in -{ - avaSystem = systemFor ava; - kyokoSystem = systemFor kyoko; - marcusSystem = systemFor marcus; - tarascoSystem = systemFor tarasco; - - meta.ci.targets = [ - "avaSystem" - "kyokoSystem" - "marcusSystem" - "tarascoSystem" - ]; -} diff --git a/users/wpcarro/nixos/iso.nix b/users/wpcarro/nixos/iso.nix deleted file mode 100644 index 8102c98fb..000000000 --- a/users/wpcarro/nixos/iso.nix +++ /dev/null @@ -1,17 +0,0 @@ -# TODO(wpcarro): Support the workflow outlined in these docs. -# -# Usage: -# $ lsblk # get your USB dev path (e.g. /dev/sdb) -# $ create-installer --dev=/dev/sdb //users/wpcarro/nixos/marcus - -{ pkgs, ... }: - -{ - imports = [ - "${pkgs.nixos}/modules/installer/cd-graphical-gnome.nix" - ]; - - config = { - networking.wireless.enable = true; - }; -} diff --git a/users/wpcarro/nixos/kyoko/default.nix b/users/wpcarro/nixos/kyoko/default.nix deleted file mode 100644 index 024276afd..000000000 --- a/users/wpcarro/nixos/kyoko/default.nix +++ /dev/null @@ -1,149 +0,0 @@ -{ depot, pkgs, lib, ... }: -_: - -let - inherit (depot.users) wpcarro; - inherit (depot.users.wpcarro.lib) usermod; - - wpcarrosEmacs = wpcarro.emacs.nixos { - load = [ ./kyoko.el ]; - }; - - quasselClient = pkgs.quassel.override { - client = true; - enableDaemon = false; - monolithic = false; - }; -in -{ - imports = [ - (usermod "hardware/dell-emc-egw-5200.nix") - (usermod "hadrian-cache.nix") - ]; - - # TVL's Nix binary cache - tvl.cache.enable = true; - - # Hadrian's Nix binary cache. - hadrian.cache.enable = true; - - nix.settings.trusted-users = [ "@wheel" ]; - - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = true; - - # Additionall exit node settings that Tailscale recommends. - networking.firewall.checkReversePath = "loose"; - - time.timeZone = "America/Los_Angeles"; - - networking = { - # The global useDHCP flag is deprecated, therefore explicitly set to false - # here. Per-interface useDHCP will be mandatory in the future, so this - # generated config replicates the default behaviour. - useDHCP = false; - hostName = "kyoko"; - networkmanager.enable = true; - interfaces.enp1s0.useDHCP = true; - interfaces.enp3s0.useDHCP = true; - interfaces.wlp2s0.useDHCP = true; - }; - - services = wpcarro.common.services // { - # Check the amount of available memory and free swap a few times per second - # and kill the largest process if both are below 10%. - earlyoom.enable = true; - - tailscale.enable = true; - - openssh.enable = true; - - printing = { - enable = true; - drivers = with pkgs; [ gutenprint ]; - }; - - xserver = { - enable = true; - xkb.layout = "us"; - xkb.options = "caps:escape"; - displayManager = { - # Give EXWM permission to control the session (from tazjin's setup). - sessionCommands = "${pkgs.xorg.xhost}/bin/xhost +SI:localhost:$USER"; - lightdm.enable = true; - }; - windowManager.session = lib.singleton { - name = "exwm"; - start = "${wpcarrosEmacs}/bin/wpcarros-emacs"; - }; - }; - }; - - users.mutableUsers = true; - users.users.root.openssh.authorizedKeys.keys = with wpcarro.keys; [ - iphone - nathan - tarasco - ]; - users.users.wpcarro = { - initialPassword = "password"; - isNormalUser = true; - extraGroups = [ - "networkmanager" - "wheel" - "docker" - ]; - shell = pkgs.fish; - openssh.authorizedKeys.keys = with wpcarro.keys; [ - iphone - nathan - tarasco - ]; - }; - users.extraGroups.vboxusers.members = [ "wpcarro" ]; - - security.sudo.wheelNeedsPassword = false; - - fonts = { - packages = with pkgs; [ - jetbrains-mono - ]; - - fontconfig = { - defaultFonts = { - monospace = [ "JetBrains Mono" ]; - }; - }; - }; - - programs = wpcarro.common.programs // { - mosh.enable = true; - }; - - virtualisation.docker.enable = true; - virtualisation.virtualbox.host.enable = true; - - environment.variables = { - EDITOR = "emacsclient"; - ALTERNATE_EDITOR = "emacs -q -nw"; - VISUAL = "emacsclient"; - }; - - environment.systemPackages = - wpcarro.common.shell-utils ++ - (with pkgs; [ - alacritty - ec2-api-tools - firefox - google-chrome - httpie - pavucontrol - quasselClient - remmina - tdesktop - wpcarrosEmacs - xsecurelock - ]); - - system.stateVersion = "21.11"; -} diff --git a/users/wpcarro/nixos/kyoko/kyoko.el b/users/wpcarro/nixos/kyoko/kyoko.el deleted file mode 100644 index 310323688..000000000 --- a/users/wpcarro/nixos/kyoko/kyoko.el +++ /dev/null @@ -1,61 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'bookmark) -(require 'display) -(require 'window-manager) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(bookmark-install-kbd - (make-bookmark :label "hadrian" - :path "/hadrian" - :kbd "h")) - -(setq initial-buffer-choice "/hadrian") - -(add-to-list 'ssh-hosts "wpcarro@tarasco") - -(display-register primary - :output "DP-2" - :primary t - :coords (0 0) - :size (2560 1440) - :rate 30.0 - :dpi 96 - :rotate normal) - -(display-register secondary - :output "DP-1" - :primary nil - :coords (2561 0) - :size (2560 1440) - :rate 30.0 - :dpi 96 - :rotate normal) - -(display-arrangement main :displays (primary secondary)) - -(setq window-manager-named-workspaces - (list (make-window-manager-named-workspace - :label "Web Browsing" - :kbd "c" - :display display-secondary) - (make-window-manager-named-workspace - :label "Coding I" - :kbd "1" - :display display-primary) - (make-window-manager-named-workspace - :label "Coding II" - :kbd "2" - :display display-primary) - (make-window-manager-named-workspace - :label "Chatting" - :kbd "h" - :display display-secondary))) - -;; I *think* this needs to be the last statement in this file. -(window-manager-init :init-hook #'display-arrange-main) diff --git a/users/wpcarro/nixos/marcus/default.nix b/users/wpcarro/nixos/marcus/default.nix deleted file mode 100644 index 491c010ac..000000000 --- a/users/wpcarro/nixos/marcus/default.nix +++ /dev/null @@ -1,166 +0,0 @@ -{ depot, pkgs, lib, ... }: -{ ... }: - -let - inherit (depot.users) wpcarro; - inherit (depot.users.wpcarro.lib) usermod; - - wpcarrosEmacs = wpcarro.emacs.nixos { - load = [ ./marcus.el ]; - }; - - quasselClient = pkgs.quassel.override { - client = true; - enableDaemon = false; - monolithic = false; - }; -in -{ - imports = [ - (depot.path.origSrc + "/users/wpcarro/nixos/marcus/hardware.nix") - (pkgs.home-manager.src + "/nixos") - (usermod "laptop.nix") - ]; - - # Use the TVL binary cache - tvl.cache.enable = true; - - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = true; - - networking = { - # The global useDHCP flag is deprecated, therefore explicitly set to false - # here. Per-interface useDHCP will be mandatory in the future, so this - # generated config replicates the default behaviour. - useDHCP = false; - hostName = "marcus"; - networkmanager.enable = true; - interfaces.enp0s31f6.useDHCP = true; - interfaces.wlp0s20f3.useDHCP = true; - }; - - services = wpcarro.common.services // { - # Enable the Tailscale daemon to connect to work and personal Tailnet. - tailscale.enable = true; - - tzupdate.enable = true; - - depot.auto-deploy = { - enable = true; - interval = "1d"; - }; - - libinput = { - enable = true; - touchpad.naturalScrolling = false; - touchpad.tapping = false; - }; - - xserver = { - enable = true; - xkb.layout = "us"; - xkb.options = "caps:escape"; - displayManager = { - # Give EXWM permission to control the session (from tazjin's setup). - sessionCommands = "${pkgs.xorg.xhost}/bin/xhost +SI:localhost:$USER"; - lightdm.enable = true; - }; - extraConfig = '' - Section "InputClass" - Identifier "Touchscreen catchall" - MatchIsTouchscreen "on" - Option "Ignore" "on" - EndSection - ''; - windowManager.session = lib.singleton { - name = "exwm"; - start = "${wpcarrosEmacs}/bin/wpcarros-emacs"; - }; - }; - }; - - users.mutableUsers = true; - users.users.wpcarro = { - isNormalUser = true; - extraGroups = [ - "networkmanager" - "wheel" - "video" # needed to control the screen brightness - ]; - shell = pkgs.fish; - }; - - security.sudo.wheelNeedsPassword = false; - - fonts = { - packages = with pkgs; [ - jetbrains-mono - ]; - - fontconfig = { - defaultFonts = { - monospace = [ "JetBrains Mono" ]; - }; - }; - }; - - programs = wpcarro.common.programs; - - environment.variables = { - EDITOR = "emacsclient"; - ALTERNATE_EDITOR = "emacs -q -nw"; - VISUAL = "emacsclient"; - }; - - home-manager.useGlobalPkgs = true; - home-manager.users.wpcarro = { config, lib, ... }: { - programs.git = { - enable = true; - userName = "William Carroll"; - userEmail = "wpcarro@gmail.com"; - extraConfig = { - pull.rebase = true; - }; - }; - - services.picom = { - enable = true; - vSync = true; - backend = "glx"; - }; - - services.redshift = { - enable = true; - latitude = 37.4223931; - longitude = -122.0864016; - }; - - services.dunst.enable = true; - xdg.configFile."dunst/dunstrc" = { - source = wpcarro.dotfiles.dunstrc; - onChange = '' - ${pkgs.procps}/bin/pkill -u "$USER" ''${VERBOSE+-e} dunst || true - ''; - }; - - systemd.user.startServices = true; - - # Previous default version, see https://github.com/nix-community/home-manager/blob/master/docs/release-notes/rl-2211.adoc - home.stateVersion = "18.09"; - }; - - environment.systemPackages = - wpcarro.common.shell-utils ++ - (with pkgs; [ - alacritty - firefox - pavucontrol - quasselClient - tdesktop - weechat - wpcarrosEmacs - xsecurelock - ]); - - system.stateVersion = "21.11"; -} diff --git a/users/wpcarro/nixos/marcus/hardware.nix b/users/wpcarro/nixos/marcus/hardware.nix deleted file mode 100644 index 8a2672206..000000000 --- a/users/wpcarro/nixos/marcus/hardware.nix +++ /dev/null @@ -1,29 +0,0 @@ -{ config, lib, pkgs, modulesPath, ... }: - -{ - imports = [ - (modulesPath + "/installer/scan/not-detected.nix") - ]; - - boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - - fileSystems."/" = { - device = "/dev/disk/by-label/nixos"; - fsType = "ext4"; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-label/boot"; - fsType = "vfat"; - }; - - swapDevices = lib.singleton { - device = "/dev/disk/by-label/swap"; - }; - - powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; -} diff --git a/users/wpcarro/nixos/marcus/marcus.el b/users/wpcarro/nixos/marcus/marcus.el deleted file mode 100644 index 90c04f7ff..000000000 --- a/users/wpcarro/nixos/marcus/marcus.el +++ /dev/null @@ -1,40 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'tvl) -(require 'display) -(require 'window-manager) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Monitor Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(display-register laptop - :output "eDP-1" - :primary t - :coords (0 0) - :size (1920 1080) - :rate 30.0 - :dpi 96 - :rotate normal) - -(display-arrangement primary :displays (laptop)) - -(setq initial-buffer-choice tvl-depot-path) - -(setq window-manager-named-workspaces - (list (make-window-manager-named-workspace - :label "Web Browsing" - :kbd "c" - :display display-laptop) - (make-window-manager-named-workspace - :label "Coding" - :kbd "d" - :display display-laptop) - (make-window-manager-named-workspace - :label "Chatting" - :kbd "h" - :display display-laptop))) - -(window-manager-init :init-hook #'display-arrange-primary) diff --git a/users/wpcarro/nixos/modules/.skip-subtree b/users/wpcarro/nixos/modules/.skip-subtree deleted file mode 100644 index 09520f8c8..000000000 --- a/users/wpcarro/nixos/modules/.skip-subtree +++ /dev/null @@ -1 +0,0 @@ -NixOS modules are not readTree compatible. diff --git a/users/wpcarro/nixos/modules/hadrian-cache.nix b/users/wpcarro/nixos/modules/hadrian-cache.nix deleted file mode 100644 index 033c03c82..000000000 --- a/users/wpcarro/nixos/modules/hadrian-cache.nix +++ /dev/null @@ -1,17 +0,0 @@ -# If enabled, use Hadrian's Nix cache. -{ config, lib, pkgs, ... }: - -{ - options = { - hadrian.cache.enable = lib.mkEnableOption "Hadrian's binary cache"; - }; - - config = lib.mkIf config.hadrian.cache.enable { - nix.settings.trusted-public-keys = [ - "cache.hadrian.internal:XWdYSn5ZASj6IqZd4nnDBXJmahQEolBrtq9DvSe0UT0=" - ]; - nix.settings.substituters = [ - "http://cache.hadrian.internal" - ]; - }; -} diff --git a/users/wpcarro/nixos/modules/hardware/dell-emc-egw-5200.nix b/users/wpcarro/nixos/modules/hardware/dell-emc-egw-5200.nix deleted file mode 100644 index df4640562..000000000 --- a/users/wpcarro/nixos/modules/hardware/dell-emc-egw-5200.nix +++ /dev/null @@ -1,47 +0,0 @@ -# In a nutshell, this configuration defines the configuration required to run -# NixOS on the Dell EMC EGW 5200 (often the config that NixOS put in -# hardware.nix by default). -{ config, lib, modulesPath, ... }: - -{ - imports = [ - (modulesPath + "/installer/scan/not-detected.nix") - ]; - - boot.initrd.availableKernelModules = [ - "xhci_pci" - "ahci" - "usb_storage" - "usbhid" - "sd_mod" - ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = true; - - fileSystems."/" = { - device = "/dev/disk/by-label/NIXROOT"; - fsType = "ext4"; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-label/NIXBOOT"; - fsType = "vfat"; - }; - - swapDevices = [ ]; - - powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - - # Needed for Tailscale subnet routing - boot.kernel.sysctl."net.ipv4.ip_forward" = 1; - networking.useDHCP = false; - networking.interfaces.eno1.useDHCP = true; - networking.interfaces.enp3s0.useDHCP = true; - networking.interfaces.enp4s0.useDHCP = true; - - system.stateVersion = "21.11"; -} diff --git a/users/wpcarro/nixos/modules/hardware/nopn.nix b/users/wpcarro/nixos/modules/hardware/nopn.nix deleted file mode 100644 index a35695421..000000000 --- a/users/wpcarro/nixos/modules/hardware/nopn.nix +++ /dev/null @@ -1,53 +0,0 @@ -# I tried looking up the manufacturer, product name, and version, but -# `dmidecode -t system` reported "To be filled by O.E.M." for each of these -# fields. -{ config, lib, pkgs, modulesPath, ... }: - -{ - imports = [ - (modulesPath + "/installer/scan/not-detected.nix") - ]; - - fileSystems."/" = { - device = "/dev/disk/by-label/NIXROOT"; - fsType = "ext4"; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-label/NIXBOOT"; - fsType = "vfat"; - }; - - boot = { - initrd.availableKernelModules = [ - "xhci_pci" - "ehci_pci" - "ahci" - "usb_storage" - "usbhid" - "sd_mod" - ]; - initrd.kernelModules = [ ]; - kernelModules = [ "kvm-intel" ]; - extraModulePackages = [ ]; - - # Can verify these settings with: - # $ lsmod - # ...or: - # $ cat /etc/modprobe.d/nixos.conf - blacklistedKernelModules = [ - # Disabling this buggy network driver (and preferring ethernet) to prevent - # my machine from becoming unresponsive. - # TODO(wpcarro): Consider replacing this module with this fork (if NixOS - # isn't already): https://github.com/tomaspinho/rtl8821ce - "rtw88_8821ce" - ]; - }; - - swapDevices = [ ]; - - hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; - # TODO(wpcarro): https://github.com/NixOS/nixpkgs/issues/222805 - # high-resolution display - # hardware.video.hidpi.enable = lib.mkDefault true; -} diff --git a/users/wpcarro/nixos/modules/laptop.nix b/users/wpcarro/nixos/modules/laptop.nix deleted file mode 100644 index 03dd0f39b..000000000 --- a/users/wpcarro/nixos/modules/laptop.nix +++ /dev/null @@ -1,15 +0,0 @@ -# Laptop-specific NixOS configuration. -_: - -{ - # Automatically detect location for redshift. - services.geoclue2.enable = true; - location.provider = "geoclue2"; - - # Enable power-saving features. - powerManagement.powertop.enable = true; - - # Backlight control command. - programs.light.enable = true; -} - diff --git a/users/wpcarro/nixos/modules/nginx.nix b/users/wpcarro/nixos/modules/nginx.nix deleted file mode 100644 index e6cc6b0fe..000000000 --- a/users/wpcarro/nixos/modules/nginx.nix +++ /dev/null @@ -1,45 +0,0 @@ -# Common configuration for Nginx. -{ pkgs, ... }: - -{ - config = { - security.acme = { - acceptTerms = true; - defaults.email = "wpcarro@gmail.com"; - }; - - services.nginx = { - enable = true; - enableReload = true; - - recommendedTlsSettings = true; - recommendedGzipSettings = true; - - # Log errors to journald (i.e. /dev/log) with debug verbosity. - logError = "syslog:server=unix:/dev/log debug"; - - # for journaldriver - commonHttpConfig = '' - log_format json_combined escape=json - '{' - '"remote_addr":"$remote_addr",' - '"method":"$request_method",' - '"host":"$host",' - '"uri":"$request_uri",' - '"status":$status,' - '"request_size":$request_length,' - '"response_size":$body_bytes_sent,' - '"response_time":$request_time,' - '"referrer":"$http_referer",' - '"user_agent":"$http_user_agent"' - '}'; - - access_log syslog:server=unix:/dev/log,nohostname json_combined; - ''; - - appendHttpConfig = '' - add_header Permissions-Policy "interest-cohort=()"; - ''; - }; - }; -} diff --git a/users/wpcarro/nixos/tarasco/default.nix b/users/wpcarro/nixos/tarasco/default.nix deleted file mode 100644 index 75f19aa6e..000000000 --- a/users/wpcarro/nixos/tarasco/default.nix +++ /dev/null @@ -1,140 +0,0 @@ -{ depot, pkgs, lib, ... }: -{ ... }: - -let - inherit (depot.users) wpcarro; - inherit (depot.users.wpcarro.lib) usermod; - - wpcarrosEmacs = wpcarro.emacs.nixos { - load = [ ./tarasco.el ]; - }; - - quasselClient = pkgs.quassel.override { - client = true; - enableDaemon = false; - monolithic = false; - }; -in -{ - imports = [ - (usermod "hardware/nopn.nix") - ]; - - # Use the TVL binary cache - tvl.cache.enable = true; - - boot = { - loader.systemd-boot.enable = true; - loader.efi.canTouchEfiVariables = true; - - # Support IP forwarding to use this device as a Tailscale exit node. - kernel.sysctl."net.ipv4.ip_forward" = true; - kernel.sysctl."net.ipv6.conf.all.forwarding" = true; - }; - - - time.timeZone = "America/Los_Angeles"; - - networking = { - useDHCP = false; - hostName = "tarasco"; - networkmanager.enable = true; - interfaces.enp1s0.useDHCP = true; - interfaces.enp3s0.useDHCP = true; - firewall.checkReversePath = "loose"; - # Disabling wifi because the Realtek network card drivers crash. For more - # context, see the boot.blacklistedKernelModules configuration. - # interfaces.wlp2s0.useDHCP = true; - }; - - services = wpcarro.common.services // { - # Check the amount of available memory and free swap a few times per second - # and kill the largest process if both are below 10%. - earlyoom.enable = true; - - tailscale.enable = true; - - openssh.enable = true; - - xserver = { - enable = true; - xkb.layout = "us"; - xkb.options = "caps:escape"; - displayManager = { - # Give EXWM permission to control the session (from tazjin's setup). - sessionCommands = "${pkgs.xorg.xhost}/bin/xhost +SI:localhost:$USER"; - lightdm.enable = true; - }; - windowManager.session = lib.singleton { - name = "exwm"; - start = "${wpcarrosEmacs}/bin/wpcarros-emacs"; - }; - }; - }; - - users.mutableUsers = true; - users.users.root.openssh.authorizedKeys.keys = with wpcarro.keys; [ - ava - iphone - nathan - ]; - users.users.wpcarro = { - isNormalUser = true; - extraGroups = [ - "networkmanager" - "wheel" - "docker" - ]; - shell = pkgs.fish; - openssh.authorizedKeys.keys = with wpcarro.keys; [ - ava - iphone - nathan - ]; - }; - users.extraGroups.vboxusers.members = [ "wpcarro" ]; - - security.sudo.wheelNeedsPassword = false; - - fonts = { - packages = with pkgs; [ - jetbrains-mono - ]; - - fontconfig = { - defaultFonts = { - monospace = [ "JetBrains Mono" ]; - }; - }; - }; - - programs = wpcarro.common.programs // { - mosh.enable = true; - }; - - virtualisation.docker.enable = true; - virtualisation.virtualbox.host.enable = true; - - environment.variables = { - EDITOR = "emacsclient"; - ALTERNATE_EDITOR = "emacs -q -nw"; - VISUAL = "emacsclient"; - }; - - environment.systemPackages = - wpcarro.common.shell-utils ++ - (with pkgs; [ - alacritty - firefox - google-chrome - httpie - pavucontrol - quasselClient - remmina - tdesktop - wpcarrosEmacs - xsecurelock - ]); - - system.stateVersion = "21.11"; -} diff --git a/users/wpcarro/nixos/tarasco/tarasco.el b/users/wpcarro/nixos/tarasco/tarasco.el deleted file mode 100644 index c840493f2..000000000 --- a/users/wpcarro/nixos/tarasco/tarasco.el +++ /dev/null @@ -1,61 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Dependencies -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(require 'bookmark) -(require 'display) -(require 'window-manager) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Configuration -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -(bookmark-install-kbd - (make-bookmark :label "hadrian" - :path "/hadrian" - :kbd "h")) - -(setq initial-buffer-choice "/hadrian") - -(add-to-list 'ssh-hosts "wpcarro@ava") - -(display-register primary - :output "HDMI-1" - :primary t - :coords (0 0) - :size (2560 1440) - :rate 30.0 - :dpi 96 - :rotate normal) - -(display-register secondary - :output "HDMI-2" - :primary nil - :coords (2561 0) - :size (2560 1440) - :rate 30.0 - :dpi 96 - :rotate normal) - -(display-arrangement main :displays (primary secondary)) - -(setq window-manager-named-workspaces - (list (make-window-manager-named-workspace - :label "Web Browsing" - :kbd "c" - :display display-secondary) - (make-window-manager-named-workspace - :label "Coding I" - :kbd "1" - :display display-primary) - (make-window-manager-named-workspace - :label "Coding II" - :kbd "2" - :display display-primary) - (make-window-manager-named-workspace - :label "Chatting" - :kbd "h" - :display display-secondary))) - -;; I *think* this needs to be the last statement in this file. -(window-manager-init :init-hook #'display-arrange-main) diff --git a/users/wpcarro/playbooks/README.md b/users/wpcarro/playbooks/README.md deleted file mode 100644 index 70a26c8e8..000000000 --- a/users/wpcarro/playbooks/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# playbooks - -Here's the vision: playbooks for everything - not just software. diff --git a/users/wpcarro/playbooks/first-of-the-month.org b/users/wpcarro/playbooks/first-of-the-month.org deleted file mode 100644 index 7bce39ca7..000000000 --- a/users/wpcarro/playbooks/first-of-the-month.org +++ /dev/null @@ -1,12 +0,0 @@ -# In total this should take one hour to complete. This is a substantial amount -# of time, which may disincentivize me from completing it. This time is -# amortized over the length of its usefulness (i.e. an entire month), so it -# should be thought of instead as two-minutes worth of work per day that is all -# being completed upfront. -* Tasks -** TODO [10m] create habit template in journal -** TODO [30m] assess previous month's performance -** TODO [10m] book massage for the month -** TODO [10m] create go/hallpass entries (BJJ, VHP) -** TODO [10m] expense home internet -** TODO [10m] buy TSLA through tdameritrade.com diff --git a/users/wpcarro/playbooks/habits.org b/users/wpcarro/playbooks/habits.org deleted file mode 100644 index aac63735d..000000000 --- a/users/wpcarro/playbooks/habits.org +++ /dev/null @@ -1,49 +0,0 @@ -* First of the year -** [1hr] Write a post mortem for the previous year -* First of the month -** see ./first-of-the-month.org -* Payday -** [10m] Audit Monzo expenses -** [05m] Review "finances_2020" spreadsheet -** [05m] Transfer GBP to USD account -** [10m] Withdraw cash from ATM -* Morning -** [00m] Wake up at 7:00 -** [15m] Read -** [02m] Brush teeth -** [01m] Make bed -** [01m] Water plants -** [10m] 12 rounds of forward folds -** [05m] 12 rounds Pranayama -** [30m] Transcendental meditation -** [10m] Shower -** [05m] Put on clothes -* Evening -** [01m] Layout tomorrow's outfit -** [01m] Floss -** [02m] Brush teeth -** [01m] Mouth wash -** [30m] Read -** [01m] Journal daily progress -* Monday -** [1hr] Jiu Jitsu -* Tuesday -** Work from 6PS -** [1hr] Jiu Jitsu -* Wednesday -** [1hr] Hot Yoga -** [10m] Shave -** [15m] Clean apartment sinks -* Thursday -* Friday -** [1hr] Hot Yoga -* Saturday -** [10m] Vacuum -** [30m] Nap -* Sunday -** [1hr] Jiu Jitsu -** [30m] Nap -** [10m] Shave -** [05m] Trim nails -** [05m] Take out trash -** [05m] Laundry diff --git a/users/wpcarro/playbooks/hip_opening_challenge/poses.pdf b/users/wpcarro/playbooks/hip_opening_challenge/poses.pdf deleted file mode 100644 index d292ef832..000000000 Binary files a/users/wpcarro/playbooks/hip_opening_challenge/poses.pdf and /dev/null differ diff --git a/users/wpcarro/playbooks/hip_opening_challenge/progress.org b/users/wpcarro/playbooks/hip_opening_challenge/progress.org deleted file mode 100644 index 80749a3c6..000000000 --- a/users/wpcarro/playbooks/hip_opening_challenge/progress.org +++ /dev/null @@ -1,65 +0,0 @@ -# From Lucas Rockwood's 21-day hip challenge from yogabody.com -* DONE day 1 -** pigeon -** butterfly -* DONE day 2 -** blaster -** squat -* DONE day 3 -** happy baby -** thread the needle (supine) -* DONE day 4 -** frog -** jackknife blaster -* DONE day 5 -** lightning bolt -** scissors -* DONE day 6 -** zorro -** supine butterfly (w/ strap) -* TODO day 7 -** thread the needle (wall) -** prone butterfly -* TODO day 8 -** ninja squat -** chair scissors -** lateral chain stretch -* TODO day 9 -** psoas blaster (chair) -** reclined scissors -* DONE day 10 -** twisted blaster -** twisted squat -* TODO day 11 -** double pigeon -** bound butterfly -* TODO day 12 -** eagle fold -** cross-thread -* DONE day 13 -** swiss army knife -** saddle -* TODO day 14 -** butterfly squat -** half lightning bolt -* DONE day 15 -** fallen blaster -** asymmetric baby -* DONE day 16 -** standing psoas -** standing pigeon -* TODO day 17 -** marichi B -** long butterfly -* TODO day 18 -** eagle legs -** chair squat -* DONE day 19 -** twisted pigeon -** bound baby -* DONE day 20 -** seated pigeon -** railroad squat -* DONE day 21 -** thunderbolt -** yogi squat diff --git a/users/wpcarro/playbooks/nix_gcr/README.md b/users/wpcarro/playbooks/nix_gcr/README.md deleted file mode 100644 index 9d111cf6b..000000000 --- a/users/wpcarro/playbooks/nix_gcr/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# Nix + Google Cloud Run (i.e. GCR) - -I'm documenting how I currently deploy projects that I package with Nix on -Google Cloud Run. - -I'd like to automate this workflow as much as possible, and I intend to do just -that. For now, I'm running things manually until I can design an generalization -that appeals to me. - -## Dependencies -- `nix-build` -- `docker` -- `gcloud` - -## Step-by-step - -1. Use `nix-build` to create our Docker image for Cloud Run. - -```shell -> nix-build ./cloud_run.nix -``` - -This outputs a Docker image at `./result`. - -1. Load the built image (i.e. `./result`) into `docker` so that we can tag it - and push it to the Google Container Registry (i.e. GCR). - -```shell -> sudo docker load <./result -``` - -1. (Optionally) Run the image locally to verify its integrity. - -```shell -> sudo docker run -d -p 8080:4242 : -``` - -1. Tag and push the image to GCR. - -```shell -> sudo docker tag :