mirror of
https://github.com/abhinav/git-spice.git
synced 2026-08-31 07:47:47 +02:00
Add a documentation website (#262)
We need more documentation than we can cover in a reasonably sized README. Replace stitchmd setup with a mkdocs-material based website. Resolves #43
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
name: GitHub Pages
|
||||
|
||||
on:
|
||||
# TODO: uncomment closer to release
|
||||
# push:
|
||||
# branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.22
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: pipenv
|
||||
cache-dependency-path: doc/Pipfile.lock
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: pipenv install --deploy
|
||||
working-directory: doc
|
||||
|
||||
- name: Build
|
||||
run: make build
|
||||
working-directory: doc
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: doc/_site/
|
||||
|
||||
deploy:
|
||||
needs: build
|
||||
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -1,40 +0,0 @@
|
||||
name: Stitch README.md
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
# Change the event to pull_request_target
|
||||
# so that it runs in the context of the base repository.
|
||||
pull_request_target:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
stitchmd:
|
||||
name: ${{ github.event_name == 'pull_request_target' && 'Update' || 'Check' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
- name: Check or update README
|
||||
uses: abhinav/stitchmd-action@v1
|
||||
with:
|
||||
mode: ${{ github.event_name == 'pull_request_target' && 'write' || 'check' }}
|
||||
summary: doc/SUMMARY.md
|
||||
preface: doc/preface.txt
|
||||
output: README.md
|
||||
|
||||
- uses: stefanzweifel/git-auto-commit-action@v5
|
||||
if: ${{ github.event_name == 'pull_request_target' }}
|
||||
with:
|
||||
file_pattern: README.md
|
||||
commit_message: 'Update README.md'
|
||||
+5
-5
@@ -13,9 +13,9 @@ The following tools are needed to work on this project:
|
||||
- [Changie](https://changie.dev/):
|
||||
We use Changie to manage the changelog.
|
||||
You'll need this if you make user-facing changes.
|
||||
- [stitchmd](https://github.com/abhinav/stitchmd):
|
||||
We use stitchmd to generate the README from files inside the doc/ directory.
|
||||
You'll need this to edit the README.
|
||||
- [pipenv](https://pipenv.pypa.io/en/latest/):
|
||||
We use pipenv to manage Python dependencies for documentation generation.
|
||||
You'll need this to preview changes to the doc/ directory.
|
||||
|
||||
## Making contributions
|
||||
|
||||
@@ -30,8 +30,8 @@ with the following notes:
|
||||
[skip changelog]: reason why no changelog entry is needed
|
||||
```
|
||||
|
||||
- If you edit documentation in doc/, run `make README.md` to update the README.
|
||||
This requires stitchmd to be installed.
|
||||
- If you edit documentation in doc/,
|
||||
run `pipenv install && pipenv run mkdocs serve` to preview changes.
|
||||
|
||||
- All commits must include meaningful commit messages.
|
||||
- Test new features and bug fixes.
|
||||
|
||||
@@ -12,7 +12,6 @@ export PATH := $(GOBIN):$(PATH)
|
||||
export GOEXPERIMENT = rangefunc
|
||||
|
||||
TEST_FLAGS ?=
|
||||
STITCHMD_FLAGS ?= -o README.md -preface doc/preface.txt doc/SUMMARY.md
|
||||
|
||||
GS = bin/gs
|
||||
MOCKGEN = bin/mockgen
|
||||
@@ -24,8 +23,6 @@ GO_SRC_FILES = $(shell find . \
|
||||
-path '*/.*' -prune -o \
|
||||
'(' -type f -a -name '*.go' -a -not -name '*_test.go' ')' -print)
|
||||
|
||||
DOC_MD_FILES = $(shell find doc -name '*.md')
|
||||
|
||||
.PHONY: all
|
||||
all: build lint test
|
||||
|
||||
@@ -38,6 +35,7 @@ lint: golangci-lint requiredfield-lint tidy-lint generate-lint
|
||||
.PHONY: generate
|
||||
generate: $(TOOLS)
|
||||
go generate -x ./...
|
||||
make -C doc generate
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
@@ -52,9 +50,6 @@ cover:
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
README.md: $(DOC_MD_FILES)
|
||||
stitchmd $(STITCHMD_FLAGS)
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint:
|
||||
golangci-lint run
|
||||
@@ -78,19 +73,6 @@ generate-lint: $(TOOLS)
|
||||
git diff --exit-code || \
|
||||
(echo "'go generate' changed files" && false)
|
||||
|
||||
# readme-lint depends on generate-lint
|
||||
# because that updates doc/reference.md.
|
||||
# In the future, that can be make-managed.
|
||||
.PHONE: readme-lint
|
||||
readme-lint: generate-lint
|
||||
@echo "[lint] readme"
|
||||
@DIFF=$$(stitchmd -diff $(STITCHMD_FLAGS)); \
|
||||
if [[ -n "$$DIFF" ]]; then \
|
||||
echo "stitchmd would change README:"; \
|
||||
echo "$$DIFF"; \
|
||||
false; \
|
||||
fi \
|
||||
|
||||
$(GS): $(GO_SRC_FILES) go.mod
|
||||
go install go.abhg.dev/gs
|
||||
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
<!-- DO NOT EDIT. This file is generated from doc/*.md. Edit those instead. -->
|
||||
|
||||
# git-spice
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [License](#license)
|
||||
|
||||
## Introduction
|
||||
|
||||
<div align="center">
|
||||
<img src="doc/img/logo.png" width="300"/>
|
||||
<img src="doc/src/img/logo.png" width="300"/>
|
||||
</div>
|
||||
|
||||
[](https://github.com/abhinav/git-spice/actions/workflows/ci.yml)
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ func (*branchUntrackCmd) Help() string {
|
||||
The current branch is deleted from git-spice's data store
|
||||
but not deleted from the repository.
|
||||
Branches upstack from it are not affected,
|
||||
and will to the next branch downstack.
|
||||
and will use the next branch downstack as their new base.
|
||||
|
||||
Provide a branch name as an argument to target
|
||||
a different branch.
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
** linguist-documentation
|
||||
*.svg -diff
|
||||
*.drawio -diff
|
||||
@@ -0,0 +1,3 @@
|
||||
/_site
|
||||
/.cache
|
||||
/bin
|
||||
@@ -0,0 +1,49 @@
|
||||
SHELL = /bin/bash
|
||||
|
||||
MAKEFILE_DIR = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
export GOBIN = $(MAKEFILE_DIR)/bin
|
||||
export PATH := $(GOBIN):$(PATH)
|
||||
|
||||
GS = bin/gs
|
||||
FREEZE = bin/freeze
|
||||
|
||||
# Non-test Go files.
|
||||
GO_SRC_FILES = $(shell find .. \
|
||||
-path '*/.*' -prune -o \
|
||||
'(' -type f -a -name '*.go' -a -not -name '*_test.go' ')' -print)
|
||||
|
||||
TOOLS = bin/pikchr bin/freeze
|
||||
|
||||
CC ?= gcc
|
||||
|
||||
.PHONY: build
|
||||
build: install generate
|
||||
pipenv run mkdocs build
|
||||
|
||||
.PHONY: serve
|
||||
serve: install generate
|
||||
pipenv run mkdocs serve
|
||||
|
||||
.PHONY: install
|
||||
install: .cache/.install $(TOOLS)
|
||||
|
||||
.PHONY: generate
|
||||
generate: $(GS)
|
||||
$(GS) dumpmd \
|
||||
--ref includes/cli-reference.md \
|
||||
--shorthands includes/cli-shorthands.md
|
||||
|
||||
# Marker file for having run 'pipenv install'.
|
||||
.cache/.install: Pipfile.lock
|
||||
pipenv install
|
||||
mkdir -p .cache
|
||||
touch .cache/.install
|
||||
|
||||
bin/pikchr: cmd/pikchr/pikchr.c
|
||||
gcc -DPIKCHR_SHELL -o $@ $< -lm
|
||||
|
||||
bin/gs: $(GO_SRC_FILES)
|
||||
go install -tags dumpmd go.abhg.dev/gs
|
||||
|
||||
bin/freeze: go.mod
|
||||
go install github.com/charmbracelet/freeze
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
mkdocs-material = {extras = ["imaging"], version = "*"}
|
||||
markdown-exec = {extras = ["ansi"], version = "*"}
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.12"
|
||||
Generated
+770
@@ -0,0 +1,770 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "9163ac195dc2c2d6a084be93e43235ba89fc8c99eed4e319556a92438aebd959"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.12"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"babel": {
|
||||
"hashes": [
|
||||
"sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb",
|
||||
"sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.15.0"
|
||||
},
|
||||
"cairocffi": {
|
||||
"hashes": [
|
||||
"sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b",
|
||||
"sha256:9803a0e11f6c962f3b0ae2ec8ba6ae45e957a146a004697a1ac1bbf16b073b3f"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.7.1"
|
||||
},
|
||||
"cairosvg": {
|
||||
"hashes": [
|
||||
"sha256:432531d72347291b9a9ebfb6777026b607563fd8719c46ee742db0aef7271ba0",
|
||||
"sha256:8a5222d4e6c3f86f1f7046b63246877a63b49923a1cd202184c3a634ef546b3b"
|
||||
],
|
||||
"version": "==2.7.1"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b",
|
||||
"sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2024.7.4"
|
||||
},
|
||||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc",
|
||||
"sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a",
|
||||
"sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417",
|
||||
"sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab",
|
||||
"sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520",
|
||||
"sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36",
|
||||
"sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743",
|
||||
"sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8",
|
||||
"sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed",
|
||||
"sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684",
|
||||
"sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56",
|
||||
"sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324",
|
||||
"sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d",
|
||||
"sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235",
|
||||
"sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e",
|
||||
"sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088",
|
||||
"sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000",
|
||||
"sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7",
|
||||
"sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e",
|
||||
"sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673",
|
||||
"sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c",
|
||||
"sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe",
|
||||
"sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2",
|
||||
"sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098",
|
||||
"sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8",
|
||||
"sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a",
|
||||
"sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0",
|
||||
"sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b",
|
||||
"sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896",
|
||||
"sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e",
|
||||
"sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9",
|
||||
"sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2",
|
||||
"sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b",
|
||||
"sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6",
|
||||
"sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404",
|
||||
"sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f",
|
||||
"sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0",
|
||||
"sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4",
|
||||
"sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc",
|
||||
"sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936",
|
||||
"sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba",
|
||||
"sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872",
|
||||
"sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb",
|
||||
"sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614",
|
||||
"sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1",
|
||||
"sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d",
|
||||
"sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969",
|
||||
"sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b",
|
||||
"sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4",
|
||||
"sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627",
|
||||
"sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956",
|
||||
"sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"charset-normalizer": {
|
||||
"hashes": [
|
||||
"sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027",
|
||||
"sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087",
|
||||
"sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786",
|
||||
"sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8",
|
||||
"sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09",
|
||||
"sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185",
|
||||
"sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574",
|
||||
"sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e",
|
||||
"sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519",
|
||||
"sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898",
|
||||
"sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269",
|
||||
"sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3",
|
||||
"sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f",
|
||||
"sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6",
|
||||
"sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8",
|
||||
"sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a",
|
||||
"sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73",
|
||||
"sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc",
|
||||
"sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714",
|
||||
"sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2",
|
||||
"sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc",
|
||||
"sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce",
|
||||
"sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d",
|
||||
"sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e",
|
||||
"sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6",
|
||||
"sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269",
|
||||
"sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96",
|
||||
"sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d",
|
||||
"sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a",
|
||||
"sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4",
|
||||
"sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77",
|
||||
"sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d",
|
||||
"sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0",
|
||||
"sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed",
|
||||
"sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068",
|
||||
"sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac",
|
||||
"sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25",
|
||||
"sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8",
|
||||
"sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab",
|
||||
"sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26",
|
||||
"sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2",
|
||||
"sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db",
|
||||
"sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f",
|
||||
"sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5",
|
||||
"sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99",
|
||||
"sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c",
|
||||
"sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d",
|
||||
"sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811",
|
||||
"sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa",
|
||||
"sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a",
|
||||
"sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03",
|
||||
"sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b",
|
||||
"sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04",
|
||||
"sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c",
|
||||
"sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001",
|
||||
"sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458",
|
||||
"sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389",
|
||||
"sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99",
|
||||
"sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985",
|
||||
"sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537",
|
||||
"sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238",
|
||||
"sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f",
|
||||
"sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d",
|
||||
"sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796",
|
||||
"sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a",
|
||||
"sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143",
|
||||
"sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8",
|
||||
"sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c",
|
||||
"sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5",
|
||||
"sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5",
|
||||
"sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711",
|
||||
"sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4",
|
||||
"sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6",
|
||||
"sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c",
|
||||
"sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7",
|
||||
"sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4",
|
||||
"sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b",
|
||||
"sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae",
|
||||
"sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12",
|
||||
"sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c",
|
||||
"sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae",
|
||||
"sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8",
|
||||
"sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887",
|
||||
"sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b",
|
||||
"sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4",
|
||||
"sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f",
|
||||
"sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5",
|
||||
"sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33",
|
||||
"sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519",
|
||||
"sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"
|
||||
],
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==3.3.2"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28",
|
||||
"sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==8.1.7"
|
||||
},
|
||||
"colorama": {
|
||||
"hashes": [
|
||||
"sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44",
|
||||
"sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'",
|
||||
"version": "==0.4.6"
|
||||
},
|
||||
"cssselect2": {
|
||||
"hashes": [
|
||||
"sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a",
|
||||
"sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"defusedxml": {
|
||||
"hashes": [
|
||||
"sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69",
|
||||
"sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
|
||||
"version": "==0.7.1"
|
||||
},
|
||||
"ghp-import": {
|
||||
"hashes": [
|
||||
"sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619",
|
||||
"sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"
|
||||
],
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc",
|
||||
"sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"
|
||||
],
|
||||
"markers": "python_version >= '3.5'",
|
||||
"version": "==3.7"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369",
|
||||
"sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==3.1.4"
|
||||
},
|
||||
"markdown": {
|
||||
"hashes": [
|
||||
"sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f",
|
||||
"sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==3.6"
|
||||
},
|
||||
"markdown-exec": {
|
||||
"extras": [
|
||||
"ansi"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:6ad206b75306020779144835f44de115235903755c46a7ccd3b754aad74661e1",
|
||||
"sha256:6b3f5f35d9c74e3c7ba9011376ad1732aa3ed3806cadefb8522dee3afe02b1ec"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.9.3"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf",
|
||||
"sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff",
|
||||
"sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f",
|
||||
"sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3",
|
||||
"sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532",
|
||||
"sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f",
|
||||
"sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617",
|
||||
"sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df",
|
||||
"sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4",
|
||||
"sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906",
|
||||
"sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f",
|
||||
"sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4",
|
||||
"sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8",
|
||||
"sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371",
|
||||
"sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2",
|
||||
"sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465",
|
||||
"sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52",
|
||||
"sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6",
|
||||
"sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169",
|
||||
"sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad",
|
||||
"sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2",
|
||||
"sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0",
|
||||
"sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029",
|
||||
"sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f",
|
||||
"sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a",
|
||||
"sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced",
|
||||
"sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5",
|
||||
"sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c",
|
||||
"sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf",
|
||||
"sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9",
|
||||
"sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb",
|
||||
"sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad",
|
||||
"sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3",
|
||||
"sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1",
|
||||
"sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46",
|
||||
"sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc",
|
||||
"sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a",
|
||||
"sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee",
|
||||
"sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900",
|
||||
"sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5",
|
||||
"sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea",
|
||||
"sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f",
|
||||
"sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5",
|
||||
"sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e",
|
||||
"sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a",
|
||||
"sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f",
|
||||
"sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50",
|
||||
"sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a",
|
||||
"sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b",
|
||||
"sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4",
|
||||
"sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff",
|
||||
"sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2",
|
||||
"sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46",
|
||||
"sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b",
|
||||
"sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf",
|
||||
"sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5",
|
||||
"sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5",
|
||||
"sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab",
|
||||
"sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd",
|
||||
"sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"version": "==2.1.5"
|
||||
},
|
||||
"mergedeep": {
|
||||
"hashes": [
|
||||
"sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8",
|
||||
"sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==1.3.4"
|
||||
},
|
||||
"mkdocs": {
|
||||
"hashes": [
|
||||
"sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7",
|
||||
"sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.6.0"
|
||||
},
|
||||
"mkdocs-get-deps": {
|
||||
"hashes": [
|
||||
"sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c",
|
||||
"sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==0.2.0"
|
||||
},
|
||||
"mkdocs-material": {
|
||||
"extras": [
|
||||
"imaging"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:3e977598ec15a4ddad5c4dfc9e08edab6023edb51e88f0729bd27be77e3d322a",
|
||||
"sha256:afc1f508e2662ded95f0a35a329e8a5acd73ee88ca07ba73836eb6fcdae5d8b4"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==9.5.29"
|
||||
},
|
||||
"mkdocs-material-extensions": {
|
||||
"hashes": [
|
||||
"sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443",
|
||||
"sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.3.1"
|
||||
},
|
||||
"packaging": {
|
||||
"hashes": [
|
||||
"sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002",
|
||||
"sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==24.1"
|
||||
},
|
||||
"paginate": {
|
||||
"hashes": [
|
||||
"sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"
|
||||
],
|
||||
"version": "==0.5.6"
|
||||
},
|
||||
"pathspec": {
|
||||
"hashes": [
|
||||
"sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08",
|
||||
"sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==0.12.1"
|
||||
},
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885",
|
||||
"sha256:030abdbe43ee02e0de642aee345efa443740aa4d828bfe8e2eb11922ea6a21ea",
|
||||
"sha256:06b2f7898047ae93fad74467ec3d28fe84f7831370e3c258afa533f81ef7f3df",
|
||||
"sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5",
|
||||
"sha256:0a9ec697746f268507404647e531e92889890a087e03681a3606d9b920fbee3c",
|
||||
"sha256:0ae24a547e8b711ccaaf99c9ae3cd975470e1a30caa80a6aaee9a2f19c05701d",
|
||||
"sha256:134ace6dc392116566980ee7436477d844520a26a4b1bd4053f6f47d096997fd",
|
||||
"sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06",
|
||||
"sha256:1b5dea9831a90e9d0721ec417a80d4cbd7022093ac38a568db2dd78363b00908",
|
||||
"sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a",
|
||||
"sha256:1ef61f5dd14c300786318482456481463b9d6b91ebe5ef12f405afbba77ed0be",
|
||||
"sha256:297e388da6e248c98bc4a02e018966af0c5f92dfacf5a5ca22fa01cb3179bca0",
|
||||
"sha256:298478fe4f77a4408895605f3482b6cc6222c018b2ce565c2b6b9c354ac3229b",
|
||||
"sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80",
|
||||
"sha256:2db98790afc70118bd0255c2eeb465e9767ecf1f3c25f9a1abb8ffc8cfd1fe0a",
|
||||
"sha256:32cda9e3d601a52baccb2856b8ea1fc213c90b340c542dcef77140dfa3278a9e",
|
||||
"sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9",
|
||||
"sha256:416d3a5d0e8cfe4f27f574362435bc9bae57f679a7158e0096ad2beb427b8696",
|
||||
"sha256:43efea75eb06b95d1631cb784aa40156177bf9dd5b4b03ff38979e048258bc6b",
|
||||
"sha256:4b35b21b819ac1dbd1233317adeecd63495f6babf21b7b2512d244ff6c6ce309",
|
||||
"sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e",
|
||||
"sha256:5161eef006d335e46895297f642341111945e2c1c899eb406882a6c61a4357ab",
|
||||
"sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d",
|
||||
"sha256:551d3fd6e9dc15e4c1eb6fc4ba2b39c0c7933fa113b220057a34f4bb3268a060",
|
||||
"sha256:59291fb29317122398786c2d44427bbd1a6d7ff54017075b22be9d21aa59bd8d",
|
||||
"sha256:5b001114dd152cfd6b23befeb28d7aee43553e2402c9f159807bf55f33af8a8d",
|
||||
"sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4",
|
||||
"sha256:5dc6761a6efc781e6a1544206f22c80c3af4c8cf461206d46a1e6006e4429ff3",
|
||||
"sha256:5e84b6cc6a4a3d76c153a6b19270b3526a5a8ed6b09501d3af891daa2a9de7d6",
|
||||
"sha256:6209bb41dc692ddfee4942517c19ee81b86c864b626dbfca272ec0f7cff5d9fb",
|
||||
"sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94",
|
||||
"sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b",
|
||||
"sha256:7086cc1d5eebb91ad24ded9f58bec6c688e9f0ed7eb3dbbf1e4800280a896496",
|
||||
"sha256:73664fe514b34c8f02452ffb73b7a92c6774e39a647087f83d67f010eb9a0cf0",
|
||||
"sha256:76a911dfe51a36041f2e756b00f96ed84677cdeb75d25c767f296c1c1eda1319",
|
||||
"sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b",
|
||||
"sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856",
|
||||
"sha256:7970285ab628a3779aecc35823296a7869f889b8329c16ad5a71e4901a3dc4ef",
|
||||
"sha256:7a8d4bade9952ea9a77d0c3e49cbd8b2890a399422258a77f357b9cc9be8d680",
|
||||
"sha256:7c1ee6f42250df403c5f103cbd2768a28fe1a0ea1f0f03fe151c8741e1469c8b",
|
||||
"sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42",
|
||||
"sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e",
|
||||
"sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597",
|
||||
"sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a",
|
||||
"sha256:87dd88ded2e6d74d31e1e0a99a726a6765cda32d00ba72dc37f0651f306daaa8",
|
||||
"sha256:8bc1a764ed8c957a2e9cacf97c8b2b053b70307cf2996aafd70e91a082e70df3",
|
||||
"sha256:8d4d5063501b6dd4024b8ac2f04962d661222d120381272deea52e3fc52d3736",
|
||||
"sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da",
|
||||
"sha256:930044bb7679ab003b14023138b50181899da3f25de50e9dbee23b61b4de2126",
|
||||
"sha256:950be4d8ba92aca4b2bb0741285a46bfae3ca699ef913ec8416c1b78eadd64cd",
|
||||
"sha256:961a7293b2457b405967af9c77dcaa43cc1a8cd50d23c532e62d48ab6cdd56f5",
|
||||
"sha256:9b885f89040bb8c4a1573566bbb2f44f5c505ef6e74cec7ab9068c900047f04b",
|
||||
"sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026",
|
||||
"sha256:a02364621fe369e06200d4a16558e056fe2805d3468350df3aef21e00d26214b",
|
||||
"sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc",
|
||||
"sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46",
|
||||
"sha256:b15e02e9bb4c21e39876698abf233c8c579127986f8207200bc8a8f6bb27acf2",
|
||||
"sha256:b2724fdb354a868ddf9a880cb84d102da914e99119211ef7ecbdc613b8c96b3c",
|
||||
"sha256:bbc527b519bd3aa9d7f429d152fea69f9ad37c95f0b02aebddff592688998abe",
|
||||
"sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984",
|
||||
"sha256:bd2880a07482090a3bcb01f4265f1936a903d70bc740bfcb1fd4e8a2ffe5cf5a",
|
||||
"sha256:bee197b30783295d2eb680b311af15a20a8b24024a19c3a26431ff83eb8d1f70",
|
||||
"sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca",
|
||||
"sha256:c76e5786951e72ed3686e122d14c5d7012f16c8303a674d18cdcd6d89557fc5b",
|
||||
"sha256:cbed61494057c0f83b83eb3a310f0bf774b09513307c434d4366ed64f4128a91",
|
||||
"sha256:cfdd747216947628af7b259d274771d84db2268ca062dd5faf373639d00113a3",
|
||||
"sha256:d7480af14364494365e89d6fddc510a13e5a2c3584cb19ef65415ca57252fb84",
|
||||
"sha256:dbc6ae66518ab3c5847659e9988c3b60dc94ffb48ef9168656e0019a93dbf8a1",
|
||||
"sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5",
|
||||
"sha256:dfe91cb65544a1321e631e696759491ae04a2ea11d36715eca01ce07284738be",
|
||||
"sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f",
|
||||
"sha256:e4db64794ccdf6cb83a59d73405f63adbe2a1887012e308828596100a0b2f6cc",
|
||||
"sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9",
|
||||
"sha256:e88d5e6ad0d026fba7bdab8c3f225a69f063f116462c49892b0149e21b6c0a0e",
|
||||
"sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141",
|
||||
"sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef",
|
||||
"sha256:f5f0c3e969c8f12dd2bb7e0b15d5c468b51e5017e01e2e867335c81903046a22",
|
||||
"sha256:f7baece4ce06bade126fb84b8af1c33439a76d8a6fd818970215e0560ca28c27",
|
||||
"sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e",
|
||||
"sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1"
|
||||
],
|
||||
"version": "==10.4.0"
|
||||
},
|
||||
"platformdirs": {
|
||||
"hashes": [
|
||||
"sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee",
|
||||
"sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==4.2.2"
|
||||
},
|
||||
"pycparser": {
|
||||
"hashes": [
|
||||
"sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6",
|
||||
"sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.22"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
|
||||
"sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.18.0"
|
||||
},
|
||||
"pygments-ansi-color": {
|
||||
"hashes": [
|
||||
"sha256:7018954cf5b11d1e734383a1bafab5af613213f246109417fee3f76da26d5431",
|
||||
"sha256:7eb063feaecadad9d4d1fd3474cbfeadf3486b64f760a8f2a00fc25392180aba"
|
||||
],
|
||||
"version": "==0.3.0"
|
||||
},
|
||||
"pymdown-extensions": {
|
||||
"hashes": [
|
||||
"sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940",
|
||||
"sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==10.8.1"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3",
|
||||
"sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.9.0.post0"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5",
|
||||
"sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc",
|
||||
"sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df",
|
||||
"sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741",
|
||||
"sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206",
|
||||
"sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27",
|
||||
"sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595",
|
||||
"sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62",
|
||||
"sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98",
|
||||
"sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696",
|
||||
"sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290",
|
||||
"sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9",
|
||||
"sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d",
|
||||
"sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6",
|
||||
"sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867",
|
||||
"sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47",
|
||||
"sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486",
|
||||
"sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6",
|
||||
"sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3",
|
||||
"sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007",
|
||||
"sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938",
|
||||
"sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0",
|
||||
"sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c",
|
||||
"sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735",
|
||||
"sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d",
|
||||
"sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28",
|
||||
"sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4",
|
||||
"sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba",
|
||||
"sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8",
|
||||
"sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef",
|
||||
"sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5",
|
||||
"sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd",
|
||||
"sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3",
|
||||
"sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0",
|
||||
"sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515",
|
||||
"sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c",
|
||||
"sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c",
|
||||
"sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924",
|
||||
"sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34",
|
||||
"sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43",
|
||||
"sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859",
|
||||
"sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673",
|
||||
"sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54",
|
||||
"sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a",
|
||||
"sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b",
|
||||
"sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab",
|
||||
"sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa",
|
||||
"sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c",
|
||||
"sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585",
|
||||
"sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d",
|
||||
"sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==6.0.1"
|
||||
},
|
||||
"pyyaml-env-tag": {
|
||||
"hashes": [
|
||||
"sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb",
|
||||
"sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==0.1"
|
||||
},
|
||||
"regex": {
|
||||
"hashes": [
|
||||
"sha256:0721931ad5fe0dda45d07f9820b90b2148ccdd8e45bb9e9b42a146cb4f695649",
|
||||
"sha256:10002e86e6068d9e1c91eae8295ef690f02f913c57db120b58fdd35a6bb1af35",
|
||||
"sha256:10e4ce0dca9ae7a66e6089bb29355d4432caed736acae36fef0fdd7879f0b0cb",
|
||||
"sha256:119af6e56dce35e8dfb5222573b50c89e5508d94d55713c75126b753f834de68",
|
||||
"sha256:1337b7dbef9b2f71121cdbf1e97e40de33ff114801263b275aafd75303bd62b5",
|
||||
"sha256:13cdaf31bed30a1e1c2453ef6015aa0983e1366fad2667657dbcac7b02f67133",
|
||||
"sha256:1595f2d10dff3d805e054ebdc41c124753631b6a471b976963c7b28543cf13b0",
|
||||
"sha256:16093f563098448ff6b1fa68170e4acbef94e6b6a4e25e10eae8598bb1694b5d",
|
||||
"sha256:1878b8301ed011704aea4c806a3cadbd76f84dece1ec09cc9e4dc934cfa5d4da",
|
||||
"sha256:19068a6a79cf99a19ccefa44610491e9ca02c2be3305c7760d3831d38a467a6f",
|
||||
"sha256:19dfb1c504781a136a80ecd1fff9f16dddf5bb43cec6871778c8a907a085bb3d",
|
||||
"sha256:1b5269484f6126eee5e687785e83c6b60aad7663dafe842b34691157e5083e53",
|
||||
"sha256:1c1c174d6ec38d6c8a7504087358ce9213d4332f6293a94fbf5249992ba54efa",
|
||||
"sha256:2431b9e263af1953c55abbd3e2efca67ca80a3de8a0437cb58e2421f8184717a",
|
||||
"sha256:287eb7f54fc81546346207c533ad3c2c51a8d61075127d7f6d79aaf96cdee890",
|
||||
"sha256:2b4c884767504c0e2401babe8b5b7aea9148680d2e157fa28f01529d1f7fcf67",
|
||||
"sha256:35cb514e137cb3488bce23352af3e12fb0dbedd1ee6e60da053c69fb1b29cc6c",
|
||||
"sha256:391d7f7f1e409d192dba8bcd42d3e4cf9e598f3979cdaed6ab11288da88cb9f2",
|
||||
"sha256:3ad070b823ca5890cab606c940522d05d3d22395d432f4aaaf9d5b1653e47ced",
|
||||
"sha256:3cd7874d57f13bf70078f1ff02b8b0aa48d5b9ed25fc48547516c6aba36f5741",
|
||||
"sha256:3e507ff1e74373c4d3038195fdd2af30d297b4f0950eeda6f515ae3d84a1770f",
|
||||
"sha256:455705d34b4154a80ead722f4f185b04c4237e8e8e33f265cd0798d0e44825fa",
|
||||
"sha256:4a605586358893b483976cffc1723fb0f83e526e8f14c6e6614e75919d9862cf",
|
||||
"sha256:4babf07ad476aaf7830d77000874d7611704a7fcf68c9c2ad151f5d94ae4bfc4",
|
||||
"sha256:4eee78a04e6c67e8391edd4dad3279828dd66ac4b79570ec998e2155d2e59fd5",
|
||||
"sha256:5397de3219a8b08ae9540c48f602996aa6b0b65d5a61683e233af8605c42b0f2",
|
||||
"sha256:5b5467acbfc153847d5adb21e21e29847bcb5870e65c94c9206d20eb4e99a384",
|
||||
"sha256:5eaa7ddaf517aa095fa8da0b5015c44d03da83f5bd49c87961e3c997daed0de7",
|
||||
"sha256:632b01153e5248c134007209b5c6348a544ce96c46005d8456de1d552455b014",
|
||||
"sha256:64c65783e96e563103d641760664125e91bd85d8e49566ee560ded4da0d3e704",
|
||||
"sha256:64f18a9a3513a99c4bef0e3efd4c4a5b11228b48aa80743be822b71e132ae4f5",
|
||||
"sha256:673b5a6da4557b975c6c90198588181029c60793835ce02f497ea817ff647cb2",
|
||||
"sha256:68811ab14087b2f6e0fc0c2bae9ad689ea3584cad6917fc57be6a48bbd012c49",
|
||||
"sha256:6e8d717bca3a6e2064fc3a08df5cbe366369f4b052dcd21b7416e6d71620dca1",
|
||||
"sha256:71a455a3c584a88f654b64feccc1e25876066c4f5ef26cd6dd711308aa538694",
|
||||
"sha256:72d7a99cd6b8f958e85fc6ca5b37c4303294954eac1376535b03c2a43eb72629",
|
||||
"sha256:7b59138b219ffa8979013be7bc85bb60c6f7b7575df3d56dc1e403a438c7a3f6",
|
||||
"sha256:7dbe2467273b875ea2de38ded4eba86cbcbc9a1a6d0aa11dcf7bd2e67859c435",
|
||||
"sha256:833616ddc75ad595dee848ad984d067f2f31be645d603e4d158bba656bbf516c",
|
||||
"sha256:87e2a9c29e672fc65523fb47a90d429b70ef72b901b4e4b1bd42387caf0d6835",
|
||||
"sha256:8fe45aa3f4aa57faabbc9cb46a93363edd6197cbc43523daea044e9ff2fea83e",
|
||||
"sha256:9e717956dcfd656f5055cc70996ee2cc82ac5149517fc8e1b60261b907740201",
|
||||
"sha256:9efa1a32ad3a3ea112224897cdaeb6aa00381627f567179c0314f7b65d354c62",
|
||||
"sha256:9ff11639a8d98969c863d4617595eb5425fd12f7c5ef6621a4b74b71ed8726d5",
|
||||
"sha256:a094801d379ab20c2135529948cb84d417a2169b9bdceda2a36f5f10977ebc16",
|
||||
"sha256:a0981022dccabca811e8171f913de05720590c915b033b7e601f35ce4ea7019f",
|
||||
"sha256:a0bd000c6e266927cb7a1bc39d55be95c4b4f65c5be53e659537537e019232b1",
|
||||
"sha256:a32b96f15c8ab2e7d27655969a23895eb799de3665fa94349f3b2fbfd547236f",
|
||||
"sha256:a81e3cfbae20378d75185171587cbf756015ccb14840702944f014e0d93ea09f",
|
||||
"sha256:ac394ff680fc46b97487941f5e6ae49a9f30ea41c6c6804832063f14b2a5a145",
|
||||
"sha256:ada150c5adfa8fbcbf321c30c751dc67d2f12f15bd183ffe4ec7cde351d945b3",
|
||||
"sha256:b2b6f1b3bb6f640c1a92be3bbfbcb18657b125b99ecf141fb3310b5282c7d4ed",
|
||||
"sha256:b802512f3e1f480f41ab5f2cfc0e2f761f08a1f41092d6718868082fc0d27143",
|
||||
"sha256:ba68168daedb2c0bab7fd7e00ced5ba90aebf91024dea3c88ad5063c2a562cca",
|
||||
"sha256:bfc4f82cabe54f1e7f206fd3d30fda143f84a63fe7d64a81558d6e5f2e5aaba9",
|
||||
"sha256:c0c18345010870e58238790a6779a1219b4d97bd2e77e1140e8ee5d14df071aa",
|
||||
"sha256:c3bea0ba8b73b71b37ac833a7f3fd53825924165da6a924aec78c13032f20850",
|
||||
"sha256:c486b4106066d502495b3025a0a7251bf37ea9540433940a23419461ab9f2a80",
|
||||
"sha256:c49e15eac7c149f3670b3e27f1f28a2c1ddeccd3a2812cba953e01be2ab9b5fe",
|
||||
"sha256:c6a2b494a76983df8e3d3feea9b9ffdd558b247e60b92f877f93a1ff43d26656",
|
||||
"sha256:cab12877a9bdafde5500206d1020a584355a97884dfd388af3699e9137bf7388",
|
||||
"sha256:cac27dcaa821ca271855a32188aa61d12decb6fe45ffe3e722401fe61e323cd1",
|
||||
"sha256:cdd09d47c0b2efee9378679f8510ee6955d329424c659ab3c5e3a6edea696294",
|
||||
"sha256:cf2430df4148b08fb4324b848672514b1385ae3807651f3567871f130a728cc3",
|
||||
"sha256:d0a3d8d6acf0c78a1fff0e210d224b821081330b8524e3e2bc5a68ef6ab5803d",
|
||||
"sha256:d0c0c0003c10f54a591d220997dd27d953cd9ccc1a7294b40a4be5312be8797b",
|
||||
"sha256:d1f059a4d795e646e1c37665b9d06062c62d0e8cc3c511fe01315973a6542e40",
|
||||
"sha256:d347a741ea871c2e278fde6c48f85136c96b8659b632fb57a7d1ce1872547600",
|
||||
"sha256:d3ee02d9e5f482cc8309134a91eeaacbdd2261ba111b0fef3748eeb4913e6a2c",
|
||||
"sha256:d99ceffa25ac45d150e30bd9ed14ec6039f2aad0ffa6bb87a5936f5782fc1569",
|
||||
"sha256:e38a7d4e8f633a33b4c7350fbd8bad3b70bf81439ac67ac38916c4a86b465456",
|
||||
"sha256:e4682f5ba31f475d58884045c1a97a860a007d44938c4c0895f41d64481edbc9",
|
||||
"sha256:e5bb9425fe881d578aeca0b2b4b3d314ec88738706f66f219c194d67179337cb",
|
||||
"sha256:e64198f6b856d48192bf921421fdd8ad8eb35e179086e99e99f711957ffedd6e",
|
||||
"sha256:e6662686aeb633ad65be2a42b4cb00178b3fbf7b91878f9446075c404ada552f",
|
||||
"sha256:ec54d5afa89c19c6dd8541a133be51ee1017a38b412b1321ccb8d6ddbeb4cf7d",
|
||||
"sha256:f5b1dff3ad008dccf18e652283f5e5339d70bf8ba7c98bf848ac33db10f7bc7a",
|
||||
"sha256:f8ec0c2fea1e886a19c3bee0cd19d862b3aa75dcdfb42ebe8ed30708df64687a",
|
||||
"sha256:f9ebd0a36102fcad2f03696e8af4ae682793a5d30b46c647eaf280d6cfb32796"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2024.5.15"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
|
||||
"sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.32.3"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"tinycss2": {
|
||||
"hashes": [
|
||||
"sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d",
|
||||
"sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472",
|
||||
"sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==2.2.2"
|
||||
},
|
||||
"watchdog": {
|
||||
"hashes": [
|
||||
"sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7",
|
||||
"sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767",
|
||||
"sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175",
|
||||
"sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459",
|
||||
"sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5",
|
||||
"sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429",
|
||||
"sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6",
|
||||
"sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d",
|
||||
"sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7",
|
||||
"sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28",
|
||||
"sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235",
|
||||
"sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57",
|
||||
"sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a",
|
||||
"sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5",
|
||||
"sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709",
|
||||
"sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee",
|
||||
"sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84",
|
||||
"sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd",
|
||||
"sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba",
|
||||
"sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db",
|
||||
"sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682",
|
||||
"sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35",
|
||||
"sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d",
|
||||
"sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645",
|
||||
"sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253",
|
||||
"sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193",
|
||||
"sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b",
|
||||
"sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44",
|
||||
"sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b",
|
||||
"sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625",
|
||||
"sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e",
|
||||
"sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5"
|
||||
],
|
||||
"markers": "python_version >= '3.8'",
|
||||
"version": "==4.0.1"
|
||||
},
|
||||
"webencodings": {
|
||||
"hashes": [
|
||||
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
|
||||
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
|
||||
],
|
||||
"version": "==0.5.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# git-spice
|
||||
|
||||
- [Introduction](intro.md)
|
||||
- [License](license.md)
|
||||
@@ -0,0 +1 @@
|
||||
pikchr.c linguist-vendored
|
||||
Vendored
+8246
File diff suppressed because it is too large
Load Diff
@@ -1,4 +0,0 @@
|
||||
// Package doc is a placeholder for documentation.
|
||||
package doc
|
||||
|
||||
//go:generate gs dump-md --out reference.md
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
module go.abhg.dev/gs/doc
|
||||
|
||||
go 1.22.5
|
||||
|
||||
replace go.abhg.dev/gs => ../
|
||||
|
||||
require (
|
||||
github.com/charmbracelet/freeze v0.1.7-0.20240607113933-578e9d05c319
|
||||
go.abhg.dev/gs v0.1.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/adrg/xdg v0.4.0 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
|
||||
github.com/alecthomas/kong v0.9.0 // indirect
|
||||
github.com/alessio/shellescape v1.4.1 // indirect
|
||||
github.com/atotto/clipboard v0.1.4 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/beevik/etree v1.3.0 // indirect
|
||||
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10 // indirect
|
||||
github.com/caarlos0/go-shellwords v1.0.12 // indirect
|
||||
github.com/catppuccin/go v0.2.0 // indirect
|
||||
github.com/charmbracelet/bubbles v0.18.0 // indirect
|
||||
github.com/charmbracelet/bubbletea v0.26.6 // indirect
|
||||
github.com/charmbracelet/huh v0.3.1-0.20240327025511-ec643317aa10 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.12.1 // indirect
|
||||
github.com/charmbracelet/log v0.4.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.1.4 // indirect
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 // indirect
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240327191656-1e1cd98f30d4 // indirect
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240403043919-dea9035a27d4 // indirect
|
||||
github.com/charmbracelet/x/input v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/term v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.1.2 // indirect
|
||||
github.com/creack/pty v1.1.21 // indirect
|
||||
github.com/danieljoos/wincred v1.2.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/shurcooL/githubv4 v0.0.0-20240429030203-be2daab69064 // indirect
|
||||
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 // indirect
|
||||
github.com/tetratelabs/wazero v1.7.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/zalando/go-keyring v0.2.5 // indirect
|
||||
go.abhg.dev/requiredfield v0.3.0 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/oauth2 v0.21.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
golang.org/x/tools v0.20.0 // indirect
|
||||
)
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
|
||||
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
|
||||
github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
|
||||
github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA=
|
||||
github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0=
|
||||
github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||
github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU=
|
||||
github.com/beevik/etree v1.3.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc=
|
||||
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10 h1:XwHQ5xDtYPdtBbVPyRO6UZoWZe8/mbKUb076f8x7RvI=
|
||||
github.com/buildkite/shellwords v0.0.0-20180315110454-59467a9b8e10/go.mod h1:gv0DYOzHEsKgo31lTCDGauIg4DTTGn41Bzp+t3wSOlk=
|
||||
github.com/caarlos0/go-shellwords v1.0.12 h1:HWrUnu6lGbWfrDcFiHcZiwOLzHWjjrPVehULaTFgPp8=
|
||||
github.com/caarlos0/go-shellwords v1.0.12/go.mod h1:bYeeX1GrTLPl5cAMYEzdm272qdsQAZiaHgeF0KTk1Gw=
|
||||
github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
|
||||
github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
||||
github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0=
|
||||
github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw=
|
||||
github.com/charmbracelet/bubbletea v0.26.6 h1:zTCWSuST+3yZYZnVSvbXwKOPRSNZceVeqpzOLN2zq1s=
|
||||
github.com/charmbracelet/bubbletea v0.26.6/go.mod h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk=
|
||||
github.com/charmbracelet/freeze v0.1.7-0.20240607113933-578e9d05c319 h1:t9ALQwGQH/Xmh267X1QYKdXwBpwCmWEYBlg76ajFAr0=
|
||||
github.com/charmbracelet/freeze v0.1.7-0.20240607113933-578e9d05c319/go.mod h1:gQ/e9NCWaG1E/tuLF0u7xn8XFJVsU4hm0O9pYR6Ii8U=
|
||||
github.com/charmbracelet/huh v0.3.1-0.20240327025511-ec643317aa10 h1:779PmXc9Zt/Hxa0yg4I8sQk/1Nfa5TQisXaHZEW60Yk=
|
||||
github.com/charmbracelet/huh v0.3.1-0.20240327025511-ec643317aa10/go.mod h1:x0rYoA1kpsaefXhRJZuxLM+qP4CYyEFE67T3ZGl7zPU=
|
||||
github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
|
||||
github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
|
||||
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
|
||||
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
|
||||
github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
|
||||
github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651 h1:3RXpZWGWTOeVXCTv0Dnzxdv/MhNUkBfEcbaTY0zrTQI=
|
||||
github.com/charmbracelet/x/errors v0.0.0-20240117030013-d31dba354651/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240327191656-1e1cd98f30d4 h1:E3qdydPjQJIGnT6t6lY0P70sou+Vmh+VcQHAYR4qTtA=
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20240327191656-1e1cd98f30d4/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240403043919-dea9035a27d4 h1:LewLBFkff+bCxgMZn1m8xNYQbUksWaY71d1QARHA11s=
|
||||
github.com/charmbracelet/x/exp/term v0.0.0-20240403043919-dea9035a27d4/go.mod h1:6GZ13FjIP6eOCqWU4lqgveGnYxQo9c3qBzHPeFu4HBE=
|
||||
github.com/charmbracelet/x/input v0.1.1 h1:YDOJaTUKCqtGnq9PHzx3pkkl4pXDOANUHmhH3DqMtM4=
|
||||
github.com/charmbracelet/x/input v0.1.1/go.mod h1:jvdTVUnNWj/RD6hjC4FsoB0SeZCJ2ZBkiuFP9zXvZI0=
|
||||
github.com/charmbracelet/x/term v0.1.1 h1:3cosVAiPOig+EV4X9U+3LDgtwwAoEzJjNdwbXDjF6yI=
|
||||
github.com/charmbracelet/x/term v0.1.1/go.mod h1:wB1fHt5ECsu3mXYusyzcngVWWlu1KKUmmLhfgr/Flxw=
|
||||
github.com/charmbracelet/x/windows v0.1.2 h1:Iumiwq2G+BRmgoayww/qfcvof7W/3uLoelhxojXlRWg=
|
||||
github.com/charmbracelet/x/windows v0.1.2/go.mod h1:GLEO/l+lizvFDBPLIOk+49gdX49L9YWMB5t+DZd0jkQ=
|
||||
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/creack/pty/v2 v2.0.1 h1:RDY1VY5b+7m2mfPsugucOYPIxMp+xal5ZheSyVzUA+k=
|
||||
github.com/creack/pty/v2 v2.0.1/go.mod h1:2dSssKp3b86qYEMwA/FPwc3ff+kYpDdQI8osU8J7gxQ=
|
||||
github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE=
|
||||
github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec=
|
||||
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/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5 h1:BXnB1Gz4y/zwQh+ZFNy7rgd+ZfMOrwRr4uZSHEI+ieY=
|
||||
github.com/kanrichan/resvg-go v0.0.2-0.20231001163256-63db194ca9f5/go.mod h1:c9+VS9GaommgIOzNWb5ze4lYwfT8BZ2UDyGiuQTT7yc=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||
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/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/shurcooL/githubv4 v0.0.0-20240429030203-be2daab69064 h1:RCQBSFx5JrsbHltqTtJ+kN3U0Y3a/N/GlVdmRSoxzyE=
|
||||
github.com/shurcooL/githubv4 v0.0.0-20240429030203-be2daab69064/go.mod h1:zqMwyHmnN/eDOZOdiTohqIUKUrTFX62PNlu7IJdu0q8=
|
||||
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZVHkmAsGEkcIu0oCe3AM420QDgGwZx0=
|
||||
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tetratelabs/wazero v1.7.0 h1:jg5qPydno59wqjpGrHph81lbtHzTrWzwwtD4cD88+hQ=
|
||||
github.com/tetratelabs/wazero v1.7.0/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
|
||||
github.com/vito/midterm v0.1.5-0.20240307214207-d0271a7ca452 h1:I5FdiUvkD++87hOiZYuDu0BqsaJXAnpOCed3kqkjCEE=
|
||||
github.com/vito/midterm v0.1.5-0.20240307214207-d0271a7ca452/go.mod h1:2ujYuyOObdWrQtnXAzwSBcPRKhC5Q96ex0nsf2Dmfzk=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/zalando/go-keyring v0.2.5 h1:Bc2HHpjALryKD62ppdEzaFG6VxL6Bc+5v0LYpN8Lba8=
|
||||
github.com/zalando/go-keyring v0.2.5/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk=
|
||||
go.abhg.dev/requiredfield v0.3.0 h1:/fOqPt7t1SktSZVGUNXMg5djO8GasUh+G1ez111UEcs=
|
||||
go.abhg.dev/requiredfield v0.3.0/go.mod h1:ML+QbQ96X7jzJK68sDI4BafOEIZNAB4DHLXl78TrPZI=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
|
||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
||||
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/dnaeon/go-vcr.v3 v3.2.0 h1:Rltp0Vf+Aq0u4rQXgmXgtgoRDStTnFN83cWgSGSoRzM=
|
||||
gopkg.in/dnaeon/go-vcr.v3 v3.2.0/go.mod h1:2IMOnnlx9I6u9x+YBsM3tAMx6AlOxnJ0pWxQAzZ79Ag=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
|
||||
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
|
||||
@@ -0,0 +1,32 @@
|
||||
# Introduces a $$...$$ syntax for references to CLI commands in the reference.
|
||||
# $$command|text$$ will use {text} as the link text.
|
||||
|
||||
import re
|
||||
from mkdocs.structure.pages import Page
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
from mkdocs.structure.files import Files
|
||||
|
||||
|
||||
_CLI_PAGE = "cli/index.md"
|
||||
_cmd_re = re.compile(r"\$\$([^$]+)\$\$")
|
||||
|
||||
|
||||
def on_page_markdown(
|
||||
markdown: str,
|
||||
page: Page,
|
||||
config: MkDocsConfig,
|
||||
files: Files,
|
||||
) -> str:
|
||||
# Don't process the target page itself.
|
||||
if page.file.src_uri == _CLI_PAGE:
|
||||
return markdown
|
||||
|
||||
def _replace(match):
|
||||
cmd = match.group(1)
|
||||
text = cmd
|
||||
if "|" in cmd:
|
||||
cmd, text = cmd.split("|", 1)
|
||||
id = cmd.replace(" ", "-")
|
||||
return f'[:material-console:{{ .middle }} {text}](/{_CLI_PAGE}#{id})'
|
||||
|
||||
return _cmd_re.sub(_replace, markdown)
|
||||
@@ -0,0 +1,60 @@
|
||||
import logging
|
||||
from os.path import normpath
|
||||
|
||||
from mkdocs.structure.pages import Page
|
||||
from mkdocs.utils.templates import TemplateContext
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
from mkdocs.structure.nav import Navigation
|
||||
|
||||
log = logging.getLogger("mkdocs.plugins.footer")
|
||||
|
||||
# A variant of the footer functionality in mkdocs-material
|
||||
# but with support for pages to define their own next_page or prev_page
|
||||
# in front matter.
|
||||
#
|
||||
# Useful for pages that are not part of the main nav,
|
||||
# but still want to have a next/prev page.
|
||||
|
||||
|
||||
def on_page_context(
|
||||
ctx: TemplateContext,
|
||||
page: Page,
|
||||
config: MkDocsConfig,
|
||||
nav: Navigation,
|
||||
) -> TemplateContext:
|
||||
next_page_name = page.meta.get('next_page', None)
|
||||
prev_page_name = page.meta.get('prev_page', None)
|
||||
if not next_page_name and not prev_page_name:
|
||||
return ctx
|
||||
|
||||
# foo/bar/baz.md -> foo/bar
|
||||
uri = page.file.src_uri
|
||||
dir = '/'.join(uri.split('/')[:-1])
|
||||
|
||||
next_page_uri, prev_page_uri = None, None
|
||||
if next_page_name:
|
||||
next_page_uri = normpath(f'{dir}/{next_page_name}')
|
||||
if prev_page_name:
|
||||
prev_page_uri = normpath(f'{dir}/{prev_page_name}')
|
||||
|
||||
next_page, prev_page = None, None
|
||||
for file in ctx['pages']:
|
||||
uri = file.src_uri
|
||||
if next_page_uri and uri == next_page_uri:
|
||||
next_page = file.page
|
||||
if prev_page_uri and uri == prev_page_uri:
|
||||
prev_page = file.page
|
||||
|
||||
if next_page_name and next_page is None:
|
||||
log.warn(f'page {next_page_uri} not found')
|
||||
if prev_page_name and prev_page is None:
|
||||
log.warn(f'page {prev_page_uri} not found')
|
||||
|
||||
if not hasattr(page, 'overrides'):
|
||||
page.overrides = {}
|
||||
|
||||
if next_page:
|
||||
page.next_page = next_page
|
||||
if prev_page:
|
||||
page.previous_page = prev_page
|
||||
return ctx
|
||||
@@ -0,0 +1,137 @@
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
from typing import Any
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
|
||||
|
||||
def on_config(config: MkDocsConfig) -> MkDocsConfig | None:
|
||||
mdx_configs = config.setdefault("mdx_configs", {})
|
||||
superfences = mdx_configs.setdefault("pymdownx.superfences", {})
|
||||
custom_fences = superfences.setdefault("custom_fences", [])
|
||||
custom_fences.append({
|
||||
"name": "freeze",
|
||||
"class": "freeze",
|
||||
"validator": _validator,
|
||||
"format": _formatter
|
||||
})
|
||||
|
||||
|
||||
def _validator(
|
||||
language: str,
|
||||
inputs: dict[str, str],
|
||||
options: dict[str, Any],
|
||||
attrs: dict[str, Any], # noqa: ARG001
|
||||
*args, **kwargs,
|
||||
) -> bool:
|
||||
default_center = "true"
|
||||
if "float" in inputs:
|
||||
options["float"] = inputs.pop("float")
|
||||
default_center = "false"
|
||||
|
||||
if "width" in inputs:
|
||||
options["width"] = inputs.pop("width")
|
||||
if "language" in inputs:
|
||||
options["language"] = inputs.pop("language")
|
||||
|
||||
options["center"] = inputs.pop("center", default_center) == "true"
|
||||
if options["center"]:
|
||||
options.pop("float", None)
|
||||
|
||||
return "language" in options
|
||||
|
||||
|
||||
# freeze generates svgs with a width and height parameter.
|
||||
# We can use that to generate a viewBox attribute,
|
||||
# allowing the svg to scale to the width of the container.
|
||||
_widthRe = re.compile(r'width="(?P<width>[\d\.]+)"')
|
||||
_heightRe = re.compile(r'height="(?P<height>[\d\.]+)"')
|
||||
|
||||
|
||||
_terminalReplacements = [
|
||||
('\\x1b', '\x1b'),
|
||||
('{red}', '\x1b[0;31m'),
|
||||
('{green}', '\x1b[0;32m'),
|
||||
('{yellow}', '\x1b[0;33m'),
|
||||
('{blue}', '\x1b[0;34m'),
|
||||
('{mag}', '\x1b[0;35m'),
|
||||
('{cyan}', '\x1b[0;36m'),
|
||||
('{gray}', '\x1b[0;90m'),
|
||||
('{reset}', '\x1b[0;0m'),
|
||||
]
|
||||
|
||||
|
||||
# run freeze --window --language=$language in a subprocess,
|
||||
# writing to a temporary file.
|
||||
def _formatter(
|
||||
source: str,
|
||||
language: str,
|
||||
css_class: str,
|
||||
options: dict[str, Any],
|
||||
*args, **kwargs,
|
||||
):
|
||||
# Convenience:
|
||||
# If language is terminal, we actually want "ansi",
|
||||
# but we want to transform escapes in the source.
|
||||
if options["language"] == "terminal":
|
||||
options["language"] = "ansi"
|
||||
for pattern, replacement in _terminalReplacements:
|
||||
source = source.replace(pattern, replacement)
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
outfile = f"{tmpdir}/output.svg"
|
||||
try:
|
||||
args = [
|
||||
"freeze",
|
||||
"--language", options["language"],
|
||||
"--output", outfile,
|
||||
# same as -c full, but with no shadow.
|
||||
# auto-width calculation is broken with shadow.
|
||||
"--window", "--theme=charm",
|
||||
"--border.radius=8", "--border.width=1",
|
||||
"--border.color=#515151",
|
||||
"--padding=10,10,10,10",
|
||||
"--margin=10,10,10,10",
|
||||
"--background=#171717",
|
||||
]
|
||||
subprocess.run(
|
||||
args, input=source.encode("utf-8"), check=True,
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
return f'<code>{e.output.decode("utf-8")}</code>'
|
||||
except Exception as e:
|
||||
return f'<code>{e}</code>'
|
||||
|
||||
with open(outfile, "r") as f:
|
||||
svg = f.read()
|
||||
|
||||
width, height = None, None
|
||||
if m := _widthRe.search(svg):
|
||||
width = m.group("width")
|
||||
if m := _heightRe.search(svg):
|
||||
height = m.group("height")
|
||||
if not width or not height:
|
||||
return '<code>Could not find width and height in svg</code>'
|
||||
|
||||
# insert viewBox="0 0 width height" into the svg,
|
||||
# and drop the width and height attributes.
|
||||
svg = svg.replace(
|
||||
'<svg', f'<svg viewBox="0 0 {width} {height}"', 1,
|
||||
)
|
||||
svg = svg.replace(f' width="{width}"', "", 1)
|
||||
svg = svg.replace(f' height="{height}"', "", 1)
|
||||
|
||||
if "width" in options:
|
||||
width = options["width"]
|
||||
height = "auto"
|
||||
else:
|
||||
width = f"{width}px"
|
||||
height = f"{height}px"
|
||||
|
||||
style = f'width:{width};height:{height};max-width:100%;'
|
||||
if "float" in options:
|
||||
style += f'float:{options["float"]};'
|
||||
if options["center"]:
|
||||
style += 'margin:0 auto;'
|
||||
|
||||
return f'<div style="{style}">{svg}</div>'
|
||||
@@ -0,0 +1,64 @@
|
||||
import logging
|
||||
from os.path import normpath
|
||||
|
||||
from mkdocs.structure.pages import Page
|
||||
from mkdocs.utils.templates import TemplateContext
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
from mkdocs.structure.nav import Navigation
|
||||
|
||||
log = logging.getLogger("mkdocs.plugins.listing")
|
||||
|
||||
|
||||
# Given a page with meta:
|
||||
#
|
||||
# listing:
|
||||
# - foo.md
|
||||
# - bar.md
|
||||
#
|
||||
# Will add a listing attribute to that page
|
||||
# with the pages for foo.md and bar.md.
|
||||
#
|
||||
# Use with template: listing.html.
|
||||
|
||||
|
||||
def on_page_context(
|
||||
ctx: TemplateContext,
|
||||
page: Page,
|
||||
config: MkDocsConfig,
|
||||
nav: Navigation,
|
||||
) -> TemplateContext:
|
||||
# cur_page = page
|
||||
children = page.meta.get('listing', [])
|
||||
if not children:
|
||||
return ctx
|
||||
|
||||
# foo/bar/baz.md -> foo/bar
|
||||
uri = page.file.src_uri
|
||||
dir = '/'.join(uri.split('/')[:-1])
|
||||
|
||||
want_uris = [normpath(f'{dir}/{child}') for child in children]
|
||||
got_pages = [None] * len(want_uris)
|
||||
|
||||
# mapping from requested page URI
|
||||
# to index of that page in got_pages.
|
||||
# Will be used to fill in got_pages
|
||||
# as we iterate over all pages.
|
||||
page_idxes = {
|
||||
uri: idx for idx, uri in enumerate(want_uris)
|
||||
}
|
||||
|
||||
for file in ctx['pages']:
|
||||
uri = file.src_uri
|
||||
idx = page_idxes.get(uri)
|
||||
if idx is not None:
|
||||
got_pages[idx] = file.page
|
||||
|
||||
# If there are any missing pages, fail.
|
||||
result = []
|
||||
for idx, page in enumerate(got_pages):
|
||||
if page is None:
|
||||
log.warn(f'page {want_uris[idx]} not found')
|
||||
result.append(page)
|
||||
|
||||
ctx['page_listing'] = result
|
||||
return ctx
|
||||
@@ -0,0 +1,81 @@
|
||||
import re
|
||||
import subprocess
|
||||
from typing import Any
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
|
||||
|
||||
def on_config(config: MkDocsConfig) -> MkDocsConfig | None:
|
||||
mdx_configs = config.setdefault("mdx_configs", {})
|
||||
superfences = mdx_configs.setdefault("pymdownx.superfences", {})
|
||||
custom_fences = superfences.setdefault("custom_fences", [])
|
||||
custom_fences.append({
|
||||
"name": "pikchr",
|
||||
"class": "pikchr",
|
||||
"validator": _validator,
|
||||
"format": _formatter
|
||||
})
|
||||
|
||||
|
||||
def _validator(
|
||||
language: str,
|
||||
inputs: dict[str, str],
|
||||
options: dict[str, Any],
|
||||
attrs: dict[str, Any], # noqa: ARG001
|
||||
*args, **kwargs,
|
||||
) -> bool:
|
||||
options["width"] = inputs.pop("width", "100%")
|
||||
|
||||
default_center = "true"
|
||||
if "float" in inputs:
|
||||
options["float"] = inputs.pop("float")
|
||||
default_center = "false"
|
||||
|
||||
options["center"] = inputs.pop("center", default_center) == "true"
|
||||
if options["center"]:
|
||||
options.pop("float", None)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
_viewboxRe = re.compile(
|
||||
r'viewBox="\d+ +\d+ +(?P<w>[\d\.]+) +(?P<h>[\d\.]+)"',
|
||||
)
|
||||
|
||||
|
||||
# Run 'pikchr -' with the source code as input
|
||||
# and return the SVG output as a string.
|
||||
def _formatter(
|
||||
source: str,
|
||||
language: str,
|
||||
css_class: str,
|
||||
options: dict[str, Any],
|
||||
*args, **kwargs,
|
||||
):
|
||||
try:
|
||||
svg = subprocess.run(
|
||||
["pikchr", "--dark-mode", "--svg-only", "-"],
|
||||
input=source.encode("utf-8"),
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
check=True
|
||||
).stdout.decode("utf-8")
|
||||
|
||||
width = options["width"]
|
||||
height = "auto"
|
||||
match = _viewboxRe.search(svg)
|
||||
if match:
|
||||
w, h = map(float, match.groups())
|
||||
width = f"{w}px"
|
||||
height = f"{h}px"
|
||||
|
||||
style = f'width:{width};height:{height};max-width:100%;'
|
||||
if "float" in options:
|
||||
style += f'float:{options["float"]};'
|
||||
if options["center"]:
|
||||
style += 'margin:0 auto;'
|
||||
|
||||
return f'<div style="{style}">{svg}</div>'
|
||||
except subprocess.CalledProcessError as e:
|
||||
return f'<code>{e.output.decode("utf-8")}</code>'
|
||||
except Exception as e:
|
||||
return f'<code>{e}</code>'
|
||||
@@ -0,0 +1,5 @@
|
||||
[32m$[0m gs branch submit
|
||||
[2m[32mTitle[0m: branch submit: Fix directory+ref conflict
|
||||
[2m[32mBody[0m: Press [[95me[39m[0m] to open [92mnvim[0m or [[95menter/tab[0m] to skip
|
||||
[2m[32mDraft[0m: [[95my[39m/[95mN[0m]
|
||||
[1m[92mINF[0m Created #261: https://github.com/abhinav/git-spice/pull/261
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
../../CHANGELOG.md
|
||||
@@ -1,5 +1,3 @@
|
||||
# gs command reference
|
||||
|
||||
```
|
||||
gs <command> [flags]
|
||||
```
|
||||
@@ -411,7 +409,7 @@ Forget a tracked branch
|
||||
The current branch is deleted from git-spice's data store
|
||||
but not deleted from the repository.
|
||||
Branches upstack from it are not affected,
|
||||
and will to the next branch downstack.
|
||||
and will use the next branch downstack as their new base.
|
||||
|
||||
Provide a branch name as an argument to target
|
||||
a different branch.
|
||||
@@ -0,0 +1,31 @@
|
||||
| **Shorthand** | **Long form** |
|
||||
| --- | --- |
|
||||
| gs bc | [gs branch create](/cli/index.md#gs-branch-create) |
|
||||
| gs bco | [gs branch checkout](/cli/index.md#gs-branch-checkout) |
|
||||
| gs bd | [gs branch delete](/cli/index.md#gs-branch-delete) |
|
||||
| gs be | [gs branch edit](/cli/index.md#gs-branch-edit) |
|
||||
| gs bfo | [gs branch fold](/cli/index.md#gs-branch-fold) |
|
||||
| gs bon | [gs branch onto](/cli/index.md#gs-branch-onto) |
|
||||
| gs br | [gs branch restack](/cli/index.md#gs-branch-restack) |
|
||||
| gs brn | [gs branch rename](/cli/index.md#gs-branch-rename) |
|
||||
| gs bs | [gs branch submit](/cli/index.md#gs-branch-submit) |
|
||||
| gs bsp | [gs branch split](/cli/index.md#gs-branch-split) |
|
||||
| gs btr | [gs branch track](/cli/index.md#gs-branch-track) |
|
||||
| gs buntr | [gs branch untrack](/cli/index.md#gs-branch-untrack) |
|
||||
| gs ca | [gs commit amend](/cli/index.md#gs-commit-amend) |
|
||||
| gs cc | [gs commit create](/cli/index.md#gs-commit-create) |
|
||||
| gs csp | [gs commit split](/cli/index.md#gs-commit-split) |
|
||||
| gs dse | [gs downstack edit](/cli/index.md#gs-downstack-edit) |
|
||||
| gs dss | [gs downstack submit](/cli/index.md#gs-downstack-submit) |
|
||||
| gs ll | [gs log long](/cli/index.md#gs-log-long) |
|
||||
| gs ls | [gs log short](/cli/index.md#gs-log-short) |
|
||||
| gs rba | [gs rebase abort](/cli/index.md#gs-rebase-abort) |
|
||||
| gs rbc | [gs rebase continue](/cli/index.md#gs-rebase-continue) |
|
||||
| gs ri | [gs repo init](/cli/index.md#gs-repo-init) |
|
||||
| gs rs | [gs repo sync](/cli/index.md#gs-repo-sync) |
|
||||
| gs se | [gs stack edit](/cli/index.md#gs-stack-edit) |
|
||||
| gs sr | [gs stack restack](/cli/index.md#gs-stack-restack) |
|
||||
| gs ss | [gs stack submit](/cli/index.md#gs-stack-submit) |
|
||||
| gs uso | [gs upstack onto](/cli/index.md#gs-upstack-onto) |
|
||||
| gs usr | [gs upstack restack](/cli/index.md#gs-upstack-restack) |
|
||||
| gs uss | [gs upstack submit](/cli/index.md#gs-upstack-submit) |
|
||||
@@ -1,13 +0,0 @@
|
||||
# Introduction
|
||||
|
||||
<div align="center">
|
||||
<img src="img/logo.png" width=300>
|
||||
|
||||
[](https://github.com/abhinav/git-spice/actions/workflows/ci.yml)
|
||||
[](https://codecov.io/gh/abhinav/git-spice)
|
||||
|
||||
</div>
|
||||
|
||||
git-spice is a tool for stacking Git branches.
|
||||
|
||||
TODO: more details
|
||||
@@ -1,29 +0,0 @@
|
||||
# License
|
||||
|
||||
This software is distributed under the GPL-3.0 License:
|
||||
|
||||
```
|
||||
git-spice: Stacked Pull Requests
|
||||
Copyright (C) 2024 Abhinav Gupta
|
||||
|
||||
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/>.
|
||||
```
|
||||
|
||||
See LICENSE for details.
|
||||
|
||||
As an exception to the above, the following files are distributed
|
||||
under a different license. See the file headers for details:
|
||||
|
||||
internal/komplete/komplete.go
|
||||
internal/komplete/komplete_test.go
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
site_name: git-spice
|
||||
site_url: https://abhinav.github.io/git-spice
|
||||
site_description: >-
|
||||
git-spice is a tool for stacking Git branches.
|
||||
It helps you manage and navigate a stack of branches
|
||||
that build on top of each other.
|
||||
copyright: '© 2024 Abhinav Gupta'
|
||||
|
||||
repo_url: https://github.com/abhinav/git-spice
|
||||
repo_name: abhinav/git-spice
|
||||
edit_uri: edit/main/doc/src/
|
||||
|
||||
docs_dir: src
|
||||
site_dir: _site
|
||||
|
||||
extra:
|
||||
analytics:
|
||||
provider: custom
|
||||
token: !ENV [CLOUDFLARE_ANALYTICS_TOKEN, '']
|
||||
|
||||
social:
|
||||
- icon: fontawesome/brands/github-alt
|
||||
link: https://github.com/abhinav
|
||||
- icon: fontawesome/brands/mastodon
|
||||
link: https://hachyderm.io/@abhinav
|
||||
- icon: fontawesome/brands/bluesky
|
||||
link: https://bsky.app/profile/abhg.dev
|
||||
|
||||
validation:
|
||||
omitted_files: warn
|
||||
absolute_links: relative_to_docs
|
||||
unrecognized_links: warn
|
||||
anchors: warn # New in MkDocs 1.6
|
||||
strict: true
|
||||
|
||||
theme:
|
||||
name: material
|
||||
custom_dir: overrides
|
||||
palette:
|
||||
scheme: slate
|
||||
|
||||
logo: img/logo.png
|
||||
favicon: img/logo.png
|
||||
|
||||
icon:
|
||||
repo: fontawesome/brands/github-alt
|
||||
|
||||
features:
|
||||
- content.action.edit
|
||||
- content.code.copy
|
||||
- header.autohide
|
||||
- navigation.expand
|
||||
- navigation.indexes
|
||||
- search.suggest
|
||||
- toc.follow
|
||||
|
||||
exclude_docs: |
|
||||
img/README.md
|
||||
|
||||
plugins:
|
||||
- markdown-exec
|
||||
- privacy:
|
||||
enabled: !ENV [CI, false]
|
||||
- search
|
||||
- social:
|
||||
enabled: !ENV [CI, false]
|
||||
|
||||
hooks:
|
||||
- hooks/cliref.py
|
||||
- hooks/footer.py
|
||||
- hooks/freeze.py
|
||||
- hooks/listing.py
|
||||
- hooks/pikchr.py
|
||||
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
- attr_list
|
||||
- def_list
|
||||
- md_in_html
|
||||
- pymdownx.details
|
||||
- pymdownx.emoji:
|
||||
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
||||
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
||||
- pymdownx.snippets:
|
||||
base_path: [includes]
|
||||
- pymdownx.superfences
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
slugify: !!python/object/apply:pymdownx.slugs.slugify
|
||||
kwds:
|
||||
case: lower
|
||||
- pymdownx.tasklist:
|
||||
custom_checkbox: true
|
||||
- toc: {permalink: true}
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Get started:
|
||||
- start/index.md
|
||||
- start/install.md
|
||||
- User Guide:
|
||||
- guide/index.md
|
||||
- guide/concepts.md
|
||||
- guide/branch.md
|
||||
- guide/pr.md
|
||||
- guide/limits.md
|
||||
- guide/internals.md
|
||||
- Setting up:
|
||||
- setup/index.md
|
||||
- setup/auth.md
|
||||
- setup/completion.md
|
||||
- CLI:
|
||||
- cli/index.md
|
||||
- cli/shorthand.md
|
||||
- how-to.md
|
||||
- FAQ: faq.md
|
||||
- Changelog: changelog.md
|
||||
|
||||
not_in_nav: |
|
||||
# Listed manually
|
||||
start/stack.md
|
||||
start/submit.md
|
||||
|
||||
watch:
|
||||
- includes
|
||||
- overrides
|
||||
@@ -0,0 +1,74 @@
|
||||
<!-- Footer -->
|
||||
<footer class="md-footer">
|
||||
|
||||
<!-- Link to previous and/or next page -->
|
||||
{% if page.previous_page or page.next_page %}
|
||||
{% if page.meta and page.meta.hide %}
|
||||
{% set hidden = "hidden" if "footer" in page.meta.hide %}
|
||||
{% endif %}
|
||||
<nav
|
||||
class="md-footer__inner md-grid"
|
||||
aria-label="{{ lang.t('footer') }}"
|
||||
{{ hidden }}
|
||||
>
|
||||
|
||||
<!-- Link to previous page -->
|
||||
{% if page.previous_page %}
|
||||
{% set direction = lang.t("footer.previous") %}
|
||||
<a
|
||||
href="{{ page.previous_page.url | url }}"
|
||||
class="md-footer__link md-footer__link--prev"
|
||||
aria-label="{{ direction }}: {{ page.previous_page.title | e }}"
|
||||
>
|
||||
<div class="md-footer__button md-icon">
|
||||
{% set icon = config.theme.icon.previous or "material/arrow-left" %}
|
||||
{% include ".icons/" ~ icon ~ ".svg" %}
|
||||
</div>
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
{{ direction }}
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
{{ page.previous_page.title }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
<!-- Link to next page -->
|
||||
{% if page.next_page %}
|
||||
{% set direction = lang.t("footer.next") %}
|
||||
<a
|
||||
href="{{ page.next_page.url | url }}"
|
||||
class="md-footer__link md-footer__link--next"
|
||||
aria-label="{{ direction }}: {{ page.next_page.title | e }}"
|
||||
>
|
||||
<div class="md-footer__title">
|
||||
<span class="md-footer__direction">
|
||||
{{ direction }}
|
||||
</span>
|
||||
<div class="md-ellipsis">
|
||||
{{ page.next_page.title }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="md-footer__button md-icon">
|
||||
{% set icon = config.theme.icon.next or "material/arrow-right" %}
|
||||
{% include ".icons/" ~ icon ~ ".svg" %}
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
<!-- Further information -->
|
||||
<div class="md-footer-meta md-typeset">
|
||||
<div class="md-footer-meta__inner md-grid">
|
||||
{% include "partials/copyright.html" %}
|
||||
|
||||
<!-- Social links -->
|
||||
{% if config.extra.social %}
|
||||
{% include "partials/social.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -0,0 +1,3 @@
|
||||
{% if config.extra.analytics.token -%}
|
||||
<script defer src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon='{"token": "{{ config.extra.analytics.token }}"}'></script>
|
||||
{%- endif %}
|
||||
@@ -0,0 +1,58 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% macro render_content(nav_item, ref = nav_item) %}
|
||||
{% if nav_item.is_page and nav_item.meta.icon %}
|
||||
<span class="twemoji lg middle">
|
||||
{% include ".icons/" ~ nav_item.meta.icon ~ ".svg" %}
|
||||
</span>
|
||||
{% elif nav_item.is_section and nav_item.children %}
|
||||
{% set first = nav_item.children | first %}
|
||||
{% if first.is_index and first.meta.icon %}
|
||||
<span class="twemoji lg middle">
|
||||
{% include ".icons/" ~ first.meta.icon ~ ".svg" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<span class="md-ellipsis">
|
||||
{{ ref.title }}
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_item(item) %}
|
||||
<li>
|
||||
<a href="{{ item.url | url }}" class="md-nav__link"
|
||||
{{ render_content(item) }}
|
||||
</a>
|
||||
{% if item.meta.description %}
|
||||
<hr/>
|
||||
<p>{{ item.meta.description }}</p>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_index_children(index_page) %}
|
||||
{% set parent = page.parent %}
|
||||
{% if parent and (parent.children | length > 1) %}
|
||||
<div class="grid cards">
|
||||
<ul>
|
||||
{% for item in parent.children %}
|
||||
{% if item.is_page and item != index_page %}
|
||||
{{ render_item(item) }}
|
||||
{% elif item.is_section and item.children and (item.children|first).is_index %}
|
||||
{{ render_item(item.children|first) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
{{ super() }}
|
||||
|
||||
{% if page.is_index %}
|
||||
<hr/>
|
||||
|
||||
{{ render_index_children(page) }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,47 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% macro render_content(nav_item, ref = nav_item) %}
|
||||
{% if nav_item.is_page and nav_item.meta.icon %}
|
||||
<span class="twemoji lg middle">
|
||||
{% include ".icons/" ~ nav_item.meta.icon ~ ".svg" %}
|
||||
</span>
|
||||
{% elif nav_item.is_section and nav_item.children %}
|
||||
{% set first = nav_item.children | first %}
|
||||
{% if first.is_index and first.meta.icon %}
|
||||
<span class="twemoji lg middle">
|
||||
{% include ".icons/" ~ first.meta.icon ~ ".svg" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<span class="md-ellipsis">
|
||||
{{ ref.title }}
|
||||
</span>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_item(item) %}
|
||||
<li>
|
||||
<a href="{{ item.url | url }}" class="md-nav__link"
|
||||
{{ render_content(item) }}
|
||||
</a>
|
||||
{% if item.meta.description %}
|
||||
<hr/>
|
||||
<p>{{ item.meta.description }}</p>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
{{ super() }}
|
||||
|
||||
{% if page_listing %}
|
||||
<hr/>
|
||||
<div class="grid cards">
|
||||
<ul>
|
||||
{% for item in page_listing %}
|
||||
{{ render_item(item) }}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
<!-- DO NOT EDIT. This file is generated from doc/*.md. Edit those instead. -->
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
icon: material/format-list-group
|
||||
description: >-
|
||||
Release history of the project.
|
||||
---
|
||||
|
||||
--8<-- "changelog.md"
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
icon: material/console
|
||||
description: >-
|
||||
Comprehensive list of all available commands and options
|
||||
for the git-spice CLI.
|
||||
---
|
||||
|
||||
# CLI Reference
|
||||
|
||||
--8<-- "cli-reference.md"
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
icon: material/scissors-cutting
|
||||
title: Shorthands
|
||||
description: >-
|
||||
Most commands come with intuitive shorthand variants
|
||||
that are easy to remember and type.
|
||||
---
|
||||
|
||||
# CLI shorthands
|
||||
|
||||
git-spice offers short versions of most commands
|
||||
to make them easier to remember and type.
|
||||
|
||||
To determine the shorthand for a command,
|
||||
run the command with the `--help` flag.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch create --help
|
||||
Usage: gs branch (b) create (c) [<name>] [flags]
|
||||
|
||||
{gray}# ...{reset}
|
||||
```
|
||||
|
||||
The shorthand is built by joining the bits in parentheses.
|
||||
For example, the shorthand for $$gs branch create$$ above is `gs bc`.
|
||||
Another example:
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch checkout --help
|
||||
Usage: gs branch (b) checkout (co) [<branch>] [flags]
|
||||
|
||||
{gray}# ...{reset}
|
||||
```
|
||||
|
||||
The shorthand for $$gs branch checkout$$ is `gs bco`.
|
||||
|
||||
## When to use shorthands?
|
||||
|
||||
We encourage adopting the command shorthands
|
||||
after you are comfortable with the corresponding full command names.
|
||||
The shorthands are designed to be easy to remember and type,
|
||||
but they may not be obvious if you don't know the full command name.
|
||||
|
||||
The shorthands act as a mnemonic aid:
|
||||
invoke the full command name in your head while typing the shorthand.
|
||||
|
||||
## Available shorthands
|
||||
|
||||
--8<-- "cli-shorthands.md"
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
icon: material/frequently-asked-questions
|
||||
description: >-
|
||||
Frequently asked questions about git-spice,
|
||||
a tool to manage stacked branches in Git.
|
||||
---
|
||||
|
||||
# Frequently Asked Questions
|
||||
|
||||
## What is stacking?
|
||||
|
||||
Stacking refers to the practice of creating interdependent branches
|
||||
on top of each other.
|
||||
Each branch in the stack builds on top of the previous one.
|
||||
For example, you might have a branch `feature-a` that adds a new feature,
|
||||
and a branch `feature-b` that builds on top of `feature-a`.
|
||||
|
||||
Stacking your changes lets you:
|
||||
|
||||
- **Unblock yourself**:
|
||||
While one branch is under review, you can start working on the next one.
|
||||
- **Be kinder to your team**:
|
||||
By keeping changes small and focused, you make it easier for your team
|
||||
to review, test, and understand your work.
|
||||
A 100 line PR gets a more meaningful review than a 1000 line PR.
|
||||
|
||||
git-spice helps you manage your stack of branches,
|
||||
keeping them up-to-date and in sync with each other.
|
||||
|
||||
**Related**:
|
||||
|
||||
- [The stacking workflow](https://www.stacking.dev/)
|
||||
|
||||
## Where is the GitHub authentication token stored?
|
||||
|
||||
git-spice stores the GitHub authentication in a system-specific secure storage.
|
||||
See [Secret storage](guide/internals.md#secret-storage) for more details.
|
||||
@@ -0,0 +1,558 @@
|
||||
---
|
||||
title: Branch stacks
|
||||
icon: octicons/git-branch-16
|
||||
description: >-
|
||||
Manage, navigate, and manipulate stacks of branches with git-spice.
|
||||
---
|
||||
|
||||
# Branch stacks
|
||||
|
||||
Starting at the trunk branch, any number of branches may be stacked on top.
|
||||
You may stack branches using one of the following methods:
|
||||
|
||||
- [**Automatic stacking**](#automatic-stacking):
|
||||
Use git-spice to create a branch, commit to it,
|
||||
and stack it on top of the current branch in one go.
|
||||
- [**Manual stacking**](#manual-stacking):
|
||||
Create a branch with Git as usual, and then track it with git-spice.
|
||||
|
||||
## Automatic stacking
|
||||
|
||||
```freeze language="terminal" float="right"
|
||||
{green}${reset} $EDITOR file.txt
|
||||
{gray}# make your changes{reset}
|
||||
{green}${reset} git add file.txt
|
||||
{green}${reset} gs branch create my-feature
|
||||
```
|
||||
|
||||
The preferred way to create a stacked branch is:
|
||||
make your changes, prepare them to be committed with `git add`,
|
||||
and then use $$gs branch create$$ to commit these changes to a new branch
|
||||
stacked on top of the current branch.
|
||||
|
||||
This creates a new branch `my-feature` stacked on top of the current branch,
|
||||
and commits the staged changes to it.
|
||||
An editor will open to let you write a commit message
|
||||
if one was not provided with the `-m`/`--message` flag.
|
||||
|
||||
!!! tip "But I use `git commit -a`"
|
||||
|
||||
If you prefer to use `git commit -a` to automatically stage files
|
||||
before committing, use `gs branch create -a` to do the same with git-spice.
|
||||
|
||||
Explore the full list of options at $$gs branch create$$.
|
||||
|
||||
## Manual stacking
|
||||
|
||||
git-spice does not require to change your workflow too drastically.
|
||||
If you prefer to use your usual workflow to create branches and commit changes,
|
||||
use $$gs branch track$$ to inform git-spice of the branch after creating it.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} git checkout -b my-feature
|
||||
{gray}# make your changes{reset}
|
||||
{green}${reset} git commit
|
||||
{green}${reset} gs branch track
|
||||
{green}INF{reset} my-feature: tracking with base main
|
||||
```
|
||||
|
||||
$$gs branch track$$ automatically detects the base branch.
|
||||
Use the `--base` option to specify it manually.
|
||||
|
||||
## Navigating the stack
|
||||
|
||||
git-spice offers the following commands to navigate within a stack of branches:
|
||||
|
||||
<div class="grid" markdown>
|
||||
|
||||
<div markdown>
|
||||
* $$gs down$$ checks out the branch below the current branch
|
||||
* $$gs up$$ checks out a branch stacked on top of the current branch,
|
||||
prompting to pick one if there are multiple
|
||||
* $$gs bottom$$ moves to the bottommost branch in the stack,
|
||||
right above the trunk
|
||||
* $$gs top$$ moves to the topmost branch in the stack,
|
||||
prompting to pick one if there are multiple
|
||||
* $$gs trunk$$ checks out the trunk branch
|
||||
* $$gs branch checkout$$ checks out any branch in the repository
|
||||
</div>
|
||||
|
||||
```pikchr float="right"
|
||||
lineht = 0.3in
|
||||
linewid = 0.4in
|
||||
|
||||
up
|
||||
Main: box "main" fit ht 0.25in fill 0xffffff
|
||||
dot; line
|
||||
|
||||
box "A" same
|
||||
dot; line
|
||||
box "B" same fill 0xd0cee0
|
||||
dot; line lineht/2
|
||||
|
||||
ADot: dot invis
|
||||
left; line
|
||||
up; line ht lineht/2
|
||||
box "C" same fill A.fill
|
||||
|
||||
move to ADot
|
||||
right; line
|
||||
up; line ht lineht/2
|
||||
box "D" same
|
||||
|
||||
dot; line
|
||||
box "E" same
|
||||
|
||||
color = gray
|
||||
linerad = 0.05in
|
||||
|
||||
arrow chop thin \
|
||||
from B go left 0.3in \
|
||||
then down until even with Main \
|
||||
then to Main
|
||||
text "gs trunk " mono rjust \
|
||||
at 0.3in west of 1/2 way between B and Main
|
||||
|
||||
arrow chop thin \
|
||||
from B go right 0.3in \
|
||||
then down until even with A \
|
||||
then to A
|
||||
text " gs down" mono ljust \
|
||||
at 0.3in east of 1/2 way between A and B
|
||||
|
||||
arrow behind Main chop thin \
|
||||
from B up until even with C \
|
||||
then to C
|
||||
arrow behind Main chop thin \
|
||||
from B up until even with D \
|
||||
then to D
|
||||
text "gs up" mono at 0.1in north of 1/2 way between C and D
|
||||
|
||||
arrow chop thin \
|
||||
from B go right until even with 0.1in east of E.e \
|
||||
then up until even with E \
|
||||
then to E
|
||||
text " gs top" mono ljust \
|
||||
at (0.1in east of E.e.x, B.y+(E.y-B.y)/2)
|
||||
|
||||
arrow chop thin \
|
||||
from B go left until even with 0.1in west of C.w \
|
||||
then up until even with C \
|
||||
then to C
|
||||
text "gs top " mono rjust \
|
||||
at (0.1in west of C.w.x, B.y+(C.y-B.y)/2)
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
These commands allow for relative movement within the stack,
|
||||
so that you don't have to remember exact branch names
|
||||
or their positions in the stack.
|
||||
|
||||
!!! question "What's the value of `gs branch checkout`?"
|
||||
|
||||
```freeze language="terminal" float="right"
|
||||
{green}${reset} gs branch checkout my-feature
|
||||
```
|
||||
|
||||
You may be wondering about $$gs branch checkout$$
|
||||
when `git checkout` exists.
|
||||
The command behaves not much differently than `git checkout`
|
||||
when provided with a branch name as an argument.
|
||||
|
||||
```freeze language="terminal" float="right"
|
||||
{green}${reset} gs branch checkout {gray}# or gs bco{reset}
|
||||
{green}Select a branch to checkout{reset}:
|
||||
┏━■ {yellow}docs ◀{reset}
|
||||
┃ ┏━□ github-optimization
|
||||
┣━┻□ github-support
|
||||
main
|
||||
```
|
||||
|
||||
Its real value lies in the interactive mode.
|
||||
Invoke it without arguments to get a fuzzy-searchable list of branches,
|
||||
visualized as a tree-like structure to help you navigate the stack.
|
||||
|
||||
## Committing and restacking
|
||||
|
||||
With a stacked branch checked out,
|
||||
you can commit to it as usual with `git commit`, `git commit --amend`, etc.
|
||||
However, after committing, the branches upstack from the current branch
|
||||
need to be restacked to maintain a linear history.
|
||||
Use $$gs upstack restack$$ to do this.
|
||||
|
||||
<div class="grid" markdown>
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch checkout feat1
|
||||
{green}${reset} $EDITOR file.txt
|
||||
{gray}# prepare your changes{reset}
|
||||
{green}${reset} git commit
|
||||
{green}${reset} gs upstack restack
|
||||
```
|
||||
|
||||
```pikchr
|
||||
linewid = 0.25in
|
||||
|
||||
X: [
|
||||
right
|
||||
text "A" small; line; text "B" small;
|
||||
line go linewid heading 45; right; text "C" small
|
||||
|
||||
text "feat1" with e at A.w
|
||||
text "feat2" with e at (last text.e.x, C.y)
|
||||
line thin chop dotted from last to C
|
||||
]
|
||||
|
||||
Y: [
|
||||
right
|
||||
text "A" small; line; text "B" small; line; text "D" small
|
||||
move to B.ne;
|
||||
line go linewid heading 45; right;
|
||||
text "C" small
|
||||
|
||||
text "feat1" with e at A.w
|
||||
text "feat2" with e at (last text.e.x, C.y)
|
||||
line thin chop dotted from last to C
|
||||
] with nw at 0.5in south of last.sw
|
||||
|
||||
Z: [
|
||||
right
|
||||
text "A" small; line; text "B" small; line; text "D" small
|
||||
line go linewid heading 45; right; text "C" small
|
||||
|
||||
text "feat1" with e at A.w
|
||||
text "feat2" with e at (last text.e.x, C.y)
|
||||
line thin chop dotted from last to C
|
||||
] with nw at 0.5in south of last.sw
|
||||
|
||||
arrow color gray from X.s down until even with Y.n
|
||||
text "git commit" mono with w at last.e
|
||||
|
||||
arrow color gray from Y.s down until even with Z.n
|
||||
text "gs upstack restack" mono with w at last.e
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! tip
|
||||
|
||||
git-spice also offers
|
||||
$$gs branch restack$$ to restack just the current branch onto its base,
|
||||
and $$gs stack restack$$ to restack all branches in the current stack.
|
||||
|
||||
### Automatic restacking
|
||||
|
||||
git-spice provides a handful of convenience commands
|
||||
for common commit-related tasks
|
||||
that will automatically restack upstack branches for you:
|
||||
|
||||
- $$gs commit create$$ (or $$gs commit create|gs cc$$)
|
||||
commits changes to the current branch and restacks upstack branches
|
||||
- $$gs commit amend$$ (or $$gs commit amend|gs ca$$)
|
||||
amends the last commit and restacks upstack branches
|
||||
- $$gs commit split$$ (or $$gs commit split|gs csp$$)
|
||||
interactively splits the last commit into two and restacks upstack branches
|
||||
- $$gs branch edit$$ (or $$gs branch edit|gs be$$)
|
||||
opens an interactive rebase of the commits in the current branch
|
||||
and restacks upstack branches after the rebase completes successfully
|
||||
|
||||
For example, the interaction above can be shortened to:
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch checkout feat1
|
||||
{green}${reset} $EDITOR file.txt
|
||||
{gray}# prepare your changes{reset}
|
||||
{green}${reset} gs commit create {gray}# or gs cc{reset}
|
||||
```
|
||||
|
||||
## Inserting into the stack
|
||||
|
||||
By default, $$gs branch create$$ creates a branch
|
||||
stacked on top of the current branch.
|
||||
It does not manipulate the existing stack in any way.
|
||||
|
||||
If you're in the middle of the stack, use the `--insert` option
|
||||
to stack the new branch between the current branch and its upstack branches.
|
||||
|
||||
=== "With `--insert`"
|
||||
|
||||
<div class="grid" markdown>
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch checkout feat1
|
||||
{green}${reset} gs branch create --insert feat4
|
||||
```
|
||||
|
||||
```pikchr
|
||||
linerad = 0.05in
|
||||
|
||||
X: [
|
||||
up; text "feat1"; F1: dot invis
|
||||
line go up 0.15in then go right 0.15in
|
||||
text "feat2"
|
||||
line from F1 go up 0.3in then go right 0.15in
|
||||
text "feat3"
|
||||
]
|
||||
|
||||
|
||||
Y: [
|
||||
up; text "feat1"; F1: dot invis
|
||||
line go up 0.15in then go right 0.15in
|
||||
text "feat4"; up; F2: dot invis
|
||||
line from F2 go up 0.15in then go right 0.15in
|
||||
text "feat2"
|
||||
line from F2 go up 0.30in then go right 0.15in
|
||||
text "feat3"
|
||||
] with sw at 0.5in east of last.se
|
||||
|
||||
arrow color gray from X.e go right until even with Y.w
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
=== "Without `--insert`"
|
||||
|
||||
<div class="grid" markdown>
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch checkout feat1
|
||||
{green}${reset} gs branch create feat4
|
||||
```
|
||||
|
||||
```pikchr
|
||||
linerad = 0.05in
|
||||
|
||||
X: [
|
||||
up; text "feat1"; F1: dot invis
|
||||
line go up 0.15in then go right 0.15in
|
||||
text "feat2"
|
||||
line from F1 go up 0.3in then go right 0.15in
|
||||
text "feat3"
|
||||
]
|
||||
|
||||
|
||||
Y: [
|
||||
up; text "feat1"; F1: dot invis
|
||||
line go up 0.15in then go right 0.15in
|
||||
text "feat2"
|
||||
line from F1 go up 0.3in then go right 0.15in
|
||||
text "feat3"
|
||||
line from F1 go up 0.45in then go right 0.15in
|
||||
text "feat4"
|
||||
] with sw at 0.5in east of last.se
|
||||
|
||||
arrow color gray from X.e go right until even with Y.w
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
## Splitting the stack
|
||||
|
||||
Use $$gs branch split$$ to split a branch with one or more commits
|
||||
into two or more branches.
|
||||
|
||||
The command presents a prompt allowing you to select one or more
|
||||
*split points* in the branch's history.
|
||||
After selecting the split points,
|
||||
it will prompt you for a name for each new branch.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch split
|
||||
{green}Select commits{reset}:
|
||||
{yellow}▶ c4fb996{reset} Add an aardvark {gray}(12 minutes ago){reset}
|
||||
{yellow} f1d2d2f{reset} Refactor the pangolin {gray}(5 minutes ago){reset}
|
||||
■ {yellow}4186a53{reset} Invent penguins {gray}(1 second ago){reset} [penguin]
|
||||
Done
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
You can use $$gs commit split$$ and $$gs branch edit$$
|
||||
to safely and easily manipulate the commits in the branch
|
||||
before splitting it into multiple branches.
|
||||
|
||||
### Splitting non-interactively
|
||||
|
||||
```freeze language="terminal" float="right"
|
||||
{green}${reset} gs branch split {gray}\{reset}
|
||||
--at HEAD~2:aardvark {gray}\{reset}
|
||||
--at HEAD~1:pangolin
|
||||
```
|
||||
|
||||
If the interactive prompt is not suitable for your workflow,
|
||||
you can also split a branch non-interactively
|
||||
by specifying the split points with the `--at` option
|
||||
one or more times.
|
||||
|
||||
The option takes the form:
|
||||
|
||||
```
|
||||
--at COMMIT:NAME
|
||||
```
|
||||
|
||||
Where `COMMIT` is a reference to a commit in the branch's history,
|
||||
and `NAME` is the name of the new branch.
|
||||
|
||||
## Moving branches around
|
||||
|
||||
Use the $$gs upstack onto$$ command to move a branch onto another base branch,
|
||||
and bring its upstack branches along with it.
|
||||
|
||||
<div class="grid" markdown>
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch checkout feat2
|
||||
{green}${reset} gs upstack onto main
|
||||
```
|
||||
|
||||
```pikchr
|
||||
linerad = 0.05in
|
||||
lineht = 0.15in
|
||||
linewid = 0.15in
|
||||
|
||||
X: [
|
||||
text "main"; up;
|
||||
line go up then go right
|
||||
text "feat1"; up;
|
||||
line go up then go right
|
||||
text "feat2"; up;
|
||||
line go up then go right
|
||||
text "feat3"
|
||||
]
|
||||
|
||||
Y: [
|
||||
text "main"; up; M: dot invis
|
||||
line go up then go right
|
||||
text "feat1"; up;
|
||||
move to M
|
||||
line go up lineht*2.5 then go right
|
||||
text "feat2"; up;
|
||||
line go up then go right
|
||||
text "feat3"
|
||||
] with sw at 0.5in east of last.se
|
||||
|
||||
color = gray
|
||||
arrow from X.e go right until even with Y.w
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! tip
|
||||
|
||||
Omit the target branch name
|
||||
to get a list of branches to choose from.
|
||||
|
||||
This is useful when you realize that a branch
|
||||
does not actually depend on the base branch it is stacked on.
|
||||
With this command, you can move an entire section of the stack
|
||||
down to a different base branch, or even to the trunk branch,
|
||||
reducing the number of changes that need to merge before the target branch.
|
||||
|
||||
### Moving only the current branch
|
||||
|
||||
In rarer cases, you want to extract the current branch from the stack
|
||||
and move it to a different base branch,
|
||||
while leaving the upstack branches where they are.
|
||||
|
||||
Use $$gs branch onto$$ for this purpose.
|
||||
|
||||
<div class="grid" markdown>
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch checkout feat2
|
||||
{green}${reset} gs branch onto main
|
||||
```
|
||||
|
||||
```pikchr
|
||||
linerad = 0.05in
|
||||
lineht = 0.15in
|
||||
linewid = 0.15in
|
||||
|
||||
X: [
|
||||
text "main"; up;
|
||||
line go up then go right
|
||||
text "feat1"; up;
|
||||
line go up then go right
|
||||
text "feat2"; up;
|
||||
line go up then go right
|
||||
text "feat3"
|
||||
]
|
||||
|
||||
Y: [
|
||||
text "main"; up; M: dot invis
|
||||
line go up then go right
|
||||
text "feat1"; up;
|
||||
line go up then go right
|
||||
text "feat3"; up
|
||||
move to M
|
||||
line go up lineht*4 then go right
|
||||
text "feat2"
|
||||
] with sw at 0.5in east of last.se
|
||||
|
||||
color = gray
|
||||
arrow from X.e go right until even with Y.w
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
This is most useful when you find that a branch is completely independent
|
||||
of other changes in the stack.
|
||||
|
||||
## Removing branches from the stack
|
||||
|
||||
Use $$gs branch delete$$ to remove a branch from the stack
|
||||
and delete it from the repository.
|
||||
Branches that are upstack from the deleted branch
|
||||
will be restacked on top of the deleted branch's original base branch.
|
||||
|
||||
<div class="grid" markdown>
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch delete feat2
|
||||
{green}INF{reset} feat2: deleted (was 644a286)
|
||||
```
|
||||
|
||||
```pikchr
|
||||
linerad = 0.05in
|
||||
lineht = 0.15in
|
||||
linewid = 0.15in
|
||||
|
||||
X: [
|
||||
text "main"; up;
|
||||
line go up then go right
|
||||
text "feat1"; up;
|
||||
line go up then go right
|
||||
text "feat2"; up;
|
||||
line go up then go right
|
||||
text "feat3"
|
||||
]
|
||||
|
||||
Y: [
|
||||
text "main"; up;
|
||||
line go up then go right
|
||||
text "feat1"; up;
|
||||
line go up then go right
|
||||
text "feat3"
|
||||
] with sw at 0.5in east of last.se
|
||||
|
||||
color = gray
|
||||
arrow from X.e go right until even with Y.w
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! tip
|
||||
|
||||
Omit the target branch name
|
||||
to get a list of branches to choose from.
|
||||
|
||||
### Removing a branch without deleting it
|
||||
|
||||
```freeze language="terminal" float="left"
|
||||
{green}${reset} gs branch untrack feat2
|
||||
```
|
||||
|
||||
If you want to remove a branch from the stack
|
||||
but don't want to delete the branch from the repository,
|
||||
use the $$gs branch untrack$$ command.
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: Concepts
|
||||
icon: material/lightbulb
|
||||
description: >-
|
||||
Terminology used throughout the documentation and commands.
|
||||
hide: [toc]
|
||||
---
|
||||
|
||||
# Concepts
|
||||
|
||||
git-spice introduces a few concepts on top of Git.
|
||||
This section lists a few that are frequently used in the documentation.
|
||||
|
||||
```pikchr float="right"
|
||||
lineht = 0.3in
|
||||
linewid = 0.4in
|
||||
|
||||
up
|
||||
Main: box "main" fit ht 0.25in fill 0xffffff
|
||||
dot; line
|
||||
|
||||
box "A" same
|
||||
dot; line
|
||||
box "B" same fill 0xd0cee0
|
||||
dot; line lineht/2
|
||||
|
||||
ADot: dot invis
|
||||
left; line
|
||||
up; line ht lineht/2
|
||||
box "C" same fill A.fill
|
||||
|
||||
move to ADot
|
||||
right; line
|
||||
up; line ht lineht/2
|
||||
box "D" same
|
||||
|
||||
dot; line
|
||||
box "E" same
|
||||
|
||||
$padding = 0.1in
|
||||
|
||||
US: box thin behind A fill 0xb0fbfd \
|
||||
with ne at E.ne+($padding, $padding) \
|
||||
wid E.e.x-C.w.x+($padding*2) \
|
||||
ht E.n.y-B.y+$padding/2
|
||||
text "Upstack" with nw at last.nw
|
||||
|
||||
DS: box thin behind A fill 0xc49bf9 \
|
||||
with nw at (last box.w.x, B.y-$padding/2) \
|
||||
wid US.wid \
|
||||
ht B.y-A.s.y+$padding/2
|
||||
text "Downstack" with nw at last.nw-(0,$padding)
|
||||
|
||||
S: box thin behind US fill 0xccccfb \
|
||||
with nw at US.nw+(-$padding, $padding*2) \
|
||||
wid US.wid+$padding*2 \
|
||||
ht US.n.y-DS.s.y+$padding*3
|
||||
text "Stack" with nw at last.nw
|
||||
|
||||
text "Current" "branch" with e at (S.w.x-$padding, B.y)
|
||||
arrow chop thin dashed from last to B
|
||||
|
||||
text "Trunk" with w at Main.e
|
||||
|
||||
box "F" same as A \
|
||||
with nw at $padding east of (S.e, B.ne)
|
||||
line from 1/2 way between A.n and B.s \
|
||||
go right until even with F \
|
||||
then to F.s
|
||||
text "Sibling" with s at F.n
|
||||
```
|
||||
|
||||
**Branch**
|
||||
: A regular Git branch.
|
||||
Branches can have a *base*: the branch they were created from.
|
||||
The branch currently checked out is called the *current branch*.
|
||||
|
||||
In the diagram, `B` is the current branch, and `A` is its base.
|
||||
|
||||
**Trunk**
|
||||
: The default branch of a repository.
|
||||
This is "main" or "master" in most repositories.
|
||||
Trunk is the only branch that does not have a base branch.
|
||||
|
||||
**Stack**
|
||||
: A stack is a collection of branches stacked on top of each other
|
||||
in a way that each branch except the trunk has a base branch.
|
||||
|
||||
In the diagram, `A` is stacked on top of trunk,
|
||||
`B` is stacked on top of `A`, and so on.
|
||||
A branch can have multiple branches stacked on top of it.
|
||||
|
||||
**Downstack**
|
||||
: Downstack refers to the branches below the current branch,
|
||||
all the way to, but not including, the trunk branch.
|
||||
|
||||
**Upstack**
|
||||
: Upstack refers to the branches stacked on top of the current branch,
|
||||
those branches' upstacks, and so on until no more branches remain.
|
||||
If a branch has multiple branches stacked on top of it,
|
||||
they are both upstack from it.
|
||||
|
||||
**Sibling**
|
||||
: A sibling to a branch is a branch that shares the same base branch.
|
||||
In the diagram, `F` is a sibling to `B`, and `C` is a sibling to `D`.
|
||||
|
||||
|
||||
**Restacking**
|
||||
: Restacking is the process of moving a rebasing the contents of a branch
|
||||
on top of its base branch, which it may have diverged from.
|
||||
This is done to keep the branch up-to-date with its base branch,
|
||||
and maintain a linear history.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
icon: material/compass
|
||||
template: templates/index_page.html
|
||||
title: User Guide
|
||||
hide: [toc]
|
||||
description: >-
|
||||
Details on how to use git-spice to manage your repositories.
|
||||
---
|
||||
|
||||
The User Guide covers the features of git-spice in more detail.
|
||||
|
||||
For a list of all available commands, see the [Command Reference](../cli/index.md).
|
||||
@@ -0,0 +1,80 @@
|
||||
---
|
||||
title: Internals
|
||||
icon: octicons/codescan-16
|
||||
description: >-
|
||||
A look at the inner workings of git-spice for the curious.
|
||||
---
|
||||
|
||||
# git-spice internals
|
||||
|
||||
!!! warning
|
||||
|
||||
This page covers internal details about the implementation of git-spice.
|
||||
Most users do not need to read this.
|
||||
It is presented here for the curious,
|
||||
and in the interest of transparency.
|
||||
|
||||
Do not rely on internal details to remain stable.
|
||||
These may change at any time.
|
||||
|
||||
## Local storage
|
||||
|
||||
git-spice stores information about your repository and branches
|
||||
in a local Git ref named: `refs/spice/data`.
|
||||
|
||||
Information is stored in JSON files with roughly the following structure:
|
||||
|
||||
```tree
|
||||
repo # repository-level information
|
||||
templates # cached GitHub PR templates
|
||||
rebase-continue # information about ongoing operations
|
||||
branches # branch tracking information
|
||||
feat1
|
||||
feat2
|
||||
...
|
||||
prepared # ephemeral per-branch PR form information
|
||||
feat1
|
||||
feat2
|
||||
...
|
||||
```
|
||||
|
||||
git-spice operations that manipulate this information
|
||||
will usually include what prompted the change.
|
||||
|
||||
You can explore this information by running
|
||||
the following command in a repository using git-spice:
|
||||
|
||||
```bash
|
||||
git log --patch refs/spice/data
|
||||
```
|
||||
|
||||
## Secret storage
|
||||
|
||||
git-spice stores your GitHub authentication token
|
||||
in a system-specific secure storage.
|
||||
|
||||
On macOS, this is the system Keychain.
|
||||
On Linux, it uses the [Secret Service](https://specifications.freedesktop.org/secret-service/latest/),
|
||||
which is typically provided by [GNOME Keyring](https://specifications.freedesktop.org/secret-service/latest/).
|
||||
<!-- TODO (if we enable Windows): On Windows, it uses the Windows Credential Manager APIs. -->
|
||||
|
||||
Credit goes to [zalando/go-keyring](https://github.com/zalando/go-keyring)
|
||||
for providing a cross-platform API for this purpose.
|
||||
|
||||
## Git interactions
|
||||
|
||||
git-spice does not use a third-party Git implementation.
|
||||
All operations are performed directly against the Git CLI,
|
||||
often relying on Git's [plumbing commands](https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain).
|
||||
|
||||
!!! question "Why?"
|
||||
|
||||
Most third-party Git implementations trail behind in feature parity.
|
||||
For example, many third-party implementations can misbehave when you make
|
||||
use of advanced features like
|
||||
[git worktree](https://git-scm.com/docs/git-worktree),
|
||||
[git sparse-checkout](https://git-scm.com/docs/git-sparse-checkout),
|
||||
or [sparse indexes](https://git-scm.com/docs/sparse-index).
|
||||
|
||||
By relying on the highly scriptable and machine-consumable Git plumbing
|
||||
we don't have to deal with those issues.
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
icon: octicons/stop-16
|
||||
title: Limitations
|
||||
description: >-
|
||||
Usage constraints and limitations when using git-spice
|
||||
to interact with GitHub.
|
||||
---
|
||||
|
||||
git-spice's handling of GitHub Pull Requests is limited
|
||||
by what's possible with GitHub and its handling of Git commits.
|
||||
Some limitations imposed on git-spice are listed below.
|
||||
|
||||
## Write access required
|
||||
|
||||
When a branch `F` is stacked on another branch `B`,
|
||||
and you want to create stacked Pull Requests from them,
|
||||
the PR for `F` will be created against `B`.
|
||||
To do this, git-spice needs to push both branches to the same repository.
|
||||
|
||||
Therefore, to use git-spice to stack PRs,
|
||||
you need write access to the repository:
|
||||
specifically the ability to push new branches.
|
||||
|
||||
## Squash-merges restack the upstack
|
||||
|
||||
If a Pull Request is squash-merged into the trunk branch,
|
||||
all commits in that PR are replaced with a single commit with a different hash.
|
||||
|
||||
The branches upstack from that PR are not aware of this new commit,
|
||||
still referring to the old, unsquashed history of the branch.
|
||||
GitHub does not yet know to reconcile this new commit with the upstack branches,
|
||||
even though the contents are the same.
|
||||
|
||||
```pikchr
|
||||
linewid = 0.25in
|
||||
|
||||
X: [
|
||||
right
|
||||
text "A" small; line; text "B" small
|
||||
line go linewid heading 45; right
|
||||
text "C" small; line; text "D" small
|
||||
line go linewid heading 45; right
|
||||
text "E" small
|
||||
|
||||
text "main" with e at A.w
|
||||
text "feat1" with e at (last.e.x, C.y)
|
||||
line thin chop dotted from last to C
|
||||
text "feat2" with e at (last text.e.x, E.y)
|
||||
line thin chop dotted from last to E
|
||||
]
|
||||
|
||||
Y: [
|
||||
right
|
||||
text "A" small; line; text "B" small; line; text "CD" small
|
||||
move to B.ne
|
||||
line go linewid heading 45; right
|
||||
text "C" small; line; text "D" small
|
||||
line go linewid heading 45; right
|
||||
text "E" small
|
||||
|
||||
text "main" with e at A.w
|
||||
|
||||
text "feat2" with e at (last text.e.x, E.y)
|
||||
line thin chop dotted from last to E
|
||||
] with n at 0.5in below last.s
|
||||
|
||||
Z: [
|
||||
right
|
||||
text "A" small; line; text "B" small; line; text "CD" small
|
||||
line go linewid*2 heading 45; right
|
||||
text "E" small
|
||||
|
||||
text "main" with e at A.w
|
||||
|
||||
text "feat2" with e at (last text.e.x, E.y)
|
||||
line thin chop dotted from last to E
|
||||
] with n at 0.5in below last.s
|
||||
|
||||
arrow " squash-merge" ljust from X.s to Y.n
|
||||
arrow " restack" ljust from Y.s to Z.n
|
||||
```
|
||||
|
||||
As a result of this, when a branch is squash-merged into the trunk branch,
|
||||
branches upstack from it need to be restacked, and all their PRs updated.
|
||||
|
||||
<!-- TODO: can be alleviated somewhat if we implement
|
||||
https://github.com/abhinav/git-spice/issues/65 -->
|
||||
|
||||
## Base branch change may dismiss approvals
|
||||
|
||||
Some GitHub repositories are configured to dismiss prior approvals of PRs
|
||||
when the base branch of that PR is changed.
|
||||
There is no workaround to this except to reconfigure the repository
|
||||
as this setting is fundamentally incompatible with a PR stacking workflow.
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
title: PR stacks
|
||||
icon: octicons/git-pull-request-16
|
||||
description: >-
|
||||
Create and update stacked pull requests from a stack of branches.
|
||||
---
|
||||
|
||||
# Pull Request Stacks
|
||||
|
||||
## Submitting pull requests
|
||||
|
||||
When your local changes are ready,
|
||||
use the following commands to submit your changes upstream:
|
||||
|
||||
- $$gs branch submit$$ (or $$gs branch submit|gs bs$$)
|
||||
submits the current branch
|
||||
- $$gs downstack submit$$ (or $$gs downstack submit|gs dss$$)
|
||||
submits the current branch and all branches below it
|
||||
- $$gs upstack submit$$ (or $$gs upstack submit|gs uss$$)
|
||||
submits the current branch and all branches above it
|
||||
- $$gs stack submit$$ (or $$gs stack submit|gs ss$$)
|
||||
submits all branches in the stack
|
||||
|
||||
Branch submission is an idempotent operation:
|
||||
pull requests will be created for branches that don't already have them,
|
||||
and updated for branches that do.
|
||||
|
||||
For new pull requests, these commands will prompt you for PR information.
|
||||
For example:
|
||||
|
||||
```freeze language="ansi"
|
||||
--8<-- "captures/branch-submit.txt"
|
||||
```
|
||||
|
||||
!!! important
|
||||
|
||||
Be aware that for stacks with multiple branches,
|
||||
you must have write access to the repository
|
||||
so that you can push branches to it.
|
||||
See [Limitations](limits.md) for more information.
|
||||
|
||||
### Non-interactive submission
|
||||
|
||||
Use the `--fill` flag provided by all the above commands
|
||||
to fill in the PR information from commit messages
|
||||
and skip the interactive prompts.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs stack submit --fill
|
||||
{green}INF{reset} Created #123: https://github.com/abhinav/git-spice/pull/123
|
||||
{green}INF{reset} Created #125: https://github.com/abhinav/git-spice/pull/125
|
||||
```
|
||||
|
||||
Additionally, with $$gs branch submit$$,
|
||||
you may also specify title and body directly.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs branch submit {gray}\{reset}
|
||||
--title {blue}"Fix a bug"{reset} {gray}\{reset}
|
||||
--body {blue}"This fixes a very bad bug."{reset}
|
||||
{green}INF{reset} Created #123: https://github.com/abhinav/git-spice/pull/123
|
||||
```
|
||||
|
||||
!!! info "Setting draft status non-interactively"
|
||||
|
||||
Pull requests may be marked as draft or ready for review
|
||||
non-interactively with the `--draft` and `--no-draft` flags.
|
||||
|
||||
By default, the submit commands will leave
|
||||
the draft state of existing PRs unchanged.
|
||||
If the `--draft` or `--no-draft` flags are provided,
|
||||
the draft state of all PRs will be set accordingly.
|
||||
|
||||
## Syncing with upstream
|
||||
|
||||
To sync with the upstream repository,
|
||||
use $$gs repo sync$$ (or $$gs repo sync|gs rs$$).
|
||||
|
||||
```freeze language="terminal" float="right"
|
||||
{green}${reset} gs repo sync
|
||||
{green}INF{reset} main: pulled 3 new commit(s)
|
||||
{green}INF{reset} feat1: #123 was merged
|
||||
{green}INF{reset} feat1: deleted (was 9f1c9af)
|
||||
```
|
||||
|
||||
This will update the trunk branch (e.g. `main`)
|
||||
with the latest changes from the upstream repository,
|
||||
and delete any local branches whose PRs have been merged.
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
icon: material/tooltip-check
|
||||
title: How-to
|
||||
description: >-
|
||||
Common tasks and how to perform them with git-spice.
|
||||
---
|
||||
|
||||
# How-to...
|
||||
|
||||
## Manage an existing stack with git-spice
|
||||
|
||||
If you have an existing, manually managed stack of branches,
|
||||
you can import it into git-spice with repeated use of $$gs branch track$$.
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. Check out the base branch and initialize git-spice.
|
||||
|
||||
```bash
|
||||
git checkout main
|
||||
gs repo init
|
||||
```
|
||||
|
||||
2. Check out the first branch in the stack and track it.
|
||||
|
||||
```bash
|
||||
git checkout feat1
|
||||
gs branch track
|
||||
```
|
||||
|
||||
3. Repeat the previous step for each branch in the stack.
|
||||
|
||||
```bash
|
||||
git checkout feat2
|
||||
gs branch track
|
||||
# ... repeat until done ...
|
||||
```
|
||||
|
||||
4. You may now use git-spice to manage the stack as usual.
|
||||
|
||||
## Import an existing Pull Request
|
||||
|
||||
git-spice can recognize and manage GitHub Pull Requests
|
||||
that were not created using git-spice.
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. Check the PR out locally.
|
||||
For example, if you're using the GitHub CLI:
|
||||
|
||||
```bash
|
||||
gh pr checkout 123
|
||||
```
|
||||
|
||||
2. Track the branch with git-spice.
|
||||
|
||||
```bash
|
||||
gs branch track
|
||||
```
|
||||
|
||||
3. Attempt to re-submit the branch.
|
||||
git-spice will automatically detect the existing open PR for it,
|
||||
and associate the branch with that PR.
|
||||
|
||||
```bash
|
||||
gs branch submit
|
||||
```
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
icon: material/home
|
||||
hide:
|
||||
- toc
|
||||
description: >-
|
||||
git-spice is a tool for stacking Git branches.
|
||||
It helps you manage and navigate a stack of branches
|
||||
that build on top of each other.
|
||||
---
|
||||
|
||||
# git-spice
|
||||
|
||||
{ align=right width=250px }
|
||||
|
||||
git-spice is a tool for stacking Git branches.
|
||||
It lets you manage and navigate stacks of branches,
|
||||
conveniently modify and rebase them,
|
||||
and create GitHub Pull Requests from them.
|
||||
|
||||
<div class="grid" markdown>
|
||||
|
||||
```freeze language="shell"
|
||||
# Create a branch
|
||||
$ gs branch create
|
||||
|
||||
# Restack a branck
|
||||
$ gs branch restack
|
||||
|
||||
# Restack all branches
|
||||
$ gs stack restack
|
||||
```
|
||||
|
||||
```freeze language="shell"
|
||||
# Submit a PR
|
||||
$ gs branch submit
|
||||
|
||||
# Submit all PRs
|
||||
$ gs stack submit
|
||||
|
||||
# Sync with trunk
|
||||
$ gs repo sync
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
!!! question "What is stacking?"
|
||||
|
||||
Stacking refers to the practice of creating branches or pull requests
|
||||
that build on top of each other.
|
||||
It allows chaining interdependent changes together,
|
||||
while still keeping the individual changes small and focused.
|
||||
|
||||
See also [:material-frequently-asked-questions: FAQ > What is stacking?](faq.md#what-is-stacking)
|
||||
|
||||
[:material-run: Get started](start/index.md){ .md-button }
|
||||
[:material-compass: Learn more](guide/index.md){ .md-button }
|
||||
|
||||
## Features
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [:octicons-git-branch-16:{ .lg .middle } __Branch management__](guide/branch.md)
|
||||
|
||||
---
|
||||
|
||||
Create, edit, and navigate stacks of branches with ease.
|
||||
With git-spice's branch management commands,
|
||||
you can keep your stack in sync with the trunk branch,
|
||||
automatically rebase dependent branches, and more.
|
||||
|
||||
- [:octicons-git-pull-request-16:{ .lg .middle } __Pull Request Management__](guide/pr.md)
|
||||
|
||||
---
|
||||
|
||||
Create GitHub Pull Requests from your stack with a single command.
|
||||
git-spice can create
|
||||
[a PR for the current branch](cli/index.md#gs-branch-submit),
|
||||
[PRs for the entire stack](cli/index.md#gs-stack-submit), or
|
||||
[parts of](cli/index.md#gs-upstack-submit)
|
||||
[the stack](cli/index.md#gs-downstack-submit).
|
||||
If a branch already has a PR, git-spice will update it.
|
||||
If a PR is merged,
|
||||
git-spice will automatically restack branches that depend on it.
|
||||
|
||||
- [:material-stairs:{ .lg .middle } __Incremental improvements__](start/stack.md)
|
||||
|
||||
---
|
||||
|
||||
git-spice does not need to be adopted all at once.
|
||||
It does not expect you to flip your entire workflow upside down.
|
||||
Incorporate it into your workflow at your own pace,
|
||||
one feature at a time.
|
||||
|
||||
- [:material-cloud-off-outline:{ .lg .middle } __Offline-first__](guide/internals.md)
|
||||
|
||||
---
|
||||
|
||||
git-spice operates entirely locally.
|
||||
It talks directly to Git, and when you ask for it, to GitHub.
|
||||
All state is stored locally in your Git repository.
|
||||
A network connection is not required, except when pushing or pulling.
|
||||
|
||||
- [:material-lightbulb-on:{ .lg .middle } __Intuitive shorthands__](cli/shorthand.md)
|
||||
|
||||
---
|
||||
|
||||
Most commands in git-spice have easy-to-remember shorthands.
|
||||
For example, $$gs branch create$$ can be shortened to $$gs branch create|gs bc$$.
|
||||
Explore the list of shorthands with `--help` or at [Shorthands](cli/shorthand.md).
|
||||
We recommend adopting these incrementally.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,193 @@
|
||||
---
|
||||
icon: material/lock
|
||||
description: >-
|
||||
Authenticate with GitHub to push and pull changes.
|
||||
---
|
||||
|
||||
# Authentication
|
||||
|
||||
git-spice is offline-first.
|
||||
It does not require authentication for local stacking operations.
|
||||
However, once you want to push or pull changes to/from a GitHub repository,
|
||||
you will need to authenticate with GitHub.
|
||||
|
||||
This page covers the authentication options for git-spice.
|
||||
|
||||
## Logging in
|
||||
|
||||
To authenticate with GitHub, run:
|
||||
|
||||
```sh
|
||||
gs auth login github
|
||||
```
|
||||
|
||||
This will present you with a list of authentication methods.
|
||||
|
||||
See [Authentication methods](#authentication-methods) for details
|
||||
on what to expect from each method,
|
||||
or skip on to [Pick an authentication method](#picking-an-authentication-method).
|
||||
|
||||
## Authentication methods
|
||||
|
||||
git-spice provides several ways to authenticate with GitHub.
|
||||
|
||||
### OAuth
|
||||
|
||||
With OAuth authentication, you will take the following steps:
|
||||
|
||||
1. Authenticate yourself on github.com in your browser.
|
||||
2. Authorize git-spice to act on your behalf on the **current device only**.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs auth login
|
||||
Select an authentication method: {red}OAuth{reset}
|
||||
{gray}1.{reset} Visit {cyan}https://github.com/login/device{reset}
|
||||
{gray}2.{reset} Enter code: ABCD-1234
|
||||
The code expires in a few minutes.
|
||||
It will take a few seconds to verify after you enter it.
|
||||
```
|
||||
|
||||
Two options are available for OAuth:
|
||||
|
||||
- **OAuth**: grants access to all repositories, public and private.
|
||||
- **OAuth: Public repositories only**:
|
||||
grants access to public repositories only.
|
||||
|
||||
For more granular control, use [GitHub App](#github-app) authentication.
|
||||
|
||||
!!! note
|
||||
|
||||
For private repositories owned by organizations,
|
||||
you will need a member with administrative access to the repository
|
||||
to allow installation of the git-spice OAuth App.
|
||||
If that is not an option,
|
||||
use a [Personal Access Token](#personal-access-token).
|
||||
|
||||
### GitHub App
|
||||
|
||||
With GitHub App authentication, you will take the following steps:
|
||||
|
||||
1. Authenticate yourself on github.com in your browser.
|
||||
2. Authorize git-spice to act on your behalf on the **current device only**.
|
||||
3. Install the [git-spice GitHub App](https://github.com/apps/git-spice)
|
||||
on the repositories you want to use git-spice with.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs auth login
|
||||
Select an authentication method: {red}GitHub App{reset}
|
||||
{gray}1.{reset} Visit {cyan}https://github.com/login/device{reset}
|
||||
{gray}2.{reset} Enter code: ABCD-1234
|
||||
The code expires in a few minutes.
|
||||
It will take a few seconds to verify after you enter it.
|
||||
```
|
||||
|
||||
**Important**: Authentication alone does not grant any access.
|
||||
You **must** install the GitHub App to access repositories with git-spice.
|
||||
|
||||
!!! note
|
||||
|
||||
For private repositories owned by organizations,
|
||||
you will need a member with administrative access to the repository
|
||||
to allow installation of the git-spice GitHub App.
|
||||
If that is not an option,
|
||||
use a [Personal Access Token](#personal-access-token).
|
||||
|
||||
### Personal Access Token
|
||||
|
||||
To use a Personal Access Token with git-spice,
|
||||
you will generate a Personal Access Token on GitHub
|
||||
and enter it in the prompt.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} gs auth login
|
||||
Select an authentication method: {red}Personal Access Token{reset}
|
||||
{green}Enter Personal Access Token{reset}:
|
||||
```
|
||||
|
||||
The token may be a classic token or a fine-grained token.
|
||||
|
||||
=== "Classic token"
|
||||
|
||||
With classic tokens, you can grant access to all repositories,
|
||||
or all public repositories only.
|
||||
These tokens have the ability to never expire.
|
||||
|
||||
To use a classic token:
|
||||
|
||||
1. Go to <https://github.com/settings/tokens/new>.
|
||||
This may ask you to re-authenticate.
|
||||
2. In the token creation form:
|
||||
|
||||
- enter a descriptive note for the token
|
||||
- pick an expiration window, or select "No expiration"
|
||||
- select `repo` scope for full access to all repositories,
|
||||
or `public_repo` for access to public repositories only
|
||||
|
||||
3. Click "Generate token" and copy the token.
|
||||
|
||||
=== "Fine-grained token"
|
||||
|
||||
With fine-grained tokens, you have more granular control over
|
||||
repositories that you grant access to.
|
||||
These token must always have an expiration date.
|
||||
|
||||
To use a fine-grained token:
|
||||
|
||||
1. Go to <https://github.com/settings/personal-access-tokens/new>.
|
||||
This may ask you to re-authenticate.
|
||||
2. In the token creation form:
|
||||
|
||||
- pick a descriptive note for the token
|
||||
- pick an expiration window
|
||||
- in the *Repository access* section, select the repositories
|
||||
you want to use git-spice with
|
||||
- in the *Repository permissions* section,
|
||||
grant **Read and write** access to **Pull requests** and **Contents**
|
||||
|
||||
3. Click "Generate token" and copy the token.
|
||||
|
||||
After you have a token, enter it into the prompt.
|
||||
|
||||
### GitHub CLI
|
||||
|
||||
If you have the [GitHub CLI](https://cli.github.com/) installed and authenticated,
|
||||
you can select this as the authentication method.
|
||||
|
||||
This requires no additional steps.
|
||||
We'll request a token from GitHub CLI as needed.
|
||||
|
||||
### GITHUB_TOKEN
|
||||
|
||||
If you have a `GITHUB_TOKEN` environment variable set,
|
||||
that takes precedence over all other authentication methods.
|
||||
|
||||
The $$gs auth login$$ operation will fail if you use this method.
|
||||
|
||||
## Picking an authentication method
|
||||
|
||||
[OAuth](#oauth) and [GitHub App](#github-app) authentication are best if you
|
||||
have the permissions needed to install OAuth/GitHub Apps
|
||||
on all repositories that you want to use git-spice with.
|
||||
The two are equivalent in terms of user experience.
|
||||
Use GitHub App authentication if you don't want to give git-spice access
|
||||
to all your repositories.
|
||||
|
||||
[GitHub CLI](#github-cli) is the most convenient method if you already have
|
||||
the GitHub CLI installed and authenticated.
|
||||
It loses some security benefits of the other methods,
|
||||
as it re-uses the token from the GitHub CLI.
|
||||
You lose the ability to revoke the git-spice token
|
||||
without revoking the GitHub CLI token.
|
||||
|
||||
[Personal Access Token](#personal-access-token) is flexible and secure.
|
||||
It may be used even with repositories where you don't have permission to
|
||||
install OAuth/GitHub Apps.
|
||||
However, it requires manual token management, making it less convenient.
|
||||
|
||||
[GITHUB_TOKEN](#github_token) is the least convenient and the least secure method.
|
||||
It is intended only for CI/CD environments where you have no other choice.
|
||||
|
||||
!!! question "Where is my token stored?"
|
||||
|
||||
The token is stored in a system-specific secure storage.
|
||||
See [Secret storage](../guide/internals.md#secret-storage) for details.
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
icon: material/console-line
|
||||
description: >-
|
||||
Set up shell completion for Bash, Zsh, and Fish.
|
||||
---
|
||||
|
||||
# Shell completion
|
||||
|
||||
git-spice supports completion for Bash, Zsh, and Fish.
|
||||
To set up completion, follow the instructions below.
|
||||
|
||||
=== "Bash"
|
||||
|
||||
Add the following line to your `.bashrc` or `.bash_profile`:
|
||||
|
||||
```bash
|
||||
eval "$(gs shell completion bash)"
|
||||
```
|
||||
|
||||
=== "Zsh"
|
||||
|
||||
Add the following line to your `.zshrc` or `.zprofile`:
|
||||
|
||||
```zsh
|
||||
eval "$(gs shell completion zsh)"
|
||||
```
|
||||
|
||||
=== "Fish"
|
||||
|
||||
Add the following line to your `config.fish`:
|
||||
|
||||
```fish
|
||||
eval "$(gs shell completion fish)"
|
||||
```
|
||||
|
||||
Then restart the shell or create a new shell session.
|
||||
|
||||
??? info "Debugging shell completion"
|
||||
|
||||
If shell completion misbehaves and you want to file a bug report,
|
||||
first retry the completion with `COMP_DEBUG=1` set.
|
||||
|
||||
```freeze language="terminal"
|
||||
{green}${reset} {blue}export{reset} COMP_DEBUG=1
|
||||
{green}${reset} gs branch onto {gray}# <TAB>{reset}
|
||||
```
|
||||
|
||||
This will print debugging information about the completion process.
|
||||
Include this output in your bug report.
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
icon: octicons/gear-16
|
||||
template: templates/index_page.html
|
||||
hide: [toc]
|
||||
description: >-
|
||||
Configuring git-spice for your workflow.
|
||||
---
|
||||
|
||||
# Setting up
|
||||
|
||||
This section guides you through various **optional** setup steps for git-spice.
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
icon: material/run
|
||||
hide: [toc]
|
||||
description: >-
|
||||
Get started using git-spice, a tool for stacking Git branches.
|
||||
template: templates/listing.html
|
||||
listing:
|
||||
- install.md
|
||||
- stack.md
|
||||
- submit.md
|
||||
---
|
||||
|
||||
# Get started
|
||||
|
||||
Start here if you're just exploring
|
||||
and would like to see what git-spice can do.
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
icon: material/download
|
||||
description: >-
|
||||
Install git-spice on your system and start using it.
|
||||
next_page: stack.md
|
||||
---
|
||||
|
||||
# Installation
|
||||
|
||||
git-spice may be installed with a pre-built binary
|
||||
or built from source.
|
||||
|
||||
## Pre-built binary
|
||||
|
||||
To install a **pre-built binary**, take the following steps:
|
||||
|
||||
=== "Homebrew/Linuxbrew"
|
||||
|
||||
```bash
|
||||
brew install abhinav/tap/git-spice
|
||||
```
|
||||
|
||||
=== "AUR (ArchLinux)"
|
||||
|
||||
```bash
|
||||
git clone https://aur.archlinux.org/git-spice-bin.git
|
||||
cd git-spice-bin
|
||||
makepkg -si
|
||||
|
||||
# Or, with an AUR helper like yay:
|
||||
yay -S git-spice-bin
|
||||
```
|
||||
|
||||
Pre-built binaries for other platforms can be found on the
|
||||
[GitHub Releases page](https://github.com/abhinav/git-spice/releases).
|
||||
|
||||
## Build from source
|
||||
|
||||
To **build from source**, follow these steps:
|
||||
|
||||
|
||||
1. Install the [Go compiler](https://go.dev/dl).
|
||||
2. Run the following command:
|
||||
|
||||
```bash
|
||||
go install go.abhg.dev/gs@latest
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
- [ ] [Create your first stack](stack.md)
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
title: Your first stack
|
||||
icon: material/baby-carriage
|
||||
description: >-
|
||||
Create your first stack of branches with git-spice.
|
||||
Modify and restack them with ease.
|
||||
prev_page: install.md
|
||||
next_page: submit.md
|
||||
---
|
||||
|
||||
With git-spice installed, start experimenting with stacking.
|
||||
|
||||
## Initialize git-spice
|
||||
|
||||
1. Start by creating an new Git repository to play inside.
|
||||
|
||||
```bash
|
||||
mkdir repo
|
||||
cd repo
|
||||
git init
|
||||
git commit --allow-empty -m "Initial commit"
|
||||
```
|
||||
|
||||
2. Initialize git-spice in the repository.
|
||||
This will set up the internal storage for git-spice in your repository.
|
||||
|
||||
```bash
|
||||
gs repo init
|
||||
```
|
||||
|
||||
!!! info
|
||||
|
||||
This step isn't absolutely required.
|
||||
git-spice will initialize itself automatically when needed.
|
||||
|
||||
## Track a branch
|
||||
|
||||
Next, stack a branch on top of `main`.
|
||||
|
||||
1. Create a new branch and make some changes:
|
||||
|
||||
```bash
|
||||
git checkout -b feat1
|
||||
echo "Hello, world!" > hello.txt
|
||||
git add hello.txt
|
||||
git commit -m "Add hello.txt"
|
||||
```
|
||||
|
||||
2. Add the branch to git-spice.
|
||||
|
||||
```bash
|
||||
gs branch track
|
||||
```
|
||||
|
||||
This results in a single branch stacked on top of `main`.
|
||||
|
||||
```pikchr center="false"
|
||||
linerad = 0.05in
|
||||
text "main"
|
||||
up; line go up 0.15in then go right 0.15in
|
||||
text "feat1"
|
||||
```
|
||||
|
||||
The above operations are frequently done together.
|
||||
git-spice provides a command to do all of them in one go: `gs branch create`.
|
||||
|
||||
## Use gs branch create
|
||||
|
||||
Stack another branch on top of `feat1` with $$gs branch create$$.
|
||||
|
||||
1. Check out feat1 and prepare another change:
|
||||
|
||||
```bash
|
||||
echo "This project is cool!" > README.md
|
||||
git add README.md
|
||||
```
|
||||
|
||||
2. Create a new branch, commit the staged changes,
|
||||
and add the branch to git-spice.
|
||||
|
||||
```bash
|
||||
gs branch create feat2
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
Use `gs branch create -a` to automatically stage changes to tracked
|
||||
files.
|
||||
This behaves similarly to `git commit -a`.
|
||||
|
||||
This results in a stack that looks like this:
|
||||
|
||||
```pikchr center="false"
|
||||
linerad = 0.05in
|
||||
text "main"
|
||||
up; line go up 0.15in then go right 0.15in
|
||||
text "feat1"
|
||||
up; line go up 0.15in then go right 0.15in
|
||||
text "feat2"
|
||||
```
|
||||
|
||||
## Modify mid-stack
|
||||
|
||||
Time to modify a branch in the middle of the stack.
|
||||
|
||||
1. Check out `feat1`:
|
||||
|
||||
```bash
|
||||
gs down
|
||||
```
|
||||
|
||||
!!! info
|
||||
|
||||
The $$gs down$$ command moves us "down" the stack,
|
||||
as opposed to $$gs up$$ which moves us "up".
|
||||
|
||||
2. Make a change to `hello.txt` and commit it:
|
||||
|
||||
```bash
|
||||
echo "How are you?" >> hello.txt
|
||||
git add hello.txt
|
||||
git commit -m "Add a question to hello.txt"
|
||||
```
|
||||
|
||||
3. **Restack** branches that are out of sync with the current branch.
|
||||
|
||||
```bash
|
||||
gs upstack restack
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
You can use $$gs commit create$$ to combine the commit and restack steps.
|
||||
|
||||
4. Go back to `feat2` and verify:
|
||||
|
||||
```bash
|
||||
gs up
|
||||
cat hello.txt
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**This section covered:**
|
||||
|
||||
- [x] $$gs branch create$$ is a shortcut for creating a branch,
|
||||
committing to it, and tracking it with git-spice.
|
||||
- [x] $$gs up$$ and $$gs down$$ provide relative navigation through the stack.
|
||||
- [x] $$gs upstack restack$$ updates branches
|
||||
that are out of sync with the current branch.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [ ] Use $$gs commit create$$ to combine the commit and restack steps
|
||||
- [ ] Explore different flags of $$gs branch create$$
|
||||
- [ ] [Create your first stacked pull requests](submit.md)
|
||||
@@ -0,0 +1,192 @@
|
||||
---
|
||||
title: Your first stacked PRs
|
||||
icon: material/slide
|
||||
description: >-
|
||||
Turn a stack of branches into Pull Requests.
|
||||
Update them all in one go.
|
||||
prev_page: stack.md
|
||||
next_page: ../guide/index.md
|
||||
---
|
||||
|
||||
# Your first stacked Pull Requests
|
||||
|
||||
This page will walk you through creating and updating
|
||||
GitHub Pull Requests with git-spice.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [x] [Create a stack of branches](stack.md).
|
||||
For this tutorial, we'll assume the following stack.
|
||||
Go back to the previous page if you need to create it.
|
||||
|
||||
```pikchr center="false"
|
||||
linerad = 0.05in
|
||||
text "main"
|
||||
up; line go up 0.15in then go right 0.15in
|
||||
text "feat1"
|
||||
up; line go up 0.15in then go right 0.15in
|
||||
text "feat2"
|
||||
```
|
||||
|
||||
- [x] Set up a GitHub repository.
|
||||
|
||||
??? info "Optional: Create an experimental repository"
|
||||
|
||||
If you're following along with the tutorial,
|
||||
you may want to create a new repository on GitHub
|
||||
to experiment with instead of using a real project.
|
||||
|
||||
To do this, if you have the GitHub CLI installed,
|
||||
run the following inside your experimental repository:
|
||||
|
||||
```bash
|
||||
gh repo create gs-playground \
|
||||
--public \
|
||||
--source=$(pwd) \
|
||||
--push
|
||||
```
|
||||
|
||||
If you don't have the GitHub CLI installed,
|
||||
go to <https://github.com/new> and follow the instructions there.
|
||||
|
||||
## Create a Pull Request
|
||||
|
||||
1. Check out `feat1`.
|
||||
|
||||
=== "git"
|
||||
|
||||
```bash
|
||||
git checkout feat1
|
||||
```
|
||||
|
||||
=== "gs"
|
||||
|
||||
```bash
|
||||
gs branch checkout feat1
|
||||
```
|
||||
|
||||
=== "gs shorthand"
|
||||
|
||||
```bash
|
||||
gs bco feat1
|
||||
```
|
||||
|
||||
2. Submit a PR.
|
||||
|
||||
=== "gs"
|
||||
|
||||
```bash
|
||||
gs branch submit
|
||||
```
|
||||
|
||||
=== "gs shorthand"
|
||||
|
||||
```bash
|
||||
gs bs
|
||||
```
|
||||
|
||||
3. Follow the prompts on-screen to create the PR.
|
||||
For example:
|
||||
|
||||
```freeze language="ansi"
|
||||
--8<-- "captures/branch-submit.txt"
|
||||
```
|
||||
|
||||
## Stack on top
|
||||
|
||||
1. Check out `feat2`.
|
||||
|
||||
```bash
|
||||
gs up
|
||||
```
|
||||
|
||||
2. Submit a PR.
|
||||
|
||||
```bash
|
||||
gs branch submit
|
||||
```
|
||||
|
||||
3. Follow the prompts on-screen to create the PR.
|
||||
|
||||
The new PR will now be stacked on top of the previous one:
|
||||
GitHub will show `feat1` as the base branch for the PR.
|
||||
|
||||
## Modify mid-stack
|
||||
|
||||
Modify the `feat1` branch and update the PR.
|
||||
|
||||
1. Check out `feat1`.
|
||||
|
||||
```bash
|
||||
gs down
|
||||
```
|
||||
|
||||
2. Make some changes.
|
||||
|
||||
=== "gs"
|
||||
|
||||
```bash
|
||||
echo "Not bad, how about you?" >> hello.txt
|
||||
git add hello.txt
|
||||
gs commit create -m "follow up"
|
||||
```
|
||||
|
||||
=== "gs shorthand"
|
||||
|
||||
```bash
|
||||
echo "Not bad, how about you?" >> hello.txt
|
||||
git add hello.txt
|
||||
gs cc -m "follow up"
|
||||
```
|
||||
|
||||
!!! info
|
||||
|
||||
We use the $$gs commit create$$ command here.
|
||||
This will commit to the current branch,
|
||||
and rebase the upstack branches on top of the new commit.
|
||||
|
||||
3. Update all PRs in the stack.
|
||||
|
||||
```bash
|
||||
gs stack submit
|
||||
```
|
||||
|
||||
This will push to both PRs in the stack.
|
||||
If one of the branches was not submitted yet,
|
||||
it will prompt you to create a PR for it.
|
||||
|
||||
## Merge a PR
|
||||
|
||||
1. Open up the Pull Request for `feat1` on GitHub
|
||||
and merge it into `main`.
|
||||
|
||||
2. Run the following command to sync the stack with the trunk:
|
||||
|
||||
```bash
|
||||
gs repo sync
|
||||
```
|
||||
|
||||
This will delete `feat1` locally,
|
||||
and rebase `feat2` on top of `main`.
|
||||
|
||||
3. Submit the PR for `feat2` to update the pull request
|
||||
if necessary.
|
||||
|
||||
```bash
|
||||
gs branch submit
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**This section covered:**
|
||||
|
||||
- [x] $$gs branch submit$$ creates or updates a PR for the current branch.
|
||||
- [x] $$gs stack submit$$ creates or updates PRs for the entire stack.
|
||||
- [x] $$gs repo sync$$ syncs the stack with the trunk branch,
|
||||
deletes merged branches, and rebases the remaining branches.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [ ] Explore other submit commands:
|
||||
$$gs upstack submit$$, $$gs downstack submit$$
|
||||
- [ ] Browse the [User Guide](../guide/index.md) to learn more
|
||||
@@ -0,0 +1,8 @@
|
||||
//go:build tools
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/charmbracelet/freeze"
|
||||
_ "go.abhg.dev/gs"
|
||||
)
|
||||
@@ -1,8 +1,8 @@
|
||||
//go:build dumpmd
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -12,52 +12,107 @@ import (
|
||||
"github.com/alecthomas/kong"
|
||||
)
|
||||
|
||||
// dumpMarkdownCmd is a hidden flag that makes the command
|
||||
// dupm a Markdown reference to stdout and exit.
|
||||
// dumpMarkdownCmd is a hidden commnad that dumps
|
||||
// a Markdown reference to stdout and exit.
|
||||
type dumpMarkdownCmd struct {
|
||||
Out string `help:"Output file" type:"path"`
|
||||
|
||||
w io.Writer
|
||||
Ref string `name:"ref" help:"Output file for command reference."`
|
||||
Shorthands string `name:"shorthands" help:"Output file for shorthands table."`
|
||||
}
|
||||
|
||||
func (cmd *dumpMarkdownCmd) Run(app *kong.Kong) (err error) {
|
||||
var w io.Writer = os.Stdout
|
||||
if cmd.Out != "" && cmd.Out != "-" {
|
||||
f, err := os.Create(cmd.Out)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create output file: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
err = errors.Join(err, f.Close())
|
||||
}()
|
||||
w = f
|
||||
func (cmd *dumpMarkdownCmd) Run(app *kong.Kong, shorts shorthands) (err error) {
|
||||
ref, err := os.Create(cmd.Ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = ref.Close() }()
|
||||
|
||||
buf := bufio.NewWriter(w)
|
||||
defer func() {
|
||||
err = errors.Join(err, buf.Flush())
|
||||
}()
|
||||
d := cliDumper{w: ref}
|
||||
d.dump(app.Model)
|
||||
|
||||
cmd.w = buf
|
||||
cmd.dump(app.Model)
|
||||
if cmd.Shorthands != "" {
|
||||
f, err := os.Create(cmd.Shorthands)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
dumpShorthands(f, shorts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cmd *dumpMarkdownCmd) println(args ...interface{}) {
|
||||
fmt.Fprintln(cmd.w, args...)
|
||||
func dumpShorthands(w io.Writer, shorts shorthands) {
|
||||
keys := make([]string, 0, len(shorts))
|
||||
for key := range shorts {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
slices.Sort(keys)
|
||||
|
||||
var t table
|
||||
t.appendHeaders("Shorthand", "Long form")
|
||||
for _, key := range keys {
|
||||
cmd := cmdFullName(shorts[key].Command)
|
||||
link := fmt.Sprintf("[%v](/cli/index.md#%v)", cmd, strings.ReplaceAll(cmd, " ", "-"))
|
||||
t.addRow("gs "+key, link)
|
||||
}
|
||||
t.dump(w)
|
||||
}
|
||||
|
||||
func (cmd *dumpMarkdownCmd) print(args ...interface{}) {
|
||||
fmt.Fprint(cmd.w, args...)
|
||||
type table struct {
|
||||
headers []string
|
||||
rows [][]string
|
||||
|
||||
headerColumn bool
|
||||
}
|
||||
|
||||
func (cmd *dumpMarkdownCmd) printf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(cmd.w, format, args...)
|
||||
func (t *table) appendHeaders(headers ...string) {
|
||||
t.headers = append(t.headers, headers...)
|
||||
}
|
||||
|
||||
func (cmd dumpMarkdownCmd) dump(app *kong.Application) {
|
||||
cmd.header(1, app.Name+" command reference")
|
||||
func (t *table) addRow(row ...string) {
|
||||
t.rows = append(t.rows, row)
|
||||
}
|
||||
|
||||
func (t *table) dump(w io.Writer) {
|
||||
fmt.Fprint(w, "|")
|
||||
for _, h := range t.headers {
|
||||
fmt.Fprintf(w, " **%s** |", h)
|
||||
}
|
||||
fmt.Fprintln(w)
|
||||
|
||||
fmt.Fprintln(w, "|", strings.Repeat(" --- |", len(t.headers)))
|
||||
for _, row := range t.rows {
|
||||
if t.headerColumn {
|
||||
row[0] = "**" + row[0] + "**"
|
||||
}
|
||||
fmt.Fprintln(w, "|", strings.Join(row, " | "), "|")
|
||||
}
|
||||
}
|
||||
|
||||
type cliDumper struct {
|
||||
w io.Writer
|
||||
}
|
||||
|
||||
func (cmd *cliDumper) dump(app *kong.Application) {
|
||||
// H1 is filled by the Markdown file that includes the result.
|
||||
|
||||
var groupKeys, groupTitles []string
|
||||
cmdByGroup := make(map[string][]*kong.Node)
|
||||
for _, subcmd := range app.Leaves(true) {
|
||||
var key, title string
|
||||
if grp := subcmd.ClosestGroup(); grp != nil {
|
||||
key = grp.Key
|
||||
title = grp.Title
|
||||
}
|
||||
|
||||
if _, ok := cmdByGroup[key]; !ok {
|
||||
groupKeys = append(groupKeys, key)
|
||||
groupTitles = append(groupTitles, title)
|
||||
}
|
||||
|
||||
cmdByGroup[key] = append(cmdByGroup[key], subcmd)
|
||||
}
|
||||
|
||||
// TODO: separate "inspect" and "dump" steps
|
||||
cmd.println("```")
|
||||
cmd.println("gs" + app.Summary())
|
||||
cmd.println("```")
|
||||
@@ -79,23 +134,6 @@ func (cmd dumpMarkdownCmd) dump(app *kong.Application) {
|
||||
}
|
||||
cmd.println()
|
||||
|
||||
var groupKeys, groupTitles []string
|
||||
cmdByGroup := make(map[string][]*kong.Node)
|
||||
for _, subcmd := range app.Leaves(true) {
|
||||
var key, title string
|
||||
if grp := subcmd.ClosestGroup(); grp != nil {
|
||||
key = grp.Key
|
||||
title = grp.Title
|
||||
}
|
||||
|
||||
if _, ok := cmdByGroup[key]; !ok {
|
||||
groupKeys = append(groupKeys, key)
|
||||
groupTitles = append(groupTitles, title)
|
||||
}
|
||||
|
||||
cmdByGroup[key] = append(cmdByGroup[key], subcmd)
|
||||
}
|
||||
|
||||
for i, key := range groupKeys {
|
||||
lvl := 2
|
||||
title := groupTitles[i]
|
||||
@@ -110,19 +148,12 @@ func (cmd dumpMarkdownCmd) dump(app *kong.Application) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd dumpMarkdownCmd) dumpCommand(node *kong.Node, level int) {
|
||||
func (cmd cliDumper) dumpCommand(node *kong.Node, level int) {
|
||||
if node.Hidden {
|
||||
return
|
||||
}
|
||||
|
||||
var parts []string
|
||||
for n := node; n != nil && n.Type == kong.CommandNode; n = n.Parent {
|
||||
parts = append(parts, n.Name)
|
||||
}
|
||||
parts = append(parts, "gs")
|
||||
slices.Reverse(parts)
|
||||
|
||||
cmd.header(level, strings.Join(parts, " "))
|
||||
cmd.header(level, cmdFullName(node))
|
||||
cmd.println("```")
|
||||
cmd.println("gs " + node.Summary())
|
||||
cmd.println("```")
|
||||
@@ -159,11 +190,11 @@ func (cmd dumpMarkdownCmd) dumpCommand(node *kong.Node, level int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd dumpMarkdownCmd) dumpArg(arg *kong.Positional) {
|
||||
func (cmd cliDumper) dumpArg(arg *kong.Positional) {
|
||||
cmd.printf("* `%s`: %s\n", arg.Name, arg.Help)
|
||||
}
|
||||
|
||||
func (cmd dumpMarkdownCmd) dumpFlag(flag *kong.Flag) {
|
||||
func (cmd cliDumper) dumpFlag(flag *kong.Flag) {
|
||||
if flag.Hidden {
|
||||
return
|
||||
}
|
||||
@@ -191,6 +222,28 @@ func (cmd dumpMarkdownCmd) dumpFlag(flag *kong.Flag) {
|
||||
cmd.printf("`: %s\n", flag.Help)
|
||||
}
|
||||
|
||||
func (cmd dumpMarkdownCmd) header(level int, text string) {
|
||||
func (cmd cliDumper) header(level int, text string) {
|
||||
cmd.printf("%s %s\n\n", strings.Repeat("#", level), text)
|
||||
}
|
||||
|
||||
func (cmd cliDumper) println(args ...interface{}) {
|
||||
fmt.Fprintln(cmd.w, args...)
|
||||
}
|
||||
|
||||
func (cmd cliDumper) print(args ...interface{}) {
|
||||
fmt.Fprint(cmd.w, args...)
|
||||
}
|
||||
|
||||
func (cmd cliDumper) printf(format string, args ...interface{}) {
|
||||
fmt.Fprintf(cmd.w, format, args...)
|
||||
}
|
||||
|
||||
func cmdFullName(node *kong.Node) string {
|
||||
var parts []string
|
||||
for n := node; n != nil && n.Type == kong.CommandNode; n = n.Parent {
|
||||
parts = append(parts, n.Name)
|
||||
}
|
||||
parts = append(parts, "gs")
|
||||
slices.Reverse(parts)
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
//go:build !dumpmd
|
||||
|
||||
package main
|
||||
|
||||
// When building without the "dumpmd" build tag,
|
||||
// the dumpmd does not do anything.
|
||||
|
||||
type dumpMarkdownCmd struct{}
|
||||
@@ -124,9 +124,7 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
shorthands := map[string][]string{
|
||||
"can": {"commit", "amend", "--no-edit"},
|
||||
}
|
||||
shorthands := make(shorthands)
|
||||
|
||||
// For each leaf subcommand, define a combined shorthand alias.
|
||||
// For example, if the command was "branch (b) create (c)",
|
||||
@@ -150,27 +148,31 @@ func main() {
|
||||
}
|
||||
|
||||
slices.Reverse(fragments)
|
||||
shorthand := strings.Join(fragments, "")
|
||||
if other, ok := shorthands[shorthand]; ok {
|
||||
panic(fmt.Sprintf("shorthand %q for %v is already in use by %v", shorthand, n.Path(), other))
|
||||
short := strings.Join(fragments, "")
|
||||
if other, ok := shorthands[short]; ok {
|
||||
panic(fmt.Sprintf("shorthand %q for %v is already in use by %v", short, n.Path(), other.Expanded))
|
||||
}
|
||||
// TODO: check if shorthand conflicts with any other aliases.
|
||||
|
||||
shorthands[shorthand] = fragments
|
||||
shorthands[short] = shorthand{
|
||||
Expanded: fragments,
|
||||
Command: n,
|
||||
}
|
||||
}
|
||||
|
||||
args := os.Args[1:]
|
||||
if len(args) > 0 {
|
||||
if path, ok := shorthands[args[0]]; ok {
|
||||
args = slices.Replace(args, 0, 1, path...)
|
||||
if short, ok := shorthands[args[0]]; ok {
|
||||
// TODO: Replace first non-flag argument instead.
|
||||
args = slices.Replace(args, 0, 1, short.Expanded...)
|
||||
}
|
||||
}
|
||||
|
||||
komplete.Run(parser,
|
||||
komplete.WithTransformCompleted(func(args []string) []string {
|
||||
if len(args) > 0 {
|
||||
if path, ok := shorthands[args[0]]; ok {
|
||||
args = slices.Replace(args, 0, 1, path...)
|
||||
if short, ok := shorthands[args[0]]; ok {
|
||||
args = slices.Replace(args, 0, 1, short.Expanded...)
|
||||
}
|
||||
}
|
||||
return args
|
||||
@@ -187,11 +189,18 @@ func main() {
|
||||
logger.Fatalf("gs: %v", err)
|
||||
}
|
||||
|
||||
if err := kctx.Run(); err != nil {
|
||||
if err := kctx.Run(shorthands); err != nil {
|
||||
logger.Fatalf("gs: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type shorthand struct {
|
||||
Expanded []string
|
||||
Command *kong.Node
|
||||
}
|
||||
|
||||
type shorthands map[string]shorthand
|
||||
|
||||
type globalOptions struct {
|
||||
// Flags that are not accessed directly by command implementations:
|
||||
|
||||
@@ -231,7 +240,7 @@ type mainCmd struct {
|
||||
Trunk trunkCmd `cmd:"" group:"Navigation" help:"Move to the trunk branch"`
|
||||
|
||||
// Hidden commands:
|
||||
DumpMD dumpMarkdownCmd `name:"dump-md" hidden:"" cmd:"" help:"Dump a Markdown reference to stdout and quit"`
|
||||
DumpMD dumpMarkdownCmd `name:"dumpmd" hidden:"" cmd:"" help:"Dump a Markdown reference to stdout and quit"`
|
||||
}
|
||||
|
||||
func (cmd *mainCmd) AfterApply(kctx *kong.Context, logger *log.Logger) error {
|
||||
|
||||
Reference in New Issue
Block a user