1
1
mirror of https://github.com/wez/wezterm.git synced 2024-08-16 17:50:28 +03:00

Merge branch 'wez:main' into title-argument

This commit is contained in:
Rózsavölgyi Dénes 2023-12-27 20:01:24 +01:00 committed by GitHub
commit ffa4ae4878
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
79 changed files with 3604 additions and 2584 deletions

View File

@ -1,17 +1,18 @@
compute_engine_instance:
image_project: freebsd-org-cloud-dev
image: family/freebsd-13-2
platform: freebsd
cpu: 4
memory: 8G
disk: 100 # Gb
env:
CIRRUS_CLONE_SUBMODULES: true
CIRRUS_CLONE_DEPTH: 1
task:
name: freebsd-13
compute_engine_instance:
image_project: freebsd-org-cloud-dev
image: family/freebsd-13-2
platform: freebsd
cpu: 4
memory: 8G
disk: 100 # Gb
stateful: false
only_if: "changesInclude('**.toml', '**.rs', '.gitmodules', '.cirrus.yml', 'get-deps', 'Cargo.lock')"
install_rust_script:
@ -35,3 +36,73 @@ task:
- env PATH=$HOME/.cargo/bin:$PATH cargo build --all --release
test_script:
- env PATH=$HOME/.cargo/bin:$PATH cargo test --all --release
task:
name: ubuntu-22.04-arm
only_if: "$CIRRUS_REPO_OWNER == 'wez' && changesInclude('**.toml', '**.rs', '.gitmodules', '.cirrus.yml', 'get-deps', 'Cargo.lock')"
arm_container:
image: ubuntu:22.04
cpu: 4
memory: 12G
environment:
GITHUB_TOKEN: ENCRYPTED[23bd9513fa7174e74eaddce6a3099cabb22118423591553b23518e8c34bf155e07c559838b1d3422f561c73c1e31e6fc]
stateful: false
install_rust_script:
- echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
- apt update
- apt-get install -y git curl
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
install_gh_cli_script:
- curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg > /usr/share/keyrings/githubcli-archive-keyring.gpg
- chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list
- apt update
- apt install gh -y
- gh --version
getdeps_script:
- env PATH=$HOME/.cargo/bin:$PATH bash get-deps
build_script:
- env PATH=$HOME/.cargo/bin:$PATH cargo build --release -p wezterm-gui -p wezterm -p wezterm-mux-server -p strip-ansi-escapes
- export BUILD_REASON="Schedule"
- export RELEASE="nightly"
- "test -n \"$CIRRUS_TAG\" && BUILD_REASON=\"tag\""
- "test -n \"$CIRRUS_TAG\" && RELEASE=$(ci/tag-name.sh)"
- "./ci/deploy.sh"
- "ls -l *.deb"
- "bash ci/retry.sh gh release upload --clobber ${RELEASE} *.deb"
task:
name: debian-12-arm
only_if: "$CIRRUS_REPO_OWNER == 'wez' && changesInclude('**.toml', '**.rs', '.gitmodules', '.cirrus.yml', 'get-deps', 'Cargo.lock')"
arm_container:
image: debian:12
cpu: 4
memory: 12G
environment:
GITHUB_TOKEN: ENCRYPTED[23bd9513fa7174e74eaddce6a3099cabb22118423591553b23518e8c34bf155e07c559838b1d3422f561c73c1e31e6fc]
stateful: false
install_rust_script:
- echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
- apt update
- apt-get install -y git curl
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
install_gh_cli_script:
- curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg > /usr/share/keyrings/githubcli-archive-keyring.gpg
- chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list
- apt update
- apt install gh -y
- gh --version
getdeps_script:
- env PATH=$HOME/.cargo/bin:$PATH bash get-deps
build_script:
- env PATH=$HOME/.cargo/bin:$PATH cargo build --release -p wezterm-gui -p wezterm -p wezterm-mux-server -p strip-ansi-escapes
- export BUILD_REASON="Schedule"
- export RELEASE="nightly"
- "test -n \"$CIRRUS_TAG\" && BUILD_REASON=\"tag\""
- "test -n \"$CIRRUS_TAG\" && RELEASE=$(ci/tag-name.sh)"
- "./ci/deploy.sh"
- "ls -l *.deb"
- "bash ci/retry.sh gh release upload --clobber ${RELEASE} *.deb"

2
.copr/Makefile Normal file
View File

@ -0,0 +1,2 @@
srpm:
COPR_SRPM=$(outdir) ./ci/copr-build.sh

55
.github/DISCUSSION_TEMPLATE/q-a.yml vendored Normal file
View File

@ -0,0 +1,55 @@
labels: []
body:
- type: markdown
attributes:
value: |
When asking for help troubleshooting something, please remember
to share as much context about what you're trying to do,
specifically what configuration you tried, what happened and how it
didn't match up to what you expected!
- type: dropdown
id: os
attributes:
label: What Operating System(s) are you running on?
multiple: true
options:
- Windows
- Linux X11
- Linux Wayland
- macOS
- FreeBSD X11
- FreeBSD Wayland
validations:
required: true
- type: textarea
id: window_manager
attributes:
label: Which Wayland compositor or X11 Window manager(s) are you using?
description: |
If running on a unix system, please include the name and version of the compositor/WM.
Windows and macOS typically can leave this blank, but if you are using additional window
management software on top of the standard for those systems, please indicate that here.
placeholder: "ex: Sway, Mutter, wayfire, i3."
- type: input
id: version
attributes:
label: WezTerm version
description: |
Please run `wezterm -V` and include its output here.
If you installed the flatpak version of wezterm, please consider trying
the native package format for your system and comparing the behavior,
as flatpak runs in an isolated sandbox that can prevent some functionality
from working fully.
placeholder: "ex: 20210816-085256-935c1f48"
validations:
required: true
- type: textarea
id: description
attributes:
label: Ask your question!
description: |
Please remember to share as much context as you can, as that makes it
quicker and easier for others to understand and respond
placeholder: Tell us what is on your mind!
validations:
required: true

View File

@ -1,4 +1,4 @@
name: fedora36
name: fedora39
on:
pull_request:
@ -8,7 +8,7 @@ on:
- "**/*.rs"
- "**/Cargo.lock"
- "**/Cargo.toml"
- ".github/workflows/gen_fedora36.yml"
- ".github/workflows/gen_fedora39.yml"
- "assets/fonts/**/*"
- "assets/icon/*"
- "assets/open-wezterm-here"
@ -25,7 +25,7 @@ on:
jobs:
build:
runs-on: "ubuntu-latest"
container: "fedora:36"
container: "fedora:39"
steps:
- name: "Install config manager"
@ -55,7 +55,7 @@ jobs:
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "fedora36-None-2-${{ runner.os }}-cargo"
key: "fedora39-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
@ -66,7 +66,7 @@ jobs:
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "fedora36"
cache-key: "fedora39"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
@ -79,5 +79,5 @@ jobs:
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "fedora36"
name: "fedora39"
path: "wezterm-*.rpm"

View File

@ -1,4 +1,4 @@
name: fedora36_continuous
name: fedora39_continuous
on:
schedule:
@ -10,7 +10,7 @@ on:
- "**/*.rs"
- "**/Cargo.lock"
- "**/Cargo.toml"
- ".github/workflows/gen_fedora36_continuous.yml"
- ".github/workflows/gen_fedora39_continuous.yml"
- "assets/fonts/**/*"
- "assets/icon/*"
- "assets/open-wezterm-here"
@ -27,7 +27,7 @@ on:
jobs:
build:
runs-on: "ubuntu-latest"
container: "fedora:36"
container: "fedora:39"
env:
BUILD_REASON: "Schedule"
@ -59,7 +59,7 @@ jobs:
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "fedora36-None-2-${{ runner.os }}-cargo"
key: "fedora39-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
@ -70,7 +70,7 @@ jobs:
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "fedora36"
cache-key: "fedora39"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
@ -79,11 +79,11 @@ jobs:
run: "bash ci/deploy.sh"
- name: "Move RPM"
shell: bash
run: "mv ~/rpmbuild/RPMS/*/*.rpm wezterm-nightly-fedora36.rpm"
run: "mv ~/rpmbuild/RPMS/*/*.rpm wezterm-nightly-fedora39.rpm"
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "fedora36"
name: "fedora39"
path: "wezterm-*.rpm"
retention-days: 5
@ -100,7 +100,7 @@ jobs:
- name: "Download artifact"
uses: actions/download-artifact@v3
with:
name: "fedora36"
name: "fedora39"
- name: "Checksum"
shell: bash
run: "for f in wezterm-*.rpm ; do sha256sum $f > $f.sha256 ; done"

View File

@ -1,4 +1,4 @@
name: fedora36_tag
name: fedora39_tag
on:
push:
@ -8,7 +8,7 @@ on:
jobs:
build:
runs-on: "ubuntu-latest"
container: "fedora:36"
container: "fedora:39"
steps:
- name: "Install config manager"
@ -38,7 +38,7 @@ jobs:
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "fedora36-None-2-${{ runner.os }}-cargo"
key: "fedora39-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
@ -49,7 +49,7 @@ jobs:
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "fedora36"
cache-key: "fedora39"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
@ -62,7 +62,7 @@ jobs:
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "fedora36"
name: "fedora39"
path: "wezterm-*.rpm"
upload:
@ -78,7 +78,7 @@ jobs:
- name: "Download artifact"
uses: actions/download-artifact@v3
with:
name: "fedora36"
name: "fedora39"
- name: "Checksum"
shell: bash
run: "for f in wezterm-*.rpm ; do sha256sum $f > $f.sha256 ; done"

View File

@ -1,86 +0,0 @@
name: opensuse_leap
on:
pull_request:
branches:
- main
paths:
- "**/*.rs"
- "**/Cargo.lock"
- "**/Cargo.toml"
- ".github/workflows/gen_opensuse_leap.yml"
- "assets/fonts/**/*"
- "assets/icon/*"
- "assets/open-wezterm-here"
- "assets/shell-completion/**/*"
- "assets/shell-integration/**/*"
- "assets/wezterm-nautilus.py"
- "assets/wezterm.appdata.xml"
- "assets/wezterm.desktop"
- "ci/deploy.sh"
- "ci/tag-name.sh"
- "get-deps"
- "termwiz/data/wezterm.terminfo"
jobs:
build:
runs-on: "ubuntu-latest"
container: "registry.opensuse.org/opensuse/leap:15.4"
steps:
- name: "Seed GITHUB_PATH to work around possible @action/core bug"
shell: bash
run: 'echo "$PATH:/bin:/usr/bin" >> $GITHUB_PATH'
- name: "Install util-linux"
shell: bash
run: "zypper install -y util-linux"
- name: "Install git"
shell: bash
run: "zypper install -y git"
- name: "Install curl"
shell: bash
run: "zypper install -y curl"
- name: "Ensure /run/sshd exists"
shell: bash
run: "mkdir -p /run/sshd"
- name: "Install openssh-server"
shell: bash
run: "zypper install -y openssh-server"
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
with:
submodules: "recursive"
- name: "Install Rust"
uses: dtolnay/rust-toolchain@stable
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "opensuse_leap-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
- name: "Build (Release mode)"
shell: bash
run: "cargo build --all --release"
- name: "Install cargo-nextest from Cargo"
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "opensuse_leap"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
- name: "Package"
shell: bash
run: "bash ci/deploy.sh"
- name: "Move RPM"
shell: bash
run: "mv /usr/src/packages/RPMS/*/*.rpm ."
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "opensuse_leap"
path: "wezterm-*.rpm"

View File

@ -1,114 +0,0 @@
name: opensuse_leap_continuous
on:
schedule:
- cron: "10 3 * * *"
push:
branches:
- main
paths:
- "**/*.rs"
- "**/Cargo.lock"
- "**/Cargo.toml"
- ".github/workflows/gen_opensuse_leap_continuous.yml"
- "assets/fonts/**/*"
- "assets/icon/*"
- "assets/open-wezterm-here"
- "assets/shell-completion/**/*"
- "assets/shell-integration/**/*"
- "assets/wezterm-nautilus.py"
- "assets/wezterm.appdata.xml"
- "assets/wezterm.desktop"
- "ci/deploy.sh"
- "ci/tag-name.sh"
- "get-deps"
- "termwiz/data/wezterm.terminfo"
jobs:
build:
runs-on: "ubuntu-latest"
container: "registry.opensuse.org/opensuse/leap:15.4"
env:
BUILD_REASON: "Schedule"
steps:
- name: "Seed GITHUB_PATH to work around possible @action/core bug"
shell: bash
run: 'echo "$PATH:/bin:/usr/bin" >> $GITHUB_PATH'
- name: "Install util-linux"
shell: bash
run: "zypper install -y util-linux"
- name: "Install git"
shell: bash
run: "zypper install -y git"
- name: "Install curl"
shell: bash
run: "zypper install -y curl"
- name: "Ensure /run/sshd exists"
shell: bash
run: "mkdir -p /run/sshd"
- name: "Install openssh-server"
shell: bash
run: "zypper install -y openssh-server"
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
with:
submodules: "recursive"
- name: "Install Rust"
uses: dtolnay/rust-toolchain@stable
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "opensuse_leap-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
- name: "Build (Release mode)"
shell: bash
run: "cargo build --all --release"
- name: "Install cargo-nextest from Cargo"
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "opensuse_leap"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
- name: "Package"
shell: bash
run: "bash ci/deploy.sh"
- name: "Move RPM"
shell: bash
run: "mv /usr/src/packages/RPMS/*/*.rpm wezterm-nightly-opensuse_leap.rpm"
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "opensuse_leap"
path: "wezterm-*.rpm"
retention-days: 5
upload:
runs-on: ubuntu-latest
needs: build
steps:
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
- name: "Download artifact"
uses: actions/download-artifact@v3
with:
name: "opensuse_leap"
- name: "Checksum"
shell: bash
run: "for f in wezterm-*.rpm ; do sha256sum $f > $f.sha256 ; done"
- name: "Upload to Nightly Release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: "bash ci/retry.sh gh release upload --clobber nightly wezterm-*.rpm *.sha256"

View File

@ -1,97 +0,0 @@
name: opensuse_leap_tag
on:
push:
tags:
- "20*"
jobs:
build:
runs-on: "ubuntu-latest"
container: "registry.opensuse.org/opensuse/leap:15.4"
steps:
- name: "Seed GITHUB_PATH to work around possible @action/core bug"
shell: bash
run: 'echo "$PATH:/bin:/usr/bin" >> $GITHUB_PATH'
- name: "Install util-linux"
shell: bash
run: "zypper install -y util-linux"
- name: "Install git"
shell: bash
run: "zypper install -y git"
- name: "Install curl"
shell: bash
run: "zypper install -y curl"
- name: "Ensure /run/sshd exists"
shell: bash
run: "mkdir -p /run/sshd"
- name: "Install openssh-server"
shell: bash
run: "zypper install -y openssh-server"
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
with:
submodules: "recursive"
- name: "Install Rust"
uses: dtolnay/rust-toolchain@stable
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "opensuse_leap-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
- name: "Build (Release mode)"
shell: bash
run: "cargo build --all --release"
- name: "Install cargo-nextest from Cargo"
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "opensuse_leap"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
- name: "Package"
shell: bash
run: "bash ci/deploy.sh"
- name: "Move RPM"
shell: bash
run: "mv /usr/src/packages/RPMS/*/*.rpm ."
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "opensuse_leap"
path: "wezterm-*.rpm"
upload:
runs-on: ubuntu-latest
needs: build
steps:
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
- name: "Download artifact"
uses: actions/download-artifact@v3
with:
name: "opensuse_leap"
- name: "Checksum"
shell: bash
run: "for f in wezterm-*.rpm ; do sha256sum $f > $f.sha256 ; done"
- name: "Create pre-release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: "bash ci/retry.sh bash ci/create-release.sh $(ci/tag-name.sh)"
- name: "Upload to Tagged Release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: "bash ci/retry.sh gh release upload --clobber $(ci/tag-name.sh) wezterm-*.rpm *.sha256"

View File

@ -1,89 +0,0 @@
name: opensuse_tumbleweed
on:
pull_request:
branches:
- main
paths:
- "**/*.rs"
- "**/Cargo.lock"
- "**/Cargo.toml"
- ".github/workflows/gen_opensuse_tumbleweed.yml"
- "assets/fonts/**/*"
- "assets/icon/*"
- "assets/open-wezterm-here"
- "assets/shell-completion/**/*"
- "assets/shell-integration/**/*"
- "assets/wezterm-nautilus.py"
- "assets/wezterm.appdata.xml"
- "assets/wezterm.desktop"
- "ci/deploy.sh"
- "ci/tag-name.sh"
- "get-deps"
- "termwiz/data/wezterm.terminfo"
jobs:
build:
runs-on: "ubuntu-latest"
container: "registry.opensuse.org/opensuse/tumbleweed"
steps:
- name: "Seed GITHUB_PATH to work around possible @action/core bug"
shell: bash
run: 'echo "$PATH:/bin:/usr/bin" >> $GITHUB_PATH'
- name: "Install util-linux"
shell: bash
run: "zypper install -y util-linux"
- name: "Install which"
shell: bash
run: "zypper install -y which"
- name: "Install git"
shell: bash
run: "zypper install -y git"
- name: "Install curl"
shell: bash
run: "zypper install -y curl"
- name: "Ensure /run/sshd exists"
shell: bash
run: "mkdir -p /run/sshd"
- name: "Install openssh-server"
shell: bash
run: "zypper install -y openssh-server"
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
with:
submodules: "recursive"
- name: "Install Rust"
uses: dtolnay/rust-toolchain@stable
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "opensuse_tumbleweed-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
- name: "Build (Release mode)"
shell: bash
run: "cargo build --all --release"
- name: "Install cargo-nextest from Cargo"
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "opensuse_tumbleweed"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
- name: "Package"
shell: bash
run: "bash ci/deploy.sh"
- name: "Move RPM"
shell: bash
run: "mv /usr/src/packages/RPMS/*/*.rpm ."
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "opensuse_tumbleweed"
path: "wezterm-*.rpm"

View File

@ -1,117 +0,0 @@
name: opensuse_tumbleweed_continuous
on:
schedule:
- cron: "10 3 * * *"
push:
branches:
- main
paths:
- "**/*.rs"
- "**/Cargo.lock"
- "**/Cargo.toml"
- ".github/workflows/gen_opensuse_tumbleweed_continuous.yml"
- "assets/fonts/**/*"
- "assets/icon/*"
- "assets/open-wezterm-here"
- "assets/shell-completion/**/*"
- "assets/shell-integration/**/*"
- "assets/wezterm-nautilus.py"
- "assets/wezterm.appdata.xml"
- "assets/wezterm.desktop"
- "ci/deploy.sh"
- "ci/tag-name.sh"
- "get-deps"
- "termwiz/data/wezterm.terminfo"
jobs:
build:
runs-on: "ubuntu-latest"
container: "registry.opensuse.org/opensuse/tumbleweed"
env:
BUILD_REASON: "Schedule"
steps:
- name: "Seed GITHUB_PATH to work around possible @action/core bug"
shell: bash
run: 'echo "$PATH:/bin:/usr/bin" >> $GITHUB_PATH'
- name: "Install util-linux"
shell: bash
run: "zypper install -y util-linux"
- name: "Install which"
shell: bash
run: "zypper install -y which"
- name: "Install git"
shell: bash
run: "zypper install -y git"
- name: "Install curl"
shell: bash
run: "zypper install -y curl"
- name: "Ensure /run/sshd exists"
shell: bash
run: "mkdir -p /run/sshd"
- name: "Install openssh-server"
shell: bash
run: "zypper install -y openssh-server"
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
with:
submodules: "recursive"
- name: "Install Rust"
uses: dtolnay/rust-toolchain@stable
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "opensuse_tumbleweed-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
- name: "Build (Release mode)"
shell: bash
run: "cargo build --all --release"
- name: "Install cargo-nextest from Cargo"
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "opensuse_tumbleweed"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
- name: "Package"
shell: bash
run: "bash ci/deploy.sh"
- name: "Move RPM"
shell: bash
run: "mv /usr/src/packages/RPMS/*/*.rpm wezterm-nightly-opensuse_tumbleweed.rpm"
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "opensuse_tumbleweed"
path: "wezterm-*.rpm"
retention-days: 5
upload:
runs-on: ubuntu-latest
needs: build
steps:
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
- name: "Download artifact"
uses: actions/download-artifact@v3
with:
name: "opensuse_tumbleweed"
- name: "Checksum"
shell: bash
run: "for f in wezterm-*.rpm ; do sha256sum $f > $f.sha256 ; done"
- name: "Upload to Nightly Release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: "bash ci/retry.sh gh release upload --clobber nightly wezterm-*.rpm *.sha256"

View File

@ -1,100 +0,0 @@
name: opensuse_tumbleweed_tag
on:
push:
tags:
- "20*"
jobs:
build:
runs-on: "ubuntu-latest"
container: "registry.opensuse.org/opensuse/tumbleweed"
steps:
- name: "Seed GITHUB_PATH to work around possible @action/core bug"
shell: bash
run: 'echo "$PATH:/bin:/usr/bin" >> $GITHUB_PATH'
- name: "Install util-linux"
shell: bash
run: "zypper install -y util-linux"
- name: "Install which"
shell: bash
run: "zypper install -y which"
- name: "Install git"
shell: bash
run: "zypper install -y git"
- name: "Install curl"
shell: bash
run: "zypper install -y curl"
- name: "Ensure /run/sshd exists"
shell: bash
run: "mkdir -p /run/sshd"
- name: "Install openssh-server"
shell: bash
run: "zypper install -y openssh-server"
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
with:
submodules: "recursive"
- name: "Install Rust"
uses: dtolnay/rust-toolchain@stable
- name: "Cache cargo"
uses: Swatinem/rust-cache@v2
with:
key: "opensuse_tumbleweed-None-2-${{ runner.os }}-cargo"
- name: "Install System Deps"
shell: bash
run: "env CI=yes PATH=$PATH ./get-deps"
- name: "Build (Release mode)"
shell: bash
run: "cargo build --all --release"
- name: "Install cargo-nextest from Cargo"
uses: baptiste0928/cargo-install@v2
with:
crate: "cargo-nextest"
cache-key: "opensuse_tumbleweed"
- name: "Test (Release mode)"
shell: bash
run: "cargo nextest run --all --release --no-fail-fast"
- name: "Package"
shell: bash
run: "bash ci/deploy.sh"
- name: "Move RPM"
shell: bash
run: "mv /usr/src/packages/RPMS/*/*.rpm ."
- name: "Upload artifact"
uses: actions/upload-artifact@v3
with:
name: "opensuse_tumbleweed"
path: "wezterm-*.rpm"
upload:
runs-on: ubuntu-latest
needs: build
steps:
- name: "Workaround git permissions issue"
shell: bash
run: "git config --global --add safe.directory /__w/wezterm/wezterm"
- name: "checkout repo"
uses: actions/checkout@v4
- name: "Download artifact"
uses: actions/download-artifact@v3
with:
name: "opensuse_tumbleweed"
- name: "Checksum"
shell: bash
run: "for f in wezterm-*.rpm ; do sha256sum $f > $f.sha256 ; done"
- name: "Create pre-release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: "bash ci/retry.sh bash ci/create-release.sh $(ci/tag-name.sh)"
- name: "Upload to Tagged Release"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: "bash ci/retry.sh gh release upload --clobber $(ci/tag-name.sh) wezterm-*.rpm *.sha256"

View File

@ -16,7 +16,7 @@ jobs:
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v4
- uses: dessant/lock-threads@v5
with:
issue-inactive-days: '30'
issue-comment: >

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ dhat-heap.json
/termwiz/codegen/target
/termwiz/codegen/Cargo.lock
/gh_pages/
/.cache/
/docs/releases.json
/docs/SUMMARY.md
/docs/cli/cli/index.md

View File

@ -11,6 +11,20 @@ and smoother if you have the time and energy to read and follow these suggestion
There's never enough! Pretty much anything is fair game to improve here.
### Running the doc build yourself
To check your documentation additions, you can optionally build the docs yourself and see how the changes will look on the webpage.
To serve them up, and then automatically rebuild and refresh the docs in your browser, run:
```console
$ ci/build-docs.sh serve
```
And then click on the URL that it prints out after it has performed the first build.
Any arguments passed to `build-docs.sh` are passed down to the underlying `mkdocs` utility.
Look at [mkdocs serve](https://www.mkdocs.org/user-guide/cli/#mkdocs-serve) for more information on additional parameters.
### Operating system specific installation instructions?
There are a lot of targets out there. Today we have docs that are Ubuntu biased
@ -44,14 +58,14 @@ I tend to iterate and sanity check as I develop using `cargo check`; it
will type-check your code without generating code which is much faster
than building everything in release mode:
```
```console
$ cargo check
```
Likewise, if you want to quick check that something works, you can run it
in debug mode using:
```
```console
$ cargo run
```
@ -60,7 +74,7 @@ give you more detail in the backtrace produced if you run `RUST_BACKTRACE=1 carg
If you get a panic and want to examine local variables, you'll need to use gdb:
```
```console
$ cargo build
$ gdb ./target/debug/wezterm
$ break rust_panic # hit tab to complete the name of the panic symbol!
@ -74,7 +88,7 @@ This will help ensure that your contributions keep working as things change.
You can run the existing tests using:
```
```console
$ cargo test --all
```
@ -109,7 +123,7 @@ how that process works.
Make sure that the tests are working and that the code is correctly
formatted otherwise the continuous integration system will fail your build:
```
```console
$ rustup component add rustfmt-preview # you only need to do this once
$ cargo test --all
$ cargo fmt --all

1503
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1574,12 +1574,16 @@ _wezterm() {
return 0
;;
wezterm__record)
opts="-h --help [PROG]..."
opts="-h --cwd --help [PROG]..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
fi
case "${prev}" in
--cwd)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
*)
COMPREPLY=()
;;

View File

@ -168,10 +168,10 @@ complete -c wezterm -n "__fish_seen_subcommand_from cli; and __fish_seen_subcomm
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l width -d 'Specify the display width; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value `N` to specify the number of cells, or `Npx` to specify the number of pixels, or `N%` to size relative to the terminal width' -r
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l height -d 'Specify the display height; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value `N` to specify the number of cells, or `Npx` to specify the number of pixels, or `N%` to size relative to the terminal height' -r
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l position -d 'Set the cursor position prior to displaying the image. The default is to use the current cursor position. Coordinates are expressed in cells with 0,0 being the top left cell position' -r
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l tmux-passthru -d 'How to manage passing the escape through to tmux' -r -f -a "{disable ,enable ,detect }"
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l tmux-passthru -d 'How to manage passing the escape through to tmux' -r -f -a "{disable '',enable '',detect ''}"
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l max-pixels -d 'Set the maximum number of pixels per image frame. Images will be scaled down so that they do not exceed this size, unless `--no-resample` is also used. The default value matches the limit set by wezterm. Note that resampling the image here will reduce any animated images to a single frame' -r
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l resample-format -d 'Specify the image format to use to encode resampled/resized images. The default is to match the input format, but you can choose an alternative format' -r -f -a "{png ,jpeg ,input }"
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l resample-filter -d 'Specify the filtering technique used when resizing/resampling images. The default is a reasonable middle ground of speed and quality' -r -f -a "{nearest ,triangle ,catmull-rom ,gaussian ,lanczos3 }"
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l resample-format -d 'Specify the image format to use to encode resampled/resized images. The default is to match the input format, but you can choose an alternative format' -r -f -a "{png '',jpeg '',input ''}"
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l resample-filter -d 'Specify the filtering technique used when resizing/resampling images. The default is a reasonable middle ground of speed and quality' -r -f -a "{nearest '',triangle '',catmull-rom '',gaussian '',lanczos3 ''}"
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l resize -d 'Pre-process the image to resize it to the specified dimensions, expressed as eg: 800x600 (width x height). The resize is independent of other parameters that control the image placement and dimensions in the terminal; this is provided as a convenience preprocessing step' -r
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l no-preserve-aspect-ratio -d 'Do not respect the aspect ratio. The default is to respect the aspect ratio'
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l no-move-cursor -d 'Do not move the cursor after displaying the image. Note that when used like this from the shell, there is a very high chance that shell prompt will overwrite the image; you may wish to also use `--hold` in that case'
@ -179,14 +179,15 @@ complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l hold -d 'Wait for
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l no-resample -d 'Do not resample images whose frames are larger than the max-pixels value. Note that this will typically result in the image refusing to display in wezterm'
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l show-resample-timing -d 'When resampling or resizing, display some diagnostics around the timing/performance of that operation'
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -s h -l help -d 'Print help (see more with \'--help\')'
complete -c wezterm -n "__fish_seen_subcommand_from set-working-directory" -l tmux-passthru -d 'How to manage passing the escape through to tmux' -r -f -a "{disable ,enable ,detect }"
complete -c wezterm -n "__fish_seen_subcommand_from set-working-directory" -l tmux-passthru -d 'How to manage passing the escape through to tmux' -r -f -a "{disable '',enable '',detect ''}"
complete -c wezterm -n "__fish_seen_subcommand_from set-working-directory" -s h -l help -d 'Print help'
complete -c wezterm -n "__fish_seen_subcommand_from record" -l cwd -d 'Start in the specified directory, instead of the default_cwd defined by your wezterm configuration' -r -F
complete -c wezterm -n "__fish_seen_subcommand_from record" -s h -l help -d 'Print help'
complete -c wezterm -n "__fish_seen_subcommand_from replay" -l explain -d 'Explain what is being sent/received'
complete -c wezterm -n "__fish_seen_subcommand_from replay" -l explain-only -d 'Don\'t replay, just show the explanation'
complete -c wezterm -n "__fish_seen_subcommand_from replay" -l cat -d 'Just emit raw escape sequences all at once, with no timing information'
complete -c wezterm -n "__fish_seen_subcommand_from replay" -s h -l help -d 'Print help'
complete -c wezterm -n "__fish_seen_subcommand_from shell-completion" -l shell -d 'Which shell to generate for' -r -f -a "{bash ,elvish ,fish ,power-shell ,zsh ,fig }"
complete -c wezterm -n "__fish_seen_subcommand_from shell-completion" -l shell -d 'Which shell to generate for' -r -f -a "{bash '',elvish '',fish '',power-shell '',zsh '',fig ''}"
complete -c wezterm -n "__fish_seen_subcommand_from shell-completion" -s h -l help -d 'Print help'
complete -c wezterm -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from start; and not __fish_seen_subcommand_from ssh; and not __fish_seen_subcommand_from serial; and not __fish_seen_subcommand_from connect; and not __fish_seen_subcommand_from ls-fonts; and not __fish_seen_subcommand_from show-keys; and not __fish_seen_subcommand_from cli; and not __fish_seen_subcommand_from imgcat; and not __fish_seen_subcommand_from set-working-directory; and not __fish_seen_subcommand_from record; and not __fish_seen_subcommand_from replay; and not __fish_seen_subcommand_from shell-completion; and not __fish_seen_subcommand_from help" -f -a "start" -d 'Start the GUI, optionally running an alternative program'
complete -c wezterm -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from start; and not __fish_seen_subcommand_from ssh; and not __fish_seen_subcommand_from serial; and not __fish_seen_subcommand_from connect; and not __fish_seen_subcommand_from ls-fonts; and not __fish_seen_subcommand_from show-keys; and not __fish_seen_subcommand_from cli; and not __fish_seen_subcommand_from imgcat; and not __fish_seen_subcommand_from set-working-directory; and not __fish_seen_subcommand_from record; and not __fish_seen_subcommand_from replay; and not __fish_seen_subcommand_from shell-completion; and not __fish_seen_subcommand_from help" -f -a "ssh" -d 'Establish an ssh session'

View File

@ -422,9 +422,10 @@ _arguments "${_arguments_options[@]}" \
;;
(record)
_arguments "${_arguments_options[@]}" \
'--cwd=[Start in the specified directory, instead of the default_cwd defined by your wezterm configuration]:CWD:_files' \
'-h[Print help]' \
'--help[Print help]' \
'*::prog:' \
'*::prog -- Start prog instead of the default_prog defined by your wezterm configuration:' \
&& ret=0
;;
(replay)

16
ci/copr-build.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/bash
set -x
set -e
command -v git || dnf install -y git
git config --global --add safe.directory $PWD
git config --global --add safe.directory $PWD/deps/freetype/freetype2
git config --global --add safe.directory $PWD/deps/freetype/libpng
git config --global --add safe.directory $PWD/deps/freetype/zlib
git config --global --add safe.directory $PWD/deps/harfbuzz/harfbuzz
./ci/source-archive.sh
./ci/deploy.sh

View File

@ -134,10 +134,16 @@ case $OSTYPE in
WEZTERM_RPM_VERSION=$(echo ${TAG_NAME#nightly-} | tr - _)
distroid=$(sh -c "source /etc/os-release && echo \$ID" | tr - _)
distver=$(sh -c "source /etc/os-release && echo \$VERSION_ID" | tr - _)
SPEC_RELEASE="1.${distroid}${distver}"
if test -n "${COPR_SRPM}" ; then
SPEC_RELEASE=0
fi
cat > wezterm.spec <<EOF
Name: wezterm
Version: ${WEZTERM_RPM_VERSION}
Release: 1.${distroid}${distver}
Release: ${SPEC_RELEASE}
Packager: Wez Furlong <wez@wezfurlong.org>
License: MIT
URL: https://wezfurlong.org/wezterm/
@ -147,14 +153,60 @@ Requires: dbus-1, fontconfig, openssl, libxcb1, libxkbcommon0, libxkbcommon-x11-
%else
Requires: dbus, fontconfig, openssl, libxcb, libxkbcommon, libxkbcommon-x11, libwayland-client, libwayland-egl, libwayland-cursor, mesa-libEGL, xcb-util-keysyms, xcb-util-wm
%endif
EOF
BUILD_COMMAND=<<EOF
%build
echo build
EOF
if test -n "${COPR_SRPM}" ; then
TAR_NAME=$(git -c "core.abbrev=8" show -s "--format=%cd_%h" "--date=format:%Y%m%d_%H%M%S")
cat >> wezterm.spec <<EOF
BuildRequires: gcc, gcc-c++, make, curl, fontconfig-devel, openssl-devel, libxcb-devel, libxkbcommon-devel, libxkbcommon-x11-devel, wayland-devel, xcb-util-devel, xcb-util-keysyms-devel, xcb-util-image-devel, xcb-util-wm-devel, git
%if 0%{?suse_version}
BuildRequires: Mesa-libEGL-devel
%else
BuildRequires: mesa-libEGL-devel
%endif
Source0: wezterm-${TAR_NAME}.tar.gz
%global debug_package %{nil}
%changelog
* Mon Oct 2 2023 Wez Furlong
- See git for full changelog
EOF
HERE="."
BUILD_COMMAND=$(cat <<EOF
%prep
%autosetup
%build
echo Here I am
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/env
cargo build --release \
-p wezterm-gui -p wezterm -p wezterm-mux-server \
-p strip-ansi-escapes
EOF
)
fi
cat >> wezterm.spec <<EOF
%description
wezterm is a terminal emulator with support for modern features
such as fonts with ligatures, hyperlinks, tabs and multiple
windows.
%build
echo "Doing the build bit here"
${BUILD_COMMAND}
%install
set -x
@ -188,7 +240,12 @@ install -Dm644 assets/wezterm-nautilus.py %{buildroot}/usr/share/nautilus-python
/etc/profile.d/*
EOF
/usr/bin/rpmbuild -bb --rmspec wezterm.spec --verbose
if test -n "${COPR_SRPM}" ; then
/usr/bin/rpmbuild -bs --rmspec wezterm.spec --verbose
mv $(rpm --eval '%{_srcrpmdir}')/wezterm-${TAR_NAME}*.src.rpm "${COPR_SRPM}"/
else
/usr/bin/rpmbuild -bb --rmspec wezterm.spec --verbose
fi
;;
Ubuntu*|Debian*)
@ -249,11 +306,21 @@ EOF
install -Dm644 assets/shell-completion/bash pkg/debian/usr/share/bash-completion/completions/wezterm
install -Dm644 assets/shell-completion/zsh pkg/debian/usr/share/zsh/functions/Completion/Unix/_wezterm
install -Dm644 assets/shell-integration/* -t pkg/debian/etc/profile.d
if [[ "$BUILD_REASON" == "Schedule" ]] ; then
debname=wezterm-nightly.$distro$distver
else
debname=wezterm-$TAG_NAME.$distro$distver
fi
arch=$(dpkg-architecture -q DEB_BUILD_ARCH_CPU)
case $arch in
amd64)
;;
*)
debname="${debname}.${arch}"
;;
esac
fakeroot dpkg-deb --build pkg/debian $debname.deb
if [[ "$BUILD_REASON" != '' ]] ; then

View File

@ -946,15 +946,10 @@ TARGETS = [
Target(name="centos9", container="quay.io/centos/centos:stream9"),
Target(name="macos", os="macos-11"),
# https://fedoraproject.org/wiki/End_of_life?rd=LifeCycle/EOL
Target(container="fedora:36"),
Target(container="fedora:37"),
Target(container="fedora:38"),
Target(container="fedora:39"),
# Target(container="alpine:3.15"),
Target(name="opensuse_leap", container="registry.opensuse.org/opensuse/leap:15.4"),
Target(
name="opensuse_tumbleweed",
container="registry.opensuse.org/opensuse/tumbleweed",
),
Target(name="windows", os="windows-latest", rust_target="x86_64-pc-windows-msvc"),
]

View File

@ -11,6 +11,11 @@ else
TAR_NAME=wezterm-${TAG_NAME}-src.tar
fi
if test -n "${COPR_SRPM}" ; then
TAG_NAME=$(git -c "core.abbrev=8" show -s "--format=%cd_%h" "--date=format:%Y%m%d_%H%M%S")
TAR_NAME=wezterm-${TAG_NAME}.tar
fi
rm -f ${TAR_NAME}*
NAME_PREFIX=wezterm-${TAG_NAME}
@ -47,3 +52,6 @@ tar --delete \
gzip ${TAR_NAME}
if test -n "${COPR_SRPM}" ; then
mv ${TAR_NAME}.gz $(rpm --eval '%{_sourcedir}')
fi

View File

@ -13,6 +13,8 @@ CATEGORIZE = {
r"Debian(\d+)(\.\d+)?\.deb$": "debian\\1_deb",
r"Ubuntu(\d+)(\.\d+)?.AppImage$": "ubuntu\\1_AppImage",
r"Ubuntu(\d+)(\.\d+)?.deb$": "ubuntu\\1_deb",
r"Ubuntu(\d+)(\.\d+)?\.arm64\.deb$": "ubuntu\\1_arm64_deb",
r"Debian(\d+)(\.\d+)?\.arm64\.deb$": "debian\\1_arm64_deb",
r"Ubuntu20.04.tar.xz$": "linux_raw_bin",
r"^wezterm-\d+-\d+-[a-f0-9]+.tar.xz$": "linux_raw_bin",
r"src.tar.gz$": "src",

View File

@ -27,7 +27,7 @@ mlua = {version="0.9", features=["vendored", "lua54", "async", "send"]}
# file change notification
notify = "5.0.0"
once_cell = "1.8"
ordered-float = { version = "3.0", features = ["serde"] }
ordered-float = { version = "4.1", features = ["serde"] }
portable-pty = { path = "../pty", features = ["serde_support"]}
promise = { path = "../promise" }
serde = {version="1.0", features = ["rc", "derive"]}
@ -35,7 +35,7 @@ serde_json = "1.0"
shlex = "1.1"
smol = "1.2"
termwiz = { path = "../termwiz", features=["use_serde"] }
toml = "0.7"
toml = "0.8"
umask = { path = "../umask" }
wezterm-config-derive = { version="0.1", path="derive" }
wezterm-dynamic = { path = "../wezterm-dynamic" }

View File

@ -148,6 +148,7 @@ pub struct Config {
#[dynamic(default = "default_command_palette_font_size")]
pub command_palette_font_size: f64,
pub command_palette_rows: Option<usize>,
#[dynamic(default = "default_command_palette_fg_color")]
pub command_palette_fg_color: RgbaColor,
@ -661,6 +662,9 @@ pub struct Config {
#[dynamic(default)]
pub ime_preedit_rendering: ImePreeditRendering,
#[dynamic(default)]
pub notification_handling: NotificationHandling,
#[dynamic(default = "default_true")]
pub use_dead_keys: bool,
@ -2008,6 +2012,16 @@ pub enum ImePreeditRendering {
System,
}
#[derive(Debug, FromDynamic, ToDynamic, Clone, Copy, PartialEq, Eq, Default)]
pub enum NotificationHandling {
#[default]
AlwaysShow,
NeverShow,
SuppressFromFocusedPane,
SuppressFromFocusedTab,
SuppressFromFocusedWindow,
}
fn validate_row_or_col(value: &u16) -> Result<(), String> {
if *value < 1 {
Err("initial_cols and initial_rows must be non-zero".to_string())

View File

@ -477,6 +477,27 @@ pub struct InputSelector {
#[dynamic(default)]
pub fuzzy: bool,
#[dynamic(default = "default_num_alphabet")]
pub alphabet: String,
#[dynamic(default = "default_description")]
pub description: String,
#[dynamic(default = "default_fuzzy_description")]
pub fuzzy_description: String,
}
fn default_num_alphabet() -> String {
"1234567890abcdefghilmnopqrstuvwxyz".to_string()
}
fn default_description() -> String {
"Select an item and press Enter = accept, Esc = cancel, / = filter".to_string()
}
fn default_fuzzy_description() -> String {
"Fuzzy matching: ".to_string()
}
#[derive(Debug, Clone, PartialEq, FromDynamic, ToDynamic)]

File diff suppressed because it is too large Load Diff

@ -1 +1 @@
Subproject commit 1d665c2b521512cdd56964138fc601debd1f1177
Subproject commit 894a1f72ee93a1fd8dc1d9218cb3fd8f048be29a

View File

@ -1,4 +1,4 @@
/* automatically generated by rust-bindgen 0.65.1 */
/* automatically generated by rust-bindgen 0.66.1 */
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
@ -1303,6 +1303,15 @@ pub type hb_paint_pop_transform_func_t = ::std::option::Option<
user_data: *mut ::std::os::raw::c_void,
),
>;
pub type hb_paint_color_glyph_func_t = ::std::option::Option<
unsafe extern "C" fn(
funcs: *mut hb_paint_funcs_t,
paint_data: *mut ::std::os::raw::c_void,
glyph: hb_codepoint_t,
font: *mut hb_font_t,
user_data: *mut ::std::os::raw::c_void,
) -> hb_bool_t,
>;
pub type hb_paint_push_clip_glyph_func_t = ::std::option::Option<
unsafe extern "C" fn(
funcs: *mut hb_paint_funcs_t,
@ -1523,6 +1532,14 @@ extern "C" {
destroy: hb_destroy_func_t,
);
}
extern "C" {
pub fn hb_paint_funcs_set_color_glyph_func(
funcs: *mut hb_paint_funcs_t,
func: hb_paint_color_glyph_func_t,
user_data: *mut ::std::os::raw::c_void,
destroy: hb_destroy_func_t,
);
}
extern "C" {
pub fn hb_paint_funcs_set_push_clip_glyph_func(
funcs: *mut hb_paint_funcs_t,
@ -1629,6 +1646,14 @@ extern "C" {
paint_data: *mut ::std::os::raw::c_void,
);
}
extern "C" {
pub fn hb_paint_color_glyph(
funcs: *mut hb_paint_funcs_t,
paint_data: *mut ::std::os::raw::c_void,
glyph: hb_codepoint_t,
font: *mut hb_font_t,
) -> hb_bool_t;
}
extern "C" {
pub fn hb_paint_push_clip_glyph(
funcs: *mut hb_paint_funcs_t,

View File

@ -61,7 +61,8 @@ As features stabilize some brief notes about them will accumulate here.
In addition, there are now a number of options for explicitly resizing
as a preprocessing step, and controlling the filtering and format used
by the resizing, along with showing diagnostics around the resize operation. #3264
* Color schemes: [Ef-Cyprus](colorschemes/e/index.md#ef-cyprus),
* Color schemes: [Campbell (Gogh)](colorschemes/c/index.md#campbell-gogh),
[Ef-Cyprus](colorschemes/e/index.md#ef-cyprus),
[Ef-Day](colorschemes/e/index.md#ef-day),
[Ef-Deuteranopia-Dark](colorschemes/e/index.md#ef-deuteranopia-dark),
[Ef-Deuteranopia-Light](colorschemes/e/index.md#ef-deuteranopia-light),
@ -72,13 +73,36 @@ As features stabilize some brief notes about them will accumulate here.
[Ef-Frost](colorschemes/e/index.md#ef-frost),
[Ef-Kassio](colorschemes/e/index.md#ef-kassio),
[Ef-Light](colorschemes/e/index.md#ef-light),
[Ef-Maris-Dark](colorschemes/e/index.md#ef-maris-dark),
[Ef-Maris-Light](colorschemes/e/index.md#ef-maris-light),
[Ef-Night](colorschemes/e/index.md#ef-night),
[Ef-Symbiosis](colorschemes/e/index.md#ef-symbiosis),
[iTerm2 Dark Background](colorschemes/i/index.md#iterm2-dark-background),
[iTerm2 Default](colorschemes/i/index.md#iterm2-default),
[iTerm2 Light Background](colorschemes/i/index.md#iterm2-light-background),
[iTerm2 Pastel Dark Background](colorschemes/i/index.md#iterm2-pastel-dark-background),
[iTerm2 Smoooooth](colorschemes/i/index.md#iterm2-smoooooth),
[iTerm2 Tango Dark](colorschemes/i/index.md#iterm2-tango-dark),
[iTerm2 Tango Light](colorschemes/i/index.md#iterm2-tango-light),
[Modus-Operandi-Deuteranopia](colorschemes/m/index.md#modus-operandi-deuteranopia),
[Modus-Operandi-Tinted](colorschemes/m/index.md#modus-operandi-tinted),
[Modus-Vivendi-Deuteranopia](colorschemes/m/index.md#modus-vivendi-deuteranopia),
[Modus-Vivendi-Tinted](colorschemes/m/index.md#modus-vivendi-tinted),
[Modus-Vivendi-Tritanopia](colorschemes/m/index.md#modus-vivendi-tritanopia),
[Oxocarbon Dark (Gogh)](colorschemes/o/index.md#oxocarbon-dark-gogh),
[Rosé Pine Moon (base16)](colorschemes/r/index.md#rosé-pine-moon-base16)
* Preliminary support for rasterizing fonts with COLR v1 glyphs, such as
more recent versions of Noto Color Emoji. #4148
* [wezterm cli zoom-pane](cli/cli/zoom-pane.md). Thanks to @quantonganh! #4160
* [InputSelector](config/lua/keyassignment/InputSelector.md) has been
enhanced to allow setting an alphabet for quickly launching items beyond
the first 10 items, as well as customizing the description/label text.
Thanks to @Danielkonge! #4226 #4227
* [notification_handling](config/lua/config/notification_handling.md) to
control whether notifications are suppressed based on focus. #3727
* [command_palette_rows](config/lua/config/command_palette_rows.md) to
control how many rows are displayed in the command palette. Thanks to
@exastone! #4595
#### Fixed
* Command Palette was using now-invalid Nerd Font 2.0 symbols for macOS
@ -94,11 +118,30 @@ As features stabilize some brief notes about them will accumulate here.
than the native font dimensions and looked weird when either config option was
not set to `1.0`. #2882
* Using `CloseCurrentPane` could sometimes leave a stranded pane in a tab. #4030
* Wayland: wezterm wouldn't start on Plasma 6 or newer versions of sway. Thanks
to @hexchain! #3996 #4322.
* font-config: when resolving a fallback font for a text cluster like `U+3065,U+2686`
where no single font contains both glyphs, wezterm would fail to show a glyph
for either codepoint. We now split the fallback query up and query for each
individual codepoint separately. #4310
* Gogh color schemes all had the incorrect cursor foreground color. #4257
* Windows: crash on Windows 11 when using DX 12 with the WebGpu frontend. #4279
* macOS: Leak of NSWindow and NSView objects. Thanks to @0f-0b! #4457
* Initial G1 state is non-conformant. Thanks to @ninjalj! #4534 #3962
* Make RIS also clear the alternate screen. Thanks to @ninjalj! #4563
* DECRQCRA: treat uninitialized cells as spaces. Thanks to @ninjalj! #4565
* Clamp cursor position reported by CPR. Thanks to @ninjalj! #4564
* Correct `SUPER` modifier key handling in kitty protocol. Thanks to @gabyx! #4605
* macOS: honor the `window_close_confirmation` config option when quitting the
application. Thanks to @quantonganh! #4420 #4362
* terminfo: added missing terminator to Sync capability. Thanks to @gpanders! #4578
#### Updated
* Bundled harfbuzz to 8.1.1
* Bundled harfbuzz to 8.3.0
* Bundled freetype to 2.13.1
* Bundled Noto Color Emoji font to 2.038
* wgpu to 0.18, which [improves OpenGL compatibility with older GPUs when using
WebGpu with its GL backend on Windows](https://github.com/gfx-rs/wgpu/releases/tag/v0.18.0)
### 20230712-072601-f4abf8fd

File diff suppressed because it is too large Load Diff

View File

@ -263,7 +263,7 @@ $ for scheme in *.sh ; do ; echo $scheme ; \
### Tab Bar Appearance & Colors
The tab bar has two modes; the default is a native looking style, but
is is also possible to enable a retro aesthetic. The configuration
it is also possible to enable a retro aesthetic. The configuration
for the two styles is broadly similar, but there are a few different
details.

View File

@ -0,0 +1,12 @@
---
tags:
- appearance
- command_palette
---
# `command_palette_rows = 14`
{{since('nightly')}}
Specifies the number of rows displayed by the command palette.
[ActivateCommandPalette](../keyassignment/ActivateCommandPalette.md).
If unset or `nil`, a default value based on the terminal display will be used.

View File

@ -2,15 +2,12 @@
tags:
- font
---
# `font_size = 10.0`
# `font_size = 12.0`
Specifies the size of the font, measured in points.
You may use fractional point sizes, such as `13.3`, to fine tune the size.
The default font size is `10.0` points.
{{since('20210314-114017-04b7cedd')}}
The default font size is now `12.0` points.
The default font size is `12.0` points. In earlier versions prior to
`20210314-114017-04b7cedd` it was `10.0`.

View File

@ -2,7 +2,7 @@
tags:
- appearance
---
# `integrated_title_button_style = BUTTONS`
# `integrated_title_buttons = BUTTONS`
{{since('20230408-112425-69ae8472')}}

View File

@ -16,4 +16,4 @@ The value can be a number to specify the number of pixels, or a string with a un
* `"1cell"` - the `cell` suffix indicates the height of the terminal cell, which in turn depends on the font size, font scaling and dpi.
* `"1%"` - the `%` suffix indicates the size of the terminal portion of the display, which is computed based on the number of rows and the size of the cell.
You may use a fractional number such as `"0.5cell"` or numbers large than one such as `"72pt"`.
You may use a fractional number such as `"0.5cell"` or numbers larger than one such as `"72pt"`.

View File

@ -0,0 +1,30 @@
---
tags:
- notifications
---
# `notification_handling = "AlwaysShow"`
{{since('nightly')}}
This option controls how wezterm behaves when a toast notification escape
sequence is received.
The following escape sequences will generate a toast notification:
```console
$ printf "\e]777;notify;%s;%s\e\\" "title" "body"
```
```console
$ printf "\e]9;%s\e\\" "hello there"
```
This configuration option can have one of the following values,
which have the following effects:
* `AlwaysShow` - Show the notification regardless of the current focus
* `NeverShow` - Never show the notification
* `SuppressFromFocusedPane` - Show the notification unless it was generated from the currently focused pane
* `SuppressFromFocusedTab` - Show the notification unless it was generated from the currently focused tab
* `SuppressFromFocusedWindow` - Show the notification unless it was generated from the currently focused window

View File

@ -33,7 +33,7 @@ a string value with a unit suffix:
* `"1cell"` - the `cell` suffix indicates the size of the terminal cell, which in turn depends on the font size, font scaling and dpi. When used for width, the width of the cell is used. When used for height, the height of the cell is used.
* `"1%"` - the `%` suffix indicates the size of the terminal portion of the display, which is computed based on the number of rows/columns and the size of the cell. While it is possible to specify percentage, there are some resize scenarios where the percentage value may not be 100% stable/deterministic, as the size of the padding is used to compute the number of rows/columns.
You may use a fractional number such as `"0.5cell"` or numbers large than one such as `"72pt"`.
You may use a fractional number such as `"0.5cell"` or numbers larger than one such as `"72pt"`.
The default padding is shown below. In earlier releases, the default padding was 0 for each of the possible edges.

View File

@ -40,6 +40,7 @@ Activating the selected item will close the command palette and then invoke the
action.
See also:
* [command_palette_font_size](../config/command_palette_font_size.md)
* [command_palette_fg_color](../config/command_palette_fg_color.md)
* [command_palette_bg_color](../config/command_palette_bg_color.md)
* [command_palette_font_size](../config/command_palette_font_size.md)
* [command_palette_fg_color](../config/command_palette_fg_color.md)
* [command_palette_bg_color](../config/command_palette_bg_color.md)

View File

@ -8,7 +8,7 @@ to select from.
When the user accepts a line, emits an event that allows you to act
upon the input.
`InputSelector` accepts three fields:
`InputSelector` accepts the following fields:
* `title` - the title that will be set for the overlay pane
* `choices` - a lua table consisting of the potential choices. Each entry
@ -22,6 +22,51 @@ upon the input.
objects from the current pane and window, and `id` and `label` hold the
corresponding fields from the selected choice. Both will be `nil` if
the overlay is cancelled without selecting anything.
* `fuzzy` - a boolean that defaults to `false`. If `true`, InputSelector will start
in its fuzzy finding mode (this is equivalent to starting the InputSelector and
pressing / in the default mode).
{{since('nightly')}}
These additional fields are also available:
* `alphabet` - a string of unique characters. The characters in the string are used
to calculate one or two click shortcuts that can be used to quickly choose from
the InputSelector when in the default mode. Defaults to:
`"1234567890abcdefghilmnopqrstuvwxyz"`. (Without j/k so they can be used for movement
up and down.)
* `description` - a string to display when in the default mode. Defaults to:
`"Select an item and press Enter = accept, Esc = cancel, / = filter"`.
* `fuzzy_description` - a string to display when in fuzzy finding mode. Defaults to:
`"Fuzzy matching: "`.
### Key Assignments
The default key assignments in the InputSelector are as follows:
| Action | Key Assignment |
|---------|-------------------|
| Add to selection string until a match is found (if in the default mode) | Any key in `alphabet` {{since('nightly', inline=True)}} |
| Select matching number (if in the default mode) | <kbd>1</kbd> to <kbd>9</kbd> {{since('20230408-112425-69ae8472', inline=True)}} |
| Start fuzzy search (if in the default mode) | <kbd>/</kbd> |
| Add to filtering string (if in fuzzy finding mode) | Any key not listed below |
| Remove from selection or filtering string | <kbd>Backspace</kbd> |
| Pick currently highlighted line | <kbd>Enter</kbd> |
| | <kbd>LeftClick</kbd> (with mouse) |
| Move Down | <kbd>DownArrow</kbd> |
| | <kbd>Ctrl</kbd> + <kbd>N</kbd> |
| | <kbd>Ctrl</kbd> + <kbd>J</kbd> {{since('nightly', inline=True)}} |
| | <kbd>j</kbd> (if not in `alphabet`) |
| Move Up | <kbd>UpArrow</kbd> |
| | <kbd>Ctrl</kbd> + <kbd>P</kbd> |
| | <kbd>Ctrl</kbd> + <kbd>K</kbd> {{since('nightly', inline=True)}} |
| | <kbd>k</kbd> (if not in `alphabet`) |
| Quit | <kbd>Ctrl</kbd> + <kbd>G</kbd> |
| | <kbd>Ctrl</kbd> + <kbd>C</kbd> {{since('nightly', inline=True)}} |
| | <kbd>Escape</kbd> |
Note: If the InputSelector is started with `fuzzy` set to `false`, then <kbd>Backspace</kbd> can go from fuzzy finding mode back to the default mode when pressed while the filtering string is empty.
## Example of choosing some canned text to enter into the terminal
@ -95,7 +140,7 @@ config.keys = {
-- could read or compute data from other sources
local choices = {}
for n = 1, 10 do
for n = 1, 20 do
table.insert(choices, { label = tostring(n) })
end
@ -113,6 +158,8 @@ config.keys = {
end),
title = 'I am title',
choices = choices,
alphabet = '123456789',
description = 'Write the number you want to choose or press / to search.',
},
pane
)
@ -123,5 +170,66 @@ config.keys = {
return config
```
## Example of switching between a list of workspaces with the InputSelector
```lua
local wezterm = require 'wezterm'
local act = wezterm.action
local config = wezterm.config_builder()
config.keys = {
{
key = 'S',
mods = 'CTRL|SHIFT',
action = wezterm.action_callback(function(window, pane)
-- Here you can dynamically construct a longer list if needed
local home = wezterm.home_dir
local workspaces = {
{ id = home, label = 'Home' },
{ id = home .. '/work', label = 'Work' },
{ id = home .. '/personal', label = 'Personal' },
{ id = home .. '/.config', label = 'Config' },
}
window:perform_action(
act.InputSelector {
action = wezterm.action_callback(
function(inner_window, inner_pane, id, label)
if not id and not label then
wezterm.log_info 'cancelled'
else
wezterm.log_info('id = ' .. id)
wezterm.log_info('label = ' .. label)
inner_window:perform_action(
act.SwitchToWorkspace {
name = label,
spawn = {
label = 'Workspace: ' .. label,
cwd = id,
},
},
inner_pane
)
end
end
),
title = 'Choose Workspace',
choices = workspaces,
fuzzy = true,
fuzzy_description = 'Fuzzy find and/or make a workspace',
},
pane
)
end),
},
}
return config
```
See also [PromptInputLine](PromptInputLine.md).

View File

@ -0,0 +1,32 @@
---
title: wezterm.to_string
tags:
- utility
---
# `wezterm.to_string(arg)`
{{since('nightly')}}
This function returns a string representation of any Lua value. In particular
this can be used to get a string representation of a table or userdata.
The intended purpose is as a human readable way to inspect lua values. It is not machine
readable; do not attempt to use it as a serialization format as the format is not guaranteed
to remain the same across different versions of wezterm.
This same representation is used in the [debug overlay](../keyassignment/ShowDebugOverlay.md
when printing the result of an expression from the Lua REPL and for the implicit string
conversions of the parameters passed to [wezterm.log_info](log_info.md).
```lua
local wezterm = require 'wezterm'
assert(wezterm.to_string { 1, 2 } == [=[[
1,
2,
]]=])
assert(wezterm.to_string { a = 1, b = 2 } == [[{
"a": 1,
"b": 2,
}]])
```

View File

@ -1,9 +1,12 @@
Record a terminal session as an asciicast
Usage: wezterm record [PROG]...
Usage: wezterm record [OPTIONS] [PROG]...
Arguments:
[PROG]...
[PROG]... Start prog instead of the default_prog defined by your wezterm
configuration
Options:
-h, --help Print help
--cwd <CWD> Start in the specified directory, instead of the default_cwd
defined by your wezterm configuration
-h, --help Print help

View File

@ -87,13 +87,13 @@ that exactly matches your system you can try installing one from an older versio
of your distribution, or use one of the Debian packages linked below. Failing that,
you can try the AppImage download which should work on most Linux systems.
|Distro | Stable | Nightly |
|------------|------------------|---------------------|
|Ubuntu20 |[{{ ubuntu20_deb_stable_asset }}]({{ ubuntu20_deb_stable }}) |[{{ ubuntu20_deb_nightly_asset }}]({{ ubuntu20_deb_nightly }})|
|Ubuntu22 |[{{ ubuntu22_deb_stable_asset }}]({{ ubuntu22_deb_stable }}) |[{{ ubuntu22_deb_nightly_asset }}]({{ ubuntu22_deb_nightly }})|
|Debian10 |[{{ debian10_deb_stable_asset }}]({{ debian10_deb_stable }}) |[{{ debian10_deb_nightly_asset }}]({{ debian10_deb_nightly }})|
|Debian11 |[{{ debian11_deb_stable_asset }}]({{ debian11_deb_stable }}) |[{{ debian11_deb_nightly_asset }}]({{ debian11_deb_nightly }})|
|Debian12 |Nightly builds only|[{{ debian12_deb_nightly_asset }}]({{ debian12_deb_nightly }})|
|Distro | Stable | Nightly| |
|------------|------------------|--------|------------|
|Ubuntu20 |[amd64]({{ ubuntu20_deb_stable }}) |[amd64]({{ ubuntu20_deb_nightly }})| |
|Ubuntu22 |[amd64]({{ ubuntu22_deb_stable }}) |[amd64]({{ ubuntu22_deb_nightly }})|[arm64]({{ ubuntu22_arm64_deb_nightly}})|
|Debian10 |[amd64]({{ debian10_deb_stable }}) |[amd64]({{ debian10_deb_nightly }})| |
|Debian11 |[amd64]({{ debian11_deb_stable }}) |[amd64]({{ debian11_deb_nightly }})| |
|Debian12 |Nightly builds only|[amd64]({{ debian12_deb_nightly }})|[arm64]({{ debian12_arm64_deb_nightly }}) |
To download and install from the CLI, you can use something like this, which
shows how to install the Ubuntu 20 package:
@ -106,6 +106,33 @@ $ sudo apt install -y ./{{ ubuntu20_deb_stable_asset }}
* The package installs `/usr/bin/wezterm` and `/usr/share/applications/org.wezfurlong.wezterm.desktop`
* Configuration instructions can be [found here](../config/files.md)
## Installing on Fedora and rpm-based Systems via Copr
Nightly builds of wezterm are now available via the [Copr](https://copr.fedorainfracloud.org/) build service.
You can see the current list of available distributions and architectures
[on the wezterm-nightly project page](https://copr.fedorainfracloud.org/coprs/wezfurlong/wezterm-nightly/).
At the time that this page was written, the following distributions are available in Copr for `x86_64` and `aarch64`:
* Centos Stream 8 and 9
* Fedora 38, 39, rawhide
* OpenSUSE Leap 15.5
* OpenSUSE Tumbleweed
* RHEL 8, 9
To perform initial installation:
```console
$ sudo dnf copr enable wezfurlong/wezterm-nightly
$ sudo dnf install wezterm
```
To update:
```console
$ sudo dnf update wezterm
```
## Installing on Fedora and rpm-based Systems
The CI system builds `.rpm` files on CentOS, Fedora and openSUSE systems.
@ -118,11 +145,12 @@ on most Linux systems.
|CentOS7 |[{{ centos7_rpm_stable_asset }}]({{ centos7_rpm_stable }}) |[{{ centos7_rpm_nightly_asset }}]({{ centos7_rpm_nightly }})|
|CentOS8 |[{{ centos8_rpm_stable_asset }}]({{ centos8_rpm_stable }}) |[{{ centos8_rpm_nightly_asset }}]({{ centos8_rpm_nightly }})|
|CentOS9 |[{{ centos9_rpm_stable_asset }}]({{ centos9_rpm_stable }})|[{{ centos9_rpm_nightly_asset }}]({{ centos9_rpm_nightly }})|
|Fedora36 |[{{ fedora36_rpm_stable_asset }}]({{ fedora36_rpm_stable }})|[{{ fedora36_rpm_nightly_asset }}]({{ fedora36_rpm_nightly }})|
|Fedora36 |[{{ fedora36_rpm_stable_asset }}]({{ fedora36_rpm_stable }})|No longer supported|
|Fedora37 |[{{ fedora37_rpm_stable_asset }}]({{ fedora37_rpm_stable }})|[{{ fedora37_rpm_nightly_asset }}]({{ fedora37_rpm_nightly }})|
|Fedora38 |[{{ fedora38_rpm_stable_asset }}]({{ fedora38_rpm_stable }})|[{{ fedora38_rpm_nightly_asset }}]({{ fedora38_rpm_nightly }})|
|openSUSE Leap |[{{ opensuse_leap_rpm_stable_asset }}]({{ opensuse_leap_rpm_stable }})|[{{ opensuse_leap_rpm_nightly_asset }}]({{ opensuse_leap_rpm_nightly }})|
|openSUSE Tumbleweed |[{{ opensuse_tumbleweed_rpm_stable_asset }}]({{ opensuse_tumbleweed_rpm_stable }})|[{{ opensuse_tumbleweed_rpm_nightly_asset }}]({{ opensuse_tumbleweed_rpm_nightly }})|
|Fedora39 |Nightly only|[{{ fedora39_rpm_nightly_asset }}]({{ fedora39_rpm_nightly }})|
|openSUSE Leap |[{{ opensuse_leap_rpm_stable_asset }}]({{ opensuse_leap_rpm_stable }})|Use COPR instead|
|openSUSE Tumbleweed |[{{ opensuse_tumbleweed_rpm_stable_asset }}]({{ opensuse_tumbleweed_rpm_stable }})|Use COPR instead|
To download and install from the CLI you can use something like this, which
shows how to install the Fedora 37 package:
@ -146,9 +174,9 @@ $ zypper install wezterm
## Arch Linux
WezTerm is available in the [Community repository](https://archlinux.org/packages/community/x86_64/wezterm/).
WezTerm is available in the [Extra repository](https://archlinux.org/packages/extra/x86_64/wezterm/).
The version available in the community repository may lag behind the latest wezterm release, so you may
The version available in the extra repository may lag behind the latest wezterm release, so you may
wish to use one of these AUR options:
|What |Where|

View File

@ -115,8 +115,8 @@ markdown_extensions:
base_path: "./docs"
- pymdownx.inlinehilite
- pymdownx.emoji:
emoji_index: !!python/name:materialx.emoji.twemoji
emoji_generator: !!python/name:materialx.emoji.to_svg
emoji_index: !!python/name:material.extensions.emoji.twemoji
emoji_generator: !!python/name:material.extensions.emoji.to_svg
- pymdownx.tasklist:
custom_checkbox: true
- pymdownx.tabbed:

View File

@ -1,18 +1,23 @@
#!/bin/sh
case $1 in
--testing)
TESTING=0
;;
'')
TESTING=1
;;
*)
echo 'get-deps:'
echo ' --testing include dependencies required for tests'
exit 1
;;
esac
TESTING=0
DOCS=0
for arg in "$@"; do
case $arg in
--testing)
TESTING=1
;;
--docs)
DOCS=1
;;
*)
echo 'get-deps:'
echo ' --docs include dependencies required for testing docs'
echo ' --testing include dependencies required for tests'
exit 1
;;
esac
done
NOTFOUND=0
@ -21,7 +26,11 @@ test_cmd() {
}
test_flag() {
test $TESTING -eq 0
test $TESTING -eq 1
}
docs_flag() {
test $DOCS -eq 1
}
if test -z "$SUDO"; then
@ -164,6 +173,9 @@ debian_deps() {
if test_flag; then
$APT install -y 'openssh-server'
fi
if docs_flag; then
$APT install -y 'python3-pip mkdocs'
fi
}
arch_deps() {

View File

@ -55,12 +55,13 @@ impl GoghTheme {
for s in data.themes {
let cursor = RgbaColor::try_from(s.cursorColor)?;
let name = s.name;
let background = RgbaColor::try_from(s.background)?;
schemes.push(ColorSchemeFile {
colors: Palette {
foreground: Some(RgbaColor::try_from(s.foreground)?),
background: Some(RgbaColor::try_from(s.background)?),
cursor_fg: Some(cursor),
background: Some(background),
cursor_fg: Some(background),
cursor_bg: Some(cursor),
cursor_border: Some(cursor),
ansi: Some([

View File

@ -30,6 +30,14 @@ pub fn register(lua: &Lua) -> anyhow::Result<()> {
})?,
)?;
wezterm_mod.set(
"to_string",
lua.create_function(|_, arg: Value| {
let res = ValuePrinter(arg);
Ok(format!("{:#?}", res).to_string())
})?,
)?;
lua.globals().set(
"print",
lua.create_function(|_, args: Variadic<Value>| {

View File

@ -11,4 +11,4 @@ config = { path = "../../config" }
wezterm-dynamic = { path = "../../wezterm-dynamic" }
lazy_static = "1.4"
luahelper = { path = "../../luahelper" }
ordered-float = "3.0"
ordered-float = "4.1"

View File

@ -3,7 +3,7 @@
pub use mlua;
use mlua::{IntoLua, Value as LuaValue};
use std::cell::RefCell;
use std::collections::{BTreeMap, HashSet};
use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::rc::Rc;
use wezterm_dynamic::{FromDynamic, ToDynamic, Value as DynValue};
@ -262,6 +262,7 @@ impl<'lua> std::fmt::Debug for ValuePrinter<'lua> {
ValuePrinterHelper {
visited,
value: self.0.clone(),
is_cycle: false,
}
.fmt(fmt)
}
@ -270,6 +271,7 @@ impl<'lua> std::fmt::Debug for ValuePrinter<'lua> {
struct ValuePrinterHelper<'lua> {
visited: Rc<RefCell<HashSet<usize>>>,
value: LuaValue<'lua>,
is_cycle: bool,
}
impl<'lua> PartialEq for ValuePrinterHelper<'lua> {
@ -304,27 +306,55 @@ impl<'lua> ValuePrinterHelper<'lua> {
}
}
fn is_array_style_table(t: &mlua::Table) -> bool {
let mut keys = BTreeSet::new();
for pair in t.clone().pairs::<LuaValue, LuaValue>() {
match pair {
Ok((key, _)) => match key {
LuaValue::Integer(i) if i >= 1 => {
keys.insert(i);
}
_ => return false,
},
Err(_) => return false,
}
}
// Now see if we have contiguous keys.
// The BTreeSet will iterate the keys in ascending order.
let mut expect = 1;
for key in keys {
if key != expect {
return false;
}
expect += 1;
}
true
}
impl<'lua> std::fmt::Debug for ValuePrinterHelper<'lua> {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
match &self.value {
LuaValue::Table(_) if self.is_cycle => {
fmt.write_fmt(format_args!("table: {:?}", self.value.to_pointer()))
}
LuaValue::Table(t) => {
self.visited
.borrow_mut()
.insert(self.value.to_pointer() as usize);
if let Ok(true) = t.contains_key(1) {
if is_array_style_table(&t) {
// Treat as list
let mut list = fmt.debug_list();
for (idx, value) in t.clone().sequence_values().enumerate() {
for value in t.clone().sequence_values() {
match value {
Ok(value) => {
if !self.has_cycle(&value) {
list.entry(&Self {
visited: Rc::clone(&self.visited),
value,
});
} else {
log::warn!("Ignoring value at ordinal position {} which has cyclical reference", idx);
}
let is_cycle = self.has_cycle(&value);
list.entry(&Self {
visited: Rc::clone(&self.visited),
value,
is_cycle,
});
}
Err(err) => {
list.entry(&err);
@ -341,26 +371,19 @@ impl<'lua> std::fmt::Debug for ValuePrinterHelper<'lua> {
for pair in t.clone().pairs::<LuaValue, LuaValue>() {
match pair {
Ok(pair) => {
if !self.has_cycle(&pair.1) {
map.insert(
Self {
visited: Rc::clone(&self.visited),
value: pair.0,
},
Self {
visited: Rc::clone(&self.visited),
value: pair.1,
},
);
} else {
log::warn!(
"Ignoring field {:?} which has cyclical reference",
Self {
visited: Rc::clone(&self.visited),
value: pair.0
}
);
}
let is_cycle = self.has_cycle(&pair.1);
map.insert(
Self {
visited: Rc::clone(&self.visited),
value: pair.0,
is_cycle: false,
},
Self {
visited: Rc::clone(&self.visited),
value: pair.1,
is_cycle,
},
);
}
Err(err) => {
log::error!("error while retrieving map entry: {}", err);
@ -371,6 +394,9 @@ impl<'lua> std::fmt::Debug for ValuePrinterHelper<'lua> {
fmt.debug_map().entries(&map).finish()
}
}
LuaValue::UserData(_) if self.is_cycle => {
fmt.write_fmt(format_args!("userdata: {:?}", self.value.to_pointer()))
}
LuaValue::UserData(ud) => {
if let Ok(mt) = ud.get_metatable() {
if let Ok(to_dynamic) = mt.get::<mlua::Function>("__wezterm_to_dynamic") {
@ -378,6 +404,7 @@ impl<'lua> std::fmt::Debug for ValuePrinterHelper<'lua> {
Ok(value) => Self {
visited: Rc::clone(&self.visited),
value,
is_cycle: false,
}
.fmt(fmt),
Err(err) => write!(fmt, "Error calling __wezterm_to_dynamic: {err}"),
@ -390,6 +417,23 @@ impl<'lua> std::fmt::Debug for ValuePrinterHelper<'lua> {
}
}
LuaValue::Error(e) => fmt.write_fmt(format_args!("error {}", e)),
LuaValue::String(s) => match s.to_str() {
Ok(s) => fmt.write_fmt(format_args!("\"{}\"", s.escape_default())),
Err(_) => {
let mut binary_string = "b\"".to_string();
for &b in s.as_bytes() {
if let Some(c) = char::from_u32(b as u32) {
if c.is_ascii_alphanumeric() || c.is_ascii_punctuation() || c == ' ' {
binary_string.push(c);
continue;
}
}
binary_string.push_str(&format!("\\x{b:02x}"));
}
binary_string.push('"');
fmt.write_str(&binary_string)
}
},
_ => match self.value.to_string() {
Ok(s) => fmt.write_str(&s),
Err(err) => write!(fmt, "({err:#})"),

View File

@ -485,6 +485,15 @@ impl Mux {
}
}
pub fn resolve_focused_pane(
&self,
client_id: &ClientId,
) -> Option<(DomainId, WindowId, TabId, PaneId)> {
let pane_id = self.clients.read().get(client_id)?.focused_pane_id?;
let (domain, window, tab) = self.resolve_pane_id(pane_id)?;
Some((domain, window, tab, pane_id))
}
pub fn record_focus_for_client(&self, client_id: &ClientId, pane_id: PaneId) {
let mut prior = None;
if let Some(info) = self.clients.write().get_mut(client_id) {

View File

@ -22,6 +22,6 @@ sqlite-cache = "0.1.3"
tar = "0.4"
tempfile = "3.3"
tokio = { version = "1.19", features = ["rt-multi-thread", "sync", "macros"] }
toml = "0.7"
toml = "0.8"
wezterm-dynamic = { path = "../wezterm-dynamic" }
yaml-rust = "0.4.5"

View File

@ -3,7 +3,7 @@ use anyhow::Context;
use config::{ColorSchemeFile, ColorSchemeMetaData};
use serde::Deserialize;
use sqlite_cache::Cache;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use std::path::Path;
use std::time::Duration;
use tar::Archive;
@ -103,95 +103,13 @@ fn make_prefix(key: &str) -> (char, String) {
panic!("no good prefix");
}
fn bake_for_config(mut schemeses: Vec<Scheme>) -> anyhow::Result<()> {
let json_file_name = "docs/colorschemes/data.json";
let mut version_by_color_scheme = BTreeMap::new();
let mut names_by_color_scheme = BTreeMap::new();
let mut version_by_name = BTreeMap::new();
if let Ok(data) = std::fs::read_to_string(&json_file_name) {
#[derive(Deserialize)]
struct Entry {
colors: serde_json::Value,
metadata: MetaData,
}
#[derive(Deserialize)]
struct MetaData {
name: String,
aliases: Vec<String>,
wezterm_version: Option<String>,
}
let existing: Vec<Entry> = serde_json::from_str(&data)?;
for item in existing {
if let Some(version) = &item.metadata.wezterm_version {
let ident = serde_json::to_string(&item.colors)?;
version_by_color_scheme.insert(ident.to_string(), version.to_string());
version_by_name.insert(item.metadata.name.to_string(), version.to_string());
let mut names = item.metadata.aliases;
names.insert(0, item.metadata.name);
for name in names {
names_by_color_scheme
.entry(ident.to_string())
.or_insert_with(Vec::new)
.push(name);
}
}
}
let existing: Vec<serde_json::Value> = serde_json::from_str(&data)?;
for item in existing {
let data = ColorSchemeFile::from_json_value(&item)?;
push_or_alias(
&mut schemeses,
Scheme {
name: data.metadata.name.as_ref().unwrap().to_string(),
file_name: None,
data,
},
);
}
for scheme in &mut schemeses {
let json = scheme.to_json_value()?;
let ident = serde_json::to_string(json.get("colors").unwrap())?;
if let Some(version) = version_by_color_scheme
.get(&ident)
.or_else(|| version_by_name.get(&scheme.name))
.or_else(|| {
for a in &scheme.data.metadata.aliases {
if let Some(v) = version_by_name.get(a) {
return Some(v);
}
}
None
})
{
scheme
.data
.metadata
.wezterm_version
.replace(version.to_string());
}
}
}
const DATA_FILE_NAME: &str = "docs/colorschemes/data.json";
fn bake_for_config(schemeses: SchemeSet) -> anyhow::Result<()> {
let mut all = vec![];
for s in &schemeses {
for s in schemeses.by_name.values() {
// Only interested in aliases with different-enough names
let mut aliases = s.data.metadata.aliases.clone();
let json = s.to_json_value()?;
let ident = serde_json::to_string(json.get("colors").unwrap())?;
if let Some(more_aliases) = names_by_color_scheme.get(&ident) {
for a in more_aliases {
aliases.push(a.to_string());
}
}
aliases.sort();
aliases.dedup();
aliases.retain(|name| name != &s.name);
@ -257,105 +175,200 @@ pub const SCHEMES: [(&'static str, &'static str); {count}] = [\n
}
let json = serde_json::to_string_pretty(&doc_data)?;
let update = match std::fs::read_to_string(json_file_name) {
let update = match std::fs::read_to_string(&DATA_FILE_NAME) {
Ok(existing) => existing != json,
Err(_) => true,
};
if update {
println!("Updating {json_file_name}");
std::fs::write(json_file_name, json)?;
println!("Updating {DATA_FILE_NAME}");
std::fs::write(&DATA_FILE_NAME, json)?;
}
Ok(())
}
fn push_or_alias(schemeses: &mut Vec<Scheme>, candidate: Scheme) -> bool {
let mut aliased = false;
for existing in schemeses.iter_mut() {
if candidate.data.colors == existing.data.colors {
log::info!("Adding {} as alias of {}", candidate.name, existing.name);
existing.data.metadata.aliases.push(candidate.name.clone());
aliased = true;
struct SchemeSet {
by_name: HashMap<String, Scheme>,
version_by_color_scheme: BTreeMap<String, String>,
version_by_name: BTreeMap<String, String>,
}
impl SchemeSet {
pub fn accumulate(&mut self, to_add: Vec<Scheme>) {
for candidate in to_add {
self.add(candidate);
}
}
if !aliased {
log::info!("Adding {}", candidate.name);
schemeses.push(candidate);
}
aliased
}
fn accumulate(schemeses: &mut Vec<Scheme>, to_add: Vec<Scheme>) {
// Only accumulate if the scheme looks different enough
for candidate in to_add {
push_or_alias(schemeses, candidate);
}
}
pub fn load_existing() -> anyhow::Result<Self> {
let mut by_name = HashMap::new();
let mut version_by_color_scheme = BTreeMap::new();
let mut names_by_color_scheme = BTreeMap::new();
let mut version_by_name = BTreeMap::new();
async fn sync_toml(
repo_url: &str,
branch: &str,
suffix: &str,
schemeses: &mut Vec<Scheme>,
) -> anyhow::Result<()> {
let tarball_url = if repo_url.starts_with("https://codeberg.org/") {
format!("{repo_url}/archive/{branch}.tar.gz")
} else {
format!("{repo_url}/tarball/{branch}")
};
let tar_data = fetch_url(&tarball_url).await?;
let decoder = libflate::gzip::Decoder::new(tar_data.as_slice())?;
let mut tar = Archive::new(decoder);
for entry in tar.entries()? {
let mut entry = entry?;
if let Ok(data) = std::fs::read_to_string(&DATA_FILE_NAME) {
#[derive(Deserialize)]
struct Entry {
colors: serde_json::Value,
metadata: MetaData,
}
#[derive(Deserialize)]
struct MetaData {
name: String,
aliases: Vec<String>,
wezterm_version: Option<String>,
}
if entry
.path()?
.extension()
.and_then(|s| s.to_str())
.map(|s| s == "toml")
.unwrap_or(false)
{
let dest_file = NamedTempFile::new()?;
entry.unpack(dest_file.path())?;
let existing: Vec<Entry> = serde_json::from_str(&data)?;
for item in existing {
if let Some(version) = &item.metadata.wezterm_version {
let ident = serde_json::to_string(&item.colors)?;
version_by_color_scheme.insert(ident.to_string(), version.to_string());
version_by_name.insert(item.metadata.name.to_string(), version.to_string());
let data = std::fs::read_to_string(dest_file.path())?;
let mut names = item.metadata.aliases;
names.insert(0, item.metadata.name);
match ColorSchemeFile::from_toml_str(&data) {
Ok(mut scheme) => {
let name = match scheme.metadata.name {
Some(name) => name,
None => entry
.path()?
.file_stem()
.unwrap()
.to_str()
.unwrap()
.to_string(),
};
let name = format!("{name}{suffix}");
scheme.metadata.name = Some(name.clone());
if scheme.metadata.origin_url.is_none() {
scheme.metadata.origin_url = Some(repo_url.to_string());
for name in names {
names_by_color_scheme
.entry(ident.to_string())
.or_insert_with(Vec::new)
.push(name);
}
apply_nightly_version(&mut scheme.metadata);
let scheme = Scheme {
name: name.clone(),
file_name: None,
data: scheme,
};
push_or_alias(schemeses, scheme);
}
Err(err) => {
log::error!("{tarball_url}/{}: {err:#}", entry.path().unwrap().display());
}
let existing: Vec<serde_json::Value> = serde_json::from_str(&data)?;
for item in existing {
let data = ColorSchemeFile::from_json_value(&item)?;
let name = data.metadata.name.as_ref().unwrap().to_string();
by_name.insert(
name.to_string(),
Scheme {
name,
file_name: None,
data,
},
);
}
}
Ok(Self {
by_name,
version_by_color_scheme,
version_by_name,
})
}
pub fn add(&mut self, mut candidate: Scheme) {
for existing in self.by_name.values_mut() {
if candidate == *existing || candidate.data.colors == existing.data.colors {
log::info!("Adding {} as alias of {}", candidate.name, existing.name);
existing.data.metadata.aliases.push(candidate.name.clone());
return;
}
}
// Resolve wezterm version information for this scheme
let json = candidate.to_json_value().expect("scheme to be json compat");
let ident =
serde_json::to_string(json.get("colors").unwrap()).expect("colors to be json compat");
if let Some(version) = self
.version_by_color_scheme
.get(&ident)
.or_else(|| self.version_by_name.get(&candidate.name))
.or_else(|| {
for a in &candidate.data.metadata.aliases {
if let Some(v) = self.version_by_name.get(a) {
return Some(v);
}
}
None
})
{
candidate
.data
.metadata
.wezterm_version
.replace(version.to_string());
}
if let Some(existing) = self.by_name.remove(&candidate.name) {
// Already exists but we didn't find it by exact color match
// above.
candidate.data.metadata.aliases = existing.data.metadata.aliases;
println!("Updating {}", candidate.name);
} else {
println!("Adding {}", candidate.name);
}
self.by_name.insert(candidate.name.to_string(), candidate);
}
async fn sync_toml(
&mut self,
repo_url: &str,
branch: &str,
suffix: &str,
) -> anyhow::Result<()> {
let tarball_url = if repo_url.starts_with("https://codeberg.org/") {
format!("{repo_url}/archive/{branch}.tar.gz")
} else {
format!("{repo_url}/tarball/{branch}")
};
let tar_data = fetch_url(&tarball_url).await?;
let decoder = libflate::gzip::Decoder::new(tar_data.as_slice())?;
let mut tar = Archive::new(decoder);
for entry in tar.entries()? {
let mut entry = entry?;
if entry
.path()?
.extension()
.and_then(|s| s.to_str())
.map(|s| s == "toml")
.unwrap_or(false)
{
let dest_file = NamedTempFile::new()?;
entry.unpack(dest_file.path())?;
let data = std::fs::read_to_string(dest_file.path())?;
match ColorSchemeFile::from_toml_str(&data) {
Ok(mut scheme) => {
let name = match scheme.metadata.name {
Some(name) => name,
None => entry
.path()?
.file_stem()
.unwrap()
.to_str()
.unwrap()
.to_string(),
};
let name = format!("{name}{suffix}");
scheme.metadata.name = Some(name.clone());
if scheme.metadata.origin_url.is_none() {
scheme.metadata.origin_url = Some(repo_url.to_string());
}
apply_nightly_version(&mut scheme.metadata);
let scheme = Scheme {
name: name.clone(),
file_name: None,
data: scheme,
};
self.add(scheme);
}
Err(err) => {
log::error!("{tarball_url}/{}: {err:#}", entry.path().unwrap().display());
}
}
}
}
Ok(())
}
Ok(())
}
#[tokio::main]
@ -363,83 +376,51 @@ async fn main() -> anyhow::Result<()> {
env_logger::init();
// They color us! my precious!
let mut schemeses = vec![];
sync_toml(
"https://github.com/catppuccin/wezterm",
"main",
"",
&mut schemeses,
)
.await?;
sync_toml(
"https://github.com/EdenEast/nightfox.nvim",
"main",
"",
&mut schemeses,
)
.await?;
sync_toml(
"https://github.com/Hiroya-W/wezterm-sequoia-theme",
"main",
"",
&mut schemeses,
)
.await?;
sync_toml(
"https://github.com/dracula/wezterm",
"main",
"",
&mut schemeses,
)
.await?;
sync_toml(
"https://github.com/olivercederborg/poimandres.nvim",
"main",
"",
&mut schemeses,
)
.await?;
sync_toml(
"https://github.com/folke/tokyonight.nvim",
"main",
"",
&mut schemeses,
)
.await?;
sync_toml(
"https://codeberg.org/anhsirk0/wezterm-themes",
"main",
"",
&mut schemeses,
)
.await?;
sync_toml(
"https://github.com/hardhackerlabs/theme-wezterm",
"master",
"",
&mut schemeses,
)
.await?;
sync_toml(
"https://github.com/ribru17/bamboo.nvim",
"master",
"",
&mut schemeses,
)
.await?;
accumulate(
&mut schemeses,
iterm2::sync_iterm2().await.context("sync iterm2")?,
);
accumulate(&mut schemeses, base16::sync().await.context("sync base16")?);
accumulate(
&mut schemeses,
gogh::sync_gogh().await.context("sync gogh")?,
);
accumulate(
&mut schemeses,
sexy::sync_sexy().await.context("sync sexy")?,
);
let mut schemeses = SchemeSet::load_existing()?;
schemeses
.sync_toml("https://github.com/catppuccin/wezterm", "main", "")
.await?;
schemeses
.sync_toml("https://github.com/EdenEast/nightfox.nvim", "main", "")
.await?;
schemeses
.sync_toml(
"https://github.com/Hiroya-W/wezterm-sequoia-theme",
"main",
"",
)
.await?;
schemeses
.sync_toml("https://github.com/dracula/wezterm", "main", "")
.await?;
schemeses
.sync_toml(
"https://github.com/olivercederborg/poimandres.nvim",
"main",
"",
)
.await?;
schemeses
.sync_toml("https://github.com/folke/tokyonight.nvim", "main", "")
.await?;
schemeses
.sync_toml("https://codeberg.org/anhsirk0/wezterm-themes", "main", "")
.await?;
schemeses
.sync_toml(
"https://github.com/hardhackerlabs/theme-wezterm",
"master",
"",
)
.await?;
schemeses
.sync_toml("https://github.com/ribru17/bamboo.nvim", "master", "")
.await?;
schemeses.accumulate(iterm2::sync_iterm2().await.context("sync iterm2")?);
schemeses.accumulate(base16::sync().await.context("sync base16")?);
schemeses.accumulate(gogh::sync_gogh().await.context("sync gogh")?);
schemeses.accumulate(sexy::sync_sexy().await.context("sync sexy")?);
bake_for_config(schemeses)?;
Ok(())

View File

@ -27,7 +27,7 @@ lazy_static = "1.4"
log = "0.4"
lru = "0.7"
num-traits = "0.2"
ordered-float = "3.0"
ordered-float = "4.1"
serde = {version="1.0", features = ["rc"]}
terminfo = "0.8"
unicode-normalization = "0.1.21"

View File

@ -546,7 +546,7 @@ impl TerminalState {
last_mouse_move: None,
cursor_visible: true,
g0_charset: CharSet::Ascii,
g1_charset: CharSet::DecLineDrawing,
g1_charset: CharSet::Ascii,
shift_out: false,
newline_mode: false,
current_mouse_buttons: vec![],
@ -929,6 +929,11 @@ impl TerminalState {
}
}
/// Returns the current cell attributes of the screen
pub fn pen(&self) -> CellAttributes {
self.pen.clone()
}
pub fn user_vars(&self) -> &HashMap<String, String> {
&self.user_vars
}
@ -1248,6 +1253,9 @@ impl TerminalState {
self.reverse_video_mode = false;
self.bidi_enabled.take();
self.bidi_hint.take();
self.g0_charset = CharSet::Ascii;
self.g1_charset = CharSet::Ascii;
}
Device::RequestPrimaryDeviceAttributes => {
let mut ident = "\x1b[?65".to_string(); // Vt500
@ -1345,6 +1353,22 @@ impl TerminalState {
}
}
/// Indicates that mode is permanently enabled
fn decqrm_response_permanent(&mut self, mode: Mode) {
let (is_dec, number) = match &mode {
Mode::QueryDecPrivateMode(DecPrivateMode::Code(code)) => (true, code.to_u16().unwrap()),
Mode::QueryDecPrivateMode(DecPrivateMode::Unspecified(code)) => (true, *code),
Mode::QueryMode(TerminalMode::Code(code)) => (false, code.to_u16().unwrap()),
Mode::QueryMode(TerminalMode::Unspecified(code)) => (false, *code),
_ => unreachable!(),
};
let prefix = if is_dec { "?" } else { "" };
write!(self.writer, "\x1b[{prefix}{number};3$y").ok();
self.writer.flush().ok();
}
fn decqrm_response(&mut self, mode: Mode, mut recognized: bool, enabled: bool) {
let (is_dec, number) = match &mode {
Mode::QueryDecPrivateMode(DecPrivateMode::Code(code)) => (true, code.to_u16().unwrap()),
@ -1449,6 +1473,21 @@ impl TerminalState {
self.decqrm_response(mode, true, self.left_and_right_margin_mode);
}
Mode::SetDecPrivateMode(DecPrivateMode::Code(
DecPrivateModeCode::GraphemeClustering,
))
| Mode::ResetDecPrivateMode(DecPrivateMode::Code(
DecPrivateModeCode::GraphemeClustering,
)) => {
// Permanently enabled
}
Mode::QueryDecPrivateMode(DecPrivateMode::Code(
DecPrivateModeCode::GraphemeClustering,
)) => {
self.decqrm_response_permanent(mode);
}
Mode::SetDecPrivateMode(DecPrivateMode::Code(DecPrivateModeCode::SaveCursor)) => {
self.dec_save_cursor();
}
@ -1940,7 +1979,17 @@ impl TerminalState {
checksum += u16::from(ch as u8);
}
}
checksum
// Treat uninitialized cells as spaces.
// The concept of uninitialized cells in wezterm is not the same as that on VT520 or that
// on xterm, so, to prevent a lot of noise in esctest, treat them as spaces, at least when
// asking for the checksum of a single cell (which is what esctest does).
// See: https://github.com/wez/wezterm/pull/4565
if checksum == 0 {
32u16
} else {
checksum
}
}
fn perform_csi_window(&mut self, window: Window) {
@ -2474,11 +2523,15 @@ impl TerminalState {
})) as u32,
);
let col = OneBased::from_zero_based(
(self.cursor.x.saturating_sub(if self.dec_origin_mode {
self.left_and_right_margins.start
} else {
0
})) as u32,
(self
.cursor
.x
.min(self.screen().physical_cols - 1)
.saturating_sub(if self.dec_origin_mode {
self.left_and_right_margins.start
} else {
0
})) as u32,
);
let report = CSI::Cursor(Cursor::ActivePositionReport { line, col });
write!(self.writer, "{}", report).ok();
@ -2545,7 +2598,7 @@ impl TerminalState {
pen: Default::default(),
dec_origin_mode: false,
g0_charset: CharSet::Ascii,
g1_charset: CharSet::DecLineDrawing,
g1_charset: CharSet::Ascii,
});
debug!(
"restore cursor {:?} is_alt={}",

View File

@ -687,7 +687,7 @@ impl<'a> Performer<'a> {
self.current_mouse_buttons.clear();
self.cursor_visible = true;
self.g0_charset = CharSet::Ascii;
self.g1_charset = CharSet::DecLineDrawing;
self.g1_charset = CharSet::Ascii;
self.shift_out = false;
self.newline_mode = false;
self.tabs = TabStop::new(self.screen().physical_cols, 8);
@ -700,6 +700,8 @@ impl<'a> Performer<'a> {
self.accumulating_title.take();
self.screen.full_reset();
self.screen.activate_alt_screen(seqno);
self.erase_in_display(EraseInDisplay::EraseDisplay);
self.screen.activate_primary_screen(seqno);
self.erase_in_display(EraseInDisplay::EraseScrollback);
self.erase_in_display(EraseInDisplay::EraseDisplay);

View File

@ -726,7 +726,7 @@ fn test_dec_special_graphics() {
);
term = TestTerm::new(2, 50, 0);
term.print("\u{0e}SO-ABCabcdefghijklmnopqrstuvwxyzDEF\r\n\u{0f}SI-hello");
term.print("\u{1b})0\u{0e}SO-ABCabcdefghijklmnopqrstuvwxyzDEF\r\n\u{0f}SI-hello");
assert_visible_contents(
&term,
file!(),

View File

@ -28,7 +28,7 @@ libc = "0.2"
log = "0.4"
memmem = "0.1"
num-traits = "0.2"
ordered-float = "3.0"
ordered-float = "4.1"
pest = "2.1"
pest_derive = "2.1"
phf = "0.11"

View File

@ -29,7 +29,7 @@ wezterm|Wez's terminal emulator,
Cr=\E]112\007, Cs=\E]12;%p1%s\007, Ms=\E]52;%p1%s;%p2%s\007, Se=\E[2\sq,
Ss=\E[%p1%d\sq,
Smulx=\E[4:%p1%dm,
Sync=\E[?2026%?%p1%{1}%-%tl%eh,
Sync=\E[?2026%?%p1%{1}%-%tl%eh%;,
Setulc=\E[58:2::%p1%{65536}%/%d:%p1%{256}%/%{255}%&%d:%p1%{255}%&%d%;m,
Smol=\E[53m,
am, bce, ccc, km, mc5i, mir, msgr, npc, xenl,

View File

@ -219,7 +219,9 @@ impl Capabilities {
if has_true_color {
ColorLevel::TrueColor
} else if let Some(cap::MaxColors(n)) = db.get::<cap::MaxColors>() {
if n >= 256 {
if n >= 16777216 {
ColorLevel::TrueColor
} else if n >= 256 {
ColorLevel::TwoFiftySix
} else {
ColorLevel::Sixteen

View File

@ -669,9 +669,7 @@ impl TeenyString {
let len = bytes.len();
let width = width.unwrap_or_else(|| grapheme_column_width(s, unicode_version));
if len < std::mem::size_of::<u64>() {
debug_assert!(width < 3);
if len < std::mem::size_of::<u64>() && width < 3 {
let mut word = 0u64;
unsafe {
std::ptr::copy_nonoverlapping(

View File

@ -841,6 +841,11 @@ pub enum DecPrivateModeCode {
EnableAlternateScreen = 47,
OptEnableAlternateScreen = 1047,
BracketedPaste = 2004,
/// <https://github.com/contour-terminal/terminal-unicode-core/>
/// Grapheme clustering mode
GraphemeClustering = 2027,
/// Applies to sixel and regis modes
UsePrivateColorRegistersForEachGraphic = 1070,

View File

@ -136,8 +136,16 @@ impl TerminfoRenderer {
}
let has_true_color = self.caps.color_level() == ColorLevel::TrueColor;
let terminfo_color: i32 = match self.get_capability::<cap::MaxColors>() {
Some(cap::MaxColors(n)) => n,
// Whether to use terminfo to render 256 colors. If this is too large (ex. 16777216 from xterm-direct),
// then setaf expects the index to be true color, in which case we cannot use it to render 256 (or even 16) colors.
let terminfo_256_color: i32 = match self.get_capability::<cap::MaxColors>() {
Some(cap::MaxColors(n)) => {
if n > 256 {
0
} else {
n
}
}
None => 0,
};
@ -160,7 +168,7 @@ impl TerminfoRenderer {
(false, ColorAttribute::TrueColorWithPaletteFallback(_, idx))
| (_, ColorAttribute::PaletteIndex(idx)) => {
match self.get_capability::<cap::SetAForeground>() {
Some(set) if (idx as i32) < terminfo_color => {
Some(set) if (idx as i32) < terminfo_256_color => {
set.expand().color(idx).to(out.by_ref())?;
}
_ => {
@ -194,7 +202,7 @@ impl TerminfoRenderer {
(false, ColorAttribute::TrueColorWithPaletteFallback(_, idx))
| (_, ColorAttribute::PaletteIndex(idx)) => {
match self.get_capability::<cap::SetABackground>() {
Some(set) if (idx as i32) < terminfo_color => {
Some(set) if (idx as i32) < terminfo_256_color => {
set.expand().color(idx).to(out.by_ref())?;
}
_ => {

View File

@ -8,7 +8,7 @@ license = "MIT"
[dependencies]
wezterm-dynamic-derive = { version="0.1", path="derive" }
ordered-float = "3.0"
ordered-float = "4.1"
thiserror = "1.0"
strsim = "0.10"
log = "0.4"

View File

@ -136,7 +136,7 @@ impl Error {
errors.push(Self::UnknownFieldForStruct {
field_name: s.to_string(),
type_name,
possible: possible.clone(),
possible,
});
}
}

View File

@ -28,7 +28,7 @@ lfucache = { path = "../lfucache" }
log = "0.4"
memmap2 = "0.2"
metrics = { version="0.17", features=["std"]}
ordered-float = "3.0"
ordered-float = "4.1"
rangeset = { path = "../rangeset" }
termwiz = { path = "../termwiz" }
thiserror = "1.0"

View File

@ -165,73 +165,105 @@ impl FontLocator for FontConfigFontLocator {
codepoints: &[char],
) -> anyhow::Result<Vec<ParsedFont>> {
log::trace!("locate_fallback_for_codepoints: {:?}", codepoints);
let mut charset = CharSet::new()?;
for &c in codepoints {
charset.add(c)?;
}
let mut fonts: Vec<ParsedFont> = vec![];
let mut fonts = vec![];
// In <https://github.com/wez/wezterm/issues/4310> we discover
// that a font-config query for a charset containing both
// 3065 and 2686 fails because no fonts contain both codepoints,
// but querying separately does find the separate fonts.
// We therefore need to break up our query so that we resolve
// each codepoint individually.
// However, if we need to resolve a block of characters that
// are found in the same font (eg: someone is printing an
// entire unicode block) we don't want to issue N queries
// that return the same font.
//
// So we check the fonts that have been resolved in earlier
// iterations to see if any of those cover a given codepoint
// and allow that to satisfy the query if they do.
// Make two passes to locate a fallback: first try to find any
// strictly monospace version, then, if we didn't find any matches,
// look for a version with any spacing.
for only_monospace in [true, false] {
let mut pattern = FontPattern::new()?;
pattern.add_charset(&charset)?;
pattern.add_integer("weight", 80)?;
pattern.add_integer("slant", 0)?;
let mut lists = vec![pattern
.list()
.context("pattern.list with no spacing constraint")?];
if only_monospace {
for &spacing in &SPACING {
pattern.delete_property("spacing")?;
pattern.add_integer("spacing", spacing)?;
lists.push(
pattern
.list()
.with_context(|| format!("pattern.list with spacing={}", spacing))?,
);
'next_codepoint: for &c in codepoints {
if !fonts.is_empty() {
let mut wanted_range = rangeset::RangeSet::new();
wanted_range.add(c as u32);
for f in &fonts {
match f.coverage_intersection(&wanted_range) {
Ok(r) if !r.is_empty() => {
// already found a font with this one!
continue 'next_codepoint;
}
_ => {}
}
}
}
for list in lists {
for pat in list.iter() {
let num = pat.charset_intersect_count(&charset)?;
if num == 0 {
log::error!(
"Skipping bogus font-config result {:?} because it doesn't overlap",
pat
);
continue;
}
let mut pushed_this_pass = 0;
if let Ok(file) = pat.get_file().context("pat.get_file") {
log::trace!("{file:?} has {num} codepoints from {codepoints:?}");
let handle = FontDataHandle {
source: FontDataSource::OnDisk(file.into()),
index: pat.get_integer("index")?.try_into()?,
variation: 0,
origin: FontOrigin::FontConfig,
coverage: pat.get_charset().ok().map(|c| c.to_range_set()),
};
if let Ok(parsed) = crate::parser::ParsedFont::from_locator(&handle) {
fonts.push(parsed);
let mut charset = CharSet::new()?;
charset.add(c)?;
// Make two passes to locate a fallback: first try to find any
// strictly monospace version, then, if we didn't find any matches,
// look for a version with any spacing.
for only_monospace in [true, false] {
let mut pattern = FontPattern::new()?;
pattern.add_charset(&charset)?;
pattern.add_integer("weight", 80)?;
pattern.add_integer("slant", 0)?;
let mut lists = vec![pattern
.list()
.context("pattern.list with no spacing constraint")?];
if only_monospace {
for &spacing in &SPACING {
pattern.delete_property("spacing")?;
pattern.add_integer("spacing", spacing)?;
lists.push(
pattern.list().with_context(|| {
format!("pattern.list with spacing={}", spacing)
})?,
);
}
}
for list in lists {
for pat in list.iter() {
let num = pat.charset_intersect_count(&charset)?;
if num == 0 {
log::error!(
"Skipping bogus font-config result {:?} because it doesn't overlap",
pat
);
continue;
}
if let Ok(file) = pat.get_file().context("pat.get_file") {
log::trace!("{file:?} has {num} codepoints from {codepoints:?}");
let handle = FontDataHandle {
source: FontDataSource::OnDisk(file.into()),
index: pat.get_integer("index")?.try_into()?,
variation: 0,
origin: FontOrigin::FontConfig,
coverage: pat.get_charset().ok().map(|c| c.to_range_set()),
};
if let Ok(parsed) = crate::parser::ParsedFont::from_locator(&handle) {
fonts.push(parsed);
pushed_this_pass += 1;
}
}
}
}
}
if fonts.is_empty() {
// If we get here on the first iteration, then we didn't
// find a monospace version of fonts with those codepoints,
// let's continue and try any matching font
continue;
}
if pushed_this_pass == 0 {
// If we get here on the first iteration, then we didn't
// find a monospace version of fonts with those codepoints,
// let's continue and try any matching font
continue;
}
break;
break;
}
}
Ok(fonts)

View File

@ -54,7 +54,7 @@ frecency = { path = "../frecency" }
futures = "0.3"
fuzzy-matcher = "0.3"
hdrhistogram = "7.1"
http_req = "0.9"
http_req = "0.10"
image = "0.24.6"
lazy_static = "1.4"
libc = "0.2"
@ -66,7 +66,7 @@ mlua = {version="0.9", features=["send"]}
mux = { path = "../mux" }
mux-lua = { path = "../lua-api-crates/mux" }
once_cell = "1.8"
ordered-float = "3.0"
ordered-float = "4.1"
parking_lot = "0.12"
portable-pty = { path = "../pty", features = ["serde_support"]}
promise = { path = "../promise" }
@ -105,7 +105,7 @@ wezterm-open-url = { path = "../wezterm-open-url" }
wezterm-ssh = { path = "../wezterm-ssh" }
wezterm-term = { path = "../term", features=["use_serde"] }
wezterm-toast-notification = { path = "../wezterm-toast-notification" }
wgpu = "0.17"
wgpu = "0.18"
window = { path = "../window" }
window-funcs = { path = "../lua-api-crates/window-funcs" }

View File

@ -236,7 +236,7 @@ impl CommandDef {
for dom in &domains {
let name = dom.domain_name();
// FIXME: use domain_label here, but needs to be async
let label = name.clone();
let label = name;
if dom.spawnable() {
if dom.state() == DomainState::Attached {
@ -266,7 +266,7 @@ impl CommandDef {
for dom in &domains {
let name = dom.domain_name();
// FIXME: use domain_label here, but needs to be async
let label = name.clone();
let label = name;
if dom.state() == DomainState::Attached {
if name == "local" {

View File

@ -5,8 +5,8 @@ use crate::TermWindow;
use ::window::*;
use anyhow::{Context, Error};
use config::keyassignment::{KeyAssignment, SpawnCommand};
use config::ConfigSubscription;
pub use config::FrontEndSelection;
use config::{ConfigSubscription, NotificationHandling};
use mux::client::ClientId;
use mux::window::WindowId as MuxWindowId;
use mux::{Mux, MuxNotification};
@ -96,7 +96,7 @@ impl GuiFrontEnd {
MuxNotification::PaneOutput(_) => {}
MuxNotification::PaneAdded(_) => {}
MuxNotification::Alert {
pane_id: _,
pane_id,
alert:
Alert::ToastNotification {
title,
@ -104,12 +104,34 @@ impl GuiFrontEnd {
focus: _,
},
} => {
let message = if title.is_none() { "" } else { &body };
let title = title.as_ref().unwrap_or(&body);
// FIXME: if notification.focus is true, we should do
// something here to arrange to focus pane_id when the
// notification is clicked
persistent_toast_notification(title, message);
let mux = Mux::get();
if let Some((_domain, window_id, tab_id)) = mux.resolve_pane_id(pane_id) {
let config = config::configuration();
if let Some((_fdomain, f_window, f_tab, f_pane)) =
mux.resolve_focused_pane(&client_id)
{
let show = match config.notification_handling {
NotificationHandling::NeverShow => false,
NotificationHandling::AlwaysShow => true,
NotificationHandling::SuppressFromFocusedPane => f_pane != pane_id,
NotificationHandling::SuppressFromFocusedTab => f_tab != tab_id,
NotificationHandling::SuppressFromFocusedWindow => {
f_window != window_id
}
};
if show {
let message = if title.is_none() { "" } else { &body };
let title = title.as_ref().unwrap_or(&body);
// FIXME: if notification.focus is true, we should do
// something here to arrange to focus pane_id when the
// notification is clicked
persistent_toast_notification(title, message);
}
}
}
}
MuxNotification::Alert {
pane_id: _,

View File

@ -57,10 +57,32 @@ const PATTERNS: [&str; 14] = [
/// It is derived from https://github.com/fcsonline/tmux-thumbs/blob/master/src/alphabets.rs
/// which is Copyright (c) 2019 Ferran Basora and provided under the MIT license
pub fn compute_labels_for_alphabet(alphabet: &str, num_matches: usize) -> Vec<String> {
let alphabet = alphabet
.chars()
.map(|c| c.to_lowercase().to_string())
.collect::<Vec<String>>();
compute_labels_for_alphabet_impl(alphabet, num_matches, true)
}
pub fn compute_labels_for_alphabet_with_preserved_case(
alphabet: &str,
num_matches: usize,
) -> Vec<String> {
compute_labels_for_alphabet_impl(alphabet, num_matches, false)
}
fn compute_labels_for_alphabet_impl(
alphabet: &str,
num_matches: usize,
make_lowercase: bool,
) -> Vec<String> {
let alphabet = if make_lowercase {
alphabet
.chars()
.map(|c| c.to_lowercase().to_string())
.collect::<Vec<String>>()
} else {
alphabet
.chars()
.map(|c| c.to_string())
.collect::<Vec<String>>()
};
// Prefer to use single character matches to represent everything
let mut primary = alphabet.clone();
let mut secondary = vec![];
@ -144,6 +166,30 @@ mod alphabet_test {
vec!["aa", "ab", "ba", "bb"]
);
}
#[test]
fn composed_capital() {
assert_eq!(
compute_labels_for_alphabet_with_preserved_case("AB", 4),
vec!["AA", "AB", "BA", "BB"]
);
}
#[test]
fn composed_mixed() {
assert_eq!(
compute_labels_for_alphabet_with_preserved_case("aA", 4),
vec!["aa", "aA", "Aa", "AA"]
);
}
#[test]
fn lowercase_alphabet_equal() {
assert_eq!(
compute_labels_for_alphabet_with_preserved_case("abc123", 12),
compute_labels_for_alphabet("abc123", 12)
);
}
}
pub struct QuickSelectOverlay {

View File

@ -1,3 +1,4 @@
use super::quickselect;
use crate::scripting::guiwin::GuiWin;
use config::keyassignment::{InputSelector, InputSelectorEntry, KeyAssignment};
use fuzzy_matcher::skim::SkimMatcherV2;
@ -26,6 +27,8 @@ struct SelectorState {
always_fuzzy: bool,
args: InputSelector,
event_name: String,
selection: String,
labels: Vec<String>,
}
impl SelectorState {
@ -69,6 +72,14 @@ impl SelectorState {
fn render(&mut self, term: &mut TermWizTerminal) -> termwiz::Result<()> {
let size = term.get_screen_size()?;
let max_width = size.cols.saturating_sub(6);
let max_items = size.rows.saturating_sub(ROW_OVERHEAD);
if max_items != self.max_items {
self.labels = quickselect::compute_labels_for_alphabet_with_preserved_case(
&self.args.alphabet,
self.filtered_entries.len().min(max_items + 1),
);
self.max_items = max_items;
}
let mut changes = vec![
Change::ClearScreen(ColorAttribute::Default),
@ -78,16 +89,14 @@ impl SelectorState {
},
Change::Text(format!(
"{}\r\n",
truncate_right(
"Select an item and press Enter=accept \
Esc=cancel /=filter",
max_width
)
truncate_right(&self.args.description, max_width)
)),
Change::AllAttributes(CellAttributes::default()),
];
let max_items = self.max_items;
let labels = &self.labels;
let max_label_len = labels.iter().map(|s| s.len()).max().unwrap_or(0);
let mut labels_iter = labels.into_iter();
for (row_num, (entry_idx, entry)) in self
.filtered_entries
@ -107,8 +116,15 @@ impl SelectorState {
attr.set_reverse(true);
}
if row_num < 9 && !self.filtering {
changes.push(Change::Text(format!(" {}. ", row_num + 1)));
// from above we know that row_num <= max_items
// show labels as long as we have more labels left
// and we are not filtering
if !self.filtering {
if let Some(label) = labels_iter.next() {
changes.push(Change::Text(format!(" {label:>max_label_len$}. ")));
} else {
changes.push(Change::Text(" ".repeat(max_label_len + 3)));
}
} else {
changes.push(Change::Text(" ".to_string()));
}
@ -133,7 +149,7 @@ impl SelectorState {
},
Change::ClearToEndOfLine(ColorAttribute::Default),
Change::Text(truncate_right(
&format!("Fuzzy matching: {}", self.filter_term),
&format!("{}{}", self.args.fuzzy_description, self.filter_term),
max_width,
)),
]);
@ -182,32 +198,39 @@ impl SelectorState {
match event {
InputEvent::Key(KeyEvent {
key: KeyCode::Char(c),
..
}) if !self.filtering && c >= '1' && c <= '9' => {
if self.launch(self.top_row + (c as u32 - '1' as u32) as usize) {
break;
modifiers: Modifiers::NONE,
}) if !self.filtering && self.args.alphabet.contains(c) => {
self.selection.push(c);
if let Some(pos) = self.labels.iter().position(|x| *x == self.selection) {
// since the number of labels is always <= self.max_items
// by construction, we have pos as usize <= self.max_items
// for free
self.active_idx = self.top_row + pos as usize;
if self.launch(self.active_idx) {
break;
}
}
}
InputEvent::Key(KeyEvent {
key: KeyCode::Char('j'),
..
}) if !self.filtering => {
}) if !self.filtering && !self.args.alphabet.contains("j") => {
self.move_down();
}
InputEvent::Key(KeyEvent {
key: KeyCode::Char('k'),
..
}) if !self.filtering => {
}) if !self.filtering && !self.args.alphabet.contains("k") => {
self.move_up();
}
InputEvent::Key(KeyEvent {
key: KeyCode::Char('P'),
key: KeyCode::Char('P' | 'K'),
modifiers: Modifiers::CTRL,
}) => {
self.move_up();
}
InputEvent::Key(KeyEvent {
key: KeyCode::Char('N'),
key: KeyCode::Char('N' | 'J'),
modifiers: Modifiers::CTRL,
}) => {
self.move_down();
@ -222,13 +245,17 @@ impl SelectorState {
key: KeyCode::Backspace,
..
}) => {
if self.filter_term.pop().is_none() && !self.always_fuzzy {
self.filtering = false;
if !self.filtering {
self.selection.pop();
} else {
if self.filter_term.pop().is_none() && !self.always_fuzzy {
self.filtering = false;
}
self.update_filter();
}
self.update_filter();
}
InputEvent::Key(KeyEvent {
key: KeyCode::Char('G'),
key: KeyCode::Char('G' | 'C'),
modifiers: Modifiers::CTRL,
})
| InputEvent::Key(KeyEvent {
@ -301,9 +328,6 @@ impl SelectorState {
break;
}
}
InputEvent::Resized { rows, .. } => {
self.max_items = rows.saturating_sub(ROW_OVERHEAD);
}
_ => {}
}
self.render(term)?;
@ -354,11 +378,9 @@ pub fn selector(
anyhow::bail!("InputSelector requires action to be defined by wezterm.action_callback")
}
};
let size = term.get_screen_size()?;
let max_items = size.rows.saturating_sub(ROW_OVERHEAD);
let mut state = SelectorState {
active_idx: 0,
max_items,
max_items: 0,
pane,
top_row: 0,
filter_term: String::new(),
@ -368,6 +390,8 @@ pub fn selector(
always_fuzzy: args.fuzzy,
args,
event_name,
selection: String::new(),
labels: vec![],
};
term.set_raw_mode()?;

View File

@ -664,9 +664,12 @@ impl Modal for CommandPalette {
.expect("to resolve char selection font");
let metrics = RenderMetrics::with_font_metrics(&font.metrics());
let max_rows_on_screen = ((term_window.dimensions.pixel_height * 8 / 10)
let mut max_rows_on_screen = ((term_window.dimensions.pixel_height * 8 / 10)
/ metrics.cell_size.height as usize)
- 2;
if let Some(size) = term_window.config.command_palette_rows {
max_rows_on_screen = max_rows_on_screen.min(size);
}
*self.max_rows_on_screen.borrow_mut() = max_rows_on_screen;
let rebuild_matches = results

View File

@ -111,10 +111,12 @@ impl crate::TermWindow {
a: 0.,
})
},
store: true,
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
});
cleared = true;

View File

@ -1674,6 +1674,9 @@ impl KeyEvent {
if raw_modifiers.contains(Modifiers::SUPER) {
modifiers |= 8;
}
// TODO: Hyper and Meta are not handled yet.
// We should somehow detect this?
// See: https://github.com/wez/wezterm/pull/4605#issuecomment-1823604708
if self.leds.contains(KeyboardLedStatus::CAPS_LOCK) {
modifiers |= 64;
}
@ -1800,7 +1803,6 @@ impl KeyEvent {
format!("\x1b[{c};{modifiers}{event_type}~")
}
Char(shifted_key) => {
let mut use_legacy = false;
let shifted_key = if *shifted_key == '\x08' {
// Backspace is really VERASE -> ASCII DEL
'\x7f'
@ -1808,22 +1810,24 @@ impl KeyEvent {
*shifted_key
};
if !flags.contains(KittyKeyboardFlags::REPORT_ALTERNATE_KEYS)
let use_legacy = !flags.contains(KittyKeyboardFlags::REPORT_ALTERNATE_KEYS)
&& event_type.is_empty()
&& is_legacy_key
&& !(flags.contains(KittyKeyboardFlags::DISAMBIGUATE_ESCAPE_CODES)
&& (self.modifiers.contains(Modifiers::CTRL)
|| self.modifiers.contains(Modifiers::ALT)))
{
use_legacy = true;
}
&& !self.modifiers.intersects(
Modifiers::SUPER, /* TODO: Hyper and Meta should be added here. */
);
if use_legacy {
// Legacy text key
// https://sw.kovidgoyal.net/kitty/keyboard-protocol/#legacy-text-keys
let mut output = String::new();
if self.modifiers.contains(Modifiers::ALT) {
output.push('\x1b');
}
if self.modifiers.contains(Modifiers::CTRL) {
csi_u_encode(
&mut output,
@ -1833,6 +1837,7 @@ impl KeyEvent {
} else {
output.push(shifted_key);
}
return output;
}
@ -3054,4 +3059,69 @@ mod test {
"".to_string()
);
}
#[test]
fn encode_issue_4436() {
let flags = KittyKeyboardFlags::DISAMBIGUATE_ESCAPE_CODES;
assert_eq!(
KeyEvent {
key: KeyCode::Char('q'),
modifiers: Modifiers::NONE,
leds: KeyboardLedStatus::empty(),
repeat_count: 1,
key_is_down: true,
raw: None,
#[cfg(windows)]
win32_uni_char: None,
}
.encode_kitty(flags),
"q".to_string()
);
assert_eq!(
KeyEvent {
key: KeyCode::Char('f'),
modifiers: Modifiers::SUPER,
leds: KeyboardLedStatus::empty(),
repeat_count: 1,
key_is_down: true,
raw: None,
#[cfg(windows)]
win32_uni_char: None,
}
.encode_kitty(flags),
"\u{1b}[102;9u".to_string()
);
assert_eq!(
KeyEvent {
key: KeyCode::Char('f'),
modifiers: Modifiers::SUPER | Modifiers::SHIFT,
leds: KeyboardLedStatus::empty(),
repeat_count: 1,
key_is_down: true,
raw: None,
#[cfg(windows)]
win32_uni_char: None,
}
.encode_kitty(flags),
"\u{1b}[102;10u".to_string()
);
assert_eq!(
KeyEvent {
key: KeyCode::Char('f'),
modifiers: Modifiers::SUPER | Modifiers::SHIFT | Modifiers::CTRL,
leds: KeyboardLedStatus::empty(),
repeat_count: 1,
key_is_down: true,
raw: None,
#[cfg(windows)]
win32_uni_char: None,
}
.encode_kitty(flags),
"\u{1b}[102;14u".to_string()
);
}
}

View File

@ -337,6 +337,13 @@ enum Message {
#[derive(Debug, Parser, Clone)]
pub struct RecordCommand {
/// Start in the specified directory, instead of
/// the default_cwd defined by your wezterm configuration
#[arg(long)]
cwd: Option<std::path::PathBuf>,
/// Start prog instead of the default_prog defined by your
/// wezterm configuration
#[arg(value_parser)]
prog: Vec<OsString>,
}
@ -369,7 +376,7 @@ impl RecordCommand {
Some(prog)
},
config.default_prog.as_ref(),
config.default_cwd.as_ref(),
self.cwd.as_ref().or(config.default_cwd.as_ref()),
)?;
let mut child = pair.slave.spawn_command(cmd)?;

View File

@ -75,7 +75,7 @@ xcb = {version="1.2", features=["render", "randr", "dri2", "xkb", "xlib_xcb", "p
xkbcommon = { version = "0.5.0", features = ["x11", "wayland"] }
mio = {version="0.8", features=["os-ext"]}
libc = "0.2"
smithay-client-toolkit = {version = "0.16", default-features=false, optional=true}
smithay-client-toolkit = {version = "0.16.1", default-features=false, optional=true}
wayland-protocols = {version="0.29", optional=true}
wayland-client = {version="0.29", optional=true}
wayland-egl = {version="0.29", optional=true}

View File

@ -7,6 +7,7 @@ use cocoa::appkit::NSApplicationTerminateReply;
use cocoa::base::id;
use cocoa::foundation::NSInteger;
use config::keyassignment::KeyAssignment;
use config::WindowCloseConfirmation;
use objc::declare::ClassDecl;
use objc::rc::StrongPtr;
use objc::runtime::{Class, Object, Sel, BOOL, NO, YES};
@ -21,35 +22,44 @@ extern "C" fn application_should_terminate(
) -> u64 {
log::debug!("application termination requested");
unsafe {
let alert: id = msg_send![class!(NSAlert), alloc];
let alert: id = msg_send![alert, init];
let message_text = nsstring("Terminate WezTerm?");
let info_text = nsstring("Detach and close all panes and terminate wezterm?");
let cancel = nsstring("Cancel");
let ok = nsstring("Ok");
match config::configuration().window_close_confirmation {
WindowCloseConfirmation::NeverPrompt => terminate_now(),
WindowCloseConfirmation::AlwaysPrompt => {
let alert: id = msg_send![class!(NSAlert), alloc];
let alert: id = msg_send![alert, init];
let message_text = nsstring("Terminate WezTerm?");
let info_text = nsstring("Detach and close all panes and terminate wezterm?");
let cancel = nsstring("Cancel");
let ok = nsstring("Ok");
let () = msg_send![alert, setMessageText: message_text];
let () = msg_send![alert, setInformativeText: info_text];
let () = msg_send![alert, addButtonWithTitle: cancel];
let () = msg_send![alert, addButtonWithTitle: ok];
#[allow(non_upper_case_globals)]
const NSModalResponseCancel: NSInteger = 1000;
#[allow(non_upper_case_globals, dead_code)]
const NSModalResponseOK: NSInteger = 1001;
let result: NSInteger = msg_send![alert, runModal];
log::info!("alert result is {result}");
let () = msg_send![alert, setMessageText: message_text];
let () = msg_send![alert, setInformativeText: info_text];
let () = msg_send![alert, addButtonWithTitle: cancel];
let () = msg_send![alert, addButtonWithTitle: ok];
#[allow(non_upper_case_globals)]
const NSModalResponseCancel: NSInteger = 1000;
#[allow(non_upper_case_globals, dead_code)]
const NSModalResponseOK: NSInteger = 1001;
let result: NSInteger = msg_send![alert, runModal];
log::info!("alert result is {result}");
if result == NSModalResponseCancel {
NSApplicationTerminateReply::NSTerminateCancel as u64
} else {
if let Some(conn) = Connection::get() {
conn.terminate_message_loop();
if result == NSModalResponseCancel {
NSApplicationTerminateReply::NSTerminateCancel as u64
} else {
terminate_now()
}
}
NSApplicationTerminateReply::NSTerminateNow as u64
}
}
}
fn terminate_now() -> u64 {
if let Some(conn) = Connection::get() {
conn.terminate_message_loop();
}
NSApplicationTerminateReply::NSTerminateNow as u64
}
extern "C" fn application_will_finish_launching(
_self: &mut Object,
_sel: Sel,

View File

@ -511,8 +511,7 @@ impl Window {
let _: () = msg_send![*window, setRestorable: NO];
window.setReleasedWhenClosed_(NO);
let ns_color: id = msg_send![Class::get("NSColor").unwrap(), alloc];
window.setBackgroundColor_(cocoa::appkit::NSColor::clearColor(ns_color));
window.setBackgroundColor_(cocoa::appkit::NSColor::clearColor(nil));
// We could set this, but it makes the entire window, including
// its titlebar, opaque to this fixed degree.
@ -1734,15 +1733,6 @@ impl WindowView {
}
}
/// `dealloc` is called when our NSView descendant is destroyed.
/// In practice, I've not seen this trigger, which likely means
/// that there is something afoot with reference counting.
/// The cardinality of Window and View objects is low enough
/// that I'm "OK" with this for now.
/// What really matters is that the `Inner` object is dropped
/// in a timely fashion once the window is closed, so we manage
/// that by hooking into `windowWillClose` and routing both
/// `dealloc` and `windowWillClose` to `drop_inner`.
fn drop_inner(this: &mut Object) {
unsafe {
let myself: *mut c_void = *this.get_ivar(VIEW_CLS_NAME);
@ -2124,10 +2114,10 @@ impl WindowView {
.events
.dispatch(WindowEvent::Destroyed);
this.update_application_presentation(false);
let conn = Connection::get().unwrap();
let window_id = this.inner.borrow_mut().window_id;
conn.windows.borrow_mut().remove(&window_id);
}
// Release and zero out the inner member
Self::drop_inner(this);
}
fn mouse_common(this: &mut Object, nsevent: id, kind: MouseEventKind) {