Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7a890f9
.tool-versions(uv) uv 0.12.9 -> 0.12.11
tony Sep 12, 2026
70bb770
.nvmrc(nodejs) 24.20.0 -> 24.21.0
tony Sep 12, 2026
a9150de
py(deps[dev]) ruff 0.16.5 -> 0.16.6
tony Sep 12, 2026
4087791
py(deps[dev]) pytest-rerunfailures 16.6 -> 16.6.1
tony Sep 12, 2026
76c50c5
py(deps[dev]) Bump dev packages
tony Sep 12, 2026
6f2e5dd
py(deps) Refresh eligible dependencies
tony Sep 20, 2026
9fdd083
.tool-versions(uv) uv 0.12.11 -> 0.12.15
tony Sep 20, 2026
f5c9ade
docs: redirect Sphinx search page to the shell's Pagefind search
tony Sep 5, 2026
3a604ac
docs(css): add libtmux-org.css design-token adapter for Furo
tony Sep 5, 2026
8195f20
docs(css): fall back to Furo's stock values when tokens.css is unreac…
tony Sep 5, 2026
ce92238
docs: add lang attribute to the search-page redirect stub
tony Sep 5, 2026
02adc28
Load the shared shell from a root-relative path
tony Sep 5, 2026
1671e1d
docs(fix[css]): Drop a local path from the token adapter
tony Sep 6, 2026
652da1b
docs(fix[search]): Keep a working search on the standalone build
tony Sep 6, 2026
4ed4122
docs(test[conf]): Pin the shell integration's two deploy shapes
tony Sep 6, 2026
4c1ffb3
docs(ci[deploy]) Say when the standalone flag comes back out
tony Sep 6, 2026
3e66e2a
docs(CHANGES) libtmux.org chrome, search, and the 0.1.0a38 toolchain
tony Sep 6, 2026
28a754a
docs(ci[deploy]): Publish to libtmux.org under this port's prefix
tony Sep 6, 2026
f917a4f
docs(ci[deploy]) Pin the deploy workflow to v1
tony Sep 6, 2026
b96002e
docs(ci[deploy]): Publish to libtmux.org alongside git-pull.com
tony Sep 6, 2026
024aa81
docs(ci[deploy]): Pin the deploy workflow to a commit
tony Sep 6, 2026
cd09c09
docs(ci[deploy]) Move the deploy pin to v0.1.0-alpha.1
tony Sep 6, 2026
43f3c38
DO NOT MERGE: publish from docs-site-deploy, and repin
Sep 6, 2026
02b5769
fix(ci) Publish the shell tree to libtmux.org, not the Sphinx site
Sep 6, 2026
6468ff8
docs(CHANGES) A second docs publish, to libtmux.org
tony Sep 6, 2026
e9fa85b
docs(query_list): Document the two exceptions QueryList raises
tony Sep 6, 2026
e8c4b33
docs(constants): Say what the default-scope sentinel means
tony Sep 6, 2026
22cba98
Docs(ci[deploy]): Pin the current docs shell
tony Sep 20, 2026
f70faac
Docs(ci[deploy]): Pin the refreshed docs shell
tony Sep 20, 2026
f8a448f
Docs(ci): Publish selected source revisions
tony Sep 27, 2026
65ee8ef
Docs(ci): Preserve the selected dependency lock
tony Sep 27, 2026
a25e1b9
Docs(ci): Pin the merged documentation layout
tony Sep 28, 2026
da4484a
libtmux(style): Apply Ruff's spacing
tony Sep 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
groups:
actions:
patterns: ['*']
144 changes: 102 additions & 42 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -1,70 +1,133 @@
name: docs

on:
pull_request:
paths: &docs-paths
- CHANGES
- README.*
- 'docs/**'
- 'examples/**'
- 'src/libtmux/**'
- uv.lock
- pyproject.toml
- '.github/workflows/docs.yml'
push:
branches:
- master
branches: [master]
tags: ['v*']
paths: *docs-paths
workflow_dispatch:
inputs:
source-ref:
description: Exact source ref to build
required: true
default: master
version:
description: URL version slug
required: true
default: latest
version-kind:
description: Version policy
required: true
type: choice
options: [trunk, tag, alias]
default: trunk
is-default:
description: Make this version canonical
required: true
type: boolean
default: false
resolves-to:
description: Immutable target for an alias
required: false
default: ''
publish:
description: Publish the selected revision to libtmux.org
required: true
type: boolean
default: false

permissions:
contents: read
id-token: write

jobs:
build:
build-libtmux-org:
uses: libtmux/docs/.github/workflows/port-docs.yml@8fda4b89071621b9ed2c4722a68d61f6ecf9c1c4
with:
port: py
source-ref: ${{ inputs.source-ref }}
version: ${{ inputs.version }}
version-kind: ${{ inputs.version-kind }}
is-default: ${{ inputs.is-default == true }}
resolves-to: ${{ inputs.resolves-to }}
publish: ${{ inputs.publish == true }}

# Both reusable workflows must move together to the same reviewed commit.
# Pull requests build only; dispatch publication is an explicit input.
publish-libtmux-org:
needs: build-libtmux-org
if: needs.build-libtmux-org.outputs.should-publish == 'true'
concurrency:
group: docs-deploy-${{ github.repository }}-py
queue: max
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.build-libtmux-org.outputs.matrix) }}
permissions:
contents: read
id-token: write
uses: libtmux/docs/.github/workflows/reusable-deploy.yml@8fda4b89071621b9ed2c4722a68d61f6ecf9c1c4
with:
path-prefix: py/${{ matrix.version }}
artifact: docs-py-${{ matrix.version }}
version-kind: ${{ matrix.kind }}
port: py
version: ${{ matrix.version }}
label: ${{ matrix.version }}
is-default: ${{ matrix.isDefault }}
resolves-to: ${{ matrix.resolvesTo }}
environment: docs
secrets:
role-arn: ${{ secrets.LIBTMUX_ORG_ROLE_ARN }}
bucket: ${{ secrets.LIBTMUX_ORG_BUCKET }}
distribution: ${{ secrets.LIBTMUX_ORG_DISTRIBUTION }}

# The standalone site keeps its root Sphinx build and follows local symlinks.
# Only a default-branch push publishes it; branch dispatches target libtmux.org.
publish-git-pull-com:
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ubuntu-latest
environment: docs
strategy:
matrix:
python-version: ['3.14']
env:
UV_FROZEN: 'true'
permissions:
contents: read
id-token: write
concurrency:
group: docs-git-pull-com-${{ github.repository }}
queue: max
steps:
- uses: actions/checkout@v7

- name: Filter changed file paths to outputs
uses: dorny/paths-filter@v4
id: changes
with:
filters: |
root_docs:
- CHANGES
- README.*
docs:
- 'docs/**'
- 'examples/**'
python_files:
- 'src/libtmux/**'
- uv.lock
- pyproject.toml

- name: Should publish
if: steps.changes.outputs.docs == 'true' || steps.changes.outputs.root_docs == 'true' || steps.changes.outputs.python_files == 'true'
run: echo "PUBLISH=$(echo true)" >> $GITHUB_ENV

- name: Install uv
if: env.PUBLISH == 'true'
uses: astral-sh/setup-uv@v10.0.1
with:
enable-cache: true

- name: Set up Python ${{ matrix.python-version }}
if: env.PUBLISH == 'true'
run: uv python install ${{ matrix.python-version }}
- name: Set up Python
run: uv python install 3.14

- name: Install dependencies [w/ docs]
if: env.PUBLISH == 'true'
run: uv sync --all-extras --dev
run: uv sync --frozen --all-extras --dev

- name: Install just
if: env.PUBLISH == 'true'
uses: extractions/setup-just@v4

- name: Print python versions
if: env.PUBLISH == 'true'
run: |
python -V
uv run python -V

- name: Cache sphinx fonts
if: env.PUBLISH == 'true'
uses: actions/cache@v6
with:
path: ~/.cache/sphinx-fonts
Expand All @@ -73,32 +136,29 @@ jobs:
sphinx-fonts-

- name: Build documentation
if: env.PUBLISH == 'true'
env:
LIBTMUX_DOCS_STANDALONE: '1'
run: |
cd docs && just html

- name: Configure AWS Credentials
if: env.PUBLISH == 'true'
- name: Configure AWS credentials for libtmux.git-pull.com
uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: ${{ secrets.LIBTMUX_DOCS_ROLE_ARN }}
aws-region: us-east-1

- name: Push documentation to S3
if: env.PUBLISH == 'true'
run: |
aws s3 sync docs/_build/html "s3://${{ secrets.LIBTMUX_DOCS_BUCKET }}" \
--delete --follow-symlinks

- name: Invalidate CloudFront
if: env.PUBLISH == 'true'
run: |
aws cloudfront create-invalidation \
--distribution-id "${{ secrets.LIBTMUX_DOCS_DISTRIBUTION }}" \
--paths "/index.html" "/objects.inv" "/searchindex.js"

- name: Purge cache on Cloudflare
if: env.PUBLISH == 'true'
uses: jakejarvis/cloudflare-purge-action@v0.3.0
env:
CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
24.20.0
24.21.0
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
just 1.58.0
uv 0.12.9
uv 0.12.15
python 3.14 3.13 3.12 3.11 3.10
22 changes: 22 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ _Notes on the upcoming release will go here._

### Documentation

#### libtmux.org chrome and site-wide search (#755)

Documentation pages carry libtmux.org's header, footer, and version switcher,
and take their colors from the site's shared design tokens. Sphinx's own
search page redirects to the site-wide search, which covers every libtmux
port. Pages render as stock Furo when the shared stylesheet is unreachable.

#### Cleaner `from_env` examples (#719)

The rendered examples for {meth}`Pane.from_env() <libtmux.Pane.from_env>` and
Expand All @@ -59,6 +66,21 @@ it.

### Development

#### Docs publish to libtmux.org (#756)

The docs build publishes to `libtmux.org` under `en/py/latest/` through the
shared deploy workflow every libtmux port calls, and keeps publishing to
libtmux.git-pull.com unchanged. Each destination takes its own build:
libtmux.org gets the site's shared shell with this port's reference nested
at `api/`, libtmux.git-pull.com the Sphinx site at a root.

#### Docs toolchain on gp-sphinx 0.1.0a38 (#755)

`gp-sphinx` and its sibling extensions move to 0.1.0a38. `sphinx-gp-llms`
resolves from a pinned upstream commit until a release carries its fix:
`genindex`, `py-modindex`, and `search` no longer link a `.md` twin that was
never written.

#### CI actions updated to current majors

Workflow actions moved to their current major releases: `actions/checkout` v7,
Expand Down
131 changes: 131 additions & 0 deletions docs/_static/libtmux-org.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* libtmux.org design-token adapter for Furo.
*
* tokens.css defines ~25 semantic --lt-* names and restyles nothing by
* itself. This is the other half: the table mapping each onto Furo's own
* --color-* contract. Without it a page carries those variables unused in
* the cascade and still paints Furo's stock blue.
*
* Import, never copy. The values stay live at the CDN, so a chrome-color
* fix reaches an already-published build without a rebuild here. Only the
* mapping is fixed at build time, and it moves only when Furo's own
* variable contract does.
*
* Every var(--lt-*) carries Furo's own stock value as its fallback, and
* that is load-bearing rather than decoration. tokens.css is fetched
* cross-origin, so it can 404 — a local preview, a PR preview, any deploy
* before DNS resolves. Per the custom-properties spec, a var() naming an
* undefined property with no fallback resolves to the guaranteed-invalid
* value, so --color-background-primary would compute to `unset` rather
* than white: transparent backgrounds and UA-default text, worse than the
* unskinned page this file exists to fix. The fallbacks are Furo's own
* colors, not libtmux's, so a failed fetch degrades to plain Furo instead
* of vendoring the palette. They track gp-furo-tokens, the package Furo's
* light and dark defaults are generated from.
*
* Scope and order: Furo reads its --color-* tokens at `body` and
* `body[data-theme="dark"]`. This file matches that scope and specificity
* exactly and is listed last in html_css_files (docs/conf.py), so it loads
* after furo-tw.css and wins at equal specificity.
*
* Background on the theme chain and the rejected vendoring alternative is
* in the libtmux.org docs-site repository, under notes/research/.
*/
@import url('https://libtmux.org/_shell/tokens.css');

body {
--color-background-primary: var(--lt-color-bg, white);
--color-background-secondary: var(--lt-color-bg-secondary, #f8f9fb);
--color-background-hover: var(--lt-color-bg-hover, #efeff4);

--color-foreground-primary: var(--lt-color-fg, black);
--color-foreground-secondary: var(--lt-color-fg-secondary, #5a5c63);
--color-foreground-muted: var(--lt-color-fg-muted, #6b6f76);

--color-background-border: var(--lt-color-border, #eeebee);

--color-brand-primary: var(--lt-color-accent, #0a4bff);
--color-brand-content: var(--lt-color-link, #2757dd);
--color-brand-visited: var(--lt-color-link-visited, #872ee0);

--color-inline-code-background: var(--lt-color-code-bg, #f8f9fb);
--color-highlighted-background: var(--lt-color-highlighted-bg, #ddeeff);

--color-api-added: var(--lt-color-added, #21632c);
--color-api-removed: var(--lt-color-removed, #b30000);
--color-api-changed: var(--lt-color-changed, #046172);
--color-api-deprecated: var(--lt-color-deprecated, #605706);

/* Furo's own stock admonition colors diverge per kind even though this
adapter collapses them onto four shared --lt-* accents; the fallback
restores each kind's own stock value, not the collapsed one, since a
degrade should look like unmodified Furo, not a half-applied palette. */
--color-admonition-title--danger: var(--lt-color-danger, #ff5252);
--color-admonition-title--error: var(--lt-color-danger, #ff5252);
--color-admonition-title--attention: var(--lt-color-danger, #ff5252);
--color-admonition-title--warning: var(--lt-color-warning, #ff9100);
--color-admonition-title--caution: var(--lt-color-warning, #ff9100);
--color-admonition-title--note: var(--lt-color-info, #00b0ff);
--color-admonition-title--seealso: var(--lt-color-info, #448aff);
--color-admonition-title--hint: var(--lt-color-success, #00c852);
--color-admonition-title--tip: var(--lt-color-success, #00c852);

--font-stack:
var(--lt-font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial,
sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji');
--font-stack--monospace:
var(--lt-font-mono, 'SFMono-Regular', Menlo, Consolas, Monaco, 'Liberation Mono',
'Lucida Console', monospace);
}

@media not print {
body[data-theme='dark'] {
--color-background-primary: var(--lt-color-bg, #131416);
--color-background-secondary: var(--lt-color-bg-secondary, #1a1c1e);
--color-background-hover: var(--lt-color-bg-hover, #1e2124);

--color-foreground-primary: var(--lt-color-fg, #cfd0d0);
--color-foreground-secondary: var(--lt-color-fg-secondary, #9ca0a5);
--color-foreground-muted: var(--lt-color-fg-muted, #81868d);

--color-background-border: var(--lt-color-border, #303335);

--color-brand-primary: var(--lt-color-accent, #3d94ff);
--color-brand-content: var(--lt-color-link, #5ca5ff);
--color-brand-visited: var(--lt-color-link-visited, #b27aeb);

--color-inline-code-background: var(--lt-color-code-bg, #1a1c1e);
--color-highlighted-background: var(--lt-color-highlighted-bg, #083563);

--color-api-added: var(--lt-color-added, #3db854);
--color-api-removed: var(--lt-color-removed, #ff7575);
--color-api-changed: var(--lt-color-changed, #09b0ce);
--color-api-deprecated: var(--lt-color-deprecated, #b1a10b);
}

@media (prefers-color-scheme: dark) {
body:not([data-theme='light']) {
--color-background-primary: var(--lt-color-bg, #131416);
--color-background-secondary: var(--lt-color-bg-secondary, #1a1c1e);
--color-background-hover: var(--lt-color-bg-hover, #1e2124);

--color-foreground-primary: var(--lt-color-fg, #cfd0d0);
--color-foreground-secondary: var(--lt-color-fg-secondary, #9ca0a5);
--color-foreground-muted: var(--lt-color-fg-muted, #81868d);

--color-background-border: var(--lt-color-border, #303335);

--color-brand-primary: var(--lt-color-accent, #3d94ff);
--color-brand-content: var(--lt-color-link, #5ca5ff);
--color-brand-visited: var(--lt-color-link-visited, #b27aeb);

--color-inline-code-background: var(--lt-color-code-bg, #1a1c1e);
--color-highlighted-background: var(--lt-color-highlighted-bg, #083563);

--color-api-added: var(--lt-color-added, #3db854);
--color-api-removed: var(--lt-color-removed, #ff7575);
--color-api-changed: var(--lt-color-changed, #09b0ce);
--color-api-deprecated: var(--lt-color-deprecated, #b1a10b);
}
}
}
Loading
Loading