mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-14 20:47:58 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c10e421e9b | ||
|
|
958cc6d98f | ||
|
|
f1f4a1a4a3 | ||
|
|
55859f4b56 |
@@ -11,7 +11,7 @@ indent_style = tab
|
||||
|
||||
# Autogenerated files with tabs below this line.
|
||||
|
||||
[kitty/char-props-data.h]
|
||||
[kitty/{unicode-data.c,emoji.h,wcwidth-std.h}]
|
||||
indent_style = tab
|
||||
|
||||
[kittens/unicode_input/names.h]
|
||||
|
||||
20
.gitattributes
vendored
20
.gitattributes
vendored
@@ -1,19 +1,14 @@
|
||||
kitty/terminfo.h linguist-generated=true
|
||||
terminfo/kitty.termcap linguist-generated=true
|
||||
terminfo/kitty.terminfo linguist-generated=true
|
||||
terminfo/x/xterm-kitty linguist-generated=true
|
||||
kitty/char-props-data.h linguist-generated=true
|
||||
kitty_tests/GraphemeBreakTest.json linguist-generated=true
|
||||
kitty/wcwidth-std.h linguist-generated=true
|
||||
kitty/emoji.h linguist-generated=true
|
||||
kitty/charsets.c linguist-generated=true
|
||||
kitty/key_encoding.py linguist-generated=true
|
||||
kitty/unicode-data.c linguist-generated=true
|
||||
kitty/rowcolumn-diacritics.c linguist-generated=true
|
||||
kitty/rgb.py linguist-generated=true
|
||||
kitty/srgb_gamma.* linguist-generated=true
|
||||
kitty/gl-wrapper.* linguist-generated=true
|
||||
kitty/glfw-wrapper.* linguist-generated=true
|
||||
kitty/color-names.h linguist-generated=true
|
||||
kitty/parse-graphics-command.h linguist-generated=true
|
||||
kitty/parse-multicell-command.h linguist-generated=true
|
||||
kitty/options/types.py linguist-generated=true
|
||||
kitty/options/parse.py linguist-generated=true
|
||||
kitty/options/to-c-generated.h linguist-generated=true
|
||||
@@ -23,12 +18,15 @@ glfw/*.c linguist-vendored=true
|
||||
glfw/*.h linguist-vendored=true
|
||||
3rdparty/** linguist-vendored=true
|
||||
kittens/unicode_input/names.h linguist-generated=true
|
||||
tools/wcswidth/char-props-data.go linguist-generated=true
|
||||
tools/wcswidth/std.go linguist-generated=true
|
||||
tools/unicode_names/names.txt linguist-generated=true
|
||||
terminfo/kitty.term* linguist-generated=true
|
||||
terminfo/x/* linguist-generated=true
|
||||
*_generated.* linguist-generated=true
|
||||
*_generated_test.* linguist-generated=true
|
||||
*_generated.h linguist-generated=true
|
||||
*_generated.go linguist-generated=true
|
||||
*_generated_test.go linguist-generated=true
|
||||
*_generated_test.s linguist-generated=true
|
||||
*_generated.s linguist-generated=true
|
||||
|
||||
*.py text diff=python
|
||||
*.m text diff=objc
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -23,7 +23,7 @@ If applicable, add screenshots to help explain your problem.
|
||||
**Environment details**
|
||||
```
|
||||
Press Ctrl+Shift+F6 (cmd+option+comma on macOS) in kitty, to copy debug output about kitty and its
|
||||
configuration to the clipboard and paste it here.
|
||||
configuration to the clipboard and paste it here.
|
||||
|
||||
On older versions of kitty, run kitty --debug-config instead
|
||||
```
|
||||
|
||||
35
.github/copilot-instructions.md
vendored
35
.github/copilot-instructions.md
vendored
@@ -1,35 +0,0 @@
|
||||
Before implementing any code changes or responding to a request, run the
|
||||
following command:
|
||||
|
||||
python3 .github/workflows/ci.py build
|
||||
|
||||
This will download needed dependencies, then create all generated files
|
||||
and build the project, making it ready for inspection.
|
||||
|
||||
# Repository Build & Test Instructions
|
||||
|
||||
## Build Procedures
|
||||
- **Build command:** Run `./dev.sh build` to build the project
|
||||
- Run `gen/config.py` to update generated config parsing code for both kitty
|
||||
and kitten. The `gen/go_code.py` generator is run automatically by the build
|
||||
command to keep generated Go code files up to date.
|
||||
- To build individual kittens use the build command above **do not** try to run go build
|
||||
yourself.
|
||||
|
||||
Once a build is done, the kitty and kitten binaries will be in the `kitty/launcher` directory.
|
||||
Note that the kitty binary can run python files using `kitty +launch file.py`.
|
||||
When it does so the kitty fast_data_types module is available to the python
|
||||
code.
|
||||
|
||||
## Test Procedures
|
||||
- To run the complete test suite, run `./test.py`
|
||||
- To run a specific test, run `./test.py test_name` where `test_name` is the name of the test without the
|
||||
leading `test_` for Python tests and without the leading `Test` for Go tests.
|
||||
- Do not use go test or ./setup.py test to run tests
|
||||
|
||||
## PR guidance
|
||||
When creating a pull request, if the changes in the pull request are user
|
||||
visible compared to the previous kitty release, add an entry in the file docs/changelog.rst
|
||||
describing the change. If the changes include changes to Go code, run gofmt on
|
||||
the changed Go files to ensure they are formatted correctly, before submitting
|
||||
your changes.
|
||||
12
.github/dependabot.yml
vendored
12
.github/dependabot.yml
vendored
@@ -13,15 +13,3 @@ updates:
|
||||
all-go-deps:
|
||||
patterns:
|
||||
- "*" # group all non-security update PRs
|
||||
cooldown:
|
||||
default-days: 7
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
groups:
|
||||
actions:
|
||||
patterns:
|
||||
- "*"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
155
.github/workflows/ci.py
vendored
155
.github/workflows/ci.py
vendored
@@ -4,7 +4,6 @@
|
||||
|
||||
import glob
|
||||
import io
|
||||
import lzma
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
@@ -12,21 +11,17 @@ import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import time
|
||||
from urllib.request import Request, urlopen
|
||||
from urllib.request import urlopen
|
||||
|
||||
BUNDLE_URL = 'https://download.calibre-ebook.com/ci/kitty/{}-64.tar.xz'
|
||||
FONTS_URL = 'https://download.calibre-ebook.com/ci/fonts.tar.xz'
|
||||
NERD_URL = 'https://github.com/ryanoasis/nerd-fonts/releases/latest/download/NerdFontsSymbolsOnly.tar.xz'
|
||||
is_bundle = os.environ.get('KITTY_BUNDLE') == '1'
|
||||
is_codeql = os.environ.get('KITTY_CODEQL') == '1'
|
||||
is_macos = 'darwin' in sys.platform.lower()
|
||||
SW = ''
|
||||
|
||||
|
||||
def do_print_crash_reports() -> None:
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
time.sleep(2)
|
||||
print('Printing available crash reports...')
|
||||
if is_macos:
|
||||
end_time = time.monotonic() + 90
|
||||
@@ -66,58 +61,36 @@ def run(*a: str, print_crash_reports: bool = False) -> None:
|
||||
raise SystemExit(f'The following process failed with exit code: {ret}:\n{cmd}')
|
||||
|
||||
|
||||
def download_with_retry(url: str | Request, count: int = 5) -> bytes:
|
||||
for i in range(count):
|
||||
try:
|
||||
print('Downloading', getattr(url, 'full_url', url), flush=True)
|
||||
with urlopen(url) as f:
|
||||
ans: bytes = f.read()
|
||||
return ans
|
||||
except Exception as err:
|
||||
if getattr(err, 'code', -1) == 403:
|
||||
raise
|
||||
if i >= count - 1:
|
||||
raise
|
||||
print(f'Download failed with error {err} retrying...', file=sys.stderr)
|
||||
time.sleep(1)
|
||||
return b''
|
||||
|
||||
|
||||
def install_fonts() -> None:
|
||||
data = download_with_retry(FONTS_URL)
|
||||
with urlopen(FONTS_URL) as f:
|
||||
data = f.read()
|
||||
fonts_dir = os.path.expanduser('~/Library/Fonts' if is_macos else '~/.local/share/fonts')
|
||||
os.makedirs(fonts_dir, exist_ok=True)
|
||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
||||
try:
|
||||
tf.extractall(fonts_dir, filter='fully_trusted')
|
||||
except TypeError:
|
||||
tf.extractall(fonts_dir)
|
||||
data = download_with_retry(NERD_URL)
|
||||
tf.extractall(fonts_dir)
|
||||
with urlopen(NERD_URL) as f:
|
||||
data = f.read()
|
||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
||||
try:
|
||||
tf.extractall(fonts_dir, filter='fully_trusted')
|
||||
except TypeError:
|
||||
tf.extractall(fonts_dir)
|
||||
tf.extractall(fonts_dir)
|
||||
|
||||
|
||||
def install_deps() -> None:
|
||||
print('Installing kitty dependencies...')
|
||||
sys.stdout.flush()
|
||||
if is_macos:
|
||||
if not is_codeql: # for some reason brew fails on CodeQL we dont need it anyway
|
||||
items = [x.split()[1].strip('"') for x in open('Brewfile').readlines() if x.strip().startswith('brew ')]
|
||||
openssl = 'openssl'
|
||||
items.remove('go') # already installed by ci.yml
|
||||
import ssl
|
||||
if ssl.OPENSSL_VERSION_INFO[0] == 1:
|
||||
openssl += '@1.1'
|
||||
run('brew', 'install', 'fish', openssl, *items)
|
||||
items = [x.split()[1].strip('"') for x in open('Brewfile').readlines() if x.strip().startswith('brew ')]
|
||||
openssl = 'openssl'
|
||||
items.remove('go') # already installed by ci.yml
|
||||
import ssl
|
||||
if ssl.OPENSSL_VERSION_INFO[0] == 1:
|
||||
openssl += '@1.1'
|
||||
run('brew', 'install', 'fish', openssl, *items)
|
||||
else:
|
||||
run('sudo apt-get update')
|
||||
run('sudo apt-get install -y --fix-missing libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev ca-certificates'
|
||||
run('sudo apt-get install -y libgl1-mesa-dev libxi-dev libxrandr-dev libxinerama-dev ca-certificates'
|
||||
' libxcursor-dev libxcb-xkb-dev libdbus-1-dev libxkbcommon-dev libharfbuzz-dev libx11-xcb-dev zsh'
|
||||
' libpng-dev liblcms2-dev libfontconfig-dev libxkbcommon-x11-dev libcanberra-dev libxxhash-dev uuid-dev'
|
||||
' libsimde-dev libsystemd-dev libcairo2-dev zsh bash dash systemd-coredump gdb')
|
||||
' libsimde-dev libsystemd-dev zsh bash dash systemd-coredump gdb')
|
||||
# for some reason these directories are world writable which causes zsh
|
||||
# compinit to break
|
||||
run('sudo chmod -R og-w /usr/share/zsh')
|
||||
@@ -175,98 +148,26 @@ def setup_bundle_env() -> None:
|
||||
os.environ['PATH'] = '{}:{}'.format(os.path.join(SW, 'bin'), os.environ['PATH'])
|
||||
|
||||
|
||||
def install_bundle(dest: str = '', which: str = '') -> None:
|
||||
dest = dest or SW
|
||||
def install_bundle() -> None:
|
||||
cwd = os.getcwd()
|
||||
os.makedirs(dest, exist_ok=True)
|
||||
os.chdir(dest)
|
||||
which = which or ('macos' if is_macos else 'linux')
|
||||
data = download_with_retry(BUNDLE_URL.format(which))
|
||||
os.makedirs(SW)
|
||||
os.chdir(SW)
|
||||
with urlopen(BUNDLE_URL.format('macos' if is_macos else 'linux')) as f:
|
||||
data = f.read()
|
||||
with tarfile.open(fileobj=io.BytesIO(data), mode='r:xz') as tf:
|
||||
try:
|
||||
tf.extractall(filter='fully_trusted')
|
||||
except TypeError:
|
||||
tf.extractall()
|
||||
tf.extractall()
|
||||
if not is_macos:
|
||||
replaced = 0
|
||||
for dirpath, dirnames, filenames in os.walk('.'):
|
||||
for f in filenames:
|
||||
if f.endswith('.pc') or (f.endswith('.py') and f.startswith('_sysconfig')):
|
||||
replace_in_file(os.path.join(dirpath, f), '/sw/sw', dest)
|
||||
replace_in_file(os.path.join(dirpath, f), '/sw/sw', SW)
|
||||
replaced += 1
|
||||
if replaced < 2:
|
||||
raise SystemExit('Failed to replace path to SW in bundle')
|
||||
os.chdir(cwd)
|
||||
|
||||
|
||||
def install_grype(exe: str = '/tmp/grype') -> str:
|
||||
raw = download_with_retry('https://download.calibre-ebook.com/ci/grype.xz')
|
||||
raw = lzma.decompress(raw)
|
||||
with open(exe, 'wb') as f:
|
||||
f.write(raw)
|
||||
os.fchmod(f.fileno(), 0o755)
|
||||
subprocess.check_call([exe, 'db', 'update'])
|
||||
return exe
|
||||
|
||||
|
||||
IGNORED_DEPENDENCY_CVES = [
|
||||
# Python stdlib
|
||||
'CVE-2025-8194', # DoS in tarfile
|
||||
'CVE-2025-6069', # DoS in HTMLParser
|
||||
'CVE-2025-13836', # DoS in http client reading from malicious server
|
||||
'CVE-2025-12084', # DoS in xml.dom.minidom unused in kitty
|
||||
'CVE-2025-13837', # DoS in plistlib reading plist. We only use plistlib for writing
|
||||
'CVE-2025-6075', # Quadratic complexity in os.path.expandvars()
|
||||
# python stdlib all these are erroneously marked as fixed in python 3.15
|
||||
# when it hasnt even been released. Sigh.
|
||||
'CVE-2026-1299',
|
||||
'CVE-2026-0865',
|
||||
'CVE-2025-15282',
|
||||
'CVE-2026-0672',
|
||||
'CVE-2025-15366',
|
||||
'CVE-2025-15367',
|
||||
'CVE-2025-12781',
|
||||
'CVE-2025-11468',
|
||||
'CVE-2026-2297',
|
||||
'CVE-2026-3644',
|
||||
'CVE-2026-4224',
|
||||
'CVE-2026-4519',
|
||||
'CVE-2026-1502',
|
||||
'CVE-2026-7210', # DoS in unused XML parser
|
||||
# github.com/nwaples/rardecode/v2
|
||||
'CVE-2025-11579', # rardecode is version 2.2.1, not vulnerable
|
||||
'CVE-2026-2673', # openssl fix not released
|
||||
]
|
||||
|
||||
|
||||
def check_dependencies() -> None:
|
||||
grype = install_grype()
|
||||
with open((gc := os.path.expanduser('~/.grype.yml')), 'w') as f:
|
||||
print('ignore:', file=f)
|
||||
for x in IGNORED_DEPENDENCY_CVES:
|
||||
print(' - vulnerability:', x, file=f)
|
||||
dest = os.path.join(SW, 'linux')
|
||||
os.makedirs(dest, exist_ok=True)
|
||||
install_bundle(dest, os.path.basename(dest))
|
||||
dest = os.path.join(SW, 'macos')
|
||||
os.makedirs(dest, exist_ok=True)
|
||||
install_bundle(dest, os.path.basename(dest))
|
||||
cmdline = [grype, '--by-cve', '--config', gc, '--fail-on', 'medium', '--only-fixed', '--add-cpes-if-none']
|
||||
if (subprocess.run(cmdline + ['dir:' + SW])).returncode != 0:
|
||||
raise SystemExit('grype found problems during filesystem scan')
|
||||
# Now test against the SBOM
|
||||
import runpy
|
||||
orig = sys.argv, sys.stdout
|
||||
sys.argv = ['bypy', 'sbom', 'kovidgoyal/kitty', '1.0.0']
|
||||
buf = io.StringIO()
|
||||
sys.stdout = buf
|
||||
runpy.run_path('bypy-src')
|
||||
sys.argv, sys.stdout = orig
|
||||
print(buf.getvalue())
|
||||
if (subprocess.run(cmdline, input=buf.getvalue().encode())).returncode != 0:
|
||||
raise SystemExit('grype found problems during SBOM scan')
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if is_bundle:
|
||||
setup_bundle_env()
|
||||
@@ -282,20 +183,12 @@ def main() -> None:
|
||||
package_kitty()
|
||||
elif action == 'test':
|
||||
test_kitty()
|
||||
elif action == 'test':
|
||||
test_kitty()
|
||||
elif action == 'govulncheck':
|
||||
subprocess.check_call(['go', 'install', 'golang.org/x/vuln/cmd/govulncheck@latest'])
|
||||
subprocess.check_call(['govulncheck', '-mode=binary', 'kitty/launcher/kitten'])
|
||||
subprocess.check_call(['govulncheck', './...'])
|
||||
elif action == 'gofmt':
|
||||
q = subprocess.check_output('gofmt -s -l tools kittens'.split()).decode()
|
||||
q = subprocess.check_output('gofmt -s -l tools'.split()).decode()
|
||||
if q.strip():
|
||||
q = '\n'.join(filter(lambda x: not x.rstrip().endswith('_generated.go'), q.strip().splitlines())).strip()
|
||||
if q:
|
||||
raise SystemExit(q)
|
||||
elif action == 'check-dependencies':
|
||||
check_dependencies()
|
||||
else:
|
||||
raise SystemExit(f'Unknown action: {action}')
|
||||
|
||||
|
||||
72
.github/workflows/ci.yml
vendored
72
.github/workflows/ci.yml
vendored
@@ -23,15 +23,15 @@ jobs:
|
||||
cc: [gcc, clang]
|
||||
include:
|
||||
- python: a
|
||||
pyver: "3.11"
|
||||
pyver: "3.9"
|
||||
sanitize: 0
|
||||
|
||||
- python: b
|
||||
pyver: "3.12"
|
||||
pyver: "3.10"
|
||||
sanitize: 1
|
||||
|
||||
- python: c
|
||||
pyver: "3.13"
|
||||
pyver: "3.11"
|
||||
sanitize: 1
|
||||
|
||||
|
||||
@@ -45,18 +45,17 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 10
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python ${{ matrix.pyver }}
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.pyver }}
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
@@ -73,30 +72,26 @@ jobs:
|
||||
CFLAGS: -funsigned-char
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # needed for :commit: docs role
|
||||
persist-credentials: false
|
||||
|
||||
- name: Test for trailing whitespace
|
||||
run: if grep -Inr '\s$' kitty kitty_tests kittens docs *.py *.asciidoc *.rst *.go .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi
|
||||
|
||||
- name: Test for bad code block formatting
|
||||
run: if grep -Inr ':code:`\s' kitty kitty_tests kittens docs *.py *.asciidoc *.rst *.go .gitattributes .gitignore; then echo Space at code block start found, aborting.; exit 1; fi
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.14"
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache: false
|
||||
|
||||
- name: Cache Go build artifacts separately
|
||||
uses: actions/cache@v5
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
@@ -106,7 +101,7 @@ jobs:
|
||||
${{ runner.os }}-golang-static-
|
||||
|
||||
- name: Install build-only deps
|
||||
run: python -m pip install -r docs/requirements.txt ruff mypy types-requests types-docutils types-Pygments
|
||||
run: python -m pip install -r docs/requirements.txt ruff mypy types-requests types-docutils
|
||||
|
||||
- name: Run ruff
|
||||
run: ruff check .
|
||||
@@ -124,7 +119,7 @@ jobs:
|
||||
run: which python && python -m mypy --version && ./test.py mypy
|
||||
|
||||
- name: Run go vet
|
||||
run: go version && go vet -tags testing ./...
|
||||
run: go version && go vet ./...
|
||||
|
||||
- name: Build man page
|
||||
run: make FAIL_WARN=1 man
|
||||
@@ -145,13 +140,12 @@ jobs:
|
||||
KITTY_BUNDLE: 1
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 10
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
@@ -166,18 +160,17 @@ jobs:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # needed for :commit: docs role
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v6
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.14"
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
@@ -195,30 +188,3 @@ jobs:
|
||||
|
||||
- name: Build kitty package
|
||||
run: python3 .github/workflows/ci.py package
|
||||
|
||||
- name: Run benchmarks
|
||||
run: ./benchmark.py
|
||||
|
||||
linux-dev:
|
||||
name: Test ./dev.sh and benchmark
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 10
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install build deps
|
||||
run: sudo apt-get update && sudo apt-get install -y curl xz-utils build-essential git pkg-config libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev libgl1-mesa-dev libxkbcommon-x11-dev libfontconfig-dev libx11-xcb-dev libdbus-1-dev
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Build kitty
|
||||
run: ./dev.sh build
|
||||
|
||||
- name: Run benchmarks
|
||||
run: ./benchmark.py
|
||||
|
||||
96
.github/workflows/codeql-analysis.yml
vendored
96
.github/workflows/codeql-analysis.yml
vendored
@@ -1,71 +1,49 @@
|
||||
name: "CodeQL"
|
||||
name: "Code scanning - action"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 22 * * 5'
|
||||
push:
|
||||
branches: [master, ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 22 * * 5'
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
CodeQL-Build:
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
security-events: write # to upload SARIF results (github/codeql-action/analyze)
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
security-events: write # to upload SARIF results (github/codeql-action/analyze)
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- language: python
|
||||
os: ubuntu-latest
|
||||
- language: c
|
||||
os: ubuntu-latest
|
||||
- language: c
|
||||
os: macos-latest
|
||||
- language: go
|
||||
os: ubuntu-latest
|
||||
- language: actions
|
||||
os: ubuntu-latest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
KITTY_BUNDLE: 1
|
||||
KITTY_CODEQL: 1
|
||||
steps:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
persist-credentials: false
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Install Go
|
||||
if: matrix.language == 'c' || matrix.language == 'go'
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: python, c
|
||||
setup-python-dependencies: false
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v4.35.5
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
trap-caching: false
|
||||
- name: Build kitty
|
||||
run: python3 .github/workflows/ci.py build
|
||||
|
||||
- name: Build kitty
|
||||
if: matrix.language == 'c' || matrix.language == 'go'
|
||||
run: python3 .github/workflows/ci.py build
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v4.35.5
|
||||
|
||||
- name: Run govulncheck
|
||||
if: matrix.language == 'go'
|
||||
run: python3 .github/workflows/ci.py govulncheck
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
||||
39
.github/workflows/depscan.yml
vendored
39
.github/workflows/depscan.yml
vendored
@@ -1,39 +0,0 @@
|
||||
name: Depscan
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 12 * * 5'
|
||||
|
||||
env:
|
||||
CI: 'true'
|
||||
ASAN_OPTIONS: detect_leaks=0
|
||||
LC_ALL: en_US.UTF-8
|
||||
LANG: en_US.UTF-8
|
||||
|
||||
permissions:
|
||||
contents: read # to fetch code (actions/checkout)
|
||||
|
||||
jobs:
|
||||
dependecy-scanner:
|
||||
name: Scan dependencies for vulnerabilities
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
KITTY_BUNDLE: 1
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 10
|
||||
persist-credentials: false
|
||||
|
||||
- name: Checkout bypy
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
repository: kovidgoyal/bypy
|
||||
path: bypy-src
|
||||
|
||||
- name: Check dependencies
|
||||
run: python3 .github/workflows/ci.py check-dependencies
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -29,5 +29,3 @@ __pycache__/
|
||||
.cache
|
||||
bypy/b
|
||||
bypy/virtual-machines.conf
|
||||
_codeql_detected_source_root
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
= kitty - the fast, feature-rich, cross-platform, GPU based terminal
|
||||
|
||||
If you live in the terminal, *kitty* is made for **you**!
|
||||
|
||||
See https://sw.kovidgoyal.net/kitty/[the kitty website].
|
||||
|
||||
image:https://github.com/kovidgoyal/kitty/workflows/CI/badge.svg["Build status", link="https://github.com/kovidgoyal/kitty/actions?query=workflow%3ACI"]
|
||||
@@ -13,4 +11,4 @@ https://www.reddit.com/r/KittyTerminal[Reddit community]
|
||||
|
||||
Packaging status in various repositories:
|
||||
|
||||
image:https://repology.org/badge/vertical-allrepos/kitty-terminal.svg?columns=3&header=kitty["Packaging status", link="https://repology.org/project/kitty-terminal/versions"]
|
||||
image:https://repology.org/badge/vertical-allrepos/kitty.svg?columns=3&header=kitty["Packaging status", link="https://repology.org/project/kitty/versions"]
|
||||
|
||||
12
SECURITY.md
12
SECURITY.md
@@ -7,12 +7,6 @@ and released just like all other bugs.
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
Preferably send an email to kovid at kovidgoyal.net or open a private security
|
||||
advisory using the GitHub security advisory facility.
|
||||
|
||||
Note that I will generally respond to security communication within 72 hours. Once
|
||||
the bug is confirmed, it will be fixed or at least mitigated within another 72
|
||||
hours, at which time the fix will typically be committed to master and hence be
|
||||
public. That timeline might be extended based on the severity of the issue and the
|
||||
current state of master in terms of making a new release, if so, it will be
|
||||
done in consultation with the issue reporter.
|
||||
Preferably send an email to kovid at kovidgoyal.net or open an issue in the
|
||||
GitHub repository, though the latter means you are disclosing the vulnerability
|
||||
publicly before it can be fixed.
|
||||
|
||||
90
benchmark.py
90
benchmark.py
@@ -1,90 +0,0 @@
|
||||
#!./kitty/launcher/kitty +launch
|
||||
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import fcntl
|
||||
import io
|
||||
import os
|
||||
import select
|
||||
import signal
|
||||
import struct
|
||||
import sys
|
||||
import termios
|
||||
import time
|
||||
from pty import CHILD, fork
|
||||
|
||||
from kitty.constants import kitten_exe
|
||||
from kitty.fast_data_types import Screen, safe_pipe
|
||||
from kitty.utils import read_screen_size
|
||||
|
||||
|
||||
def run_parsing_benchmark(cell_width: int = 10, cell_height: int = 20, scrollback: int = 20000) -> None:
|
||||
isatty = sys.stdout.isatty()
|
||||
if isatty:
|
||||
sz = read_screen_size()
|
||||
columns, rows = sz.cols, sz.rows
|
||||
else:
|
||||
columns, rows = 80, 25
|
||||
child_pid, master_fd = fork()
|
||||
is_child = child_pid == CHILD
|
||||
argv = [kitten_exe(), '__benchmark__', '--with-scrollback']
|
||||
if is_child:
|
||||
while read_screen_size().width != columns * cell_width:
|
||||
time.sleep(0.01)
|
||||
signal.pthread_sigmask(signal.SIG_SETMASK, ())
|
||||
os.execvp(argv[0], argv)
|
||||
# os.set_blocking(master_fd, False)
|
||||
x_pixels = columns * cell_width
|
||||
y_pixels = rows * cell_height
|
||||
s = struct.pack('HHHH', rows, columns, x_pixels, y_pixels)
|
||||
fcntl.ioctl(master_fd, termios.TIOCSWINSZ, s)
|
||||
|
||||
write_buf = b''
|
||||
r_pipe, w_pipe = safe_pipe(True)
|
||||
class ToChild:
|
||||
def write(self, x: bytes | str) -> None:
|
||||
nonlocal write_buf
|
||||
if isinstance(x, str):
|
||||
x = x.encode()
|
||||
write_buf += x
|
||||
os.write(w_pipe, b'1')
|
||||
|
||||
screen = Screen(None, rows, columns, scrollback, cell_width, cell_height, 0, ToChild())
|
||||
|
||||
def parse_bytes(data: bytes|memoryview) -> None:
|
||||
data = memoryview(data)
|
||||
while data:
|
||||
dest = screen.test_create_write_buffer()
|
||||
s = screen.test_commit_write_buffer(data, dest)
|
||||
data = data[s:]
|
||||
screen.test_parse_written_data()
|
||||
|
||||
|
||||
while True:
|
||||
rd, wd, _ = select.select([master_fd, r_pipe], [master_fd] if write_buf else [], [])
|
||||
if r_pipe in rd:
|
||||
os.read(r_pipe, 256)
|
||||
if master_fd in rd:
|
||||
try:
|
||||
data = os.read(master_fd, io.DEFAULT_BUFFER_SIZE)
|
||||
except OSError:
|
||||
data = b''
|
||||
if not data:
|
||||
break
|
||||
parse_bytes(data)
|
||||
if master_fd in wd:
|
||||
n = os.write(master_fd, write_buf)
|
||||
write_buf = write_buf[n:]
|
||||
if isatty:
|
||||
lines: list[str] = []
|
||||
screen.linebuf.as_ansi(lines.append)
|
||||
sys.stdout.write(''.join(lines))
|
||||
else:
|
||||
sys.stdout.write(str(screen.linebuf))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
run_parsing_benchmark()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -96,8 +96,8 @@ func get_dependencies(path string) (ans []dependency) {
|
||||
for _, line := range lines("otool", "-L", path) {
|
||||
line = strings.TrimSpace(line)
|
||||
if strings.Contains(line, "compatibility") && !strings.HasSuffix(line, ":") {
|
||||
before, _, _ := strings.Cut(line, "(")
|
||||
dep := strings.TrimSpace(before)
|
||||
idx := strings.IndexByte(line, '(')
|
||||
dep := strings.TrimSpace(line[:idx])
|
||||
ans = append(ans, dependency{path: dep, is_id: dep == install_name})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ def build_frozen_tools(kitty_exe):
|
||||
|
||||
def sanitize_source_folder(path: str) -> None:
|
||||
for q in walk(path):
|
||||
if os.path.splitext(q)[1] not in ('.py', '.glsl', '.ttf', '.otf', '.json'):
|
||||
if os.path.splitext(q)[1] not in ('.py', '.glsl', '.ttf', '.otf'):
|
||||
os.unlink(q)
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ def binary_includes():
|
||||
return tuple(map(get_dll_path, (
|
||||
'expat', 'sqlite3', 'ffi', 'z', 'lzma', 'png16', 'lcms2', 'ssl', 'crypto', 'crypt',
|
||||
'iconv', 'pcre2-8', 'graphite2', 'glib-2.0', 'freetype', 'xxhash',
|
||||
'pixman-1', 'cairo', 'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
|
||||
'harfbuzz', 'xkbcommon', 'xkbcommon-x11',
|
||||
# fontconfig is not bundled because in typical brain dead Linux
|
||||
# distro fashion, different distros use different default config
|
||||
# paths for fontconfig.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Requires installation of XCode >= 10.3 and go 1.26 and Python 3 and
|
||||
# python3 -m pip install certifi meson ninja
|
||||
# Requires installation of XCode >= 10.3 and go 1.23 and Python 3 and
|
||||
# python3 -m pip install certifi
|
||||
|
||||
vm_name 'macos-kitty'
|
||||
root '/Users/Shared/kitty-build'
|
||||
python '/usr/local/bin/python3'
|
||||
universal 'true'
|
||||
deploy_target '12.0'
|
||||
deploy_target '11.0'
|
||||
|
||||
@@ -95,8 +95,7 @@ def expand_dirs(items, exclude=lambda x: x.endswith('.so')):
|
||||
return items
|
||||
|
||||
|
||||
|
||||
def do_sign(app_dir: str) -> None:
|
||||
def do_sign(app_dir):
|
||||
with current_dir(join(app_dir, 'Contents')):
|
||||
# Sign all .so files
|
||||
so_files = {x for x in files_in('.') if x.endswith('.so')}
|
||||
@@ -110,10 +109,6 @@ def do_sign(app_dir: str) -> None:
|
||||
# Sign kitten
|
||||
with current_dir('MacOS'):
|
||||
codesign('kitten')
|
||||
# Sign sub-apps
|
||||
for x in os.listdir('.'):
|
||||
if x.endswith('.app'):
|
||||
codesign(x)
|
||||
|
||||
# Now sign the main app
|
||||
codesign(app_dir)
|
||||
@@ -135,7 +130,7 @@ def sign_app(app_dir, notarize):
|
||||
with make_certificate_useable():
|
||||
do_sign(app_dir)
|
||||
if notarize:
|
||||
notarize_app(app_dir, 'kitty')
|
||||
notarize_app(app_dir)
|
||||
|
||||
|
||||
class Freeze(object):
|
||||
@@ -173,7 +168,6 @@ class Freeze(object):
|
||||
self.freeze_python()
|
||||
self.add_ca_certs()
|
||||
self.build_frozen_tools()
|
||||
self.complete_sub_bundles()
|
||||
if not self.dont_strip:
|
||||
self.strip_files()
|
||||
if not self.skip_tests:
|
||||
@@ -184,16 +178,6 @@ class Freeze(object):
|
||||
|
||||
return ret
|
||||
|
||||
@flush
|
||||
def complete_sub_bundles(self):
|
||||
count = 0
|
||||
for qapp in glob.glob(join(self.contents_dir, '*.app')):
|
||||
for exe in glob.glob(join(self.contents_dir, 'MacOS', '*')):
|
||||
os.symlink(f'../../../MacOS/{os.path.basename(exe)}', os.path.join(qapp, 'Contents', 'MacOS', os.path.basename(exe)))
|
||||
count += 1
|
||||
if count < 2:
|
||||
raise SystemExit(f'Could not complete sub-bundles in {self.contents_dir}')
|
||||
|
||||
@flush
|
||||
def add_ca_certs(self):
|
||||
print('\nDownloading CA certs...')
|
||||
@@ -387,9 +371,6 @@ class Freeze(object):
|
||||
os.rename(join(dirname(self.contents_dir), 'bin', 'kitty'), join(self.contents_dir, 'MacOS', 'kitty'))
|
||||
shutil.rmtree(join(dirname(self.contents_dir), 'bin'))
|
||||
self.fix_dependencies_in_lib(join(self.contents_dir, 'MacOS', 'kitty'))
|
||||
for f in glob.glob(join(self.contents_dir, '*.app', 'Contents', 'MacOS', '*')):
|
||||
if not os.path.islink(f):
|
||||
self.fix_dependencies_in_lib(f)
|
||||
for f in walk(pdir):
|
||||
if f.endswith('.so') or f.endswith('.dylib'):
|
||||
self.fix_dependencies_in_lib(f)
|
||||
|
||||
@@ -1 +1 @@
|
||||
to_vm_excludes '/dependencies /build /dist /kitty/launcher/kitty* /.build-cache /.cache /.mypy_cache /.ruff_cache /tags __pycache__ /*_commands.json *.so *.pyd *.pyc *_generated.go'
|
||||
to_vm_excludes '/dependencies /build /dist /kitty/launcher/kitty* /.build-cache /tags __pycache__ /*_commands.json *.so *.pyd *.pyc *_generated.go'
|
||||
|
||||
@@ -1,302 +1,301 @@
|
||||
[
|
||||
{
|
||||
"name": "zlib 1.3.2",
|
||||
"name": "zlib",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:d7a0654783a4da529d1bb793b7ad9c3318020af77667bcae35f95d0e42a792f3",
|
||||
"filename": "zlib-1.3.1.tar.xz",
|
||||
"hash": "sha256:38ef96b8dfe510d42707d9c781877914792541133e1870841463bfa73f883e32",
|
||||
"urls": ["https://zlib.net/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "bzip2 1.0.8",
|
||||
"name": "bzip2",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "bzip2-1.0.8.tar.gz",
|
||||
"hash": "sha256:ab5a03176ee106d3f0fa90e381da478ddae405918153cca248e682cd0c4a2269",
|
||||
"urls": ["https://www.sourceware.org/pub/{name}/{filename}"]
|
||||
"urls": ["https://www.sourceware.org/pub/bzip2/bzip2-latest.tar.gz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "pkg-config 0.29.2",
|
||||
"type": "build",
|
||||
"name": "pkg-config",
|
||||
"os": "macos",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "pkg-config-0.29.2.tar.gz",
|
||||
"hash": "sha256:6fc69c01688c9458a57eb9a1664c9aba372ccda420a02bf4429fe610e7e7d591",
|
||||
"urls": ["https://pkg-config.freedesktop.org/releases/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "openssl 3.5.6",
|
||||
"name": "openssl",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:deae7c80cba99c4b4f940ecadb3c3338b13cb77418409238e57d7f31f2a3b736",
|
||||
"filename": "openssl-3.3.0.tar.gz",
|
||||
"hash": "sha256:53e66b043322a606abf0087e7699a0e033a37fa13feb9742df35c3a33b18fb02",
|
||||
"urls": ["https://www.openssl.org/source/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "cmake 3.29.3",
|
||||
"type": "build",
|
||||
"name": "cmake",
|
||||
"os": "macos",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "cmake-3.29.3.tar.gz",
|
||||
"hash": "sha256:252aee1448d49caa04954fd5e27d189dd51570557313e7b281636716a238bccb",
|
||||
"urls": ["https://cmake.org/files/v{version_except_last}/{filename}"]
|
||||
"urls": ["https://cmake.org/files/v3.19/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "expat 2.6.2",
|
||||
"name": "expat",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "expat-2.6.2.tar.xz",
|
||||
"hash": "sha256:ee14b4c5d8908b1bec37ad937607eab183d4d9806a08adee472c3c3121d27364",
|
||||
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_{version_with_underscores}/{filename}"]
|
||||
"urls": ["https://github.com/libexpat/libexpat/releases/download/R_2_6_2/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libxml2 2.15.3",
|
||||
"name": "libxml2",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:78262a6e7ac170d6528ebfe2efccdf220191a5af6a6cd61ea4a9a9a5042c7a07",
|
||||
"urls": ["https://download.gnome.org/sources/libxml2/{version_except_last}/{filename}"]
|
||||
"filename": "libxml2-2.12.7.tar.xz",
|
||||
"hash": "sha256:24ae78ff1363a973e6d8beba941a7945da2ac056e19b53956aeb6927fd6cfb56",
|
||||
"urls": ["https://download.gnome.org/sources/libxml2/2.12/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xkbcommon 1.7.0",
|
||||
"name": "xkbcommon",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "libxkbcommon-1.7.0.tar.xz",
|
||||
"hash": "sha256:65782f0a10a4b455af9c6baab7040e2f537520caa2ec2092805cdfd36863b247",
|
||||
"urls": ["https://xkbcommon.org/download/lib{filename}"]
|
||||
"urls": ["https://xkbcommon.org/download/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "sqlite 3.53.0",
|
||||
"name": "sqlite",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:851e9b38192fe2ceaa65e0baa665e7fa06230c3d9bd1a6a9662d02380d73365a",
|
||||
"urls": ["https://www.sqlite.org/2026/{name}-autoconf-3530000.{file_extension}"]
|
||||
"filename": "sqlite-autoconf-3450300.tar.gz",
|
||||
"hash": "sha256:b2809ca53124c19c60f42bf627736eae011afdcc205bb48270a5ee9a38191531",
|
||||
"urls": ["https://www.sqlite.org/2024/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libffi 3.4.6",
|
||||
"name": "libffi",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "libffi-3.4.6.tar.gz",
|
||||
"hash": "sha256:b0dea9df23c863a7a50e825440f3ebffabd65df1497108e5d437747843895a4e",
|
||||
"urls": ["https://github.com/libffi/libffi/releases/download/v{version}/{filename}"]
|
||||
"urls": ["https://github.com/libffi/libffi/releases/download/v3.4.6/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "ncurses 6.5",
|
||||
"name": "ncurses",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "ncurses-6.5.tar.gz",
|
||||
"hash": "sha256:136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6",
|
||||
"urls": ["https://ftp.gnu.org/gnu/ncurses/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "readline 8.2",
|
||||
"name": "readline",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "readline-8.2.tar.gz",
|
||||
"hash": "sha256:3feb7171f16a84ee82ca18a36d7b9be109a52c04f492a053331d7d1095007c35",
|
||||
"urls": ["https://ftp.gnu.org/gnu/readline/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xz 5.8.3",
|
||||
"name": "xz",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:3d3a1b973af218114f4f889bbaa2f4c037deaae0c8e815eec381c3d546b974a0",
|
||||
"filename": "xz-5.2.5.tar.gz",
|
||||
"hash": "sha256:f6f4910fd033078738bd82bfba4f49219d03b17eb0794eb91efbae419f4aba10",
|
||||
"urls": ["https://tukaani.org/xz/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libxxhash 0.8.2",
|
||||
"name": "libxxhash",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "xxHash-0.8.2.tar.gz",
|
||||
"hash": "sha256:baee0c6afd4f03165de7a4e67988d16f0f2b257b51d0e3cb91909302a26a79c4",
|
||||
"urls": ["https://github.com/Cyan4973/xxHash/archive/refs/tags/v{version}.{file_extension}"]
|
||||
"urls": ["https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.2.tar.gz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "xcrypt 4.4.36",
|
||||
"name": "xcrypt",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "xcrypt-4.4.36.tar.gz",
|
||||
"hash": "sha256:b979838d5f1f238869d467484793b72b8bca64c4eae696fdbba0a9e0b6c28453",
|
||||
"urls": ["https://github.com/besser82/libxcrypt/archive/v{version}.{file_extension}"]
|
||||
"urls": ["https://github.com/besser82/libxcrypt/archive/v4.4.36.tar.gz"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "python 3.14.5",
|
||||
"name": "python",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:7e32597b99e5d9a39abed35de4693fa169df3e5850d4c334337ffd6a19a36db6",
|
||||
"urls": ["https://www.python.org/ftp/python/{version}/Python-{version}.{file_extension}"]
|
||||
"filename": "Python-3.12.3.tar.xz",
|
||||
"hash": "sha256:56bfef1fdfc1221ce6720e43a661e3eb41785dd914ce99698d8c7896af4bdaa1",
|
||||
"urls": ["https://www.python.org/ftp/python/3.12.3/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libpng 1.6.57",
|
||||
"name": "libpng",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:d10c20d7171569804cae8dfc13ba6dcd0662c41ed39d43d4d429314aafb10a80",
|
||||
"filename": "libpng-1.6.43.tar.xz",
|
||||
"hash": "sha256:6a5ca0652392a2d7c9db2ae5b40210843c0bbc081cbd410825ab00cc59f14a6c",
|
||||
"urls": ["https://downloads.sourceforge.net/sourceforge/libpng/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "lcms2 2.17",
|
||||
"name": "lcms2",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"hash": "sha256:d11af569e42a1baa1650d20ad61d12e41af4fead4aa7964a01f93b08b53ab074",
|
||||
"urls": ["https://github.com/mm2/Little-CMS/releases/download/lcms{version}/lcms2-{version}.{file_extension}"]
|
||||
"filename": "lcms2-2.16.tar.gz",
|
||||
"hash": "sha256:d873d34ad8b9b4cea010631f1a6228d2087475e4dc5e763eb81acc23d9d45a51",
|
||||
"urls": ["https://github.com/mm2/Little-CMS/archive/2.16/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "graphite 1.3.14",
|
||||
"name": "graphite",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tgz",
|
||||
"filename": "graphite2-1.3.14.tgz",
|
||||
"hash": "sha256:f99d1c13aa5fa296898a181dff9b82fb25f6cc0933dbaa7a475d8109bd54209d",
|
||||
"urls": ["https://downloads.sourceforge.net/silgraphite/graphite2-{version}.{file_extension}"]
|
||||
"urls": ["https://downloads.sourceforge.net/silgraphite/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "pcre 10.43",
|
||||
"name": "pcre",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.bz2",
|
||||
"filename": "pcre2-10.43.tar.bz2",
|
||||
"hash": "sha256:e2a53984ff0b07dfdb5ae4486bbb9b21cca8e7df2434096cc9bf1b728c350bcb",
|
||||
"urls": ["https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.43/pcre2-{version}.{file_extension}"]
|
||||
"urls": ["https://github.com/PCRE2Project/pcre2/releases/download/pcre2-10.43/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "iconv 1.17",
|
||||
"name": "iconv",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "libiconv-1.17.tar.gz",
|
||||
"hash": "sha256:8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313",
|
||||
"urls": ["https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{version}.{file_extension}"]
|
||||
"urls": ["https://ftp.gnu.org/pub/gnu/libiconv/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "glib 2.86.3",
|
||||
"os": "linux",
|
||||
"name": "installer",
|
||||
"comment": "Needed infrastructure for installing pure python packages (wheels)",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:b3211d8d34b9df5dca05787ef0ad5d7ca75dec998b970e1aab0001d229977c65",
|
||||
"urls": ["https://download.gnome.org/sources/glib/{version_except_last}/{filename}"]
|
||||
"filename": "installer-0.7.0-py3-none-any.whl",
|
||||
"hash": "sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53",
|
||||
"urls": ["pypi"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "libbrotli 1.1.0",
|
||||
"name": "packaging",
|
||||
"comment": "Needed for glib for some absurd reason",
|
||||
"unix": {
|
||||
"filename": "packaging-23.1-py3-none-any.whl",
|
||||
"hash": "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61",
|
||||
"urls": ["pypi"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "glib",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.gz",
|
||||
"filename": "glib-2.80.2.tar.xz",
|
||||
"hash": "sha256:b9cfb6f7a5bd5b31238fd5d56df226b2dda5ea37611475bf89f6a0f9400fe8bd",
|
||||
"urls": ["https://download.gnome.org/sources/glib/2.80/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "brotli",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"filename": "brotli-1.1.0.tar.gz",
|
||||
"hash": "sha256:e720a6ca29428b803f4ad165371771f5398faba397edf6778837a18599ea13ff",
|
||||
"urls": ["https://github.com/google/brotli/archive/v{version}/{filename}"]
|
||||
"urls": ["https://github.com/google/brotli/archive/v1.1.0/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "pixman 0.44.2",
|
||||
"name": "freetype",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:50baf820dde0c5ff9714d03d2df4970f606a3d3b1024f5404c0398a9821cc4b0",
|
||||
"urls": ["https://www.cairographics.org/releases/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "freetype 2.13.2",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "freetype-2.13.2.tar.xz",
|
||||
"hash": "sha256:12991c4e55c506dd7f9b765933e62fd2be2e06d421505d7950a132e4f1bb484d",
|
||||
"urls": ["https://download.savannah.gnu.org/releases/freetype/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "fontconfig 2.17.1",
|
||||
"name": "fontconfig",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:9f5cae93f4fffc1fbc05ae99cdfc708cd60dfd6612ffc0512827025c026fa541",
|
||||
"urls": ["https://gitlab.freedesktop.org/api/v4/projects/890/packages/generic/fontconfig/{version}/{filename}"]
|
||||
"filename": "fontconfig-2.13.1.tar.bz2",
|
||||
"hash": "sha256:f655dd2a986d7aa97e052261b36aa67b0a64989496361eca8d604e6414006741",
|
||||
"urls": ["https://www.fontconfig.org/release/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "cairo 1.18.2",
|
||||
"os": "linux",
|
||||
"name": "harfbuzz",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:a62b9bb42425e844cc3d6ddde043ff39dbabedd1542eba57a2eb79f85889d45a",
|
||||
"urls": ["https://www.cairographics.org/releases/{filename}"]
|
||||
"filename": "harfbuzz-8.5.0.tar.xz",
|
||||
"hash": "sha256:77e4f7f98f3d86bf8788b53e6832fb96279956e1c3961988ea3d4b7ca41ddc27",
|
||||
"urls": ["https://github.com/harfbuzz/harfbuzz/releases/download/8.5.0/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "harfbuzz 12.3.0",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:8660ebd3c27d9407fc8433b5d172bafba5f0317cb0bb4339f28e5370c93d42b7",
|
||||
"urls": ["https://github.com/harfbuzz/harfbuzz/releases/download/{version}/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "simde 0.7.6",
|
||||
"name": "simde",
|
||||
"comment": "Cannot update till gcc in the build VM is updated as simde 0.8 requires newer gcc",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"filename": "simde-amalgamated-0.7.6.tar.xz",
|
||||
"hash": "sha256:703eac1f2af7de1f7e4aea2286130b98e1addcc0559426e78304c92e2b4eb5e1",
|
||||
"urls": ["https://github.com/simd-everywhere/simde/releases/download/v{version}/simde-amalgamated-{version}.{file_extension}"]
|
||||
"urls": ["https://github.com/simd-everywhere/simde/releases/download/v0.7.6/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "wayland 1.24.0",
|
||||
"name": "wayland",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:82892487a01ad67b334eca83b54317a7c86a03a89cfadacfef5211f11a5d0536",
|
||||
"urls": ["https://gitlab.freedesktop.org/wayland/wayland/-/releases/{version}/downloads/{filename}"]
|
||||
"filename": "wayland-1.23.0.tar.xz",
|
||||
"hash": "sha256:05b3e1574d3e67626b5974f862f36b5b427c7ceeb965cb36a4e6c2d342e45ab2",
|
||||
"urls": ["https://gitlab.freedesktop.org/wayland/wayland/-/releases/1.23.0/downloads/{filename}"]
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
"name": "wayland-protocols 1.45",
|
||||
"name": "wayland-protocols",
|
||||
"os": "linux",
|
||||
"unix": {
|
||||
"file_extension": "tar.xz",
|
||||
"hash": "sha256:4d2b2a9e3e099d017dc8107bf1c334d27bb87d9e4aff19a0c8d856d17cd41ef0",
|
||||
"urls": ["https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/{version}/downloads/{filename}"]
|
||||
"filename": "wayland-protocols-1.36.tar.xz",
|
||||
"hash": "sha256:71fd4de05e79f9a1ca559fac30c1f8365fa10346422f9fe795f74d77b9ef7e92",
|
||||
"urls": ["https://gitlab.freedesktop.org/wayland/wayland-protocols/-/releases/1.36/downloads/{filename}"]
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
@@ -13,6 +13,6 @@ for attr in ('linguist-generated', 'linguist-vendored'):
|
||||
fname = line.split(':', 1)[0]
|
||||
all_files.discard(fname)
|
||||
|
||||
all_files -= {'gen/rowcolumn-diacritics.txt'}
|
||||
all_files -= {'gen/nerd-fonts-glyphs.txt', 'gen/rowcolumn-diacritics.txt'}
|
||||
cp = subprocess.run(['cloc', '--list-file', '-'], input='\n'.join(all_files).encode())
|
||||
raise SystemExit(cp.returncode)
|
||||
|
||||
@@ -8,7 +8,4 @@ using the ``map`` and ``mouse_map`` directives in :file:`kitty.conf`. For
|
||||
configuration examples, see the default shortcut links for each action.
|
||||
To read about keyboard mapping in more detail, see :doc:`mapping`.
|
||||
|
||||
You can also browse and trigger these actions by pressing :sc:`command_palette`
|
||||
to run the :doc:`/kittens/command-palette`.
|
||||
|
||||
.. include:: /generated/actions.rst
|
||||
|
||||
@@ -25,7 +25,6 @@ Previous shell prompt :sc:`scroll_to_previous_prompt` (see :ref:`shell_int
|
||||
Next shell prompt :sc:`scroll_to_next_prompt` (see :ref:`shell_integration`)
|
||||
Browse scrollback in less :sc:`show_scrollback`
|
||||
Browse last cmd output :sc:`show_last_command_output` (see :ref:`shell_integration`)
|
||||
Search scrollback in less :sc:`search_scrollback` (also :kbd:`⌘+F` on macOS)
|
||||
========================= =======================
|
||||
|
||||
The scroll actions only take effect when the terminal is in the main screen.
|
||||
@@ -41,7 +40,7 @@ Action Shortcut
|
||||
======================== =======================
|
||||
New tab :sc:`new_tab` (also :kbd:`⌘+t` on macOS)
|
||||
Close tab :sc:`close_tab` (also :kbd:`⌘+w` on macOS)
|
||||
Next tab :sc:`next_tab` (also :kbd:`⌃+⇥` and :kbd:`⇧+⌘+]` on macOS)
|
||||
Next tab :sc:`next_tab` (also :kbd:`⇧+⌃+⇥` and :kbd:`⇧+⌘+]` on macOS)
|
||||
Previous tab :sc:`previous_tab` (also :kbd:`⇧+⌃+⇥` and :kbd:`⇧+⌘+[` on macOS)
|
||||
Next layout :sc:`next_layout`
|
||||
Move tab forward :sc:`move_tab_forward`
|
||||
@@ -117,9 +116,6 @@ Similarly, you can detach the current tab, with::
|
||||
# asks which OS Window to move the tab into
|
||||
map ctrl+f4 detach_tab ask
|
||||
|
||||
Note that tabs can be re-arranged, detached and moved to another OS Window in
|
||||
the same kitty instance using drag and drop.
|
||||
|
||||
Finally, you can define a shortcut to close all windows in a tab other than the
|
||||
currently active window::
|
||||
|
||||
|
||||
@@ -23,9 +23,7 @@ simply re-run the command.
|
||||
**Do not** copy the kitty binary out of the installation folder. If you want
|
||||
to add it to your :envvar:`PATH`, create a symlink in :file:`~/.local/bin` or
|
||||
:file:`/usr/bin` or wherever. You should create a symlink for the :file:`kitten`
|
||||
binary as well. Whichever folder you choose to create the symlink in should
|
||||
be in the **systemwide** PATH, a folder added to the PATH in your shell rc
|
||||
files will not work when running kitty from your desktop environment.
|
||||
binary as well.
|
||||
|
||||
|
||||
Manually installing
|
||||
|
||||
@@ -13,8 +13,7 @@ Build from source
|
||||
|
||||
|kitty| is designed to run from source, for easy hack-ability. All you need to
|
||||
get started is a C compiler and the `go compiler
|
||||
<https://go.dev/doc/install>`__ (on Linux, the :ref:`X11 development libraries <x11-dev-libs>` as well).
|
||||
After installing those, run the following commands::
|
||||
<https://go.dev/doc/install>`__. After installing those, run the following commands::
|
||||
|
||||
git clone https://github.com/kovidgoyal/kitty.git && cd kitty
|
||||
./dev.sh build
|
||||
@@ -24,8 +23,7 @@ That's it, kitty will be built from source, magically. You can run it as
|
||||
|
||||
This works, because the :code:`./dev.sh build` command downloads all the major
|
||||
dependencies of kitty as pre-built binaries for your platform and builds kitty
|
||||
to use these rather than system libraries. The few required system libraries
|
||||
are X11 and DBUS on Linux.
|
||||
to use these rather than system libraries.
|
||||
|
||||
If you make changes to kitty code, simply re-run :code:`./dev.sh build`
|
||||
to build kitty with your changes.
|
||||
@@ -82,15 +80,13 @@ These dependencies are needed when building against system libraries only.
|
||||
|
||||
Run-time dependencies:
|
||||
|
||||
* ``python``
|
||||
* ``python`` >= 3.8
|
||||
* ``harfbuzz`` >= 2.2.0
|
||||
* ``zlib``
|
||||
* ``libpng``
|
||||
* ``liblcms2``
|
||||
* ``libxxhash``
|
||||
* ``openssl``
|
||||
* ``pixman`` (not needed on macOS)
|
||||
* ``cairo`` (not needed on macOS)
|
||||
* ``freetype`` (not needed on macOS)
|
||||
* ``fontconfig`` (not needed on macOS)
|
||||
* ``libcanberra`` (not needed on macOS)
|
||||
@@ -109,18 +105,6 @@ Build-time dependencies:
|
||||
need to install the following packages, if they are not already installed by
|
||||
your distro:
|
||||
|
||||
- ``liblcms2-dev``
|
||||
- ``libfontconfig-dev``
|
||||
- ``libssl-dev``
|
||||
- ``libpython3-dev``
|
||||
- ``libxxhash-dev``
|
||||
- ``libsimde-dev``
|
||||
- ``libcairo2-dev``
|
||||
|
||||
.. _x11-dev-libs:
|
||||
|
||||
Also, the X11 development libraries:
|
||||
|
||||
- ``libdbus-1-dev``
|
||||
- ``libxcursor-dev``
|
||||
- ``libxrandr-dev``
|
||||
@@ -130,7 +114,11 @@ Build-time dependencies:
|
||||
- ``libxkbcommon-x11-dev``
|
||||
- ``libfontconfig-dev``
|
||||
- ``libx11-xcb-dev``
|
||||
|
||||
- ``liblcms2-dev``
|
||||
- ``libssl-dev``
|
||||
- ``libpython3-dev``
|
||||
- ``libxxhash-dev``
|
||||
- ``libsimde-dev``
|
||||
|
||||
|
||||
Build and run from source with Nix
|
||||
|
||||
1027
docs/changelog.rst
1027
docs/changelog.rst
File diff suppressed because it is too large
Load Diff
@@ -47,8 +47,7 @@ The terminal emulator will reply with a sequence of escape codes of the form::
|
||||
|
||||
Here, the ``status=DATA`` packets deliver the data (as base64 encoded bytes)
|
||||
associated with each MIME type. The terminal emulator should chunk up the data
|
||||
for an individual type, into chunks of size **no more** than 4096 bytes (4096
|
||||
is the size of a chunk *before* base64 encoding). All
|
||||
for an individual type. A recommended size for each chunk is 4096 bytes. All
|
||||
the chunks for a given type must be transmitted sequentially and only once they
|
||||
are done the chunks for the next type, if any, should be sent. The end of data
|
||||
is indicated by a ``status=DONE`` packet.
|
||||
@@ -91,8 +90,7 @@ following sequence of packets::
|
||||
|
||||
The final packet with no mime and no data indicates end of transmission. The
|
||||
data for every MIME type should be split into chunks of no more than 4096
|
||||
bytes (4096 is the size of the data before base64 encoding).
|
||||
All the chunks for a given MIME type must be sent sequentially, before
|
||||
bytes. All the chunks for a given MIME type must be sent sequentially, before
|
||||
sending chunks for the next MIME type. After the transmission is complete, the
|
||||
terminal replies with a single packet indicating success::
|
||||
|
||||
@@ -138,72 +136,6 @@ the data, but create multiple references to it in the system clipboard. Alias
|
||||
packets can be sent anytime after the initial write packet and before the end
|
||||
of data packet.
|
||||
|
||||
.. _clipboard_repeated_permission:
|
||||
|
||||
Avoiding repeated permission prompts
|
||||
--------------------------------------
|
||||
|
||||
.. versionadded:: 0.42.2
|
||||
using a password to avoid repeated confirmations
|
||||
|
||||
If a program like an editor wants to make use of the system clipboard, by
|
||||
default, the user is prompted on every read request. This can become quite
|
||||
fatiguing. To avoid this situation, this protocol allows sending a password
|
||||
and human friendly name with ``type=write`` and ``type=read`` requests. The
|
||||
terminal can then ask the user to allow all future requests using that
|
||||
password. If the user agrees, future requests on the same tty will be
|
||||
automatically allowed by the terminal. The editor or other program using
|
||||
this facility should ideally use a password randomly generated at startup,
|
||||
such as a UUID4. However, terminals may implement permanent/stored passwords.
|
||||
Users can then configure terminal programs they trust to use these password.
|
||||
|
||||
The password and the human name are encoded using the ``pw`` and ``name`` keys
|
||||
in the metadata. The values are UTF-8 strings that are base64 encoded.
|
||||
Specifying a password without a human friendly name is equivalent to not
|
||||
specifying a password and the terminal must treat the request as though
|
||||
it had no password.
|
||||
|
||||
Allowing terminal applications to respond to paste events
|
||||
--------------------------------------------------------------
|
||||
|
||||
.. versionadded:: 0.44.1
|
||||
paste events via the 5522 mode
|
||||
|
||||
If a TUI application wants to handle paste events (like the user pressing the
|
||||
paste key shortcut used by the terminal or selecting paste from a terminal UI menu)
|
||||
it can enable the *paste events* private mode (5522), as described in this `ancillary
|
||||
specification <https://rockorager.dev/misc/bracketed-paste-mime/>`__. When that
|
||||
mode is set, the terminal will send the application a list of MIME types on the
|
||||
clipboard every time the user triggers a paste action. The application is then
|
||||
free to request whatever MIME data it wants from the list of types.
|
||||
|
||||
The mode can be enabled using the standard DECSET or DECRST control sequences.
|
||||
``CSI ? 5522 h`` to enable the mode. ``CSI ? 5522 l`` to disable the mode.
|
||||
|
||||
The terminal *should* send a one time password with the list of mime
|
||||
types, as the ``pw`` key (base64 encoded). The application can then use this
|
||||
password to request data from the clipboard without needing a permission
|
||||
prompt. The human name *should* be set to ``Paste event`` (base64 encoded) when
|
||||
the application uses this one time password.
|
||||
|
||||
Detecting support for this protocol
|
||||
-----------------------------------------
|
||||
|
||||
Applications can detect if a terminal supports this protocol with a standard
|
||||
DECRQM query:
|
||||
|
||||
.. code::
|
||||
|
||||
CSI ? 5522 $ p
|
||||
|
||||
To which the terminal will respond with a DECRPM response:
|
||||
|
||||
.. code::
|
||||
|
||||
CSI ? 5522 ; Ps $ y
|
||||
|
||||
A Ps value of 0 or 4 means the mode is not supported.
|
||||
|
||||
|
||||
Support for terminal multiplexers
|
||||
------------------------------------
|
||||
@@ -218,15 +150,11 @@ other characters must be stripped out from the id by the terminal emulator
|
||||
before retransmitting it.
|
||||
|
||||
Note that when using a terminal multiplexer it is possible for two different
|
||||
programs to overwrite each other's clipboard requests. This is fundamentally
|
||||
programs to overwrite each others clipboard requests. This is fundamentally
|
||||
unavoidable since the system clipboard is a single global shared resource.
|
||||
However, there is an additional complication where responses from this protocol
|
||||
However, there is an additional complication where responses form this protocol
|
||||
could get lost if, for instance, multiple write requests are received
|
||||
simultaneously. It is up to well designed multiplexers to ensure that only a
|
||||
single request is in flight at a time. The multiplexer can abort requests by
|
||||
sending back the ``EBUSY`` error code indicating some other window is trying
|
||||
to access the clipboard.
|
||||
|
||||
When the terminal sends an unsolicited paste event because the user triggered
|
||||
a paste and the 5522 mode is enabled, there will be no associated id. In this
|
||||
case, the multiplexer must forward the event to the currently active window.
|
||||
|
||||
@@ -52,8 +52,8 @@ than numbers. The syntax of the escape code is::
|
||||
<OSC> 21 ; key=value ; key=value ; ... <ST>
|
||||
|
||||
The spaces in the above definition are for reading clarity and should be ignored.
|
||||
Here, ``<OSC>`` is the two bytes ``0x1b (ESC)`` and ``0x5d (])``. ``<ST>`` is
|
||||
either ``0x07 (BEL)`` or the two bytes ``0x1b (ESC)`` and ``0x5c (\\)``.
|
||||
Here, ``<OSC>`` is the two bytes ``0x1b (ESC)`` and ``0x5b ([)``. ``ST`` is
|
||||
either `0x7 (BEL)` or the two bytes ``0x1b (ESC)`` and ``0x5c (\\)``.
|
||||
|
||||
``key`` is a number from 0-255 to query or set the color values from the
|
||||
terminals ANSI color table, or one of the strings in the table below for
|
||||
@@ -69,7 +69,7 @@ selection_foreground The foreground color of selections
|
||||
cursor The color of the text cursor Foreground color
|
||||
cursor_text The color of text under the cursor Background color
|
||||
visual_bell The color of a visual bell Automatic color selection based on current screen colors
|
||||
transparent_background_color1..7 A background color that is rendered Unset
|
||||
transparent_background_color1..8 A background color that is rendered Unset
|
||||
with the specified opacity in cells that have
|
||||
the specified background color. An opacity
|
||||
value less than zero means, use the
|
||||
@@ -103,7 +103,7 @@ This indicates that the foreground color is red and the cursor color is
|
||||
undefined (typically the cursor takes the color of the text under it and the
|
||||
text takes the color of the background).
|
||||
|
||||
If the terminal does not know a field that a client sends to it for a query it
|
||||
If the terminal does not know a field that a client send to it for a query it
|
||||
must respond back with the ``field=?``, that is, it must send back a question
|
||||
mark as the value.
|
||||
|
||||
|
||||
126
docs/conf.py
126
docs/conf.py
@@ -18,9 +18,8 @@ from typing import Any, Callable, Dict, Iterable, Iterator, List, Tuple
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.roles import set_classes
|
||||
from pygments.lexer import RegexLexer
|
||||
from pygments.lexer import bygroups as untyped_bygroups
|
||||
from pygments.token import Comment, Error, Keyword, Literal, Name, Number, String, Whitespace
|
||||
from pygments.lexer import RegexLexer, bygroups # type: ignore
|
||||
from pygments.token import Comment, Error, Keyword, Literal, Name, Number, String, Whitespace # type: ignore
|
||||
from sphinx import addnodes, version_info
|
||||
from sphinx.util.logging import getLogger
|
||||
|
||||
@@ -30,7 +29,7 @@ if kitty_src not in sys.path:
|
||||
|
||||
from kitty.conf.types import Definition, expand_opt_references # noqa
|
||||
from kitty.constants import str_version, website_url # noqa
|
||||
from kitty.fast_data_types import DND_CODE, Shlex, TEXT_SIZE_CODE # noqa
|
||||
from kitty.fast_data_types import Shlex # noqa
|
||||
|
||||
# config {{{
|
||||
# -- Project information -----------------------------------------------------
|
||||
@@ -63,7 +62,7 @@ extensions = [
|
||||
'sphinx.ext.extlinks',
|
||||
'sphinx_copybutton',
|
||||
'sphinx_inline_tabs',
|
||||
'sphinxext.opengraph',
|
||||
"sphinxext.opengraph",
|
||||
]
|
||||
|
||||
# URL for OpenGraph tags
|
||||
@@ -120,8 +119,6 @@ def go_version(go_mod_path: str) -> str: # {{{
|
||||
string_replacements = {
|
||||
'_kitty_install_cmd': 'curl -L https://sw.kovidgoyal.net/kitty/installer.sh | sh /dev/stdin',
|
||||
'_build_go_version': go_version('../go.mod'),
|
||||
'_text_size_code': str(TEXT_SIZE_CODE),
|
||||
'_dnd_code': str(DND_CODE),
|
||||
}
|
||||
|
||||
|
||||
@@ -239,13 +236,6 @@ def write_cli_docs(all_kitten_names: Iterable[str]) -> None:
|
||||
usage='file-or-dir-to-copy ...', message=copy_message
|
||||
))
|
||||
del sys.modules['kittens.ssh.main']
|
||||
from kitty.session import save_as_session_message, save_as_session_options
|
||||
with open('generated/save-as-session.rst', 'w') as f:
|
||||
f.write(option_spec_as_rst(
|
||||
appname='save_as_session', ospec=save_as_session_options, heading_char='^',
|
||||
usage='[path-to-save-session-file-at]',
|
||||
message=save_as_session_message,
|
||||
))
|
||||
|
||||
from kitty.launch import options_spec as launch_options_spec
|
||||
with open('generated/launch.rst', 'w') as f:
|
||||
@@ -302,7 +292,7 @@ if you specify a program-to-run you can use the special placeholder
|
||||
|
||||
|
||||
def write_color_names_table() -> None: # {{{
|
||||
from kitty.fast_data_types import all_color_names
|
||||
from kitty.rgb import color_names
|
||||
def s(c: Any) -> str:
|
||||
return f'{c.red:02x}/{c.green:02x}/{c.blue:02x}'
|
||||
with open('generated/color-names.rst', 'w') as f:
|
||||
@@ -310,7 +300,7 @@ def write_color_names_table() -> None: # {{{
|
||||
p('=' * 50, '=' * 20)
|
||||
p('Name'.ljust(50), 'RGB value')
|
||||
p('=' * 50, '=' * 20)
|
||||
for name, col in all_color_names():
|
||||
for name, col in color_names.items():
|
||||
p(name.ljust(50), s(col))
|
||||
p('=' * 50, '=' * 20)
|
||||
# }}}
|
||||
@@ -361,7 +351,7 @@ def write_remote_control_protocol_docs() -> None: # {{{
|
||||
|
||||
def replace_string(app: Any, docname: str, source: List[str]) -> None: # {{{
|
||||
src = source[0]
|
||||
for k, v in string_replacements.items():
|
||||
for k, v in app.config.string_replacements.items():
|
||||
src = src.replace(k, v)
|
||||
source[0] = src
|
||||
# }}}
|
||||
@@ -369,45 +359,41 @@ def replace_string(app: Any, docname: str, source: List[str]) -> None: # {{{
|
||||
# config file docs {{{
|
||||
|
||||
|
||||
def bygroups(*args: Any) -> Any:
|
||||
return untyped_bygroups(*args) # type: ignore[no-untyped-call]
|
||||
|
||||
|
||||
class ConfLexer(RegexLexer):
|
||||
class ConfLexer(RegexLexer): # type: ignore
|
||||
name = 'Conf'
|
||||
aliases = ['conf']
|
||||
filenames = ['*.conf']
|
||||
|
||||
def map_flags(self: RegexLexer, val: str, start_pos: int) -> Iterator[Tuple[int, Any, str]]:
|
||||
expecting_arg = ''
|
||||
s = Shlex(val)
|
||||
from kitty.options.utils import allowed_key_map_options
|
||||
last_pos = 0
|
||||
while (tok := s.next_word())[0] > -1:
|
||||
x = tok[1]
|
||||
if tok[0] > last_pos:
|
||||
yield start_pos + last_pos, Whitespace, ' ' * (tok[0] - last_pos)
|
||||
last_pos = tok[0] + len(x)
|
||||
tok_start = start_pos + tok[0]
|
||||
if expecting_arg:
|
||||
yield tok_start, String, x
|
||||
expecting_arg = ''
|
||||
elif x.startswith('--'):
|
||||
expecting_arg = x[2:]
|
||||
k, sep, v = expecting_arg.partition('=')
|
||||
k = k.replace('-', '_')
|
||||
expecting_arg = k
|
||||
if expecting_arg not in allowed_key_map_options:
|
||||
yield tok_start, Error, x
|
||||
elif sep == '=':
|
||||
expecting_arg = ''
|
||||
s = Shlex(val)
|
||||
from kitty.options.utils import allowed_key_map_options
|
||||
last_pos = 0
|
||||
while (tok := s.next_word())[0] > -1:
|
||||
x = tok[1]
|
||||
if tok[0] > last_pos:
|
||||
yield start_pos + last_pos, Whitespace, ' ' * (tok[0] - last_pos)
|
||||
last_pos = tok[0] + len(x)
|
||||
tok_start = start_pos + tok[0]
|
||||
if expecting_arg:
|
||||
yield tok_start, String, x
|
||||
expecting_arg = ''
|
||||
yield tok_start, Name, x
|
||||
elif x.startswith('--'):
|
||||
expecting_arg = x[2:]
|
||||
k, sep, v = expecting_arg.partition('=')
|
||||
k = k.replace('-', '_')
|
||||
expecting_arg = k
|
||||
if expecting_arg not in allowed_key_map_options:
|
||||
yield tok_start, Error, x
|
||||
elif sep == '=':
|
||||
expecting_arg = ''
|
||||
yield tok_start, Name, x
|
||||
else:
|
||||
yield tok_start, Name, x
|
||||
else:
|
||||
yield tok_start, Name, x
|
||||
else:
|
||||
break
|
||||
break
|
||||
|
||||
def mapargs(self: 'ConfLexer', match: 're.Match[str]') -> Iterator[Tuple[int, Any, str]]:
|
||||
def mapargs(self: RegexLexer, match: 're.Match[str]') -> Iterator[Tuple[int, Any, str]]:
|
||||
start_pos = match.start()
|
||||
val = match.group()
|
||||
parts = val.split(maxsplit=1)
|
||||
@@ -471,7 +457,7 @@ class ConfLexer(RegexLexer):
|
||||
}
|
||||
|
||||
|
||||
class SessionLexer(RegexLexer):
|
||||
class SessionLexer(RegexLexer): # type: ignore
|
||||
name = 'Session'
|
||||
aliases = ['session']
|
||||
filenames = ['*.session']
|
||||
@@ -656,10 +642,33 @@ def monkeypatch_man_writer() -> None:
|
||||
'''
|
||||
Monkeypatch the docutils man translator to be nicer
|
||||
'''
|
||||
from docutils.nodes import figure
|
||||
from docutils.writers.manpage import Translator
|
||||
from docutils.nodes import Element
|
||||
from docutils.writers.manpage import Table, Translator
|
||||
from sphinx.writers.manpage import ManualPageTranslator
|
||||
|
||||
# Generate nicer tables https://sourceforge.net/p/docutils/bugs/475/
|
||||
class PatchedTable(Table): # type: ignore
|
||||
_options: list[str]
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.needs_border_removal = self._options == ['center']
|
||||
if self.needs_border_removal:
|
||||
self._options = ['box', 'center']
|
||||
|
||||
def as_list(self) -> list[str]:
|
||||
ans: list[str] = super().as_list()
|
||||
if self.needs_border_removal:
|
||||
# remove side and top borders as we use box in self._options
|
||||
ans[2] = ans[2][1:]
|
||||
a, b = ans[2].rpartition('|')[::2]
|
||||
ans[2] = a + b
|
||||
if ans[3] == '_\n':
|
||||
del ans[3] # top border
|
||||
del ans[-2] # bottom border
|
||||
return ans
|
||||
def visit_table(self: ManualPageTranslator, node: object) -> None:
|
||||
setattr(self, '_active_table', PatchedTable())
|
||||
setattr(ManualPageTranslator, 'visit_table', visit_table)
|
||||
|
||||
# Improve header generation
|
||||
def header(self: ManualPageTranslator) -> str:
|
||||
@@ -676,13 +685,13 @@ def monkeypatch_man_writer() -> None:
|
||||
|
||||
setattr(ManualPageTranslator, 'header', header)
|
||||
|
||||
def visit_image(self: ManualPageTranslator, node: figure) -> None:
|
||||
def visit_image(self: ManualPageTranslator, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_image(self: ManualPageTranslator, node: figure) -> None:
|
||||
def depart_image(self: ManualPageTranslator, node: Element) -> None:
|
||||
pass
|
||||
|
||||
def depart_figure(self: ManualPageTranslator, node: figure) -> None:
|
||||
def depart_figure(self: ManualPageTranslator, node: Element) -> None:
|
||||
self.body.append(' (images not supported)\n')
|
||||
Translator.depart_figure(self, node)
|
||||
|
||||
@@ -690,8 +699,8 @@ def monkeypatch_man_writer() -> None:
|
||||
setattr(ManualPageTranslator, 'depart_image', depart_image)
|
||||
setattr(ManualPageTranslator, 'depart_figure', depart_figure)
|
||||
|
||||
orig_astext = getattr(ManualPageTranslator, 'astext')
|
||||
def astext(self: ManualPageTranslator) -> Any:
|
||||
orig_astext = Translator.astext
|
||||
def astext(self: Translator) -> Any:
|
||||
b = []
|
||||
for line in self.body:
|
||||
if line.startswith('.SH'):
|
||||
@@ -700,9 +709,9 @@ def monkeypatch_man_writer() -> None:
|
||||
parts[0] = parts[0].capitalize()
|
||||
line = x + ' ' + '\n'.join(parts)
|
||||
b.append(line)
|
||||
setattr(self, 'body', b)
|
||||
self.body = b
|
||||
return orig_astext(self)
|
||||
setattr(ManualPageTranslator, 'astext', astext)
|
||||
setattr(Translator, 'astext', astext)
|
||||
|
||||
|
||||
def setup_man_pages() -> None:
|
||||
@@ -759,6 +768,7 @@ def setup(app: Any) -> None:
|
||||
write_remote_control_protocol_docs()
|
||||
write_color_names_table()
|
||||
write_conf_docs(app, kn)
|
||||
app.add_config_value('string_replacements', {}, True)
|
||||
app.connect('source-read', replace_string)
|
||||
app.add_config_value('analytics_id', '', 'env')
|
||||
app.connect('html-page-context', add_html_context)
|
||||
|
||||
@@ -16,8 +16,7 @@ frames-per-second. See below for an overview of all customization possibilities.
|
||||
You can open the config file within |kitty| by pressing :sc:`edit_config_file`
|
||||
(:kbd:`⌘+,` on macOS). A :file:`kitty.conf` with commented default
|
||||
configurations and descriptions will be created if the file does not exist.
|
||||
The configuration is automatically reloaded when modified, controlled by
|
||||
:opt:`auto_reload_config`. You can manually reload the config by pressing
|
||||
You can reload the config file within |kitty| by pressing
|
||||
:sc:`reload_config_file` (:kbd:`⌃+⌘+,` on macOS) or sending |kitty| the
|
||||
``SIGUSR1`` signal with ``kill -SIGUSR1 $KITTY_PID``. You can also display the
|
||||
current configuration by pressing :sc:`debug_config` (:kbd:`⌥+⌘+,` on macOS).
|
||||
@@ -46,21 +45,17 @@ expanded, so :code:`${USER}.conf` becomes :file:`name.conf` if
|
||||
to detect the operating system. It is ``linux``, ``macos`` or ``bsd``.
|
||||
Also, you can use :code:`globinclude` to include files
|
||||
matching a shell glob pattern and :code:`envinclude` to include configuration
|
||||
from environment variables. Finally, you can dynamically generate configuration
|
||||
by running a program using :code:`geninclude`. For example::
|
||||
from environment variables. For example::
|
||||
|
||||
# Include other.conf
|
||||
include other.conf
|
||||
# Include *.conf files from all subdirs of kitty.d inside the kitty config dir
|
||||
globinclude kitty.d/**/*.conf
|
||||
# Include the *contents* of all env vars starting with KITTY_CONF_
|
||||
envinclude KITTY_CONF_*
|
||||
# Run the script dynamic.py placed in the same directory as this config file
|
||||
# and include its :file:`STDOUT`. Note that Python scripts are fastest
|
||||
# as they use the embedded Python interpreter, but any executable script
|
||||
# or program is supported, in any language. Remember to mark the script
|
||||
# file executable.
|
||||
geninclude dynamic.py
|
||||
|
||||
|
||||
.. note:: Syntax highlighting for :file:`kitty.conf` in vim is available via
|
||||
`vim-kitty <https://github.com/fladson/vim-kitty>`__.
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitty.rst
|
||||
@@ -98,4 +93,3 @@ See the :doc:`list of all the things you can make |kitty| can do </actions>`.
|
||||
:hidden:
|
||||
|
||||
actions
|
||||
wide-gamut-colors
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.. _notifications_on_the_desktop:
|
||||
.. _desktop_notifications:
|
||||
|
||||
|
||||
Desktop notifications
|
||||
@@ -25,7 +25,7 @@ the set :code:`a-zA-Z0-9-_/\+.,(){}[]*&^%$#@!`~`. The payload must be
|
||||
interpreted based on the metadata section. The two semi-colons *must* always be
|
||||
present even when no metadata is present.
|
||||
|
||||
Before going into details, let's see how one can display a simple, single line
|
||||
Before going into details, lets see how one can display a simple, single line
|
||||
notification from a shell script::
|
||||
|
||||
printf '\x1b]99;;Hello world\x1b\\'
|
||||
@@ -395,17 +395,17 @@ Key Value
|
||||
``c`` ``c=1`` if the terminal supports close events, otherwise the ``c``
|
||||
must be omitted.
|
||||
|
||||
``o`` Comma separated list of occasions from the ``o`` key that the
|
||||
``o`` Comma separated list of occassions from the ``o`` key that the
|
||||
terminal implements. If no occasions are supported, the value
|
||||
``o=always`` must be sent in the query response.
|
||||
|
||||
``p`` Comma separated list of supported payload types (i.e. values of the
|
||||
``p`` Comma spearated list of supported payload types (i.e. values of the
|
||||
``p`` key that the terminal implements). These must contain at least
|
||||
``title``.
|
||||
|
||||
``s`` Comma separated list of sound names from the table of standard sound names above.
|
||||
Terminals will report the list of standard sound names they support.
|
||||
Terminals *should* support at least ``system`` and ``silent``.
|
||||
Terminals *should* support atleast ``system`` and ``silent``.
|
||||
|
||||
``u`` Comma separated list of urgency values that the terminal implements.
|
||||
If urgency is not supported, the ``u`` key must be absent from the
|
||||
@@ -450,10 +450,10 @@ Key Value Default Description
|
||||
encoded UTF-8
|
||||
application name
|
||||
|
||||
``g`` :ref:`identifier` ``unset`` Identifier for icon data. Make these globally unique,
|
||||
``g`` :ref:`identifier` ``unset`` Identifier for icon data. Make these globally unqiue,
|
||||
like an UUID.
|
||||
|
||||
``i`` :ref:`identifier` ``unset`` Identifier for the notification. Make these globally unique,
|
||||
``i`` :ref:`identifier` ``unset`` Identifier for the notification. Make these globally unqiue,
|
||||
like an UUID, so that terminal multiplexers can
|
||||
direct responses to the correct window. Note that for backwards
|
||||
compatibility reasons i=0 is special and should not be used.
|
||||
@@ -527,7 +527,7 @@ Escape code safe UTF-8
|
||||
|
||||
This must be valid UTF-8 as per the spec in :rfc:`3629`. In addition, in order
|
||||
to make it safe for transmission embedded inside an escape code, it must
|
||||
contain none of the C0 and C1 control characters, that is, the Unicode
|
||||
contain none of the C0 and C1 control characters, that is, the unicode
|
||||
characters: U+0000 (NUL) - U+1F (Unit separator), U+7F (DEL) and U+80 (PAD) - U+9F
|
||||
(APC). Note that in particular, this means that no newlines, carriage returns,
|
||||
tabs, etc. are allowed.
|
||||
|
||||
@@ -1,563 +0,0 @@
|
||||
The Drag and Drop protocol
|
||||
==============================================
|
||||
|
||||
.. versionadded:: 0.47.0
|
||||
|
||||
.. warning:: This protocol is still under development, see :iss:`9984`.
|
||||
|
||||
This protocol enables drag and drop functionality for terminal programs
|
||||
that is as good as the drag and drop functionality available for GUI
|
||||
programs.
|
||||
|
||||
There is one central escape code used for this protocol, which is of the form::
|
||||
|
||||
OSC _dnd_code ; metadata ; payload ST
|
||||
|
||||
Here, ``OSC`` is the bytes ``ESC ] (0x1b 0x5b)`` and ST is ``ESC \\ (0x1b 0x5c)``.
|
||||
The ``metadata`` is a colon separated list of ``key=value`` pairs.
|
||||
The final part of the escape code is the payload data, whose meaning depends on the metadata.
|
||||
|
||||
The payload must be no more than 4096 bytes. When the payload is larger than 4096
|
||||
bytes, it is chunked up using the ``m`` key. An escape code that has a too long
|
||||
payload is transmitted in chunks. All but the last chunk must have ``m=1`` in
|
||||
their metadata. Each chunk must have a payload of no more than 4096 bytes.
|
||||
Only the first chunk is guaranteed to have metadata other than the ``m`` key.
|
||||
Subsequent chunks may optionally omit all
|
||||
metadata except the ``m`` and ``i`` keys. While a chunked transfer is in
|
||||
progress it is a protocol error to for the sending side to
|
||||
send any protocol related escape codes other than chunked ones or query (``t=q|Q``) ones.
|
||||
In particular, this means that the receiving side should use the metadata from
|
||||
the first chunk in a chain of chunks only.
|
||||
|
||||
All integer values used in this escape code must be 32-bit signed or unsigned
|
||||
integers encoded in decimal representation.
|
||||
|
||||
When transferring binary data the payload is :rfc:`base64 <4648>` encoded. The
|
||||
4096 bytes limit applies to *encoded bytes*, that is, it is applied after
|
||||
encoding. base64 padding bytes are optional and may or may not be present at
|
||||
the end of the last chunk.
|
||||
|
||||
Accepting drops
|
||||
-----------------
|
||||
|
||||
In order to inform the terminal emulator that the client accepts drops, it
|
||||
must send the following escape code::
|
||||
|
||||
OSC _dnd_code ; t=a ; payload ST
|
||||
|
||||
The payload here is a space separated list of MIME types the program accepts.
|
||||
The list of MIME types is optional, it is needed if the program wants to accept
|
||||
exotic or private use MIME types on platforms such as macOS, where the system
|
||||
does not deliver drop events unless the MIME type is registered.
|
||||
|
||||
When the client is done accepting drops, or at exit, it should send the escape
|
||||
code::
|
||||
|
||||
OSC _dnd_code ; t=A ST
|
||||
|
||||
to inform the terminal that it no longer wants drops.
|
||||
|
||||
Whenever the user drags something over the window, the terminal will send an
|
||||
escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=m:x=x:y=y:X=X:Y=Y:o=O ; optional MIME list ST
|
||||
|
||||
Here, ``x, y`` identify the cell over which the drag is currently present.
|
||||
The ``(0, 0)`` cell is at top left of the screen. ``X and Y`` are the pixel
|
||||
offsets from the top-left. The ``O`` value is the set of allowed operations,
|
||||
which can be ``1`` for copy, ``2`` for move and ``3`` for either, at the
|
||||
client's discretion. The optional list of MIMES is a space separated
|
||||
list of MIME types that are available for dropping. To avoid overhead, the
|
||||
terminal should only send this list for the first move event and subsequently
|
||||
only if the list changes.
|
||||
|
||||
When the drag leaves the window, the terminal will send the same event but
|
||||
with ``x, y = -1, -1`` to indicate that the drag has left the window. For such
|
||||
events the list of MIME types must be empty. Note that the terminal must never
|
||||
send negative cell co-ordinates for any other reason. No more movement escape
|
||||
codes ``t=m`` will be sent until this drop or another re-enters the window.
|
||||
|
||||
The client program must inform the terminal whether it will accept
|
||||
the potential drop and which MIME types of the set of offered MIME types it
|
||||
accepts. Until the client does so the terminal will indicate to the OS that
|
||||
the drop is not accepted. To do so, the client sends an escape code of the
|
||||
form::
|
||||
|
||||
OSC _dnd_code ; t=m:o=O ; MIME list ST
|
||||
|
||||
Here the ``o`` key is the operation the client intends to perform if a drop
|
||||
occurs which can be either ``1`` for copy or ``2`` for move or ``0`` for not
|
||||
accepted. The MIME list is the ordered list of MIME types from the offered list
|
||||
that the client wants. If no MIME type list is present, it is equivalent to no
|
||||
change in the offered list of MIME types. The list should be ordered in order
|
||||
of decreasing preference. Some platforms may show the user some
|
||||
indication of the first MIME type in the list.
|
||||
|
||||
When the user triggers a drop on the window, the terminal will send an escape
|
||||
code of the form::
|
||||
|
||||
OSC _dnd_code ; t=M: ... ; MIME list ST
|
||||
|
||||
This is the same as the movement escape codes above, except that ``t=M``
|
||||
(upper case M instead of lower case m), indicating this is a drop.
|
||||
Once this escape code is received, no more movement escape codes ``t=m``
|
||||
will be sent until a new drop enters the window. The MIME list here is
|
||||
mandatory, terminals must send the full list of MIME types available in
|
||||
the drop. The client program can now request data for the MIME types
|
||||
it is interested in.
|
||||
|
||||
Requesting data is done by sending an escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx ST
|
||||
|
||||
Here ``idx`` is a 1-based index into the list of MIME types sent in the ``t=M``
|
||||
drop event. This will request data for the specified MIME type.
|
||||
The terminal must respond with a series of escape codes of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx; base64 encoded data possibly chunked ST
|
||||
|
||||
End of data is indicated by an empty payload and ``m=0``. If some error occurs while
|
||||
getting the data, the terminal must send an escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=R:x=idx ; POSIX error name:optional description ST
|
||||
|
||||
Here ``POSIX error name`` is a POSIX symbolic error name such as ``ENOENT`` or
|
||||
``EIO`` or the value ``EUNKNOWN`` for an unknown error. Unless otherwise noted,
|
||||
any error response means the drop is terminated. The description is optional
|
||||
and must consist only of :ref:`safe_utf8`.
|
||||
|
||||
Once the client program finishes reading all the dropped data it needs, it must
|
||||
send an escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:o=operation ST
|
||||
|
||||
That is, it must send a request for data with no MIME type specified. The
|
||||
terminal emulator must then inform the OS that the drop is completed. Any
|
||||
queued data requests must be discarded by the terminal. The ``operation``
|
||||
is required and must specify the final action the client took with the data.
|
||||
If unset (aka ``0``) the terminal must assume the drop was canceled.
|
||||
|
||||
Dropping from remote machines
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In order to support dropping of files from remote machines, the client
|
||||
must inform the terminal of its :ref:`machine id <machine_id>` using the escape code::
|
||||
|
||||
OSC _dnd_code ; t=a:x=1 ; machine id ST
|
||||
|
||||
Then, the client must first request the :rfc:`text/uri-list <2483>` MIME
|
||||
type to get a list of dropped URIs. When responding to this request,
|
||||
the terminal will send the usual ``t=r`` responses, but, in addition,
|
||||
if the client has sent its machine id and the terminal determines that
|
||||
the client is on a different machine based on the id, it will add the ``X=1``
|
||||
key to its response. The client should use this key to determine if it wants to
|
||||
request data for entries in the URI list. For every URI in the list, the client can
|
||||
send the terminal emulator a data request of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx:y=subidx ST
|
||||
|
||||
Here ``idx`` is the one based index of the ``text/uri-list`` MIME type. And
|
||||
``subidx`` is the one based index into the array of MIME types in
|
||||
the ``text/uri-list`` entry. The terminal will then read the file and
|
||||
transmit the data as for a normal MIME data request, except it will have
|
||||
``y=subidx`` as well in its response, for example::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx:y=subidx ; base64 encoded data possibly chunked ST
|
||||
|
||||
Similarly, error responses are as above, except for the addition of
|
||||
``y=subidx``, for example::
|
||||
|
||||
OSC _dnd_code ; t=R:x=idx:y=subidx ; POSIX error name:optional desc ST
|
||||
|
||||
Terminals must reply with ``ENOENT`` if the index is out of bounds.
|
||||
If the client does not first request the ``text/uri-list`` MIME type or that
|
||||
MIME type is not present in the drop, the terminal must reply with
|
||||
``EINVAL``. Terminals must support at least ``file://`` URIs.
|
||||
If the client requests an entry that is not a supported URI type the
|
||||
terminal must reply with ``EUNKNOWN``.
|
||||
|
||||
Terminals must ONLY send data for regular files, symbolic links and directories.
|
||||
See below for more details about sending symlinks.
|
||||
|
||||
If the terminal does not have permission to read the file it must reply with
|
||||
``EPERM``. Terminals must respond with ``EINVAL`` if the file is not a regular
|
||||
file or symlink or directory and ``ENOENT`` if the file does not exist. If an
|
||||
I/O error occurs the terminal must send ``EIO``.
|
||||
|
||||
For security reasons, terminals must reply with ``EPERM`` if the drag
|
||||
originated in the same window as the drop, this prevents malicious programs
|
||||
from reading files on the computer by starting their own drag. This is a
|
||||
defense in depth feature since drags can only be started by the terminal, but
|
||||
it helps in case of accidental drag starts and drops into the same window.
|
||||
|
||||
Clients may send multiple requests without waiting for any request to complete.
|
||||
Terminals may queue requests and respond in any order they choose, including
|
||||
interleaving responses to different requests. However, for simplicity, this
|
||||
specification recommends terminals queue requests and respond in first-in,
|
||||
first-out order. Every response can be matched to a corresponding request
|
||||
using the ``x``, ``y`` and ``Y`` keys. To prevent Denial of service attacks,
|
||||
if too many requests are received, terminals must deny the request
|
||||
with ``EMFILE`` and end the drop.
|
||||
|
||||
|
||||
Reading remote directories
|
||||
+++++++++++++++++++++++++++
|
||||
|
||||
If the file pointed to by a ``file://`` URL is actually a directory the terminal must instead respond with::
|
||||
|
||||
OSC _dnd_code ; t=r:x=idx:y=subidx:X=handle ; base64 encoded list of dir entries ST
|
||||
|
||||
The presence of ``X=handle`` indicates this is a directory response not a regular
|
||||
file or symlink. For regular files, ``X=0``. For symlinks, ``X=1``.
|
||||
For directories ``X`` is an arbitrary integer (``handle``) other than ``0`` or ``1``.
|
||||
Here, the payload is a null byte separated list of entries in the directory that are
|
||||
either regular files, directories or symlinks. The payload must be base64
|
||||
encoded and might be chunked if the directory has a lot of entries.
|
||||
|
||||
The client can now read the files in this directory using requests of the form::
|
||||
|
||||
OSC _dnd_code ; t=r:Y=handle:x=num ST
|
||||
|
||||
Here ``num`` is the 1-based index into the list of directory entries previously transmitted
|
||||
to the client. The terminal will respond with an escape code of the forms ::
|
||||
|
||||
OSC _dnd_code ; t=r:Y=handle:x=num ; base64 encoded data of regular file ST
|
||||
OSC _dnd_code ; t=r:Y=handle:x=num:X=1 ; base64 encoded symlink target ST
|
||||
OSC _dnd_code ; t=r:Y=handle:x=num:X=child-handle ; base64 encoded list of entries in sub-dir ST
|
||||
|
||||
In case of any errors, the terminal will respond with::
|
||||
|
||||
OSC _dnd_code ; t=R:Y=handle:x=num ; POSIX error name:optional desc ST
|
||||
|
||||
In the above, the ``Y=handle`` and ``x=num`` keys allow the client to know
|
||||
which directory entry the response concerns. The ``handle`` points to the
|
||||
parent directory and ``num`` to the entry within the parent dir.
|
||||
|
||||
Once the client is done reading a directory it should transmit ``t=r:Y=handle`` to the terminal. The
|
||||
terminal can then free any resources associated with that directory. The
|
||||
directory handle is now invalid and terminals must return ``EINVAL`` if the
|
||||
client sends a request using an invalid directory handle. It is recommended
|
||||
that clients traverse directories breadth first to minimise resource usage in
|
||||
the terminal. Terminals may deny directory traversal requests if too many
|
||||
resources are used, in order to prevent Denial of service attacks. In such
|
||||
cases the terminal must respond with ``ENOMEM``.
|
||||
|
||||
|
||||
Starting drags
|
||||
-----------------
|
||||
|
||||
Terminal programs can inform the terminal emulator that they
|
||||
are willing to act as a source of drag data by sending the
|
||||
sending the escape code::
|
||||
|
||||
OSC _dnd_code ; t=o:x=1 ; optional machine id ST
|
||||
|
||||
On exit, or if the program no longer is willing to start drag gestures, it must
|
||||
send ``t=o:x=2`` to the terminal to indicate it no longer wants to offer drag data.
|
||||
The ``machine id`` is optional and is used to enable dragging from remote
|
||||
machines. See :ref:`below <machine_id>` for its semantics.
|
||||
|
||||
When the user performs the platform specific gesture to start a drag operation,
|
||||
the terminal will send the escape code ``t=o`` back to the terminal program
|
||||
informing it that it can potentially start a drag. The gesture is typically holding the
|
||||
left mouse button down and dragging a short distance, but this protocol does
|
||||
not mandate any particular gesture to start drag operations. The terminal, when
|
||||
sending the event will also set the ``x, y, X, Y`` keys to indicate the cell
|
||||
and pixel locations in the window of the start drag event.
|
||||
|
||||
If the terminal program determines that it wants to start a drag at that
|
||||
location, it must send the terminal the ``t=o:o=flags`` escape code again, but
|
||||
with a payload consisting of the space separated MIME types it offers. The
|
||||
``flags`` indicate what types of operations the client supports, ``1`` for
|
||||
copy, ``2`` for move and ``3`` for either. The transmission should be chunked
|
||||
if the list of MIME types is too long. Note that at this time the drag
|
||||
operation has not actually started, this gives the terminal program the
|
||||
opportunity to pre-send some data or set one or more images to act as
|
||||
thumbnails for the drag operation. If the list of MIME types is too long the
|
||||
terminal may cancel the operation by responding with ``t=E ; EFBIG`` or ``t=E ;
|
||||
ENOMEM``.
|
||||
|
||||
If at the time the terminal receives this request the drag gesture has already
|
||||
been terminated or the terminal otherwise determines that it is not appropriate
|
||||
to start the drag, it must reply with ``t=E ; EPERM`` to indicate the drag
|
||||
offer was not accepted.
|
||||
|
||||
For some well known types like ``text/plain`` or ``text/uri-list`` the
|
||||
terminal program should pre-send the data for them unless it is very large.
|
||||
This is because some platforms, such as macOS, need pre sent data to be able
|
||||
to interoperate with native programs. The terminal emulator should reply with
|
||||
``t=E ; EFBIG`` if too much data is sent and cancel the drag. Terminals must
|
||||
accept at least 64MB of pre sent data.
|
||||
|
||||
Pre sent data is sent with escape codes of the form::
|
||||
|
||||
OSC _dnd_code ; t=p:x=idx ; base64 encoded data ST
|
||||
|
||||
Here ``idx`` is the zero based index into the list of previously sent MIME
|
||||
types indicating this data is for that MIME type. Transmission should be chunked
|
||||
using the ``m`` key. End of data is indicated by sending the escape code with no
|
||||
payload and ``m=0``. Terminal programs should pre-read this data and only send
|
||||
the ``t=o`` key indicating the offer if the data is available.
|
||||
|
||||
To associate one or more images with the drag operation, the terminal program
|
||||
must transmit the data for the image with the ``idx`` value above being a
|
||||
negative number starting with ``-1`` for the first image and so on. Clients
|
||||
**must** transmit all images consecutively in order, starting with the first,
|
||||
then the second and so on. When transmitting images, the image data format is
|
||||
specified using the ``y`` key. A value of ``y=24`` mean 24bit RGB data and
|
||||
``y=32`` means 32bit RGBA data. Colors in the RGB/A data must be in the sRGB
|
||||
color space. Using ``y=100`` means the data is a PNG image. Using ``y=0`` means
|
||||
the payload is UTF-8 base64 encoded text. The terminal will render the text to
|
||||
display the image. Additionally, the ``X`` and ``Y`` keys must be used to
|
||||
specify the width and height of the image data in pixels. If the size of the
|
||||
transmitted data does not match the image dimensions the terminal must replay
|
||||
with ``t=E ; EINVAL``. When using ``y=0`` the ``X`` and ``Y`` keys specify the
|
||||
text size as ``base_font_size * X/Y``. Where ``base_font_size`` is the normal
|
||||
font size the terminal uses for text. Note that terminals **may** ignore
|
||||
newlines and render all text on a single line so client programs should not
|
||||
send too much text. The ``o`` key is used to specify if the background the
|
||||
text is drawn on is transparent or not. ``o=0`` means transparent and ``o=1024``
|
||||
means fully opaque. In other words background opacity is ``o/1024``.
|
||||
This is particularly useful when drawing a Unicode symbol as the icon for the drag.
|
||||
|
||||
Terminals are free to impose a limit on the amount of image data, to avoid
|
||||
Denial-of-service attacks. If the image data is too much or the image is too
|
||||
large they must reply with ``t=E ; EFBIG`` and abort the drag. By default, the
|
||||
drag will be started using the first image, if any. During the drag, the
|
||||
terminal program can change the image by sending::
|
||||
|
||||
OSC _dnd_code ; t=P:x=idx ST
|
||||
|
||||
Where ``idx`` is now a zero based index with zero being the first image and so on.
|
||||
Sending an ``idx`` out of bounds means the drag image should be removed.
|
||||
|
||||
Once the terminal program has sent all data and images for the drag
|
||||
operation, it indicates the drag should be started by sending ``t=P:x=-1``. At
|
||||
this time if the user has already cancelled the drag or the terminal determines
|
||||
the drag operation is not allowed, it must respond with ``t=E ; EPERM``. If any
|
||||
other error occurs starting the drag operation, it must respond with the appropriate
|
||||
POSIX error name and optional error description. If it determines that the image data after conversion to
|
||||
display format is too large, it must respond with ``t=E ; EFBIG``. If the drag
|
||||
operation is successfully started, it must respond with ``t=E ; OK``.
|
||||
|
||||
As the drag progresses, status changes are reported using the ``t=e`` escape
|
||||
code. The variants are listed in the table below:
|
||||
|
||||
.. list-table:: Drag offer events
|
||||
|
||||
* - Code
|
||||
- Description
|
||||
* - ``t=e : x=1 : y=idx``
|
||||
- The drag has been accepted by a client. ``idx`` is a zero based index into the list of MIME types
|
||||
pointing to the MIME type the client is likely to want
|
||||
* - ``t=e : x=2 : o=O``
|
||||
- The action the client is likely to perform has changed to the value indicated by the ``o`` key
|
||||
* - ``t=e : x=3``
|
||||
- The drag offer has been dropped onto a client, there are likely to be requests for data in the near future
|
||||
* - ``t=e : x=4 : y=0 or 1``
|
||||
- The drag is finished. If ``y=1`` then the drag was canceled by the user.
|
||||
* - ``t=e : x=5 : y=idx``
|
||||
- Request data for the MIME type at the zero based index ``idx`` in the list of MIME types
|
||||
|
||||
The client program should respond to data requests with escape codes of the
|
||||
form::
|
||||
|
||||
OSC _dnd_code ; t=e:y=idx:m=0 or 1 ; base64 encoded data ST
|
||||
|
||||
This, is the data for the MIME type identified by ``idx`` which is a zero based
|
||||
index into the list of MIME types. The data should be chunked using the
|
||||
``m`` key. End of data is denoted by ``m=0`` and an empty payload. If an error
|
||||
occurs the client should send::
|
||||
|
||||
OSC _dnd_code ; t=E:y=idx ; POSIX error name:optional description ST
|
||||
|
||||
Where ``POSIX error name`` is a POSIX symbolic error name such as ``ENOENT``
|
||||
if the MIME type is not found or ``EIO`` if an IO error occurred and so on. The
|
||||
description is optional and must contain only :ref:`safe_utf8`.
|
||||
|
||||
If the client wants to cancel the full drag at any time, it should send::
|
||||
|
||||
OSC _dnd_code ; t=E:y=-1 ST
|
||||
|
||||
If ``t=e`` or ``t=E`` escape codes are sent to the terminal before the drag is
|
||||
started and the terminal has responded with ``t=E ; OK``, the terminal must respond
|
||||
with ``t=E ; EINVAL`` and abort the drag.
|
||||
|
||||
Dragging to remote machines
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
To support dragging to remote machines, first of all clients **must** pre-send
|
||||
the data for the ``text/uri-list`` MIME type. All ``file://`` URLs that point
|
||||
to directories **must** end with a ``/``. Then, terminals can
|
||||
examine the :ref:`machine_id` sent with the enable drag offers
|
||||
``t=o`` escape code to decide whether to request data for ``file://`` entries
|
||||
from the URI list. To request data for a particular entry, terminals send an
|
||||
escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=k:x=idx ST
|
||||
|
||||
Here ``idx`` is the one based index into the list of entries in the
|
||||
``text/uri-list`` MIME type. Then the client can respond with the data
|
||||
for that entry with an escape code of the form::
|
||||
|
||||
OSC _dnd_code ; t=k:x=idx:m=0 or 1 ; base64 encoded file data ST
|
||||
OSC _dnd_code ; t=k:x=idx:X=1:m=0 or 1 ; base64 encoded symlink target ST
|
||||
OSC _dnd_code ; t=k:x=idx:X=handle:m=0 or 1 ; base64 encoded null separated list of directory entries ST
|
||||
|
||||
These represent possibly chunked data for files, symlinks and directories, as
|
||||
denoted by the ``X`` key. As above, end of data for an individual entry is
|
||||
indicated by an escape code with ``m=0`` and no payload. ``idx`` is the one
|
||||
based index into the list of entries in the ``text/uri-list`` MIME type.
|
||||
Only regular files, symlinks and directories should be sent. Terminals may send
|
||||
multiple requests before the data for the first request is received. Client
|
||||
programs should queue the requests and handle them in FIFO order.
|
||||
|
||||
Every directory must be transmitted with ``X=handle``. The payload
|
||||
is a null separated list of regular files, directories and symlinks in the
|
||||
directory. ``handle`` is an integer other than ``0`` or ``1``
|
||||
that serves as an identifier for the directory. Directories should be traversed
|
||||
in breadth first order. The children of a directory are sent by
|
||||
adding ``Y=parent-handle:y=num`` to the escape codes above. Here
|
||||
``parent-handle`` is the handle of the directory being traversed and ``num``
|
||||
is the one based index into the list of entries in the directory. Thus, the
|
||||
set of keys ``x, y, Y`` uniquely determine an entry. Clients **must** send all
|
||||
children of directories, recursively, terminals **must not** make requests
|
||||
for children of directories, only for the entries from the ``text/uri-list``.
|
||||
|
||||
If any error occurs in the client while reading the data, it can inform
|
||||
the terminal using::
|
||||
|
||||
OSC _dnd_code ; t=E ; POSIX error name:optional description ST
|
||||
|
||||
The terminal must then abort the drag.
|
||||
|
||||
Terminals are free to impose resource limits on how much data they accept,
|
||||
if a limit is breached or some errors occurs, they can abort the drag and
|
||||
inform the client of it with::
|
||||
|
||||
OSC _dnd_code ; t=E ; POSIX error name:optional description ST
|
||||
|
||||
The error code for too many resources is ``EMFILE``,
|
||||
for IO errors is ``EIO`` and so on.
|
||||
|
||||
Detecting support for this protocol
|
||||
-------------------------------------
|
||||
|
||||
Clients can query the terminal emulator for support of this protocol
|
||||
using::
|
||||
|
||||
OSC _dnd_code ; t=q:i=optional ST
|
||||
|
||||
The ``i`` key is optional, if present it will be echoed back in the responses
|
||||
from the terminal. A terminal supporting this protocol **must** respond with::
|
||||
|
||||
OSC _dnd_code ; t=q:i=echoed ; payload ST
|
||||
|
||||
Here, ``payload`` is a colon separated list of ``key=value`` pairs. These
|
||||
specify support for optional/future parts of this protocol. Currently the
|
||||
payload is empty, but that might change as the protocol evolves.
|
||||
|
||||
The client should send these escape codes followed by a request for the `primary device
|
||||
attributes <https://vt100.net/docs/vt510-rm/DA1.html>`_. If a response for the
|
||||
device attributes is received before a response for the queries, then the
|
||||
terminal does not support this protocol.
|
||||
|
||||
Multiplexers
|
||||
-----------------
|
||||
|
||||
To support multiplexers, the ``i`` key exists. When the terminal receives a
|
||||
``t=a`` or ``t=o`` escape code that has the ``i`` key set, all escape codes it
|
||||
sends to the terminal program must include the ``i`` key with the same value.
|
||||
This allows terminal multiplexers to direct the response codes to the correct
|
||||
client.
|
||||
|
||||
Metadata reference
|
||||
---------------------------
|
||||
|
||||
The table below shows all the metadata keys as well as what values they can
|
||||
take, and the default value they take when missing. All integers are 32-bit.
|
||||
|
||||
======= ==================== ========= =================
|
||||
Key Value Default Description
|
||||
======= ==================== ========= =================
|
||||
``t`` Single character. ``a`` The type of drag and drop event.
|
||||
``(a, A, ``a`` - start accepting drops
|
||||
)`` ``A`` - stop accepting drops
|
||||
``m`` - a drop move event
|
||||
``M`` - a drop dropped event
|
||||
``r`` - request dropped data
|
||||
``R`` - report an error
|
||||
``o`` - start offering drags or start a drag
|
||||
``p`` - present data for drag offers
|
||||
``P`` - Change drag image or start drag
|
||||
``e`` - a drag offer event occurred
|
||||
``E`` - a drag offer data error occurred
|
||||
``k`` - data for uri-list items in drag offer
|
||||
``q`` - query support for this protocol
|
||||
|
||||
``m`` Chunking indicator ``0`` ``0`` or ``1``
|
||||
|
||||
``i`` Postive integer ``0`` This id is for use by multiplexers.
|
||||
When it is set, all responses from
|
||||
the terminal in that session will
|
||||
have it set to the same value.
|
||||
|
||||
``o`` Positive integer ``0`` What drop operation to perform. ``0``
|
||||
means rejected, ``1`` means copy and
|
||||
``2`` means move.
|
||||
|
||||
**Keys for location**
|
||||
-----------------------------------------------------------
|
||||
``x`` Integer ``0`` Cell x-coordinate origin is 0, 0 at top left of screen
|
||||
``y`` Integer ``0`` Cell y-coordinate origin is 0, 0 at top left of screen
|
||||
``X`` Integer ``0`` Pixel x-coordinate origin is 0, 0 at top left of screen
|
||||
``Y`` Integer ``0`` Pixel y-coordinate origin is 0, 0 at top left of screen
|
||||
======= ==================== ========= =================
|
||||
|
||||
|
||||
.. _machine_id:
|
||||
|
||||
Machine id
|
||||
-----------------
|
||||
|
||||
The machine id is used to detect when the source and destination machines for a
|
||||
drag and drop are different. It is of the form: ``version:ASCII printable
|
||||
chars``. The leading ``version`` field allows for changing the format or
|
||||
semantics of this field in the future. The actual id is the machine id which
|
||||
is:
|
||||
|
||||
.. tab:: macOS
|
||||
|
||||
The value returned by the ``IOPlatformUUID`` system function.
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
The contents of the :file:`HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography\\MachineGuid`
|
||||
registry key.
|
||||
|
||||
.. tab:: Other
|
||||
|
||||
The contents of the :file:`/etc/machine-id` file with trailing whitespace removed
|
||||
|
||||
This machine id is then hashed using a :rfc:`HMAC <2104>` with :rfc:`SHA-256
|
||||
<6234>` as the digest algorithm and the key being the ASCII bytes:
|
||||
``tty-dnd-protocol-machine-id``. The hashing is done so as to not easily leak
|
||||
the actual machine id and to ensure that the value is of fixed size and
|
||||
consisting only of ASCII printable characters. This gives a final value of::
|
||||
|
||||
1:hashed machine id hexadecimal encoded
|
||||
|
||||
In the future, the ``version`` field may increase if the hashing algorithm is
|
||||
changed. If the terminal sees a version it does not understand, it must assume
|
||||
that the machine id does not match, aka the source and destination machines are
|
||||
different. This assumption means that remote drag and drop will still work, just with
|
||||
reduced performance in case of version mismatch.
|
||||
|
||||
|
||||
Support in other software
|
||||
------------------------------
|
||||
|
||||
Currently this protocol is supported in:
|
||||
|
||||
* The kitty terminal emulator and the :doc:`dnd kitten </kittens/dnd>`
|
||||
* The `yazi <https://github.com/sxyazi/yazi/pull/4005>`__ terminal file manager
|
||||
260
docs/faq.rst
260
docs/faq.rst
@@ -23,18 +23,74 @@ these characters are followed by a space or en-space (U+2002) in which case
|
||||
kitty makes use of the extra cell to render them in two cells. This behavior
|
||||
can be turned off for specific symbols using :opt:`narrow_symbols`.
|
||||
|
||||
As of version 0.40 kitty has innovated a :doc:`new protocol
|
||||
<text-sizing-protocol>` that allows programs running in the terminal to control
|
||||
how many cells a character is rendered in thereby solving the issue of
|
||||
character width once and for all.
|
||||
|
||||
Similarly, some monospaced font families are buggy and have bold or italic
|
||||
faces that have characters wider than the width of the normal face, these
|
||||
will also result in clipping. Such issues should be reported to the font
|
||||
developer. Monospaced font families must have all their characters rendered
|
||||
within a fixed width across all faces of the font, otherwise they aren't really
|
||||
monospaced.
|
||||
Using a color theme with a background color does not work well in vim?
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
Sadly, vim has very poor out-of-the-box detection for modern terminal features.
|
||||
Furthermore, it `recently broke detection even more <https://github.com/vim/vim/issues/11729>`__.
|
||||
It kind of, but not really, supports terminfo, except it overrides it with its own hard-coded
|
||||
values when it feels like it. Worst of all, it has no ability to detect modern
|
||||
features not present in terminfo, at all, even security sensitive ones like
|
||||
bracketed paste.
|
||||
|
||||
Thankfully, probably as a consequence of this lack of detection, vim allows users to
|
||||
configure these low level details. So, to make vim work well with any modern
|
||||
terminal, including kitty, add the following to your :file:`~/.vimrc`.
|
||||
|
||||
.. code-block:: vim
|
||||
|
||||
" Mouse support
|
||||
set mouse=a
|
||||
set ttymouse=sgr
|
||||
set balloonevalterm
|
||||
" Styled and colored underline support
|
||||
let &t_AU = "\e[58:5:%dm"
|
||||
let &t_8u = "\e[58:2:%lu:%lu:%lum"
|
||||
let &t_Us = "\e[4:2m"
|
||||
let &t_Cs = "\e[4:3m"
|
||||
let &t_ds = "\e[4:4m"
|
||||
let &t_Ds = "\e[4:5m"
|
||||
let &t_Ce = "\e[4:0m"
|
||||
" Strikethrough
|
||||
let &t_Ts = "\e[9m"
|
||||
let &t_Te = "\e[29m"
|
||||
" Truecolor support
|
||||
let &t_8f = "\e[38:2:%lu:%lu:%lum"
|
||||
let &t_8b = "\e[48:2:%lu:%lu:%lum"
|
||||
let &t_RF = "\e]10;?\e\\"
|
||||
let &t_RB = "\e]11;?\e\\"
|
||||
" Bracketed paste
|
||||
let &t_BE = "\e[?2004h"
|
||||
let &t_BD = "\e[?2004l"
|
||||
let &t_PS = "\e[200~"
|
||||
let &t_PE = "\e[201~"
|
||||
" Cursor control
|
||||
let &t_RC = "\e[?12$p"
|
||||
let &t_SH = "\e[%d q"
|
||||
let &t_RS = "\eP$q q\e\\"
|
||||
let &t_SI = "\e[5 q"
|
||||
let &t_SR = "\e[3 q"
|
||||
let &t_EI = "\e[1 q"
|
||||
let &t_VS = "\e[?12l"
|
||||
" Focus tracking
|
||||
let &t_fe = "\e[?1004h"
|
||||
let &t_fd = "\e[?1004l"
|
||||
execute "set <FocusGained>=\<Esc>[I"
|
||||
execute "set <FocusLost>=\<Esc>[O"
|
||||
" Window title
|
||||
let &t_ST = "\e[22;2t"
|
||||
let &t_RT = "\e[23;2t"
|
||||
|
||||
" vim hardcodes background color erase even if the terminfo file does
|
||||
" not contain bce. This causes incorrect background rendering when
|
||||
" using a color theme with a background color in terminals such as
|
||||
" kitty that do not support background color erase.
|
||||
let &t_ut=''
|
||||
|
||||
These settings must be placed **before** setting the ``colorscheme``. It is
|
||||
also important that the value of the vim ``term`` variable is not changed
|
||||
after these settings.
|
||||
|
||||
I get errors about the terminal being unknown or opening the terminal failing or functional keys like arrow keys don't work?
|
||||
-------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -134,39 +190,30 @@ remote control command, for details, see :ref:`at-set-colors`.
|
||||
To change colors when SSHing into a remote host, use the :opt:`color_scheme
|
||||
<kitten-ssh.color_scheme>` setting for the :doc:`ssh kitten <kittens/ssh>`.
|
||||
|
||||
Additionally, you can use the escape code described in :doc:`color-stack`
|
||||
to set colors in a single window.
|
||||
Examples of using OSC escape codes to set colors::
|
||||
Additionally, You can use the
|
||||
`OSC terminal escape codes <https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands>`__
|
||||
to set colors. Examples of using OSC escape codes to set colors::
|
||||
|
||||
Change the default foreground color:
|
||||
printf '\x1b]21;foreground=#ff0000\x1b\\'
|
||||
printf '\x1b]10;#ff0000\x1b\\'
|
||||
Change the default background color:
|
||||
printf '\x1b]21;background=blue\x1b\\'
|
||||
printf '\x1b]11;blue\x1b\\'
|
||||
Change the cursor color:
|
||||
printf '\x1b]21;cursor=blue\x1b\\'
|
||||
printf '\x1b]12;blue\x1b\\'
|
||||
Change the selection background color:
|
||||
printf '\x1b]21;selection_background=blue\x1b\\'
|
||||
printf '\x1b]17;blue\x1b\\'
|
||||
Change the selection foreground color:
|
||||
printf '\x1b]21;selection_foreground=blue\x1b\\'
|
||||
printf '\x1b]19;blue\x1b\\'
|
||||
Change the nth color (0 - 255):
|
||||
printf '\x1b]21;n=green\x1b\\'
|
||||
printf '\x1b]4;n;green\x1b\\'
|
||||
|
||||
See :doc:`color-stack` for details on the syntax for specifying colors and
|
||||
how to query current colors.
|
||||
You can use various syntaxes/names for color specifications in the above
|
||||
examples. See `XParseColor <https://linux.die.net/man/3/xparsecolor>`__
|
||||
for full details.
|
||||
|
||||
If a ``?`` is given rather than a color specification, kitty will respond
|
||||
with the current value for the specified color.
|
||||
|
||||
Why is there padding between the text area and the window border?
|
||||
------------------------------------------------------------------
|
||||
|
||||
Terminal screens are a grid of fixed size cells. When the window size is
|
||||
not an exact multiple of the cell size, there is some leftover space that
|
||||
appears as padding. Additionally you can add your own padding with
|
||||
:opt:`window_padding_width`. This padding can be particularly noticeable when
|
||||
using TUI programs that have a background color different from the terminal
|
||||
background color. In such cases either change their background color to match
|
||||
the terminal or more correctly, open a bug report against such programs and ask
|
||||
them to :doc:`change the terminal default background color <color-stack>`
|
||||
using OSC escape codes when starting and restore it when quitting to have it work automatically.
|
||||
|
||||
How do I specify command line options for kitty on macOS?
|
||||
---------------------------------------------------------------
|
||||
@@ -176,10 +223,6 @@ workaround that limitation, |kitty| will read command line options from the file
|
||||
:file:`<kitty config dir>/macos-launch-services-cmdline` when it is launched
|
||||
from the GUI, i.e. by clicking the |kitty| application icon or using
|
||||
``open -a kitty``. Note that this file is *only read* when running via the GUI.
|
||||
The contents of the file are assumed to be the command line to pass to kitty in
|
||||
shell syntax, for example::
|
||||
|
||||
--single-instance --override background=red
|
||||
|
||||
You can, of course, also run |kitty| from a terminal with command line options,
|
||||
using: :file:`/Applications/kitty.app/Contents/MacOS/kitty`.
|
||||
@@ -220,9 +263,9 @@ fonts to be freely resizable, so it does not support bitmapped fonts.
|
||||
symbols, so to force kitty to use the pure NERD font for NERD symbols,
|
||||
add the following line to :file:`kitty.conf`::
|
||||
|
||||
# Nerd Fonts v3.4.0
|
||||
# Nerd Fonts v3.2.0
|
||||
|
||||
symbol_map U+e000-U+e00a,U+e0a0-U+e0a2,U+e0a3,U+e0b0-U+e0b3,U+e0b4-U+e0c8,U+e0ca,U+e0cc-U+e0d7,U+e200-U+e2a9,U+e300-U+e3e3,U+e5fa-U+e6b7,U+e700-U+e8ef,U+ea60-U+ec1e,U+ed00-U+efce,U+f000-U+f2ff,U+f300-U+f381,U+f400-U+f533,U+f0001-U+f1af0 Symbols Nerd Font Mono
|
||||
symbol_map U+e000-U+e00a,U+ea60-U+ebeb,U+e0a0-U+e0c8,U+e0ca,U+e0cc-U+e0d7,U+e200-U+e2a9,U+e300-U+e3e3,U+e5fa-U+e6b1,U+e700-U+e7c5,U+ed00-U+efc1,U+f000-U+f2ff,U+f000-U+f2e0,U+f300-U+f372,U+f400-U+f533,U+f0001-U+f1af0 Symbols Nerd Font Mono
|
||||
|
||||
Those Unicode symbols not in the `Unicode private use areas
|
||||
<https://en.wikipedia.org/wiki/Private_Use_Areas>`__ are
|
||||
@@ -266,9 +309,10 @@ Then, the font will be available in ``kitten choose-fonts``.
|
||||
How can I assign a single global shortcut to bring up the kitty terminal?
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Use the :ref:`panel kitten <quake>`, this allows you to use kitty as a quick
|
||||
access Quake like terminal and even to use kitty as the desktop background, if
|
||||
so desired.
|
||||
Bringing up applications on a single key press is the job of the window
|
||||
manager/desktop environment. For ways to do it with kitty (or indeed any
|
||||
terminal) in different environments,
|
||||
see :iss:`here <45>`.
|
||||
|
||||
|
||||
I do not like the kitty icon!
|
||||
@@ -318,23 +362,9 @@ many alternate icons available, click on an icon to visit its homepage:
|
||||
:target: https://github.com/sodapopcan/kitty-icon
|
||||
:width: 256
|
||||
|
||||
.. image:: https://github.com/sfsam/some_icons/raw/main/kitty.app.iconset/icon_128x128@2x.png
|
||||
:target: https://github.com/sfsam/some_icons
|
||||
:width: 256
|
||||
|
||||
.. image:: https://github.com/igrmk/twiskers/raw/main/icon/twiskers.svg
|
||||
:target: https://github.com/igrmk/twiskers
|
||||
:width: 256
|
||||
|
||||
.. image:: https://github.com/mtklr/kitty-nyan-icon/raw/main/kitty-nyan.svg
|
||||
:target: https://github.com/mtklr/kitty-nyan-icon
|
||||
:width: 256
|
||||
|
||||
You can put :file:`kitty.app.icns` (macOS only) or :file:`kitty.app.png` in the
|
||||
On macOS and X11 you can put :file:`kitty.app.icns` (macOS only) or :file:`kitty.app.png` in the
|
||||
:ref:`kitty configuration directory <confloc>`, and this icon will be applied
|
||||
automatically at startup. On X11 and Wayland, this will set the icon for kitty windows.
|
||||
Note that not all Wayland compositors support the `protocol needed <https://wayland.app/protocols/xdg-toplevel-icon-v1>`__
|
||||
for changing window icons.
|
||||
automatically at startup. On X11, this will set the icon for kitty windows.
|
||||
|
||||
Unfortunately, on macOS, Apple's Dock does not change its cached icon so the
|
||||
custom icon will revert when kitty is quit. Run the following to force the Dock
|
||||
@@ -357,20 +387,13 @@ also set it with the following command:
|
||||
|
||||
You can also change the icon manually by following the steps:
|
||||
|
||||
.. tab:: macOS
|
||||
#. Find :file:`kitty.app` in the Applications folder, select it and press :kbd:`⌘+I`
|
||||
#. Drag :file:`kitty.icns` onto the application icon in the kitty info pane
|
||||
#. Delete the icon cache and restart Dock:
|
||||
|
||||
#. Find :file:`kitty.app` in the Applications folder, select it and press :kbd:`⌘+I`
|
||||
#. Drag :file:`kitty.icns` onto the application icon in the kitty info pane
|
||||
#. Delete the icon cache and restart Dock::
|
||||
.. code-block:: sh
|
||||
|
||||
rm /var/folders/*/*/*/com.apple.dock.iconcache; killall Dock
|
||||
|
||||
.. tab:: Linux
|
||||
|
||||
#. Copy :file:`kitty.desktop` from the installation location (usually
|
||||
:file:`/usr/share/applications` to :file:`~/.local/share/applications`
|
||||
#. Edit the copied desktop file changing the ``Icon`` line to have
|
||||
the absolute path to your desired icon.
|
||||
rm /var/folders/*/*/*/com.apple.dock.iconcache; killall Dock
|
||||
|
||||
|
||||
How do I map key presses in kitty to different keys in the terminal program?
|
||||
@@ -418,18 +441,7 @@ You need to make sure that the environment variables you define in your shell's
|
||||
rc files are either also defined system wide or via the :opt:`env` directive in
|
||||
:file:`kitty.conf`. Common environment variables that cause issues are those
|
||||
related to localization, such as :envvar:`LANG`, ``LC_*`` and loading of
|
||||
configuration files such as ``XDG_*``, :envvar:`KITTY_CONFIG_DIRECTORY` and,
|
||||
most importantly, ``PATH`` to locate binaries.
|
||||
|
||||
The simplest way to fix this is to have kitty load the environment variables
|
||||
from your shell configuration at startup using the :opt:`env` directive,
|
||||
adding the following to :file:`kitty.conf`::
|
||||
|
||||
env read_from_shell=PATH LANG LC_* XDG_* EDITOR VISUAL
|
||||
|
||||
This works for POSIX compliant shells and the fish shell. Note that it
|
||||
does add significantly to kitty startup time, so use only if really necessary.
|
||||
This feature was added in version ``0.43.2``.
|
||||
configuration files such as ``XDG_*``, :envvar:`KITTY_CONFIG_DIRECTORY`.
|
||||
|
||||
To see the environment variables that kitty sees, you can add the following
|
||||
mapping to :file:`kitty.conf`::
|
||||
@@ -443,8 +455,8 @@ setup environment variables system-wide, so people end up putting them in all
|
||||
sorts of places where they may or may not work.
|
||||
|
||||
|
||||
I am using tmux/zellij and have a problem
|
||||
----------------------------------------------
|
||||
I am using tmux and have a problem
|
||||
--------------------------------------
|
||||
|
||||
First, terminal multiplexers are :iss:`a bad idea <391#issuecomment-638320745>`,
|
||||
do not use them, if at all possible. kitty contains features that do all of what
|
||||
@@ -466,10 +478,9 @@ for tmux refusing to support images.
|
||||
|
||||
If you use any of the advanced features that kitty has innovated, such as
|
||||
:doc:`styled underlines </underlines>`, :doc:`desktop notifications
|
||||
</desktop-notifications>`, :doc:`variable sized text </text-sizing-protocol>`,
|
||||
:doc:`extended keyboard support </keyboard-protocol>`,
|
||||
:doc:`file transfer </kittens/transfer>`, :doc:`the ssh kitten </kittens/ssh>`,
|
||||
:doc:`shell integration </shell-integration>` etc. they may or may not work,
|
||||
</desktop-notifications>`, :doc:`extended keyboard support
|
||||
</keyboard-protocol>`, :doc:`file transfer </kittens/transfer>`, :doc:`the ssh
|
||||
kitten </kittens/ssh>`, :doc:`shell integration </shell-integration>` etc. they may or may not work,
|
||||
depending on the whims of tmux's maintainer, your version of tmux, etc.
|
||||
|
||||
|
||||
@@ -511,79 +522,6 @@ maintains. These too allocate memory in large blocks and don't release it back
|
||||
to the OS immediately.
|
||||
|
||||
|
||||
Using a color theme with a background color does not work well in vim?
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
First, be sure to `use a color scheme in vim <https://github.com/kovidgoyal/kitty/discussions/8196#discussioncomment-11739991>`__
|
||||
instead of relying on the terminal theme. Otherwise, background and text selection colours
|
||||
may be difficult to read.
|
||||
|
||||
Sadly, vim has very poor out-of-the-box detection for modern terminal features.
|
||||
Furthermore, it `recently broke detection even more <https://github.com/vim/vim/issues/11729>`__.
|
||||
It kind of, but not really, supports terminfo, except it overrides it with its own hard-coded
|
||||
values when it feels like it. Worst of all, it has no ability to detect modern
|
||||
features not present in terminfo, at all, even security sensitive ones like
|
||||
bracketed paste.
|
||||
|
||||
Thankfully, probably as a consequence of this lack of detection, vim allows users to
|
||||
configure these low level details. So, to make vim work well with any modern
|
||||
terminal, including kitty, add the following to your :file:`~/.vimrc`.
|
||||
|
||||
.. code-block:: vim
|
||||
|
||||
" Mouse support
|
||||
set mouse=a
|
||||
set ttymouse=sgr
|
||||
set balloonevalterm
|
||||
" Styled and colored underline support
|
||||
let &t_AU = "\e[58:5:%dm"
|
||||
let &t_8u = "\e[58:2:%lu:%lu:%lum"
|
||||
let &t_Us = "\e[4:2m"
|
||||
let &t_Cs = "\e[4:3m"
|
||||
let &t_ds = "\e[4:4m"
|
||||
let &t_Ds = "\e[4:5m"
|
||||
let &t_Ce = "\e[4:0m"
|
||||
" Strikethrough
|
||||
let &t_Ts = "\e[9m"
|
||||
let &t_Te = "\e[29m"
|
||||
" Truecolor support
|
||||
let &t_8f = "\e[38:2:%lu:%lu:%lum"
|
||||
let &t_8b = "\e[48:2:%lu:%lu:%lum"
|
||||
let &t_RF = "\e]10;?\e\\"
|
||||
let &t_RB = "\e]11;?\e\\"
|
||||
" Bracketed paste
|
||||
let &t_BE = "\e[?2004h"
|
||||
let &t_BD = "\e[?2004l"
|
||||
let &t_PS = "\e[200~"
|
||||
let &t_PE = "\e[201~"
|
||||
" Cursor control
|
||||
let &t_RC = "\e[?12$p"
|
||||
let &t_SH = "\e[%d q"
|
||||
let &t_RS = "\eP$q q\e\\"
|
||||
let &t_SI = "\e[5 q"
|
||||
let &t_SR = "\e[3 q"
|
||||
let &t_EI = "\e[1 q"
|
||||
let &t_VS = "\e[?12l"
|
||||
" Focus tracking
|
||||
let &t_fe = "\e[?1004h"
|
||||
let &t_fd = "\e[?1004l"
|
||||
execute "set <FocusGained>=\<Esc>[I"
|
||||
execute "set <FocusLost>=\<Esc>[O"
|
||||
" Window title
|
||||
let &t_ST = "\e[22;2t"
|
||||
let &t_RT = "\e[23;2t"
|
||||
|
||||
" vim hardcodes background color erase even if the terminfo file does
|
||||
" not contain bce. This causes incorrect background rendering when
|
||||
" using a color theme with a background color in terminals such as
|
||||
" kitty that do not support background color erase.
|
||||
let &t_ut=''
|
||||
|
||||
These settings must be placed **before** setting the ``colorscheme``. It is
|
||||
also important that the value of the vim ``term`` variable is not changed
|
||||
after these settings.
|
||||
|
||||
|
||||
Why does kitty sometimes start slowly on my Linux system?
|
||||
-------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ receiving::
|
||||
|
||||
The client must then wait for responses from the terminal emulator. It
|
||||
is an error to send anymore commands to the terminal until an ``OK``
|
||||
response is received from the terminal. The terminal waits for the user to accept
|
||||
response is received from the terminal. The terminal wait for the user to accept
|
||||
the request. If accepted, it sends::
|
||||
|
||||
← action=status id=someid status=OK
|
||||
|
||||
@@ -224,14 +224,6 @@ Variables that kitty sets when running child programs
|
||||
Set when enabling :ref:`shell_integration`. It is automatically removed by
|
||||
the shell integration scripts.
|
||||
|
||||
.. envvar:: KITTY_SI_RUN_COMMAND_AT_STARTUP
|
||||
|
||||
Set this to an expression that the kitty shell integration scripts will
|
||||
``eval`` after the shell is started. Note that this environment variable
|
||||
is ignored when present in the environment in which kitty itself is launched
|
||||
in. It is most useful with the ``--env`` flag for the :doc:`launch <launch>`
|
||||
action.
|
||||
|
||||
.. envvar:: ZDOTDIR
|
||||
|
||||
Set when enabling :ref:`shell_integration` with :program:`zsh`, allowing
|
||||
|
||||
@@ -28,22 +28,18 @@ alpha-blending and text over graphics.
|
||||
Some applications that use the kitty graphics protocol:
|
||||
|
||||
* `awrit <https://github.com/chase/awrit>`_ - Chromium-based web browser rendered in Kitty with mouse and keyboard support
|
||||
* `blackcat <https://github.com/j-c-m/blackcat>`_ - a modern compatible cat with image support
|
||||
* `bicat <https://github.com/stevenxxiu/bicat>`_ - a terminal image viewer that also works in the Vifm file manager, with nested Tmux support
|
||||
* `broot <https://dystroy.org/broot/>`_ - a terminal file explorer and manager, with preview of images, SVG, PDF, etc.
|
||||
* `chafa <https://github.com/hpjansson/chafa>`_ - a terminal image viewer
|
||||
* :doc:`kitty-diff <kittens/diff>` - a side-by-side terminal diff program with support for images
|
||||
* `fzf <https://github.com/junegunn/fzf/commit/d8188fce7b7bea982e7f9050c35e488e49fb8fd0>`_ - A command line fuzzy finder
|
||||
* `mpv <https://github.com/mpv-player/mpv/commit/874e28f4a41a916bb567a882063dd2589e9234e1>`_ - A video player that can play videos in the terminal
|
||||
* `neofetch <https://github.com/dylanaraps/neofetch>`_ - A command line system information tool
|
||||
* `nvim <https://github.com/neovim/neovim/issues/30889>`__ - A TUI editor that can display images in the terminal
|
||||
* `pixcat <https://github.com/mirukana/pixcat>`_ - a third party CLI and python library that wraps the graphics protocol
|
||||
* `ranger <https://github.com/ranger/ranger>`_ - a terminal file manager, with image previews
|
||||
* `termpdf.py <https://github.com/dsanson/termpdf.py>`_ - a terminal PDF/DJVU/CBR viewer
|
||||
* `timg <https://github.com/hzeller/timg>`_ - a terminal image and video viewer
|
||||
* `tpix <https://github.com/jesvedberg/tpix>`_ - a statically compiled binary that can be used to display images and easily installed on remote servers without root access
|
||||
* `twitch-tui <https://github.com/Xithrius/twitch-tui>`_ - Twitch chat in the terminal
|
||||
* `vat <https://github.com/jzbrooks/vat>`_ - a terminal image viewer for vector graphics, including Android Vector Drawables
|
||||
* `viu <https://github.com/atanunq/viu>`_ - a terminal image viewer
|
||||
* `Yazi <https://github.com/sxyazi/yazi>`_ - Blazing fast terminal file manager written in Rust, based on async I/O
|
||||
|
||||
@@ -56,20 +52,14 @@ Libraries:
|
||||
* `image.nvim <https://github.com/3rd/image.nvim>`_ - Bringing images to neovim
|
||||
* `image_preview.nvim <https://github.com/adelarsq/image_preview.nvim/>`_ - Image preview for neovim
|
||||
* `kui.nvim <https://github.com/romgrk/kui.nvim>`_ - Build sophisticated UIs inside neovim using the kitty graphics protocol
|
||||
* `kitty-graphics.el <https://github.com/cashmeredev/kitty-graphics.el>`_ - Images in emacs
|
||||
* `term-image <https://github.com/AnonymouX47/term-image>`_ - A Python library, CLI and TUI to display and browse images in the terminal
|
||||
* `glkitty <https://github.com/michaeljclark/glkitty>`_ - C library to draw OpenGL shaders in the terminal with a glgears demo
|
||||
|
||||
Other terminals that have implemented the graphics protocol:
|
||||
|
||||
* `Ghostty <https://ghostty.org>`_
|
||||
* `Konsole <https://invent.kde.org/utilities/konsole/-/merge_requests/594>`_
|
||||
* `st (with a patch) <https://st.suckless.org/patches/kitty-graphics-protocol>`_
|
||||
* `Warp <https://docs.warp.dev/getting-started/changelog#id-2025.03.26-v0.2025.03.26.08.10>`_
|
||||
* `wayst <https://github.com/91861/wayst>`_
|
||||
* `WezTerm <https://github.com/wez/wezterm/issues/986>`_
|
||||
* `iTerm2 <https://github.com/gnachman/iTerm2/commit/4fe5b2173193b6c3e45234b6b2ab7a144a5cfa01>`_
|
||||
* `xterm.js <https://github.com/xtermjs/xterm.js/discussions/5683>`_
|
||||
|
||||
|
||||
Getting the window size
|
||||
@@ -106,7 +96,7 @@ code to demonstrate its use
|
||||
buf = array.array('H', [0, 0, 0, 0])
|
||||
fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)
|
||||
print((
|
||||
'number of rows: {} number of columns: {} '
|
||||
'number of rows: {} number of columns: {}'
|
||||
'screen width: {} screen height: {}').format(*buf))
|
||||
|
||||
.. tab:: Go
|
||||
@@ -137,30 +127,19 @@ code to demonstrate its use
|
||||
}
|
||||
|
||||
|
||||
.. tab:: POSIX sh
|
||||
.. tab:: Bash
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
|
||||
read rows cols <<EOF
|
||||
$(command stty size)
|
||||
EOF
|
||||
# This uses the kitten standalone binary from kitty to get the pixel sizes
|
||||
# since we can't do IOCTLs directly. Fortunately, kitten is a static exe
|
||||
# pre-built for every Unix like OS under the sun.
|
||||
|
||||
oldstty=$(command stty -g)
|
||||
command stty raw -echo
|
||||
printf "\033[14t"
|
||||
response=""
|
||||
while : ; do
|
||||
char=$(command dd bs=1 count=1 2>/dev/null)
|
||||
[ "$char" = "t" ] && break
|
||||
response="${response}${char}"
|
||||
done
|
||||
command stty "$oldstty"
|
||||
h=$(echo "$response" | cut -d';' -f2)
|
||||
w=$(echo "$response" | cut -d';' -f3)
|
||||
printf "number of rows: %d number of columns: %d" "$rows" "$cols"
|
||||
printf " screen width: %d screen height: %d\n" "$w" "$h"
|
||||
builtin read -r rows cols < <(command stty size)
|
||||
IFS=x builtin read -r width height < <(command kitten icat --print-window-size); builtin unset IFS
|
||||
builtin echo "number of rows: $rows number of columns: $cols screen width: $width screen height: $height"
|
||||
|
||||
|
||||
Note that some terminals return ``0`` for the width and height values. Such
|
||||
@@ -171,9 +150,7 @@ You can also use the *CSI t* escape code to get the screen size. Send
|
||||
``<ESC>[14t`` to ``STDOUT`` and kitty will reply on ``STDIN`` with
|
||||
``<ESC>[4;<height>;<width>t`` where ``height`` and ``width`` are the window
|
||||
size in pixels. This escape code is supported in many terminals, not just
|
||||
kitty. A more precise version of this escape code, which is however supported
|
||||
in less terminals is ``<ESC>[16t`` which causes the terminal to reply with the
|
||||
pixel dimensions of a single cell.
|
||||
kitty.
|
||||
|
||||
A minimal example
|
||||
------------------
|
||||
@@ -181,55 +158,61 @@ A minimal example
|
||||
Some minimal code to display PNG images in kitty, using the most basic
|
||||
features of the graphics protocol:
|
||||
|
||||
.. tab:: POSIX sh
|
||||
.. tab:: Bash
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
#!/bin/sh
|
||||
|
||||
send_chunked() {
|
||||
first="y"
|
||||
while IFS= read -r chunk; do
|
||||
metadata=""; [ "$first" = "y" ] && { metadata="a=T,f=100,"; first="n"; }
|
||||
printf "\033_G%sm=1;%s\033\\" "${metadata}" "${chunk}"
|
||||
done
|
||||
[ "$first" = "n" ] && { printf "\033_Gm=0;\033\\"; return 0; }
|
||||
return 1
|
||||
}
|
||||
|
||||
#!/bin/bash
|
||||
transmit_png() {
|
||||
# Different systems have different or missing base64 executables.
|
||||
# The sed command below adds a trailing newline which openssl
|
||||
# base64 does not produce and is needed for reading via read -r
|
||||
{ command base64 -w 4096 "$1" 2>/dev/null | send_chunked; } || \
|
||||
{ command base64 -b 4096 "$1" 2>/dev/null | send_chunked; } || \
|
||||
{ command openssl base64 -e -A -in "$1" | command sed '$a\' | command fold -b -w 4096 | send_chunked; }
|
||||
data=$(base64 "$1")
|
||||
data="${data//[[:space:]]}"
|
||||
builtin local pos=0
|
||||
builtin local chunk_size=4096
|
||||
while [ $pos -lt ${#data} ]; do
|
||||
builtin printf "\e_G"
|
||||
[ $pos = "0" ] && printf "a=T,f=100,"
|
||||
builtin local chunk="${data:$pos:$chunk_size}"
|
||||
pos=$(($pos+$chunk_size))
|
||||
[ $pos -lt ${#data} ] && builtin printf "m=1"
|
||||
[ ${#chunk} -gt 0 ] && builtin printf ";%s" "${chunk}"
|
||||
builtin printf "\e\\"
|
||||
done
|
||||
}
|
||||
|
||||
transmit_png "$1"
|
||||
|
||||
|
||||
.. tab:: Python
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
from base64 import standard_b64encode
|
||||
|
||||
first, eof, buf = True, False, memoryview(bytearray(3 * 4096 // 4))
|
||||
w = sys.stdout.buffer.write
|
||||
def serialize_gr_command(**cmd):
|
||||
payload = cmd.pop('payload', None)
|
||||
cmd = ','.join(f'{k}={v}' for k, v in cmd.items())
|
||||
ans = []
|
||||
w = ans.append
|
||||
w(b'\033_G'), w(cmd.encode('ascii'))
|
||||
if payload:
|
||||
w(b';')
|
||||
w(payload)
|
||||
w(b'\033\\')
|
||||
return b''.join(ans)
|
||||
|
||||
def write_chunked(**cmd):
|
||||
data = standard_b64encode(cmd.pop('data'))
|
||||
while data:
|
||||
chunk, data = data[:4096], data[4096:]
|
||||
m = 1 if data else 0
|
||||
sys.stdout.buffer.write(serialize_gr_command(payload=chunk, m=m,
|
||||
**cmd))
|
||||
sys.stdout.flush()
|
||||
cmd.clear()
|
||||
|
||||
with open(sys.argv[-1], 'rb') as f:
|
||||
while not eof:
|
||||
p = buf[:]
|
||||
while p and not eof:
|
||||
n = f.readinto1(p)
|
||||
p, eof = p[n:], n == 0
|
||||
encoded = standard_b64encode(buf[:len(buf)-len(p)])
|
||||
metadata, first = "a=T,f=100," if first else "", False
|
||||
w(f'\x1b_G{metadata}m={0 if eof else 1};'.encode('ascii'))
|
||||
w(encoded)
|
||||
w(b'\x1b\\')
|
||||
write_chunked(a='T', f=100, data=f.read())
|
||||
|
||||
|
||||
Save this script as :file:`send-png`, then you can use it to display any PNG
|
||||
@@ -350,7 +333,7 @@ similar to reporting any other kind of I/O error. Since the file paths come
|
||||
from potentially untrusted sources, terminal emulators **must** refuse to read
|
||||
any device/socket/etc. special files. Only regular files are allowed.
|
||||
Additionally, terminal emulators may refuse to read files in *sensitive*
|
||||
parts of the filesystem, such as :file:`/proc`, :file:`/sys`, :file:`/dev`, etc.
|
||||
parts of the filesystem, such as :file:`/proc`, :file:`/sys`, :file:`/dev/`, etc.
|
||||
|
||||
Local client
|
||||
^^^^^^^^^^^^^^
|
||||
@@ -368,7 +351,7 @@ Here we tell the terminal emulator to read compressed image data from
|
||||
the specified shared memory object.
|
||||
|
||||
The client can also specify a size and offset to tell the terminal emulator
|
||||
to only read a part of the specified file. This is done using the ``S`` and ``O``
|
||||
to only read a part of the specified file. The is done using the ``S`` and ``O``
|
||||
keys respectively. For example::
|
||||
|
||||
<ESC>_Gs=10,v=2,t=s,S=80,O=10;<encoded /some-shared-memory-name><ESC>\
|
||||
@@ -432,7 +415,9 @@ use the *query action*, set ``a=q``. Then the terminal emulator will try to load
|
||||
the image and respond with either OK or an error, as above, but it will not
|
||||
replace an existing image with the same id, nor will it store the image.
|
||||
|
||||
We intend that any terminal emulator that wishes to support it can do so. To
|
||||
As of May 2023, kitty has a complete implementation of this protocol and
|
||||
WezTerm has a mostly complete implementation. Konsole and wayst have partial
|
||||
support. We intend that any terminal emulator that wishes to support it can do so. To
|
||||
check if a terminal emulator supports the graphics protocol the best way is to
|
||||
send the above *query action* followed by a request for the `primary device
|
||||
attributes <https://vt100.net/docs/vt510-rm/DA1.html>`_. If you get back an
|
||||
@@ -480,11 +465,10 @@ id. To do so add the ``p`` key with a number between ``1`` and ``4294967295``.
|
||||
When you specify a placement id, it will be added to the acknowledgement code
|
||||
above. Every placement is uniquely identified by the pair of the ``image id``
|
||||
and the ``placement id``. If you specify a placement id for an image that does
|
||||
not have an id (i.e. has id=0), it will be ignored, i.e. the placement will not
|
||||
get an id. In particular this means there can exist multiple images with
|
||||
``image id=0, placement id=0``. Not specifying a placement id or using ``p=0``
|
||||
for multiple put commands (``a=p``) with the same non-zero image id results in
|
||||
multiple placements the image.
|
||||
not have an id (i.e. has id=0), it will be ignored. In particular this means
|
||||
there can exist multiple images with ``image id=0, placement id=0``. Not
|
||||
specifying a placement id or using ``p=0`` for multiple put commands (``a=p``)
|
||||
with the same non-zero image id results in multiple placements the image.
|
||||
|
||||
An example response::
|
||||
|
||||
@@ -495,14 +479,6 @@ second one will replace the first. This can be used to resize or move
|
||||
placements around the screen, without flicker.
|
||||
|
||||
|
||||
.. note::
|
||||
When re-transmitting image data for a specific id, the existing image and
|
||||
all its placements must be deleted. The new data replaces the old image data
|
||||
but is not actually displayed until a placement for it is created. This is
|
||||
to avoid divergent behavior in the case when unrelated programs happen to re-use
|
||||
image ids in the same session.
|
||||
|
||||
|
||||
.. versionadded:: 0.19.3
|
||||
Support for specifying placement ids (see :doc:`kittens/query_terminal` to query kitty version)
|
||||
|
||||
@@ -778,9 +754,6 @@ deleted, if the capital letter form above is specified. Also, when the terminal
|
||||
is running out of quota space for new images, existing images without
|
||||
placements will be preferentially deleted.
|
||||
|
||||
If an image is being loaded in chunks and the upload is not complete when any
|
||||
delete command is received, the partial upload must be aborted.
|
||||
|
||||
Some examples::
|
||||
|
||||
<ESC>_Ga=d<ESC>\ # delete all visible placements
|
||||
@@ -908,12 +881,12 @@ on.
|
||||
Finally, while transferring frame data, the frame *gap* can also be specified
|
||||
using the ``z`` key. The gap is the number of milliseconds to wait before
|
||||
displaying the next frame when the animation is running. A value of ``z=0`` is
|
||||
ignored (acts as though ``z`` was unspecified), ``z=positive number`` sets the
|
||||
gap to the specified number of milliseconds and ``z=negative number`` creates a
|
||||
*gapless* frame. Gapless frames are not displayed to the user since they are
|
||||
instantly skipped over, however they can be useful as the base data for
|
||||
subsequent frames. For example, for an animation where the background remains
|
||||
the same and a small object or two move.
|
||||
ignored, ``z=positive number`` sets the gap to the specified number of
|
||||
milliseconds and ``z=negative number`` creates a *gapless* frame. Gapless
|
||||
frames are not displayed to the user since they are instantly skipped over,
|
||||
however they can be useful as the base data for subsequent frames. For example,
|
||||
for an animation where the background remains the same and a small object or two
|
||||
move.
|
||||
|
||||
Controlling animations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@@ -943,9 +916,9 @@ animation. ``s=2`` runs the animation, but in *loading* mode, in this mode when
|
||||
reaching the last frame, instead of looping, the terminal will wait for the
|
||||
arrival of more frames. ``s=3`` runs the animation normally, after the last
|
||||
frame, the terminal loops back to the first frame. The number of loops can be
|
||||
controlled by the ``v`` key. ``v=0`` is ignored (acts as though ``v`` was not
|
||||
specified), ``v=1`` is loop infinitely, and any other positive number is loop
|
||||
``number - 1`` times. Note that stopping the animation resets the loop counter.
|
||||
controlled by the ``v`` key. ``v=0`` is ignored, ``v=1`` is loop infinitely,
|
||||
and any other positive number is loop ``number - 1`` times. Note that stopping
|
||||
the animation resets the loop counter.
|
||||
|
||||
Finally, the *gap* for frames can be set using the ``z`` key. This can be
|
||||
specified either when the frame is created as part of the transmit escape code
|
||||
@@ -1025,8 +998,8 @@ take, and the default value they take when missing. All integers are 32-bit.
|
||||
Key Value Default Description
|
||||
======= ==================== ========= =================
|
||||
``a`` Single character. ``t`` The overall action this graphics command is performing.
|
||||
``(a, c, d, f, ``t`` - transmit data, ``T`` - transmit data and display image,
|
||||
p, q, t, T)`` ``q`` - query terminal, ``p`` - put (display) previous transmitted image,
|
||||
``(a, c, d, f, `` ``t`` - transmit data, ``T`` - transmit data and display image,
|
||||
``p, q, t, T)`` ``q`` - query terminal, ``p`` - put (display) previous transmitted image,
|
||||
``d`` - delete image, ``f`` - transmit data for animation frames,
|
||||
``a`` - control animation, ``c`` - compose animation frames
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
kitty
|
||||
==========================================================
|
||||
|
||||
*If you live in the terminal, kitty is made for YOU!*
|
||||
|
||||
The fast, feature-rich, GPU based terminal emulator.
|
||||
*The fast, feature-rich, GPU based terminal emulator*
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
@@ -12,7 +10,6 @@ The fast, feature-rich, GPU based terminal emulator.
|
||||
overview
|
||||
faq
|
||||
support
|
||||
sessions
|
||||
performance
|
||||
changelog
|
||||
integrations
|
||||
@@ -22,7 +19,7 @@ The fast, feature-rich, GPU based terminal emulator.
|
||||
|
||||
.. tab:: Fast
|
||||
|
||||
* Uses GPU and SIMD vector CPU instructions for :doc:`best in class performance <performance>`
|
||||
* Uses GPU and SIMD vector CPU instructions for :doc:`best in class <performance>`
|
||||
* Uses threaded rendering for :iss:`absolutely minimal latency <2701#issuecomment-636497270>`
|
||||
* Performance tradeoffs can be :ref:`tuned <conf-kitty-performance>`
|
||||
|
||||
|
||||
@@ -14,12 +14,6 @@ Image and document viewers
|
||||
Powered by kitty's :doc:`graphics-protocol` there exist many tools for viewing
|
||||
images and other types of documents directly in your terminal, even over SSH.
|
||||
|
||||
.. _tool_bookokrat:
|
||||
|
||||
`bookokrat <https://github.com/bugzmanov/bookokrat>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal PDF/EPUB viewer
|
||||
|
||||
.. _tool_termpdf:
|
||||
|
||||
`termpdf.py <https://github.com/dsanson/termpdf.py>`_
|
||||
@@ -32,29 +26,39 @@ A terminal PDF/DJVU/CBR viewer
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal PDF viewer
|
||||
|
||||
.. _tool_fancy_cat:
|
||||
.. _tool_mdcat:
|
||||
|
||||
`fancy-cat <https://github.com/freref/fancy-cat>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal PDF viewer
|
||||
|
||||
.. _tool_meowpdf:
|
||||
|
||||
`meowpdf <https://github.com/monoamine11231/meowpdf>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal PDF viewer with GUI-like usage and Vim-like keybindings written in Rust
|
||||
|
||||
.. _tool_mcat:
|
||||
|
||||
`mcat <https://github.com/Skardyy/mcat>`_
|
||||
`mdcat <https://github.com/lunaryorn/mdcat>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Display various types of files nicely formatted with images in the terminal
|
||||
Display markdown files nicely formatted with images in the terminal
|
||||
|
||||
`dawn <https://github.com/andrewmd5/dawn>`__
|
||||
.. _tool_ranger:
|
||||
|
||||
`ranger <https://github.com/ranger/ranger>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_nnn:
|
||||
|
||||
`nnn <https://github.com/jarun/nnn/>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_yazi:
|
||||
|
||||
`Yazi <https://github.com/sxyazi/yazi>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Blazing fast terminal file manager, with built-in kitty graphics protocol support
|
||||
(implemented both Classic protocol and Unicode placeholders).
|
||||
|
||||
.. _tool_hunter:
|
||||
|
||||
`hunter <https://github.com/rabite0/hunter>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A markdown editor that uses the text-sizing protocol for large headings and
|
||||
the graphics protocol for images.
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_presentterm:
|
||||
|
||||
@@ -63,13 +67,6 @@ the graphics protocol for images.
|
||||
Show markdown based slides with images in your terminal, powered by the
|
||||
kitty graphics protocol.
|
||||
|
||||
.. _tool_mdfried:
|
||||
|
||||
`mdfried <https://github.com/benjajaja/mdfried>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Markdown viewer that can render big headers with the text-sizing-protocol, and
|
||||
also render images with the kitty graphics protocol.
|
||||
|
||||
.. _tool_term_image:
|
||||
|
||||
`term-image <https://github.com/AnonymouX47/term-image>`__
|
||||
@@ -103,30 +100,17 @@ base application that uses kitty's graphics protocol for images.
|
||||
A text mode WWW browser that supports kitty's graphics protocol to display
|
||||
images.
|
||||
|
||||
.. _tool_awrit:
|
||||
|
||||
`awrit <https://github.com/chase/awrit>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A full Chromium based web browser running in the terminal using kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_chawan:
|
||||
|
||||
`chawan <https://sr.ht/~bptato/chawan/>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A text mode WWW browser that supports kitty's graphics protocol to display
|
||||
images.
|
||||
|
||||
.. _tool_mpv:
|
||||
|
||||
`mpv <https://github.com/mpv-player/mpv/commit/874e28f4a41a916bb567a882063dd2589e9234e1>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A video player that can play videos in the terminal.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
mpv --profile=sw-fast --vo=kitty --vo-kitty-use-shm=yes --really-quiet video.mkv
|
||||
|
||||
.. _tool_timg:
|
||||
|
||||
`timg <https://github.com/hzeller/timg>`_
|
||||
@@ -136,52 +120,6 @@ plays videos. Fast multi-threaded loading, JPEG exif rotation, grid view and
|
||||
connecting to the webcam make it a versatile terminal utility.
|
||||
|
||||
|
||||
|
||||
File managers
|
||||
-------------------
|
||||
.. _tool_ranger:
|
||||
|
||||
`ranger <https://github.com/ranger/ranger>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_nnn:
|
||||
|
||||
`nnn <https://github.com/jarun/nnn/>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_yazi:
|
||||
|
||||
`Yazi <https://github.com/sxyazi/yazi>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Blazing fast terminal file manager, with built-in kitty graphics protocol support
|
||||
(implemented both Classic protocol and Unicode placeholders).
|
||||
|
||||
.. _tool_clifm:
|
||||
|
||||
`clifm <https://github.com/leo-arch/clifm>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
The shell-like, command line terminal file manager, uses the kitty graphics and
|
||||
keyboard protocols.
|
||||
|
||||
.. _tool_hunter:
|
||||
|
||||
`hunter <https://github.com/rabite0/hunter>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Another terminal file manager, with previews of file contents powered by kitty's
|
||||
graphics protocol.
|
||||
|
||||
.. _tool_far2l:
|
||||
|
||||
`far2l <https://github.com/elfmz/far2l>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Text-mode dual panel (orthodox) file manager and also terminal emulator, uses
|
||||
the kitty graphics and keyboard protocols (both as client and as terminal)
|
||||
|
||||
|
||||
System and data visualisation tools
|
||||
---------------------------------------
|
||||
|
||||
@@ -194,13 +132,9 @@ protocol
|
||||
|
||||
.. _tool_matplotlib:
|
||||
|
||||
matplotlib
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
There exist multiple backends for matplotlib to draw images directly in kitty.
|
||||
|
||||
* `matplotlib-backend-kitty <https://github.com/jktr/matplotlib-backend-kitty>`__
|
||||
* `kitcat <https://github.com/mil-ad/kitcat>`__
|
||||
`matplotlib <https://github.com/jktr/matplotlib-backend-kitty>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Show matplotlib plots directly in kitty
|
||||
|
||||
.. _tool_KittyTerminalImage:
|
||||
|
||||
@@ -220,15 +154,28 @@ by kitty's graphics protocol for displaying plots
|
||||
`gnuplot <http://www.gnuplot.info/>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
A graphing and data visualization tool that has support for the kitty graphics
|
||||
protocol, with its ``kittygd`` and ``kittycairo`` backends.
|
||||
A graphing and data visualization tool that can be made to display its output in
|
||||
kitty with the following bash snippet:
|
||||
|
||||
.. _tool_k-nine:
|
||||
.. code-block:: sh
|
||||
|
||||
`k-nine <https://github.com/talwrii/kitty-plotnine>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
function iplot {
|
||||
cat <<EOF | gnuplot
|
||||
set terminal pngcairo enhanced font 'Fira Sans,10'
|
||||
set autoscale
|
||||
set samples 1000
|
||||
set output '|kitten icat --stdin yes'
|
||||
set object 1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb"#fdf6e3" behind
|
||||
plot $@
|
||||
set output '/dev/null'
|
||||
EOF
|
||||
}
|
||||
|
||||
A wrapper around the :code:`plotnine` library which lets you plot data from the command-line with bash one-liners.
|
||||
Add this to bashrc and then to plot a function, simply do:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
iplot 'sin(x*3)*exp(x*.2)'
|
||||
|
||||
.. tool_tgutui:
|
||||
|
||||
@@ -261,14 +208,6 @@ A tool to display weather information in your terminal with curl
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
View and manage the system clipboard under Wayland in your kitty terminal
|
||||
|
||||
.. tool_nemu:
|
||||
|
||||
`NEMU <https://github.com/nemuTUI/nemu>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
TUI for QEMU used to manage virtual machines, can display the Virtual Machine
|
||||
in the terminal using the kitty graphics protocol.
|
||||
|
||||
|
||||
Editor integration
|
||||
-----------------------
|
||||
|
||||
@@ -282,14 +221,6 @@ features such a split windows, previews, REPLs etc.
|
||||
Integrates with kitty to use native kitty windows for its windows/panels and
|
||||
REPLs.
|
||||
|
||||
.. _tool_orbiton:
|
||||
|
||||
`orbiton <https://github.com/xyproto/orbiton/>`_
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A terminal text editor that uses kitty's graphics protocol to render Markdown
|
||||
documents with fonts and images inline (use the ``-B`` flag for a word
|
||||
processor-like book mode), and to preview images in its built-in file browser.
|
||||
|
||||
.. tool_vim_slime:
|
||||
|
||||
`vim-slime <https://github.com/jpalardy/vim-slime#kitty>`_
|
||||
@@ -313,11 +244,10 @@ Allows easily running tests in a terminal window
|
||||
|
||||
Various image viewing plugins for editors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
* `snacks.nvim <https://github.com/folke/snacks.nvim>`__ - Enables seamless inline images in various file formats within nvim
|
||||
|
||||
* `image.nvim <https://github.com/3rd/image.nvim>`_ - Bringing images to neovim
|
||||
* `image_preview.nvim <https://github.com/adelarsq/image_preview.nvim/>`_ - Image preview for neovim
|
||||
* `hologram.nvim <https://github.com/edluffy/hologram.nvim>`_ - view images inside nvim
|
||||
* `kitty-graphics.el <https://github.com/cashmeredev/kitty-graphics.el>`_ - view images in emacs
|
||||
|
||||
Scrollback manipulation
|
||||
-------------------------
|
||||
@@ -341,50 +271,10 @@ Live incremental search of the scrollback buffer.
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Keyboard based text selection for the kitty scrollback buffer.
|
||||
|
||||
Desktop panels
|
||||
-------------------------
|
||||
|
||||
`kitty panel <https://github.com/5hubham5ingh/kitty-panel>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A system panel for Kitty terminal that displays real-time system metrics using terminal-based utilities.
|
||||
|
||||
|
||||
`pawbar <https://github.com/codelif/pawbar>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
A kitten-panel based desktop panel for your desktop
|
||||
|
||||
Password managers
|
||||
---------------------
|
||||
|
||||
`1password <https://github.com/mm-zacharydavison/kitty-kitten-1password>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Allow injecting passwords from 1Password into kitty.
|
||||
|
||||
`BitWarden <https://github.com/dnanhkhoa/kitty-password-manager>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Inject passwords from BitWarden into kitty
|
||||
|
||||
Miscellaneous
|
||||
------------------
|
||||
|
||||
.. tool_doom:
|
||||
|
||||
DOOM
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Play the classic shooter DOOM in `kitty <https://github.com/cryptocode/terminal-doom>`__ or even inside `neovim inside kitty
|
||||
<https://github.com/seandewar/actually-doom.nvim>`__.
|
||||
|
||||
.. tool_gattino:
|
||||
|
||||
`gattino <https://github.com/salvozappa/gattino>`__
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Integrate kitty with an LLM to convert plain language prompts into shell
|
||||
commands.
|
||||
|
||||
.. tool_kitty_smart_tab:
|
||||
|
||||
`kitty-smart-tab <https://github.com/yurikhan/kitty-smart-tab>`_
|
||||
|
||||
@@ -34,26 +34,16 @@ inside the kitty terminal to report key events.
|
||||
|
||||
In addition to kitty, this protocol is also implemented in:
|
||||
|
||||
* The `alacritty terminal <https://github.com/alacritty/alacritty/pull/7125>`__
|
||||
* The `foot terminal <https://codeberg.org/dnkl/foot/issues/319>`__
|
||||
* The `ghostty terminal <https://ghostty.org>`__
|
||||
* The `iTerm2 terminal <https://gitlab.com/gnachman/iterm2/-/issues/10017>`__
|
||||
* The `Microsoft terminal <https://github.com/microsoft/terminal/pull/19817>`__
|
||||
* The `rio terminal <https://github.com/raphamorim/rio/commit/cd463ca37677a0fc48daa8795ea46dadc92b1e95>`__
|
||||
* The `TuiOS terminal (multiplexer) <https://github.com/Gaurav-Gosain/tuios/issues/26>`__
|
||||
* The `Warp terminal <https://github.com/warpdotdev/Warp/issues/8462#issuecomment-3857779488>`__
|
||||
* The `WezTerm terminal <https://wezfurlong.org/wezterm/config/lua/config/enable_kitty_keyboard.html>`__
|
||||
* The `xterm.js terminal <https://github.com/xtermjs/xterm.js/pull/5600>`__
|
||||
* The `alacritty terminal <https://github.com/alacritty/alacritty/pull/7125>`__
|
||||
* The `rio terminal <https://github.com/raphamorim/rio/commit/cd463ca37677a0fc48daa8795ea46dadc92b1e95>`__
|
||||
|
||||
Libraries implementing this protocol:
|
||||
|
||||
* The `notcurses library <https://github.com/dankamongmen/notcurses/issues/2131>`__
|
||||
* The `crossterm library <https://github.com/crossterm-rs/crossterm/pull/688>`__
|
||||
* The `textual library <https://github.com/Textualize/textual/pull/4631>`__
|
||||
* The vaxis library `go <https://sr.ht/~rockorager/vaxis/>`__ and `zig <https://github.com/rockorager/libvaxis/>`__
|
||||
* The `bubbletea library <https://github.com/charmbracelet/bubbletea/issues/869>`__
|
||||
* The `vtinput <https://unxed.github.com/vtinput>`__ and `vtui <https://github.com/unxed/vtui>`__ libraries
|
||||
* The `tcell library <https://github.com/gdamore/tcell/commit/c10909b991eb87c009554fe9b2dfa7276e2649c1>`__
|
||||
|
||||
Programs implementing this protocol:
|
||||
|
||||
@@ -63,12 +53,10 @@ Programs implementing this protocol:
|
||||
* The `kakoune text editor <https://github.com/mawww/kakoune/issues/4103>`__
|
||||
* The `dte text editor <https://gitlab.com/craigbarnes/dte/-/issues/138>`__
|
||||
* The `Helix text editor <https://github.com/helix-editor/helix/pull/4939>`__
|
||||
* The `Flow control editor <https://github.com/neurocyte/flow?tab=readme-ov-file#requirements>`__
|
||||
* The `far2l <https://github.com/elfmz/far2l/commit/e1f2ee0ef2b8332e5fa3ad7f2e4afefe7c96fc3b>`__ and `f4 <https://github.com/unxed/f4>`__ file managers
|
||||
* The `far2l file manager <https://github.com/elfmz/far2l/commit/e1f2ee0ef2b8332e5fa3ad7f2e4afefe7c96fc3b>`__
|
||||
* The `Yazi file manager <https://github.com/sxyazi/yazi>`__
|
||||
* The `awrit web browser <https://github.com/chase/awrit>`__
|
||||
* The `Turbo Vision <https://github.com/magiblot/tvision/commit/6e5a7b46c6634079feb2ac98f0b890bbed59f1ba>`__/`Free Vision <https://gitlab.com/freepascal.org/fpc/source/-/issues/40673#note_2061428120>`__ IDEs
|
||||
* The `aerc email client <https://git.sr.ht/~rjarry/aerc/commit/d73cf33c2c6c3e564ce8aff04acc329a06eafc54>`__
|
||||
|
||||
Shells implementing this protocol:
|
||||
|
||||
@@ -157,14 +145,14 @@ user presses, for example, :kbd:`ctrl+shift+a` the escape code would be ``CSI
|
||||
97;modifiers u``. It *must not* be ``CSI 65; modifiers u``.
|
||||
|
||||
If *alternate key reporting* is requested by the program running in the
|
||||
terminal, the terminal can send two additional Unicode codepoints, the *shifted
|
||||
key* and *base layout key*, separated by colons. The shifted key is simply the
|
||||
upper-case version of ``unicode-codepoint``, or more technically, the shifted
|
||||
version, in the currently active keyboard layout. So `a` becomes `A` and so on,
|
||||
based on the current keyboard layout. This is needed to be able to match
|
||||
against a shortcut such as :kbd:`ctrl+plus` which depending on the type of
|
||||
keyboard could be either :kbd:`ctrl+shift+equal` or :kbd:`ctrl+plus`. Note that
|
||||
the shifted key must be present only if shift is also present in the modifiers.
|
||||
terminal, the terminal can send two additional Unicode codepoints, the
|
||||
*shifted key* and *base layout key*, separated by colons.
|
||||
The shifted key is simply the upper-case version of ``unicode-codepoint``, or
|
||||
more technically, the shifted version. So `a` becomes `A` and so on, based on
|
||||
the current keyboard layout. This is needed to be able to match against a
|
||||
shortcut such as :kbd:`ctrl+plus` which depending on the type of keyboard could
|
||||
be either :kbd:`ctrl+shift+equal` or :kbd:`ctrl+plus`. Note that the shifted
|
||||
key must be present only if shift is also present in the modifiers.
|
||||
|
||||
The *base layout key* is the key corresponding to the physical key in the
|
||||
standard PC-101 key layout. So for example, if the user is using a Cyrillic
|
||||
@@ -172,7 +160,7 @@ keyboard with a Cyrillic keyboard layout pressing the :kbd:`ctrl+С` key will
|
||||
be :kbd:`ctrl+c` in the standard layout. So the terminal should send the *base
|
||||
layout key* as ``99`` corresponding to the ``c`` key.
|
||||
|
||||
If only one alternate key is present, it is the *shifted key*. If the terminal
|
||||
If only one alternate key is present, it is the *shifted key* if the terminal
|
||||
wants to send only a base layout key but no shifted key, it must use an empty
|
||||
sub-field for the shifted key, like this::
|
||||
|
||||
@@ -249,19 +237,13 @@ The terminal can optionally send the text associated with key events as a
|
||||
sequence of Unicode code points. This behavior is opt-in by the :ref:`progressive
|
||||
enhancement <progressive_enhancement>` mechanism described below. Some examples::
|
||||
|
||||
shift+a -> CSI 97 ; 2 ; 65 u # The text 'A' is reported as 65
|
||||
alt+a -> CSI 0 ; ; 229 u # The text 'å' is reported as 229
|
||||
shift+a -> CSI 97 ; 2 ; 65 u # The text 'A' is reported as 65
|
||||
option+a -> CSI 97 ; ; 229 u # The text 'å' is reported as 229
|
||||
|
||||
If multiple code points are present, they must be separated by colons. If no
|
||||
known key is associated with the text the key number ``0`` must be used. The
|
||||
associated text must not contain control codes (control codes are code points
|
||||
below U+0020 and codepoints in the C0 and C1 blocks). In the above example, the
|
||||
:kbd:`alt` modifier is consumed by the OS itself to produce the text å and not
|
||||
sent to the terminal emulator, which gets only a "text input" event and no
|
||||
information about modifiers, thus the event gets encoded with no modifiers.
|
||||
The exact behavior in these situations depends on the OS, keyboard layout, IME
|
||||
system in use and so on. In general, if the terminal emulator receives no key
|
||||
information, the key number 0 must be used to indicate a pure "text event".
|
||||
below U+0020 and codepoints in the C0 and C1 blocks).
|
||||
|
||||
|
||||
Non-Unicode keys
|
||||
@@ -351,7 +333,7 @@ the bytes used for CSI control codes.
|
||||
Turning on this flag will cause the terminal to report the :kbd:`Esc`, :kbd:`alt+key`,
|
||||
:kbd:`ctrl+key`, :kbd:`ctrl+alt+key`, :kbd:`shift+alt+key` keys using ``CSI u`` sequences instead
|
||||
of legacy ones. Here key is any ASCII key as described in :ref:`legacy_text`.
|
||||
Additionally, all non text keypad keys will be reported as separate keys with ``CSI u``
|
||||
Additionally, all keypad keys will be reported as separate keys with ``CSI u``
|
||||
encoding, using dedicated numbers from the :ref:`table below <functional>`.
|
||||
|
||||
With this flag turned on, all key events that do not generate text are
|
||||
@@ -368,7 +350,7 @@ are the :kbd:`Enter`, :kbd:`Tab` and :kbd:`Backspace` keys which still generate
|
||||
bytes as in legacy mode this is to allow the user to type and execute commands
|
||||
in the shell such as ``reset`` after a program that sets this mode crashes
|
||||
without clearing it. Note that the Lock modifiers are not reported for text
|
||||
producing keys, to keep them usable in legacy programs. To get lock modifiers
|
||||
producing keys, to keep them useable in legacy programs. To get lock modifiers
|
||||
for all keys use the :ref:`report_all_keys` enhancement.
|
||||
|
||||
.. _report_events:
|
||||
@@ -394,13 +376,8 @@ Report alternate keys
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This progressive enhancement (``0b100``) causes the terminal to report
|
||||
alternate key values *in addition* to the main value, to aid in shortcut
|
||||
matching. See :ref:`key_codes` for details on how these are reported. Note that
|
||||
this flag is a pure enhancement to the form of the escape code used to
|
||||
represent key events, only key events represented as escape codes due to the
|
||||
other enhancements in effect will be affected by this enhancement. In other
|
||||
words, only if a key event was already going to be represented as an escape
|
||||
code due to one of the other enhancements will this enhancement affect it.
|
||||
alternate key values in addition to the main value, to aid in shortcut
|
||||
matching. See :ref:`key_codes` for details on how these are reported.
|
||||
|
||||
.. _report_all_keys:
|
||||
|
||||
@@ -419,20 +396,17 @@ Report associated text enhancement below.
|
||||
|
||||
Additionally, with this mode, events for pressing modifier keys are reported.
|
||||
Note that *all* keys are reported as escape codes, including :kbd:`Enter`,
|
||||
:kbd:`Tab`, :kbd:`Backspace` etc. Note that this enhancement implies all keys
|
||||
are automatically disambiguated as well, since they are represented in their
|
||||
canonical escape code form.
|
||||
:kbd:`Tab`, :kbd:`Backspace` etc.
|
||||
|
||||
.. _report_text:
|
||||
|
||||
Report associated text
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This progressive enhancement (``0b10000``) *additionally* causes key events that
|
||||
generate text to be reported as ``CSI u`` escape codes with the text embedded
|
||||
in the escape code. See :ref:`text_as_codepoints` above for details on the
|
||||
mechanism. Note that this flag is an enhancement to :ref:`report_all_keys`
|
||||
and is undefined if used without it.
|
||||
This progressive enhancement (``0b10000``) causes key events that generate text
|
||||
to be reported as ``CSI u`` escape codes with the text embedded in the escape
|
||||
code. See :ref:`text_as_codepoints` above for details on the mechanism.
|
||||
|
||||
|
||||
.. _detection:
|
||||
|
||||
@@ -447,13 +421,6 @@ followed by request for the `primary device attributes
|
||||
attributes is received without getting back an answer for the progressive
|
||||
enhancement the terminal does not support this protocol.
|
||||
|
||||
.. note::
|
||||
Terminal implementations of this protocol are **strongly** encouraged to
|
||||
implement all progressive enhancements. It does not make sense to
|
||||
implement only a subset. Nonetheless, there are likely to be some terminal
|
||||
implementations that do not do so, applications can detect such
|
||||
implementations by first setting the desired progressive enhancements and
|
||||
then querying for the :ref:`current progressive enhancement <progressive_enhancement>`
|
||||
|
||||
Legacy key event encoding
|
||||
--------------------------------
|
||||
@@ -478,10 +445,7 @@ These keys are encoded using three schemes::
|
||||
|
||||
In the above, if there are no modifiers, the modifier parameter is omitted.
|
||||
The modifier value is encoded as described in the :ref:`modifiers` section,
|
||||
above, except that lock keys (such as :kbd:`Num lock` and :kbd:`Caps lock`)
|
||||
are not encoded as the legacy mode has no encoding for them.
|
||||
|
||||
When the second form is used, the number is always ``1`` and must be
|
||||
above. When the second form is used, the number is always ``1`` and must be
|
||||
omitted if the modifiers field is also absent. The third form becomes the
|
||||
second form when modifiers are present (``SS3 is the bytes 0x1b 0x4f``).
|
||||
|
||||
@@ -572,8 +536,8 @@ Any other combination of modifiers with these keys is output as the appropriate
|
||||
.. csv-table:: Example encodings
|
||||
:header: "Key", "Plain", "shift", "alt", "ctrl", "shift+alt", "alt+ctrl", "ctrl+shift"
|
||||
|
||||
"i", "i (105)", "I (73)", "ESC i", "\t (9)", "ESC I", "ESC \t", "CSI 105; 6 u"
|
||||
"3", "3 (51)", "# (35)", "ESC 3", "ESC (27)", "ESC #", "ESC ESC", "CSI 51; 6 u"
|
||||
"i", "i (105)", "I (73)", "ESC i", ") (41)", "ESC I", "ESC )", "CSI 105; 6 u"
|
||||
"3", "3 (51)", "# (35)", "ESC 3", "3 (51)", "ESC #", "ESC 3", "CSI 51; 6 u"
|
||||
";", "; (59)", ": (58)", "ESC ;", "; (59)", "ESC :", "ESC ;", "CSI 59; 6 u"
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
Selecting files, fast
|
||||
========================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
.. versionadded:: 0.45.0
|
||||
|
||||
.. only:: not man
|
||||
|
||||
.. figure:: /screenshots/choose-files.webp
|
||||
:alt: The choose files kitten, showing metadata and title from an e-book file
|
||||
:align: center
|
||||
:width: 100%
|
||||
|
||||
|
||||
The choose-files kitten is designed to allow you to select files, very fast,
|
||||
with just a few key strokes. It operates like `fzf
|
||||
<https://github.com/junegunn/fzf/>`__ and similar fuzzy finders, except that
|
||||
it is specialised for finding files. As such it supports features such as
|
||||
filtering by file type, file type icons, content previews and
|
||||
so on, out of the box. It can be used as a drop in (but much more efficient and
|
||||
keyboard friendly) replacement for the :guilabel:`File open and save`
|
||||
dialog boxes common to GUI programs. On Linux, with the help of the
|
||||
:doc:`desktop-ui </kittens/desktop-ui>` kitten, you can even convince
|
||||
most GUI programs on your computer to use this kitten instead of regular file
|
||||
dialogs.
|
||||
|
||||
Simply run it as::
|
||||
|
||||
kitten choose-files
|
||||
|
||||
to select a single file from the tree rooted at the current working directory.
|
||||
|
||||
Type a few letters from the filename and once it becomes the top selection,
|
||||
press :kbd:`Enter`. You can change the current directory by selecting a
|
||||
directory and pressing the :kbd:`Tab` key. :kbd:`Shift+Tab` goes up one
|
||||
directory level.
|
||||
|
||||
If you want to choose a file and insert it into your shell prompt at the
|
||||
current cursor position, press :sc:`insert_chosen_file` for files or
|
||||
:sc:`insert_chosen_directory` for directories. Similarly, to have a file
|
||||
chosen in a command line, use, for example::
|
||||
|
||||
some-command $(kitten choose-file)
|
||||
|
||||
Note that the above may not work in a complicated pipeline as it performs
|
||||
terminal I/O and needs exclusive access to the tty device while choosing a
|
||||
file.
|
||||
|
||||
.. note:: For content previews, this kitten uses some external programs. In
|
||||
particular `ffmpeg <https://www.ffmpeg.org/>`__ is needed for video
|
||||
previews and `calibre <https://calibre-ebook.com>`__ is needed
|
||||
for ebook metadata and cover preiews.
|
||||
|
||||
Creating shortcuts to favorite/frequently used directories
|
||||
------------------------------------------------------------
|
||||
|
||||
You can create keyboard shortcuts to quickly switch to any directory in
|
||||
:file:`choose-files.conf`. For example:
|
||||
|
||||
.. code-block:: conf
|
||||
|
||||
map ctrl+t cd /tmp
|
||||
map alt+p cd ~/my/project
|
||||
|
||||
Selecting multiple files
|
||||
-----------------------------
|
||||
|
||||
When you wish to select multiple files, start the kitten with :option:`--mode
|
||||
<kitty +kitten choose_files --mode>`:code:`=files`. Then instead of pressing
|
||||
:kbd:`Enter`, press :kbd:`Shift+Enter` instead and the file will be added to the list
|
||||
of selections. You can also hold the :kbd:`Ctrl` key and click on files to add
|
||||
them to the selections. Similarly, you can hold the :kbd:`Alt` key and click to
|
||||
select ranges of files (similar to using :kbd:`Shift+click` in a GUI app).
|
||||
Press :kbd:`Enter` on the last selected file to finish. The list of selected
|
||||
files is displayed at the bottom of the kitten and you can click on them
|
||||
to deselect a file. Similarly, pressing :kbd:`Shift+Enter` will un-select a
|
||||
previously selected file.
|
||||
|
||||
|
||||
Hidden and ignored files
|
||||
--------------------------
|
||||
|
||||
By default, the kitten does not process hidden files and directories (whose
|
||||
names start with a period). This can be :opt:`changed in the configuration <kitten-choose_files.show_hidden>`
|
||||
and also at runtime via the clickable link to the right of the search input.
|
||||
|
||||
Similarly, the kitten respects both :file:`.gitignore` and :file:`.ignore`
|
||||
files, by default. This can also be changed both :opt:`in configuration
|
||||
<kitten-choose_files.respect_ignores>` or at runtime. Note that
|
||||
:file:`.gitignore` files are only respected if there is also a :file:`.git`
|
||||
directory present. The kitten also supports the global :file:`.gitignore` file,
|
||||
though it applies only inside git working trees. You can specify :opt:`global ignore
|
||||
patterns <kitten-choose_files.ignore>`, that apply everywhere in :file:`choose-files.conf`.
|
||||
|
||||
|
||||
Selecting non-existent files (save file names)
|
||||
-------------------------------------------------
|
||||
|
||||
This kitten can also be used to select non-existent files, that is a new file
|
||||
for a :guilabel:`Save file` type of dialog using :option:`--mode <kitty +kitten
|
||||
choose_files --mode>`:code:`=save-file`. Once you have changed to the directory
|
||||
you want the file to be in (using the :kbd:`Tab` key),
|
||||
press :kbd:`Ctrl+Enter` and you will be able to type in the file name. If you
|
||||
wish to modify an existing file name use :kbd:`Alt+Enter` to modify the
|
||||
filename of the current top match instead.
|
||||
|
||||
|
||||
Selecting directories
|
||||
---------------------------
|
||||
|
||||
This kitten can also be used to select directories,
|
||||
for an :guilabel:`Open directory` type of dialog using :option:`--mode <kitty +kitten
|
||||
choose_files --mode>`:code:`=dir`. Once you have changed to the directory
|
||||
you want, press :kbd:`Ctrl+Enter` to accept it. Or if you are in a parent
|
||||
directory you can select a descendant directory by pressing :kbd:`Enter`, the
|
||||
same as you would for selecting a file to open.
|
||||
|
||||
|
||||
Configuration
|
||||
------------------------
|
||||
|
||||
You can configure various aspects of the kitten's operation by creating a
|
||||
:file:`choose-files.conf` in your :ref:`kitty config folder <confloc>`.
|
||||
See below for the supported configuration directives.
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitten-choose_files.rst
|
||||
|
||||
|
||||
.. include:: /generated/cli-kitten-choose_files.rst
|
||||
|
||||
|
||||
@@ -118,11 +118,11 @@ that is, they are used to set the variable value for some font characteristic.
|
||||
<https://harfbuzz.github.io/harfbuzz-hb-common.html#hb-feature-from-string>`__
|
||||
|
||||
``system``
|
||||
This can be used to pass an arbitrary string, usually a family or full name
|
||||
This can be used to pass an arbitrary string, usuall a family or full name
|
||||
to the OS font selection APIs. Should not be used in conjunction with any
|
||||
other keys. Is the same as specifying just the font name without any keys.
|
||||
|
||||
|
||||
In addition to these keys, any four letter key is treated as the name of a
|
||||
variable characteristic of the font. Its value is used to set the value for
|
||||
variable characteristic of the font. It's value is used to set the value for
|
||||
the name.
|
||||
|
||||
@@ -6,7 +6,7 @@ clipboard
|
||||
Overview
|
||||
--------------
|
||||
|
||||
*Copy/paste to the system clipboard from shell scripts*
|
||||
*Copy/paste to the system clipboard from shell scripts*
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
Command palette
|
||||
=================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
The command palette lets you browse, search and trigger all keyboard shortcuts
|
||||
and actions in |kitty| from a single searchable overlay. Press
|
||||
:sc:`command_palette` to open it (default: :kbd:`Ctrl+Shift+F3`).
|
||||
|
||||
.. figure:: ../screenshots/command-palette.webp
|
||||
:alt: A screenshot of the command palette kitten
|
||||
:align: center
|
||||
:width: 100%
|
||||
|
||||
The command palette showing search results for ``win close``.
|
||||
|
||||
All mapped actions (those with a keyboard shortcut) and unmapped actions (those
|
||||
available but not bound to any key) are listed, organized by category. Mouse
|
||||
bindings are shown in a separate section. Simply type to search, select a
|
||||
result, and press :kbd:`Enter` to run it.
|
||||
|
||||
|
||||
Searching
|
||||
-----------
|
||||
|
||||
As you type into the search bar, the palette filters results in real time.
|
||||
Matching is case-insensitive and works across three columns simultaneously:
|
||||
the **key** (keyboard shortcut), the **action** name, and the **category**.
|
||||
Matched characters are highlighted so you can see exactly where each term hit.
|
||||
|
||||
**Multiple words**
|
||||
Separate your terms with spaces. Typing ``scroll page`` looks for items
|
||||
that contain *scroll* and *page* anywhere across the key, action, or
|
||||
category columns. Items that match more of your terms are ranked higher
|
||||
than those that match fewer.
|
||||
|
||||
**How individual words are matched**
|
||||
Each word in your query is compared against every word in the three
|
||||
columns. The best match wins and determines the item's score for that
|
||||
term:
|
||||
|
||||
- *Exact word* — the query word equals a column word exactly (highest score).
|
||||
- *Prefix* — the column word starts with the query word,
|
||||
e.g. ``scr`` matches ``scroll``.
|
||||
- *Typo tolerance* — for words of four characters or longer, a single
|
||||
typo (one character inserted, deleted, or substituted) still produces a
|
||||
match, and two typos give a lower-scoring match.
|
||||
|
||||
An item appears in the results as long as at least one query word matches
|
||||
something. Items where more query words match rank above those where fewer
|
||||
match.
|
||||
|
||||
**Compound names**
|
||||
Delimiters such as ``_``, ``+``, ``/``, and ``-`` are kept intact inside a
|
||||
query word, so you can search for compound action names as a unit.
|
||||
Typing ``mouse_selection`` first tries to find that exact substring in each
|
||||
column. If that fails, it splits the token into its parts (``mouse`` and
|
||||
``selection``) and matches each part independently against the column words.
|
||||
|
||||
**Ranking**
|
||||
When multiple items match the same query, they are sorted by:
|
||||
|
||||
1. Number of query words that matched (more is better).
|
||||
2. Score on the action column (action matches outrank key or category matches).
|
||||
3. Score on the key column.
|
||||
4. Score on the category column.
|
||||
5. Shorter action name as a tiebreaker (more specific results first).
|
||||
|
||||
|
||||
Keyboard controls
|
||||
-------------------
|
||||
|
||||
The following keys are available while the command palette is open:
|
||||
|
||||
.. list-table::
|
||||
:widths: auto
|
||||
:header-rows: 1
|
||||
|
||||
* - Key
|
||||
- Action
|
||||
* - Any text
|
||||
- Filter results by typing a search query
|
||||
* - :kbd:`Enter`
|
||||
- Run the selected action
|
||||
* - :kbd:`Escape`
|
||||
- Clear the search query, or close the palette if the query is already empty
|
||||
* - :kbd:`Up` / :kbd:`Ctrl+K` / :kbd:`Ctrl+P`
|
||||
- Move selection up
|
||||
* - :kbd:`Down` / :kbd:`Ctrl+J` / :kbd:`Ctrl+N`
|
||||
- Move selection down
|
||||
* - :kbd:`Page Up`
|
||||
- Move selection up by a page
|
||||
* - :kbd:`Page Down`
|
||||
- Move selection down by a page
|
||||
* - :kbd:`Home`
|
||||
- Jump to the first result
|
||||
* - :kbd:`End`
|
||||
- Jump to the last result
|
||||
* - :kbd:`Backspace`
|
||||
- Delete the last character from the query
|
||||
* - :kbd:`F12`
|
||||
- Toggle display of unmapped actions
|
||||
* - Mouse click
|
||||
- Select and run the clicked action
|
||||
|
||||
|
||||
Unmapped actions
|
||||
------------------
|
||||
|
||||
By default, the palette shows both mapped actions (those bound to a shortcut)
|
||||
and unmapped actions (those with no shortcut assigned). Unmapped actions appear
|
||||
with an ``(unmapped)`` label in the key column. Press :kbd:`F12` to toggle
|
||||
their visibility. This preference is remembered across sessions.
|
||||
|
||||
Unmapped actions are useful for discovering functionality that you may not have
|
||||
configured a shortcut for. You can run them directly from the palette, or note
|
||||
the action name and add a mapping in :file:`kitty.conf`.
|
||||
|
||||
|
||||
Custom keyboard modes
|
||||
-----------------------
|
||||
|
||||
If you have defined custom :ref:`keyboard modes <modal_mappings>` in your
|
||||
configuration, their bindings appear under separate mode headers in the palette.
|
||||
The ``push_keyboard_mode`` bindings are grouped with the target mode they
|
||||
activate, making it easy to see how to enter each mode alongside its shortcuts.
|
||||
|
||||
|
||||
Configuration
|
||||
--------------
|
||||
|
||||
The default mapping to open the command palette is::
|
||||
|
||||
map kitty_mod+f3 command_palette
|
||||
|
||||
You can change this in :file:`kitty.conf` like any other mapping. For example::
|
||||
|
||||
map ctrl+p command_palette
|
||||
@@ -19,9 +19,10 @@ Create a file in the kitty config directory, :file:`~/.config/kitty/mykitten.py`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import List
|
||||
from kitty.boss import Boss
|
||||
|
||||
def main(args: list[str]) -> str:
|
||||
def main(args: List[str]) -> str:
|
||||
# this is the main entry point of the kitten, it will be executed in
|
||||
# the overlay window when the kitten is launched
|
||||
answer = input('Enter some text: ')
|
||||
@@ -29,7 +30,7 @@ Create a file in the kitty config directory, :file:`~/.config/kitty/mykitten.py`
|
||||
# handle_result() function
|
||||
return answer
|
||||
|
||||
def handle_result(args: list[str], answer: str, target_window_id: int, boss: Boss) -> None:
|
||||
def handle_result(args: List[str], answer: str, target_window_id: int, boss: Boss) -> None:
|
||||
# get the kitty window into which to paste answer
|
||||
w = boss.window_id_map.get(target_window_id)
|
||||
if w is not None:
|
||||
@@ -59,7 +60,7 @@ would pass to ``kitten @``. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def handle_result(args: list[str], answer: str, target_window_id: int, boss: Boss) -> None:
|
||||
def handle_result(args: List[str], answer: str, target_window_id: int, boss: Boss) -> None:
|
||||
# get the kitty window to which to send text
|
||||
w = boss.window_id_map.get(target_window_id)
|
||||
if w is not None:
|
||||
@@ -100,18 +101,19 @@ like. For example:
|
||||
|
||||
.. code-block:: py
|
||||
|
||||
from typing import List
|
||||
from kitty.boss import Boss
|
||||
|
||||
# in main, STDIN is for the kitten process and will contain
|
||||
# the contents of the screen
|
||||
def main(args: list[str]) -> str:
|
||||
def main(args: List[str]) -> str:
|
||||
return sys.stdin.read()
|
||||
|
||||
# in handle_result, STDIN is for the kitty process itself, rather
|
||||
# than the kitten process and should not be read from.
|
||||
from kittens.tui.handler import result_handler
|
||||
@result_handler(type_of_input='text')
|
||||
def handle_result(args: list[str], stdin_data: str, target_window_id: int, boss: Boss) -> None:
|
||||
def handle_result(args: List[str], stdin_data: str, target_window_id: int, boss: Boss) -> None:
|
||||
pass
|
||||
|
||||
|
||||
@@ -122,9 +124,9 @@ the table below:
|
||||
.. table:: Types of input to kittens
|
||||
:align: left
|
||||
|
||||
=========================== ========================================================================================
|
||||
=========================== =======================================================================================================
|
||||
Keyword Type of :file:`STDIN` input
|
||||
=========================== ========================================================================================
|
||||
=========================== =======================================================================================================
|
||||
``text`` Plain text of active window
|
||||
``ansi`` Formatted text of active window
|
||||
``screen`` Plain text of active window with line wrap markers
|
||||
@@ -141,7 +143,7 @@ the table below:
|
||||
``output-screen-ansi`` Formatted text of the output from the last run command with wrap markers
|
||||
|
||||
``selection`` The text currently selected with the mouse
|
||||
=========================== ========================================================================================
|
||||
=========================== =======================================================================================================
|
||||
|
||||
In addition to ``output``, that gets the output of the last run command,
|
||||
``last_visited_output`` gives the output of the command last jumped to
|
||||
@@ -169,14 +171,15 @@ Create a Python file in the :ref:`kitty config directory <confloc>`,
|
||||
|
||||
.. code-block:: py
|
||||
|
||||
from typing import List
|
||||
from kitty.boss import Boss
|
||||
|
||||
def main(args: list[str]) -> str:
|
||||
def main(args: List[str]) -> str:
|
||||
pass
|
||||
|
||||
from kittens.tui.handler import result_handler
|
||||
@result_handler(no_ui=True)
|
||||
def handle_result(args: list[str], answer: str, target_window_id: int, boss: Boss) -> None:
|
||||
def handle_result(args: List[str], answer: str, target_window_id: int, boss: Boss) -> None:
|
||||
tab = boss.active_tab
|
||||
if tab is not None:
|
||||
if tab.current_layout.name == 'stack':
|
||||
@@ -228,56 +231,6 @@ The function will only send the event if the program is receiving events of
|
||||
that type, and will return ``True`` if it sent the event, and ``False`` if not.
|
||||
|
||||
|
||||
.. _kitten_main_rc:
|
||||
|
||||
Using remote control inside the main() kitten function
|
||||
------------------------------------------------------------
|
||||
|
||||
You can use kitty's remote control features inside the main() function of a
|
||||
kitten, even without enabling remote control. This is useful if you want to
|
||||
probe kitty for more information before presenting some UI to the user or if
|
||||
you want the user to be able to control kitty from within your kitten's UI
|
||||
rather than after it has finished running. To enable it, simply tell kitty your kitten
|
||||
requires remote control, as shown in the example below::
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pprint import pprint
|
||||
|
||||
from kittens.tui.handler import kitten_ui
|
||||
|
||||
@kitten_ui(allow_remote_control=True)
|
||||
def main(args: list[str]) -> str:
|
||||
# get the result of running kitten @ ls
|
||||
cp = main.remote_control(['ls'], capture_output=True)
|
||||
if cp.returncode != 0:
|
||||
sys.stderr.buffer.write(cp.stderr)
|
||||
raise SystemExit(cp.returncode)
|
||||
output = json.loads(cp.stdout)
|
||||
pprint(output)
|
||||
# open a new tab with a title specified by the user
|
||||
title = input('Enter the name of tab: ')
|
||||
window_id = main.remote_control(['launch', '--type=tab', '--tab-title', title], check=True, capture_output=True).stdout.decode()
|
||||
return window_id
|
||||
|
||||
:code:`allow_remote_control=True` tells kitty to run this kitten with remote
|
||||
control enabled, regardless of whether it is enabled globally or not.
|
||||
To run a remote control command use the :code:`main.remote_control()` function
|
||||
which is a thin wrapper around Python's :code:`subprocess.run` function. Note
|
||||
that by default, for security, child processes launched by your kitten cannot use remote
|
||||
control, thus it is necessary to use :code:`main.remote_control()`. If you wish
|
||||
to enable child processes to use remote control, call
|
||||
:code:`main.allow_indiscriminate_remote_control()`.
|
||||
|
||||
Remote control access can be further secured by using
|
||||
:code:`kitten_ui(allow_remote_control=True, remote_control_password='ls set-colors')`.
|
||||
This will use a secure generated password to restrict remote control.
|
||||
You can specify a space separated list of remote control commands to allow, see
|
||||
:opt:`remote_control_password` for details. The password value is accessible
|
||||
as :code:`main.password` and is used by :code:`main.remote_control()`
|
||||
automatically.
|
||||
|
||||
|
||||
Debugging kittens
|
||||
--------------------
|
||||
|
||||
@@ -298,6 +251,107 @@ So if you run kitty from another kitty instance, the output will be visible
|
||||
in the first kitty instance.
|
||||
|
||||
|
||||
Adding options to kittens
|
||||
----------------------------
|
||||
|
||||
If you would like to use kitty's config framework to make your kittens
|
||||
configurable, you will need some boilerplate. Put the following files in the
|
||||
directory of your kitten.
|
||||
|
||||
:file:`kitten_options_definition.py`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from kitty.conf.types import Action, Definition
|
||||
|
||||
definition = Definition(
|
||||
'!kitten_options_utils',
|
||||
Action(
|
||||
'map', 'parse_map',
|
||||
{'key_definitions': 'kitty.conf.utils.KittensKeyMap'},
|
||||
['kitty.types.ParsedShortcut', 'kitty.conf.utils.KeyAction']
|
||||
),
|
||||
)
|
||||
|
||||
agr = definition.add_group
|
||||
egr = definition.end_group
|
||||
opt = definition.add_option
|
||||
map = definition.add_map
|
||||
|
||||
# main options {{{
|
||||
agr('main', 'Main')
|
||||
|
||||
opt('some_option', '33',
|
||||
option_type='some_option_parser',
|
||||
long_text='''
|
||||
Help text for this option
|
||||
'''
|
||||
)
|
||||
egr() # }}}
|
||||
|
||||
# shortcuts {{{
|
||||
agr('shortcuts', 'Keyboard shortcuts')
|
||||
|
||||
map('Quit', 'quit q quit')
|
||||
egr() # }}}
|
||||
|
||||
|
||||
:file:`kitten_options_utils.py`
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from kitty.conf.utils import KittensKeyDefinition, key_func, parse_kittens_key
|
||||
|
||||
func_with_args, args_funcs = key_func()
|
||||
FuncArgsType = Tuple[str, Sequence[Any]]
|
||||
|
||||
def some_option_parser(val: str) -> int:
|
||||
return int(val) + 3000
|
||||
|
||||
def parse_map(val: str) -> Iterable[KittensKeyDefinition]:
|
||||
x = parse_kittens_key(val, args_funcs)
|
||||
if x is not None:
|
||||
yield x
|
||||
|
||||
Then run::
|
||||
|
||||
kitty +runpy 'from kitty.conf.generate import main; main()' /path/to/kitten_options_definition.py
|
||||
|
||||
You can parse and read the options in your kitten using the following code:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from .kitten_options_types import Options, defaults
|
||||
from kitty.conf.utils import load_config as _load_config, parse_config_base
|
||||
from typing import Optional, Iterable, Dict, Any
|
||||
|
||||
def load_config(*paths: str, overrides: Optional[Iterable[str]] = None) -> Options:
|
||||
from .kitten_options_parse import (
|
||||
create_result_dict, merge_result_dicts, parse_conf_item
|
||||
)
|
||||
|
||||
def parse_config(lines: Iterable[str]) -> Dict[str, Any]:
|
||||
ans: Dict[str, Any] = create_result_dict()
|
||||
parse_config_base(
|
||||
lines,
|
||||
parse_conf_item,
|
||||
ans,
|
||||
)
|
||||
return ans
|
||||
|
||||
overrides = tuple(overrides) if overrides is not None else ()
|
||||
opts_dict, found_paths = _load_config(defaults, parse_config, merge_result_dicts, *paths, overrides=overrides)
|
||||
opts = Options(opts_dict)
|
||||
opts.config_paths = found_paths
|
||||
opts.all_config_paths = paths
|
||||
opts.config_overrides = overrides
|
||||
return opts
|
||||
|
||||
See `the code <https://github.com/kovidgoyal/kitty/tree/master/kittens/diff>`__
|
||||
for the builtin :doc:`diff kitten </kittens/diff>` for examples of creating more
|
||||
options and keyboard shortcuts.
|
||||
|
||||
|
||||
Developing builtin kittens for inclusion with kitty
|
||||
----------------------------------------------------------
|
||||
|
||||
@@ -317,12 +371,6 @@ Kittens created by kitty users
|
||||
`smart-scroll <https://github.com/yurikhan/kitty-smart-scroll>`_
|
||||
Makes the kitty scroll bindings work in full screen applications
|
||||
|
||||
`kitty-tab-switcher <https://github.com/OsiPog/kitty-tab-switcher>`__
|
||||
Fuzzy finder for kitty tabs with previews
|
||||
|
||||
`gattino <https://github.com/salvozappa/gattino>`__
|
||||
Integrate kitty with an LLM to convert plain language prompts into shell commands.
|
||||
|
||||
:iss:`insert password <1222>`
|
||||
Insert a password from a CLI password manager, taking care to only do it at
|
||||
a password prompt.
|
||||
|
||||
@@ -1,136 +0,0 @@
|
||||
Using terminal programs to provide Linux desktop components
|
||||
===============================================================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
.. versionadded:: 0.43.0
|
||||
|
||||
Power users of terminals on Linux also often like to use bare bones window
|
||||
managers instead of full fledged desktop environments. This kitten helps
|
||||
provide parts of the desktop environment that are missing from such setups,
|
||||
and does so using keyboard friendly, terminal first, UI components. Some of its
|
||||
features are:
|
||||
|
||||
* Replace the typical File Open/Save dialogs used in GUI programs with the
|
||||
fast and keyboard centric :doc:`choose-files </kittens/choose-files>` kitten
|
||||
running in a semi-transparent kitty overlay.
|
||||
|
||||
* Allow simple command line based management of the desktop light/dark modes.
|
||||
|
||||
|
||||
How to install
|
||||
-------------------
|
||||
|
||||
.. note::
|
||||
|
||||
This kitten relies on the :doc:`panel kitten </kittens/panel>`
|
||||
under the hood to supply UI components. Check :ref:`the documentation <panel_compat>`
|
||||
of that kitten to see if your window manager works with it.
|
||||
|
||||
First, run::
|
||||
|
||||
kitten desktop-ui enable-portal
|
||||
|
||||
Then, set the following two environment variables, *system wide*, that means in
|
||||
:file:`/etc/environment` or the equivalent for your distribution::
|
||||
|
||||
QT_QPA_PLATFORMTHEME=xdgdesktopportal
|
||||
GTK_USE_PORTAL=1
|
||||
|
||||
|
||||
Finally, reboot. Now, when you open a file dialog in most GUI applications, it
|
||||
should open the :doc:`choose-files kitten </kittens/choose-files>` instead
|
||||
of a normal file open dialog. You can change the current light/dark mode of
|
||||
your desktop by running::
|
||||
|
||||
kitten desktop-ui set-color-scheme dark
|
||||
kitten desktop-ui set-color-scheme light
|
||||
|
||||
Check the current value using::
|
||||
|
||||
dbus-send --session --print-reply --dest=org.freedesktop.portal.Desktop /org/freedesktop/portal/desktop org.freedesktop.portal.Settings.Read string:org.freedesktop.appearance string:color-scheme
|
||||
|
||||
How it works
|
||||
----------------
|
||||
|
||||
Modern Linux desktops have so called `portals
|
||||
<https://flatpak.github.io/xdg-desktop-portal/docs/index.html>`__ that were
|
||||
invented for sandboxed applications and provide various facilities to such
|
||||
applications over DBUS, including file open dialogs, common desktop settings,
|
||||
etc. This kitten works by implementing a backend for some of these services.
|
||||
|
||||
Normal GUI applications can then be told to make use of these services, thereby
|
||||
allowing us to replace parts of the desktop experience as needed.
|
||||
|
||||
There are multiple competing implementations of the backends. Each desktop
|
||||
environment like KDE or GNOME has it's own backend and many window managers
|
||||
provide implementations for some backends as well. Service discovery and
|
||||
configuring which backend to use happens via the :file:`xdg-desktop-portal`
|
||||
program, usually found at :file:`/usr/lib/xdg-desktop-portal`.
|
||||
|
||||
It can be configured by files in :file:`~/.local/share/xdg-desktop-portal`. See
|
||||
`man portals.conf <https://man.archlinux.org/man/portals.conf.5>`__. The
|
||||
``kitten desktop-ui enable-portal`` command takes care of the setup for you
|
||||
automatically. If you want to customize exactly which services to use this
|
||||
kitten for, run the command and then edit the conf file that the command says
|
||||
it has patched.
|
||||
|
||||
|
||||
Troubleshooting
|
||||
-------------------
|
||||
|
||||
First, ensure that DBUS is able to auto-start the kitten when it is needed. If
|
||||
the kitten is not already running, try the following command::
|
||||
|
||||
dbus-send --session --print-reply --dest=org.freedesktop.impl.portal.desktop.kitty \
|
||||
/net/kovidgoyal/kitty/portal org.freedesktop.DBus.Properties.GetAll \
|
||||
string:net.kovidgoyal.kitty.settings
|
||||
|
||||
If DBUS is able to start the kitten or if it is already running it will print
|
||||
out the version property, otherwise it will fail with an error. If it fails,
|
||||
check the file
|
||||
:file:`~/.local/share/dbus-1/services/org.freedesktop.impl.portal.desktop.kitty.service`
|
||||
that should have been created by the ``enable-portal`` command. It's ``Exec``
|
||||
key must point to the full path to the kitten executable.
|
||||
|
||||
Next, check that the XDG portal system is actually using this kitten for its
|
||||
settings backend. Run::
|
||||
|
||||
dbus-send --session --print-reply --dest=org.freedesktop.portal.Desktop \
|
||||
/org/freedesktop/portal/desktop org.freedesktop.portal.Settings.Read \
|
||||
string:net.kovidgoyal.kitty string:status
|
||||
|
||||
If this returns a reply then the kitten is being used, as expected. If it
|
||||
returns a not found error, then some other backend is being used for settings.
|
||||
|
||||
Read the ``portals.conf`` man page and run::
|
||||
|
||||
/usr/lib/xdg-desktop-portal -r v
|
||||
|
||||
this will output a lot of debug information, which should tell you which
|
||||
backend is chosen for which service. Read the debug output carefully to
|
||||
determine why the kitten is not being selected.
|
||||
|
||||
If some GUI applications are not using the choose-files kitten for their file
|
||||
select dialogs, then make sure the environment variables mentioned above are
|
||||
set, you can also try running the GUI application with them set explicitly,
|
||||
as::
|
||||
|
||||
QT_QPA_PLATFORMTHEME=xdgdesktopportal GTK_USE_PORTAL=1 my-gui-app
|
||||
|
||||
Note that not all applications use portals, so if some particular application
|
||||
is failing to use the portal but others work, report the issue to that
|
||||
applications' developers.
|
||||
|
||||
Configuration
|
||||
------------------------
|
||||
|
||||
You can configure various aspects of the kitten's operation by creating a
|
||||
:file:`desktop-ui-portal.conf` in your :ref:`kitty config folder <confloc>`.
|
||||
See below for the supported configuration directives.
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitten-desktop_ui.rst
|
||||
@@ -64,17 +64,15 @@ Keyboard controls
|
||||
=========================== ===========================
|
||||
Action Shortcut
|
||||
=========================== ===========================
|
||||
Quit :kbd:`Q`
|
||||
Quit :kbd:`Q`, :kbd:`Esc`
|
||||
Scroll line up :kbd:`K`, :kbd:`Up`
|
||||
Scroll line down :kbd:`J`, :kbd:`Down`
|
||||
Scroll page up :kbd:`PgUp`
|
||||
Scroll page down :kbd:`PgDn`
|
||||
Scroll to top :kbd:`Home`
|
||||
Scroll to bottom :kbd:`End`
|
||||
Scroll to next page :kbd:`Space`, :kbd:`PgDn`, :kbd:`Ctrl+F`
|
||||
Scroll to previous page :kbd:`PgUp`, :kbd:`Ctrl+B`
|
||||
Scroll down half page :kbd:`Ctrl+D`
|
||||
Scroll up half page :kbd:`Ctrl+U`
|
||||
Scroll to next page :kbd:`Space`, :kbd:`PgDn`
|
||||
Scroll to previous page :kbd:`PgUp`
|
||||
Scroll to next change :kbd:`N`
|
||||
Scroll to previous change :kbd:`P`
|
||||
Increase lines of context :kbd:`+`
|
||||
@@ -83,7 +81,7 @@ All lines of context :kbd:`A`
|
||||
Restore default context :kbd:`=`
|
||||
Search forwards :kbd:`/`
|
||||
Search backwards :kbd:`?`
|
||||
Clear search or exit :kbd:`Esc`
|
||||
Clear search :kbd:`Esc`
|
||||
Scroll to next match :kbd:`>`, :kbd:`.`
|
||||
Scroll to previous match :kbd:`<`, :kbd:`,`
|
||||
Copy selection to clipboard :kbd:`y`
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
Drag and Drop
|
||||
==================================================
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
*Drag and drop of files from the shell*
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
|
||||
The ``dnd`` kitten can be used to drag and drop files between
|
||||
the shell and arbitrary GUI programs, it even works over SSH, so you
|
||||
can easily and seamlessly transfer files from one computer to another,
|
||||
simply by dragging from one kitty window to another.
|
||||
Using it is as simple as::
|
||||
|
||||
kitten dnd file-to-drag.xyz
|
||||
|
||||
Then, start dragging with the mouse inside the window, and :file:`file-to-drag.xyz`
|
||||
will be dragged and you can drop it onto a GUI file manager or another window
|
||||
running this kitten. You can specify directories as well to drag entire trees.
|
||||
|
||||
Similarly, dropping works by running the kitten::
|
||||
|
||||
kitten dnd
|
||||
|
||||
Then, drag some files from a GUI file manager or another window running the dnd kitten
|
||||
and drop them onto this window. The files will be copied or moved (depending on
|
||||
which area you drop them) into the current working directory.
|
||||
|
||||
The best part is this works even over SSH. So if you just want to quickly
|
||||
transfer some files from one computer to another all you need to so is ssh into
|
||||
the remote computer::
|
||||
|
||||
kitten ssh remote-computer-name
|
||||
|
||||
Then, run the dnd kitten on the remote computer::
|
||||
|
||||
kitten dnd files-or-dirs-to-drag
|
||||
|
||||
That's it, you can now drag form or drop to the remote computer. See below for
|
||||
customising the behavior of the kitten via command line flags.
|
||||
|
||||
This kitten uses a new protocol developed by kitty to function, for details,
|
||||
see :doc:`/dnd-protocol`.
|
||||
|
||||
.. program:: kitty +kitten dnd
|
||||
|
||||
|
||||
.. include:: /generated/cli-kitten-dnd.rst
|
||||
@@ -8,214 +8,52 @@ Draw a GPU accelerated dock panel on your desktop
|
||||
Overview
|
||||
--------------
|
||||
|
||||
.. include:: ../quake-screenshots.rst
|
||||
|
||||
Draw the desktop wallpaper or docks and panels using arbitrary
|
||||
terminal programs, For example, have `btop
|
||||
<https://github.com/aristocratos/btop>`__ or `cava
|
||||
<https://github.com/karlstav/cava/>`__ be your desktop wallpaper.
|
||||
You can use this kitten to draw a GPU accelerated panel on the edge of your
|
||||
screen or as the desktop wallpaper, that shows the output from an arbitrary
|
||||
terminal program.
|
||||
|
||||
It is useful for showing status information or notifications on your desktop
|
||||
using terminal programs instead of GUI toolkits.
|
||||
|
||||
.. figure:: ../screenshots/panel.png
|
||||
:alt: Screenshot, showing a sample panel
|
||||
:align: center
|
||||
:width: 100%
|
||||
|
||||
The screenshot to the side shows some uses of the panel kitten to draw various
|
||||
desktop components such as the background, a quick access floating terminal and
|
||||
a dock panel showing system information (Linux only).
|
||||
Screenshot, showing a sample panel
|
||||
|
||||
.. versionadded:: 0.42.0
|
||||
|
||||
Support for macOS, see :ref:`compatibility matrix <panel_compat>` for details.
|
||||
and X11 (background and overlay).
|
||||
The screenshot above shows a sample panel that displays the current desktop and
|
||||
window title as well as miscellaneous system information such as network
|
||||
activity, CPU load, date/time, etc.
|
||||
|
||||
.. versionadded:: 0.34.0
|
||||
Support for Wayland
|
||||
|
||||
Support for Wayland. See :ref:`below <panel_compat>` for which
|
||||
Wayland compositors work.
|
||||
.. note::
|
||||
|
||||
This kitten currently only works on X11 desktops and Wayland compositors
|
||||
that support the `wlr layer shell protocol
|
||||
<https://wayland.app/protocols/wlr-layer-shell-unstable-v1#compositor-support>`__
|
||||
(which is almost all of them except the, as usual, crippled GNOME).
|
||||
|
||||
Using this kitten is simple, for example::
|
||||
|
||||
kitten panel sh -c 'printf "\n\n\nHello, world."; sleep 5s'
|
||||
kitty +kitten panel sh -c 'printf "\n\n\nHello, world."; sleep 5s'
|
||||
|
||||
This will show ``Hello, world.`` at the top edge of your screen for five
|
||||
seconds. Here, the terminal program we are running is :program:`sh` with a script
|
||||
to print out ``Hello, world!``. You can make the terminal program as complex as
|
||||
you like, as demonstrated in the screenshots.
|
||||
you like, as demonstrated in the screenshot above.
|
||||
|
||||
If you are on Wayland or macOS, you can, for instance, run::
|
||||
If you are on Wayland, you can, for instance run::
|
||||
|
||||
kitten panel --edge=background htop
|
||||
kitty +kitten panel --edge=background htop
|
||||
|
||||
to display ``htop`` as your desktop background. Remember this works in everything
|
||||
to display htop as your desktop background. Remember this works in everything
|
||||
but GNOME and also, in sway, you have to disable the background wallpaper as
|
||||
sway renders that over the panel kitten surface.
|
||||
|
||||
There are projects that make use of this facility to implement generalised
|
||||
panels and desktop components:
|
||||
|
||||
.. _panel_projects:
|
||||
|
||||
* `kitty panel <https://github.com/5hubham5ingh/kitty-panel>`__
|
||||
* `pawbar <https://github.com/codelif/pawbar>`__
|
||||
|
||||
|
||||
.. _remote_control_panel:
|
||||
|
||||
Controlling panels via remote control
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can control panels via the kitty :doc:`remote control </remote-control>` facility. Create a panel
|
||||
with remote control enabled::
|
||||
|
||||
kitten panel -o allow_remote_control=socket-only --lines=2 \
|
||||
--listen-on=unix:/tmp/panel kitten run-shell
|
||||
|
||||
|
||||
Now you can control this panel using remote control, for example to show/hide
|
||||
it, use::
|
||||
|
||||
kitten @ --to=unix:/tmp/panel resize-os-window --action=toggle-visibility
|
||||
|
||||
To move the panel to the bottom of the screen and increase its height::
|
||||
|
||||
kitten @ --to=unix:/tmp/panel resize-os-window --action=os-panel \
|
||||
--incremental edge=bottom lines=4
|
||||
|
||||
To create a new panel running the program top, in the same instance
|
||||
(like creating a new OS window)::
|
||||
|
||||
kitten @ --to=unix:/tmp/panel launch --type=os-panel --os-panel edge=top \
|
||||
--os-panel lines=8 top
|
||||
|
||||
|
||||
.. include:: ../generated/cli-kitten-panel.rst
|
||||
|
||||
|
||||
.. _quake_ss:
|
||||
|
||||
How the screenshots were generated
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The system statistics in the background were created using::
|
||||
|
||||
kitten panel --edge=background -o background_opacity=0.2 -o background=black btop
|
||||
|
||||
This creates a kitty background window and inside it runs the `btop
|
||||
<https://github.com/aristocratos/btop>`__ program to display the statistics.
|
||||
|
||||
The floating quick access window was created by running::
|
||||
|
||||
kitten quick-access-terminal kitten run-shell \
|
||||
zsh -c 'printf "\e]66;s=4;Quick access kitty in Hyprland\a\n\n\n\nAlso uses kitty to draw desktop background\n"'
|
||||
|
||||
This starts the quick access window and inside it runs ``kitten run-shell``, which
|
||||
in turn first runs ``zsh`` to print out the message and then starts the users login
|
||||
shell.
|
||||
|
||||
The Linux dock panel was::
|
||||
|
||||
wm bar
|
||||
|
||||
This is a custom program I wrote for my personal use. It uses kitty's kitten
|
||||
infrastructure to implement the bar in a `few hundred lines of code
|
||||
<https://github.com/kovidgoyal/wm/blob/master/bar/main.go>`__.
|
||||
This was designed for my personal use only, but, there are :ref:`public projects implementing
|
||||
general purpose panels using kitty <panel_projects>`.
|
||||
|
||||
|
||||
.. _panel_compat:
|
||||
|
||||
Compatibility with various platforms
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. only:: man
|
||||
|
||||
See the HTML documentation for the compatibility matrix.
|
||||
|
||||
.. only:: not man
|
||||
|
||||
Generated with the help of the :file:`panels.py` test script.
|
||||
|
||||
.. tab:: Wayland
|
||||
|
||||
Below is a list of the status of various Wayland compositors. The panel kitten
|
||||
relies on the `wlr layer shell protocol
|
||||
<https://wayland.app/protocols/wlr-layer-shell-unstable-v1#compositor-support>`__,
|
||||
which is technically supported by almost all Wayland compositors, but the
|
||||
implementation in some of them is quite buggy.
|
||||
|
||||
🟢 **Hyprland**
|
||||
Fully working, no known issues
|
||||
|
||||
🟢 **labwc**
|
||||
Fully working, no known issues
|
||||
|
||||
🟢 **niri**
|
||||
Fully working, no known issues
|
||||
|
||||
🟢 **river**
|
||||
Fully working, no known issues
|
||||
|
||||
🟢 **Xfce**
|
||||
Fully working, no known issues
|
||||
|
||||
🟠 **KDE** (kwin)
|
||||
Mostly working, except that clicks outside background panels cause kwin to :iss:`erroneously hide the panel <8715>`. KDE uses an `undocumented mapping <https://invent.kde.org/plasma/kwin/-/blob/3dc5cee6b34792486b343098e55e7f2b90dfcd00/src/layershellv1window.cpp#L24>`__ under Wayland to set the window type from the :code:`kitten panel --app-id` flag. You might want to use :code:`--app-id=dock` so that KDE treats the window as a dock panel, and disables window appearing/disappearing animations for it.
|
||||
|
||||
🟠 **Sway**
|
||||
Renders its configured background over the background window instead of
|
||||
under it. This is because it uses the wlr protocol for backgrounds itself.
|
||||
|
||||
🔴 **GNOME** (mutter)
|
||||
Does not implement the wlr protocol at all, nothing works.
|
||||
|
||||
.. tab:: macOS
|
||||
|
||||
Mostly everything works, with the notable exception that dock panels do not
|
||||
prevent other windows from covering them. This is because Apple does not
|
||||
provide and way to do this in their APIs.
|
||||
|
||||
.. tab:: X11
|
||||
|
||||
Support is highly dependent on the quirks of individual window
|
||||
managers. See the matrix below:
|
||||
|
||||
.. list-table:: Compatibility matrix
|
||||
:header-rows: 1
|
||||
:stub-columns: 1
|
||||
|
||||
* - WM
|
||||
- Desktop
|
||||
- Dock
|
||||
- Quick
|
||||
- Notes
|
||||
|
||||
* - KDE
|
||||
- 🟠
|
||||
- 🟢
|
||||
- 🟢
|
||||
- transparency does not work for :option:`--edge=background <--edge>`
|
||||
|
||||
* - GNOME
|
||||
- 🟢
|
||||
- 🟢
|
||||
- 🟢
|
||||
-
|
||||
|
||||
* - XFCE
|
||||
- 🟢
|
||||
- 🟢
|
||||
- 🟢
|
||||
-
|
||||
|
||||
* - i3
|
||||
- 🔴
|
||||
- 🟠
|
||||
- 🔴
|
||||
- only top and bottom dock panels, without transparency
|
||||
|
||||
* - xmonad
|
||||
- 🔴
|
||||
- 🔴
|
||||
- 🔴
|
||||
- doesn't support the needed NET_WM protocols
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
.. _quake:
|
||||
|
||||
Make a Quake like quick access terminal
|
||||
====================================================================================================
|
||||
|
||||
.. highlight:: sh
|
||||
|
||||
.. only:: man
|
||||
|
||||
Overview
|
||||
--------------
|
||||
|
||||
|
||||
.. include:: ../quake-screenshots.rst
|
||||
|
||||
.. versionadded:: 0.42.0
|
||||
See :ref:`here for what platforms it works on <panel_compat>`.
|
||||
|
||||
This kitten can be used to make a quick access terminal, that appears and
|
||||
disappears at a key press. To do so use the following command:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
kitten quick-access-terminal
|
||||
|
||||
Run this command in a terminal, and a quick access kitty window will show up at
|
||||
the top of your screen. Run it again, and the window will be hidden.
|
||||
|
||||
To make the terminal appear and disappear at a key press:
|
||||
|
||||
.. |macOs| replace:: :guilabel:`System Preferences->Keyboard->Keyboard Shortcuts->Services->General`
|
||||
|
||||
.. only:: not man
|
||||
|
||||
.. tab:: Linux
|
||||
|
||||
Simply bind the above command to some key press in your window manager or desktop
|
||||
environment settings and then you have a quick access terminal at a single key press.
|
||||
|
||||
.. tab:: macOS
|
||||
|
||||
In kitty, run the above command to show the quick access window, then close
|
||||
it by running the command again or pressing :kbd:`ctrl+d`. Now go to |macOS| and set a shortcut for
|
||||
the :guilabel:`Quick access to kitty` entry.
|
||||
|
||||
.. only:: man
|
||||
|
||||
In Linux, simply assign the above command to a global shortcut in your
|
||||
window manager. In macOS, go to |macOS| and set a shortcut
|
||||
for the :guilabel:`Quick access to kitty` entry.
|
||||
|
||||
Configuration
|
||||
------------------------
|
||||
|
||||
You can configure the appearance and behavior of the quick access window
|
||||
by creating a :file:`quick-access-terminal.conf` file in your
|
||||
:ref:`kitty config folder <confloc>`. In particular, you can use the
|
||||
:opt:`kitty_conf <kitten-quick_access_terminal.kitty_conf>` option to change
|
||||
various kitty settings, just for the quick access window.
|
||||
|
||||
.. note::
|
||||
|
||||
This kitten uses the :doc:`panel kitten </kittens/panel>` under the
|
||||
hood. You can use the :ref:`techniques described there <remote_control_panel>`
|
||||
for remote controlling the quick access window, remember to add
|
||||
``kitty_override allow_remote_control=socket-only`` and ``kitty_override
|
||||
listen_on=unix:/tmp/whatever`` to
|
||||
:file:`quick-access-terminal.conf`.
|
||||
|
||||
See below for the supported configuration directives:
|
||||
|
||||
|
||||
.. include:: /generated/conf-kitten-quick_access_terminal.rst
|
||||
|
||||
|
||||
.. include:: /generated/cli-kitten-quick_access_terminal.rst
|
||||
|
||||
|
||||
Sample quick-access-terminal.conf
|
||||
---------------------------------------
|
||||
|
||||
You can download a sample :file:`quick-access-terminal.conf` file with all default settings and
|
||||
comments describing each setting by clicking: :download:`sample quick-access-terminal.conf
|
||||
</generated/conf/quick_access_terminal.conf>`.
|
||||
@@ -47,48 +47,11 @@ Once that's done, the kitten sends kitty a signal to make it reload its config.
|
||||
|
||||
If you want to have some color settings in your :file:`kitty.conf` that the
|
||||
theme kitten does not override, move them into a separate conf file and
|
||||
``include`` it into kitty.conf. The include should be placed after the
|
||||
``include`` it into kitty.conf. The include should be places after the
|
||||
inclusion of :file:`current-theme.conf` so that the settings in it override
|
||||
conflicting settings from :file:`current-theme.conf`.
|
||||
|
||||
|
||||
.. _auto_color_scheme:
|
||||
|
||||
Change color themes automatically when the OS switches between light and dark
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
.. versionadded:: 0.38.0
|
||||
|
||||
You can have kitty automatically change its color theme when the OS switches
|
||||
between dark, light and no-preference modes. In order to do this, run the theme
|
||||
kitten as normal and at the final screen select the option to save your chosen
|
||||
theme as either light, dark, or no-preference. Repeat until you have chosen
|
||||
a theme for each of the three modes. Then, once you restart kitty, it will
|
||||
automatically use your chosen themes depending on the OS color scheme.
|
||||
|
||||
This works by creating three files: :file:`dark-theme.auto.conf`,
|
||||
:file:`light-theme.auto.conf` and :file:`no-preference-theme.auto.conf` in the
|
||||
kitty config directory. When these files exist, kitty queries the OS for its color scheme
|
||||
and uses the appropriate file. Note that the colors in these files override all other
|
||||
colors, and also all background image settings,
|
||||
even those specified using the :option:`kitty --override` command line flag.
|
||||
kitty will also automatically change colors when the OS color scheme changes,
|
||||
for example, during night/day transitions.
|
||||
|
||||
When using these colors, you can still dynamically change colors, but the next
|
||||
time the OS changes its color mode, any dynamic changes will be overridden.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
On the GNOME desktop, the desktop reports the color preference as no-preference
|
||||
when the "Dark style" is not enabled. So use :file:`no-preference-theme.auto.conf` to
|
||||
select colors for light mode on GNOME. You can manually enable light style
|
||||
with ``gsettings set org.gnome.desktop.interface color-scheme prefer-light``
|
||||
in which case GNOME will report the color scheme as light and kitty will use
|
||||
:file:`light-theme.auto.conf`.
|
||||
|
||||
|
||||
Using your own themes
|
||||
-----------------------
|
||||
|
||||
|
||||
@@ -13,11 +13,6 @@ Extend with kittens
|
||||
kittens/themes
|
||||
kittens/choose-fonts
|
||||
kittens/hints
|
||||
kittens/command-palette
|
||||
kittens/quick-access-terminal
|
||||
kittens/choose-files
|
||||
kittens/dnd
|
||||
kittens/panel
|
||||
kittens/remote_file
|
||||
kittens/hyperlinked_grep
|
||||
kittens/transfer
|
||||
@@ -56,29 +51,6 @@ Some prominent kittens:
|
||||
filenames, words, lines, etc. from the terminal screen.
|
||||
|
||||
|
||||
:doc:`Command palette <kittens/command-palette>`
|
||||
Browse, search and trigger all keyboard shortcuts and actions from a
|
||||
single searchable overlay.
|
||||
|
||||
|
||||
:doc:`Quick access terminal <kittens/quick-access-terminal>`
|
||||
Get access to a quick access floating, semi-transparent kitty window
|
||||
with a single keypress.
|
||||
|
||||
|
||||
:doc:`Panel <kittens/panel>`
|
||||
Draw the desktop wallpaper or docks and panels using arbitrary
|
||||
terminal programs.
|
||||
|
||||
|
||||
:doc:`Choose files <kittens/choose-files>`
|
||||
Preview and select files at the speed of thought
|
||||
|
||||
|
||||
:doc:`Drag and drop from the shell <kittens/dnd>`
|
||||
Drag and drop files from/to GUI programs from your shell, even over SSH
|
||||
|
||||
|
||||
:doc:`Remote file <kittens/remote_file>`
|
||||
Edit, open, or download remote files over SSH easily, by simply clicking on
|
||||
the filename.
|
||||
@@ -107,6 +79,11 @@ Some prominent kittens:
|
||||
configuration to the remote host.
|
||||
|
||||
|
||||
:doc:`Panel <kittens/panel>`
|
||||
Draw a GPU accelerated dock panel on your desktop showing the output from an
|
||||
arbitrary terminal program.
|
||||
|
||||
|
||||
:doc:`Clipboard <kittens/clipboard>`
|
||||
Copy/paste to the clipboard from shell scripts, even over SSH.
|
||||
|
||||
|
||||
@@ -122,78 +122,45 @@ create :file:`~/.config/kitty/mywatcher.py` and use :option:`launch --watcher` =
|
||||
.. code-block:: python
|
||||
|
||||
# ~/.config/kitty/mywatcher.py
|
||||
from typing import Any
|
||||
from typing import Any, Dict
|
||||
|
||||
from kitty.boss import Boss
|
||||
from kitty.window import Window
|
||||
|
||||
|
||||
def on_load(boss: Boss, data: dict[str, Any]) -> None:
|
||||
# This is a special function that is called just once when this watcher
|
||||
# module is first loaded, can be used to perform any initialization/one
|
||||
# time setup. Any exceptions in this function are printed to kitty's
|
||||
# STDERR but otherwise ignored.
|
||||
...
|
||||
|
||||
def on_resize(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
def on_resize(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
|
||||
# Here data will contain old_geometry and new_geometry
|
||||
# Note that resize is also called the first time a window is created
|
||||
# which can be detected as old_geometry will have all zero values, in
|
||||
# particular, old_geometry.xnum and old_geometry.ynum will be zero.
|
||||
...
|
||||
|
||||
def on_focus_change(boss: Boss, window: Window, data: dict[str, Any])-> None:
|
||||
def on_focus_change(boss: Boss, window: Window, data: Dict[str, Any])-> None:
|
||||
# Here data will contain focused
|
||||
...
|
||||
|
||||
def on_close(boss: Boss, window: Window, data: dict[str, Any])-> None:
|
||||
def on_close(boss: Boss, window: Window, data: Dict[str, Any])-> None:
|
||||
# called when window is closed, typically when the program running in
|
||||
# it exits
|
||||
...
|
||||
|
||||
def on_set_user_var(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
def on_set_user_var(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
|
||||
# called when a "user variable" is set or deleted on a window. Here
|
||||
# data will contain key and value
|
||||
...
|
||||
|
||||
def on_title_change(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
def on_title_change(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
|
||||
# called when the window title is changed on a window. Here
|
||||
# data will contain title and from_child. from_child will be True
|
||||
# when a title change was requested via escape code from the program
|
||||
# running in the terminal
|
||||
...
|
||||
|
||||
def on_cmd_startstop(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
def on_cmd_startstop(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
|
||||
# called when the shell starts/stops executing a command. Here
|
||||
# data will contain is_start, cmdline and time.
|
||||
...
|
||||
|
||||
def on_color_scheme_preference_change(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
# called when the color scheme preference of this window changes from
|
||||
# light to dark or vice versa. data contains is_dark and via_escape_code
|
||||
# the latter will be true if the color scheme was changed via escape
|
||||
# code received from the program running in the window
|
||||
...
|
||||
|
||||
def on_tab_bar_dirty(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
# called when any changes happen to the tab bar, such a new tabs being
|
||||
# created, tab titles changing, tabs moving, etc. Useful to display the
|
||||
# tab bar externally to kitty. This is called even if the tab bar is
|
||||
# hidden. Note that this is called only in *global watchers*, that is
|
||||
# watchers defined in kitty.conf or using the --watcher command line
|
||||
# flag. data contains tab_manager which is the object responsible for
|
||||
# managing all tabs in a single OS Window.
|
||||
...
|
||||
|
||||
def on_quit(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
# called when kitty is about to quit. This is called in *global watchers*
|
||||
# only. It is called twice: once before the quit confirmation dialog is
|
||||
# shown (data['confirmed'] will be False) and once after the user has
|
||||
# confirmed quitting (data['confirmed'] will be True). Setting
|
||||
# data['aborted'] to True will abort the quit in both cases.
|
||||
...
|
||||
|
||||
|
||||
Every callback is passed a reference to the global ``Boss`` object as well as
|
||||
the ``Window`` object the action is occurring on. The ``data`` object is a dict
|
||||
that contains event dependent data. You have full access to kitty internals in
|
||||
@@ -204,7 +171,7 @@ would pass to ``kitten @``. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def on_resize(boss: Boss, window: Window, data: dict[str, Any]) -> None:
|
||||
def on_resize(boss: Boss, window: Window, data: Dict[str, Any]) -> None:
|
||||
# send some text to the resized window
|
||||
boss.call_remote_control(window, ('send-text', f'--match=id:{window.id}', 'hello world'))
|
||||
|
||||
|
||||
@@ -179,38 +179,16 @@ define a few extra key bindings in :file:`kitty.conf`::
|
||||
map ctrl+up neighboring_window up
|
||||
map ctrl+down neighboring_window down
|
||||
|
||||
# Set the bias of the split containing the currently focused window. The
|
||||
# currently focused window will take up the specified percent of its parent
|
||||
# window's size.
|
||||
map ctrl+. layout_action bias 80
|
||||
|
||||
# Maximize the active window along the horizontal axis (fill full width),
|
||||
# keeping other windows visible in their vertical positions. Press again to
|
||||
# restore the original layout.
|
||||
map ctrl+shift+right layout_action maximize horizontal
|
||||
|
||||
# Maximize the active window along the vertical axis (fill full height),
|
||||
# keeping other windows visible in their horizontal positions. Press again
|
||||
# to restore the original layout.
|
||||
map ctrl+shift+up layout_action maximize vertical
|
||||
|
||||
|
||||
Windows can be resized using :ref:`window_resizing`. You can swap the windows
|
||||
in a split using the ``rotate`` action with an argument of ``180`` and rotate
|
||||
and swap with an argument of ``270``. The ``maximize`` action expands the active
|
||||
window to fill the maximum available space along a single axis while keeping
|
||||
the rest of the layout intact. Use ``maximize horizontal`` to fill the full
|
||||
width and ``maximize vertical`` to fill the full height. Calling it again
|
||||
restores the original split sizes.
|
||||
and swap with an argument of ``270``.
|
||||
|
||||
This layout takes one option, ``split_axis`` that controls whether new windows
|
||||
are placed into vertical or horizontal splits when a :option:`--location
|
||||
<launch --location>` is not specified. A value of ``horizontal`` (same as
|
||||
``--location=vsplit``) means when a new split is created the two windows will
|
||||
be placed side by side and a value of ``vertical`` (same as
|
||||
``--location=hsplit``) means the two windows will be placed one on top of the
|
||||
other. A value of ``auto`` means the axis of the split is chosen automatically
|
||||
(same as ``--location=split``). By default::
|
||||
are placed into vertical or horizontal splits when a :option:`--location <launch
|
||||
--location>` is not specified. A value of ``horizontal`` (same as
|
||||
``--location=vsplit``) means when a new split is created the two windows will be
|
||||
placed side by side and a value of ``vertical`` (same as ``--location=hsplit``)
|
||||
means the two windows will be placed one on top of the other. By default::
|
||||
|
||||
enabled_layouts splits:split_axis=horizontal
|
||||
|
||||
@@ -279,14 +257,7 @@ All windows are shown one below the other. This layout has no options::
|
||||
Resizing windows
|
||||
------------------
|
||||
|
||||
You can resize windows inside layouts. The easiest method is to simply drag the
|
||||
window borders using a mouse, controlled by the option :opt:`window_drag_tolerance`.
|
||||
Note that technically this resizes layout slots not actual windows, so it
|
||||
does not work exactly like resizing OS Windows on your desktop. Instead, the
|
||||
layout is changed and potentially multiple windows get resized when dragging a
|
||||
single border.
|
||||
|
||||
For keyboard friendly resizing, press :sc:`start_resizing_window` (also
|
||||
You can resize windows inside layouts. Press :sc:`start_resizing_window` (also
|
||||
:kbd:`⌘+r` on macOS) to enter resizing mode and follow the on-screen
|
||||
instructions. In a given window layout only some operations may be possible for
|
||||
a particular window. For example, in the *Tall* layout you can make the first
|
||||
|
||||
110
docs/mapping.rst
110
docs/mapping.rst
@@ -167,33 +167,6 @@ the program running in the terminal, map it to :ac:`discard_event`::
|
||||
|
||||
.. _conditional_mappings:
|
||||
|
||||
Configuring a timeout
|
||||
----------------------
|
||||
|
||||
You can also set a timeout for keyboard modes and multi-key mappings. If a
|
||||
timeout is set and you don't complete the key sequence or exit the mode within
|
||||
the specified time, the mode will be automatically cancelled. This is useful
|
||||
for multi-key mappings where you might accidentally press the first key and
|
||||
then change your mind. The timeout is specified in seconds and can be set
|
||||
globally using the :opt:`map_timeout` option or per-mode using ``--timeout``::
|
||||
|
||||
# Set a global 2 second timeout for all multi-key and modal mappings
|
||||
map_timeout 2.0
|
||||
|
||||
# This mode will have a 5 second timeout (overrides global setting)
|
||||
map --new-mode resize --timeout 5.0 kitty_mod+r
|
||||
map --mode resize h resize_window narrower
|
||||
map --mode resize l resize_window wider
|
||||
# ... more mappings
|
||||
|
||||
# Multi-key mapping with the global timeout
|
||||
map ctrl+a>h new_window
|
||||
|
||||
When a timeout occurs, the mode is exited and any buffered keys are discarded.
|
||||
A timeout value of zero disables the timeout. For multi-key sequences, the
|
||||
timeout is restarted after each valid key press in the sequence.
|
||||
|
||||
|
||||
Conditional mappings depending on the state of the focused window
|
||||
----------------------------------------------------------------------
|
||||
|
||||
@@ -221,15 +194,15 @@ running an editor::
|
||||
|
||||
map --when-focus-on var:in_editor kitty_mod+c
|
||||
|
||||
In order to make this work, you need to configure your editor as shown below:
|
||||
In order to make this work, you need to configure your editor as show below:
|
||||
|
||||
.. tab:: vim
|
||||
|
||||
In :file:`~/.vimrc` add:
|
||||
.. code-block:: vim
|
||||
|
||||
let &t_ti = &t_ti . "\033]1337;SetUserVar=in_editor=MQ==\007"
|
||||
let &t_te = &t_te . "\033]1337;SetUserVar=in_editor\007"
|
||||
let &t_ti = &t_ti . "\\033]1337;SetUserVar=in_editor=MQo\\007"
|
||||
let &t_te = &t_te . "\\033]1337;SetUserVar=in_editor\\007"
|
||||
|
||||
.. tab:: neovim
|
||||
|
||||
@@ -237,25 +210,17 @@ In order to make this work, you need to configure your editor as shown below:
|
||||
|
||||
.. code-block:: lua
|
||||
|
||||
vim.api.nvim_create_autocmd({ "VimEnter", "VimResume", "UIEnter" }, {
|
||||
vim.api.nvim_create_autocmd({ "VimEnter", "VimResume" }, {
|
||||
group = vim.api.nvim_create_augroup("KittySetVarVimEnter", { clear = true }),
|
||||
callback = function()
|
||||
if vim.api.nvim_ui_send then
|
||||
vim.api.nvim_ui_send("\x1b]1337;SetUserVar=in_editor=MQ==\007")
|
||||
else
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor=MQ==\007")
|
||||
end
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor=MQo\007")
|
||||
end,
|
||||
})
|
||||
|
||||
vim.api.nvim_create_autocmd({ "VimLeave", "VimSuspend" }, {
|
||||
group = vim.api.nvim_create_augroup("KittyUnsetVarVimLeave", { clear = true }),
|
||||
callback = function()
|
||||
if vim.api.nvim_ui_send then
|
||||
vim.api.nvim_ui_send("\x1b]1337;SetUserVar=in_editor\007")
|
||||
else
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor\007")
|
||||
end
|
||||
io.stdout:write("\x1b]1337;SetUserVar=in_editor\007")
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -265,67 +230,6 @@ copying to clipboard. In the editor, you can map it to copy to the clipboard,
|
||||
thereby allowing use of a common shortcut both inside and outside the editor
|
||||
for copying to clipboard.
|
||||
|
||||
.. note::
|
||||
|
||||
When using multi-key mappings, of the form :kbd:`k1>k2` or similar, the
|
||||
condition applies to the first key and you can have only one condition per
|
||||
key, the last in kitty.conf wins. In particular, this means you cannot have
|
||||
multiple conditions applying to multi-key mappings with the same first key
|
||||
and you cannot have mappings with and without conditions applying to multi-keys
|
||||
with the same first key.
|
||||
|
||||
|
||||
.. _mapping-fallback:
|
||||
|
||||
Non-Latin keyboard layout support
|
||||
--------------------------------------
|
||||
|
||||
When using a non-Latin keyboard layout (e.g. Russian, Arabic, Greek), letter-key
|
||||
shortcuts like :kbd:`Ctrl+C` stop working because the key produces a non-Latin
|
||||
character. kitty solves this with the ``--allow-fallback`` option on the ``map``
|
||||
directive, which controls how shortcuts fall back to the physical key position.
|
||||
|
||||
The ``--allow-fallback`` option accepts a comma-separated list of fallback types:
|
||||
|
||||
``shifted``
|
||||
Fall back to the *shifted key* — the character produced when Shift is held
|
||||
with the key. This is the default for all mappings and preserves the existing
|
||||
behavior.
|
||||
|
||||
``ascii``
|
||||
Fall back to the *alternate key* — the character that the physical key would
|
||||
produce in a standard US layout. This only triggers when the key produces a
|
||||
non-ASCII character, so it has no effect on Latin-based layouts like Dvorak
|
||||
or Colemak.
|
||||
|
||||
``none``
|
||||
Disable all fallback matching. The mapping will only match the exact key
|
||||
specified, ignoring both shifted and alternate key positions.
|
||||
|
||||
For example::
|
||||
|
||||
# Enable both shifted and ASCII fallback (used by default kitty shortcuts)
|
||||
map --allow-fallback=shifted,ascii kitty_mod+c copy_to_clipboard
|
||||
|
||||
# Only ASCII fallback, no shifted key fallback
|
||||
map --allow-fallback=ascii ctrl+s save_something
|
||||
|
||||
# Disable all fallback (neither shifted nor alternate key matching)
|
||||
map --allow-fallback=none ctrl+x some_action
|
||||
|
||||
All default kitty shortcuts use ``--allow-fallback=shifted,ascii``, so they work
|
||||
out of the box with non-Latin layouts. Custom mappings without an explicit
|
||||
``--allow-fallback`` get the default value of ``shifted``, which preserves
|
||||
backward compatibility.
|
||||
|
||||
.. note::
|
||||
|
||||
The ``ascii`` fallback uses a non-ASCII guard: it only activates when
|
||||
the key produces a character with a Unicode code point above 127. This means
|
||||
alternative Latin layouts (Dvorak, Colemak, etc.) are never affected by the
|
||||
``ascii`` fallback — only non-Latin layouts trigger it.
|
||||
|
||||
|
||||
Sending arbitrary text or keys to the program running in kitty
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -406,7 +310,7 @@ below::
|
||||
|
||||
# Beep on unknown keys
|
||||
map --new-mode XXX --on-unknown beep ...
|
||||
# Ignore unknown keys silently
|
||||
# Ingore unknown keys silently
|
||||
map --new-mode XXX --on-unknown ignore ...
|
||||
# Beep and exit the keyboard mode on unknown key
|
||||
map --new-mode XXX --on-unknown end ...
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
Miscellaneous protocol extensions
|
||||
==============================================
|
||||
|
||||
These are a few small protocol extensions kitty implements, primarily for use
|
||||
by its own kitten, they are documented here for completeness.
|
||||
|
||||
|
||||
Simple save/restore of all terminal modes
|
||||
--------------------------------------------
|
||||
|
||||
XTerm has the XTSAVE/XTRESTORE escape codes to save and restore terminal
|
||||
private modes. However, they require specifying an explicit list of modes to
|
||||
save/restore. kitty extends this protocol to specify that when no modes are
|
||||
specified, all side-effect free modes should be saved/restored. By side-effects
|
||||
we mean things that can affect other terminal state such as cursor position or
|
||||
screen contents. Examples of modes that have side effects are: `DECOM
|
||||
<https://vt100.net/docs/vt510-rm/DECOM.html>`__ and `DECCOLM
|
||||
<https://vt100.net/docs/vt510-rm/DECCOLM.html>`__.
|
||||
|
||||
This allows TUI applications to easily save and restore emulator state without
|
||||
needing to maintain lists of modes.
|
||||
|
||||
|
||||
Independent control of bold and faint SGR properties
|
||||
-------------------------------------------------------
|
||||
|
||||
In common terminal usage, bold is set via SGR 1 and faint by SGR 2. However,
|
||||
there is only one number to reset these attributes, SGR 22, which resets both.
|
||||
There is no way to reset one and not the other. kitty uses 221 and 222 to reset
|
||||
bold and faint independently.
|
||||
|
||||
.. _mouse_leave_window:
|
||||
|
||||
Reporting when the mouse leaves the window
|
||||
----------------------------------------------
|
||||
|
||||
kitty extends the SGR Pixel mouse reporting protocol created by xterm to
|
||||
also report when the mouse leaves the window. This event is delivered
|
||||
encoded as a normal SGR pixel event except that the eight bit is set on the
|
||||
first number. Additionally, bit 5 is set to indicate this is a motion related event.
|
||||
The remaining bits 1-7 (except 5) are used to encode button and modifier information.
|
||||
When bit 8 is set it means the event is a mouse has left the window event,
|
||||
and all other bits should be ignored. The pixel position values must also
|
||||
be ignored as they may not be accurate.
|
||||
|
||||
An escape code to move the contents of the screen into the scrollback
|
||||
-------------------------------------------------------------------------------------
|
||||
|
||||
The escape code is ``\x1b [ 22 J`` (ignoring spaces present for clarity). It
|
||||
moves all screen contents (text and images) into the scrollback leaving the
|
||||
screen in the same state as it would be if the standard screen clear escape
|
||||
code had been used ``\x1b [ 2 J``.
|
||||
|
||||
|
||||
kitty specific private escape codes
|
||||
---------------------------------------
|
||||
|
||||
These are a family of escape codes used by kitty for various things including
|
||||
remote control. They are all DCS (Device Control String) escape codes starting
|
||||
with ``\x1b P @ kitty-`` (ignoring spaces present for clarity).
|
||||
@@ -1,247 +0,0 @@
|
||||
The multiple cursors protocol
|
||||
==============================================
|
||||
|
||||
.. versionadded:: 0.43.0
|
||||
|
||||
Many editors support something called *multiple cursors* in which you can make
|
||||
the same changes at multiple locations in a file and the editor shows you
|
||||
cursors at each of the locations. In a terminal context editors typically
|
||||
implement this by showing some Unicode glyph at each location instead of the
|
||||
actual cursor. This is sub-optimal since actual cursors implemented by the
|
||||
terminal have many niceties like smooth animation [anim]_, auto adjust colors [rv]_,
|
||||
etc. To address this and other use cases, this protocol allows terminal programs to
|
||||
request that the terminal display multiple cursors at specific locations on the
|
||||
screen.
|
||||
|
||||
Quickstart
|
||||
----------------
|
||||
|
||||
An example, showing how to use the protocol:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
# Show cursors of the same shape as the main cursor at y=4, x=5
|
||||
printf "\e[>29;2:4:5 q"
|
||||
# Show more cursors on the seventh line, of various shapes, the underline shape is shown twice
|
||||
printf "\e[>1;2:7:1 q\e[>2;2:7:3 q\e[>3;2:7:5;2:7:7 q"
|
||||
|
||||
|
||||
The escape code to show a cursor has the following structure (ignore spaces
|
||||
they are present for readability only)::
|
||||
|
||||
CSI > SHAPE;CO-ORD TYPE : CO-ORDINATES ; CO-ORD TYPE : CO-ORDINATES ... TRAILER
|
||||
|
||||
Here ``CSI`` is the two bytes ESC (``0x1b``) and [ (``0x5b``). ``SHAPE`` can be
|
||||
one of:
|
||||
|
||||
* ``0``: No cursor
|
||||
* ``1``: Block cursor
|
||||
* ``2``: Beam cursor
|
||||
* ``3``: Underline cursor
|
||||
* ``29``: Follow the shape of the main cursor
|
||||
* ``30``: Change the color of text under extra cursors
|
||||
* ``40``: Change the color of extra cursors
|
||||
* ``100``: Used for querying currently set cursors
|
||||
|
||||
``CO-ORD TYPE`` can be one of:
|
||||
|
||||
* ``0``: This refers to the position of the main cursor and has no following
|
||||
co-ordinates.
|
||||
|
||||
* ``2``: In this case the following co-ordinates are pairs of numbers pointing
|
||||
to cells in the form ``y:x`` with the origin in the top left corner at
|
||||
``1,1``. There can be any number of pairs, the terminal must treat each pair
|
||||
as a new location to set a cursor.
|
||||
|
||||
* ``4``: In this case the following co-ordinates are sets of four numbers that
|
||||
define a rectangle in the same co-ordinate system as above of the form:
|
||||
``top:left:bottom:right``. The shape is set on every cell in the rectangle
|
||||
from the top left cell to the bottom right cell, inclusive. If no numbers
|
||||
are provided, the rectangle is the full screen. There can be any number of
|
||||
rectangles, the terminal must treat each set of four numbers as a new
|
||||
rectangle.
|
||||
|
||||
The sequence of ``CO-ORD TYPE : CO-ORDINATES`` can be repeated any number of
|
||||
times separated by ``;``. The ``SHAPE`` will be set on the cells indicated by
|
||||
each such group. For example: ``-1;2:3:4;4:5:6:7:8`` will set the shape ``-1``
|
||||
at the cell ``(3, 2)`` and in the rectangle ``(6, 5)`` to ``(8, 7)`` inclusive.
|
||||
|
||||
Finally, the ``TRAILER`` terminates the sequence and is the bytes SPACE
|
||||
(``0x20``) and q (``0x71``).
|
||||
|
||||
Terminals **must** ignore cells that fall outside the screen. That means, for
|
||||
rectangle co-ordinates only the intersection of the rectangle with the screen
|
||||
must be considered, and point co-ordinates that fall outside of the screen are
|
||||
simply ignored, with no effect.
|
||||
|
||||
Terminals **must** ignore extra co-ordinates, that means if an odd number of
|
||||
co-ordinates are specified for type ``2`` the last co-ordinate is ignored.
|
||||
Similarly for type ``4`` if the number of co-ordinates is not a multiple of
|
||||
four, the last ``1 <= n <= 3`` co-ordinates are ignored, as if they were not
|
||||
specified.
|
||||
|
||||
Querying for support
|
||||
-------------------------
|
||||
|
||||
A terminal program can query the terminal emulator for support of this
|
||||
protocol by sending the escape code::
|
||||
|
||||
CSI > TRAILER
|
||||
|
||||
In this case a supporting terminal must reply with::
|
||||
|
||||
CSI > 1;2;3;29;30;40;100;101 TRAILER
|
||||
|
||||
Here, the list of numbers indicates the cursor shapes and other operations
|
||||
the terminal supports and can be any subset of the above. No numbers
|
||||
indicates the protocol is not supported. To avoid having to wait with a
|
||||
timeout for a response from the terminal, the client should send this
|
||||
query code immediately followed by a request for the
|
||||
`primary device attributes <https://vt100.net/docs/vt510-rm/DA1.html>`_.
|
||||
If the terminal responds with an answer for the device attributes without
|
||||
an answer for the *query* the terminal emulator does not support this protocol at all.
|
||||
|
||||
Terminals **must** respond to these queries in FIFO order, so that
|
||||
multiplexers that split a single screen know which split to send responses too.
|
||||
|
||||
Clearing previously set multi-cursors
|
||||
------------------------------------------
|
||||
|
||||
The cursor at a cell is cleared by setting its shape to ``0``.
|
||||
The most common operation is to clear all previously set multi-cursors. This is
|
||||
easily done using the *rectangle* co-ordinate system above, like this::
|
||||
|
||||
CSI > 0;4 TRAILER
|
||||
|
||||
For more precise control different co-ordinate types can be used. This is
|
||||
particularly important for multiplexers that split up the screen and therefore
|
||||
need to re-write these escape codes.
|
||||
|
||||
.. _extra_cursor_color:
|
||||
|
||||
Changing the color of extra cursors
|
||||
---------------------------------------
|
||||
|
||||
In order to visually distinguish extra cursors from the main cursor, it is
|
||||
possible to specify a color pair for extra cursors. Note that for performance
|
||||
reasons, there is only a single color pair that all extra cursors share.
|
||||
The color pair consists of the cursor color and the color for text in the cell
|
||||
the cursor is on.
|
||||
|
||||
To change this color pair use an escape code of the form::
|
||||
|
||||
CSI > WHICH ; COLOR_SPACE : COLOR_PARAMETER1 : COLOR_PARAMETER2 : ... TRAILER
|
||||
|
||||
Here, ``WHICH`` is ``30`` to set the color of text under the cursor and ``40``
|
||||
to set the color of the cursor itself (these numbers mimic the SGR codes for
|
||||
foreground and background respectively).
|
||||
|
||||
The ``COLOR_SPACE`` parameter sets the type of color, it can take values:
|
||||
|
||||
``0`` - unset color is same as for main cursor. No color parameters.
|
||||
``1`` - *special* which typically means some kind of reverse video effect, see below
|
||||
``2`` - sRGB color, with three color parameters, red, green and blue as numbers
|
||||
from 0 to 255
|
||||
``5`` - Indexed color with one color parameter which is an index into the color
|
||||
table from 0 to 255
|
||||
|
||||
When the cursor color is set to *special* via ``40`` it means the block cursor
|
||||
must be rendered with a reverse video effect where the cursor color becomes the
|
||||
foreground color of the cell under the cursor and the foreground color of the
|
||||
cell becomes its background color. Implementations are free to adjust these
|
||||
colors to ensure suitable contrast levels. In this case the text color set by
|
||||
``30`` must be ignored.
|
||||
|
||||
When the cursor color is not set to *special* but the text color via ``30`` is
|
||||
set to special, then that means the foreground color of the cell with the
|
||||
cursor must be changed to its background color for a partial reverse video
|
||||
effect.
|
||||
|
||||
When unset, aka, set to ``0`` the cursors must be the same color as the main
|
||||
cursor. In particular if the main color is using a reverse video effect, the
|
||||
extra cursors must use the exact same colors as the main cursor, not the colors
|
||||
of the cells they are on.
|
||||
|
||||
Querying for already set cursors
|
||||
--------------------------------------
|
||||
|
||||
Programs can ask the terminal what extra cursors are currently set, by sending
|
||||
the escape code::
|
||||
|
||||
CSI > 100 TRAILER
|
||||
|
||||
The terminal must respond with **one** escape code::
|
||||
|
||||
CSI > 100; SHAPE:CO-ORDINATE TYPE:CO-ORDINATES ; ... TRAILER
|
||||
|
||||
Here, the ``SHAPE:CO-ORDINATE TYPE:CO-ORDINATES`` block can be repeated any
|
||||
number of times, separated by ``;``. This response gives the set of shapes and
|
||||
positions currently active. If no cursors are currently active, there will be
|
||||
no blocks, just an empty response of the form::
|
||||
|
||||
CSI > 100 TRAILER
|
||||
|
||||
Again, terminals **must** respond in FIFO order so that multiplexers know where
|
||||
to direct the responses.
|
||||
|
||||
Querying for extra cursor colors
|
||||
-------------------------------------
|
||||
|
||||
Programs can ask the terminal what cursor colors are currently set, by sending
|
||||
escape code::
|
||||
|
||||
CSI > 101 TRAILER
|
||||
|
||||
The terminal must respond with **one** escape code::
|
||||
|
||||
CSI > 101 ; 30 : COLOR_SPACE : COLOR_PARAMETERS ; 40 : COLOR_SPACE : COLOR_PARAMETERS TRAILER
|
||||
|
||||
The number and type of ``COLOR_PARAMETERS`` depends on the preceding
|
||||
``COLOR_SPACE`` and can be omitted for some ``COLOR_SPACE`` values. See the
|
||||
section :ref:`extra_cursor_color` for details.
|
||||
|
||||
|
||||
Interaction with other terminal controls and state
|
||||
-------------------------------------------------------
|
||||
|
||||
**The main cursor**
|
||||
The extra cursors must all have the same color and opacity and blink state
|
||||
as the main cursor. The main cursor's visibility must not affect the
|
||||
visibility of the extra cursors. Their visibility and shape are controlled
|
||||
only by this protocol.
|
||||
|
||||
**Clearing the screen**
|
||||
The escape codes used to clear the screen (`ED <https://vt100.net/docs/vt510-rm/ED.html>`__)
|
||||
with parameters 2, 3 and 22 must remove all extra cursors,
|
||||
this is so that the clear command can be used by users to clear the screen of extra cursors.
|
||||
|
||||
**Reset***
|
||||
This must remove all extra cursors.
|
||||
|
||||
**Alternate screen***
|
||||
Switching between the main and alternate screens must remove all extra
|
||||
cursors.
|
||||
|
||||
**Scrolling**
|
||||
The index (IND) and reverse index (RI) escape codes that cause screen
|
||||
contents to scroll into scrollback or off screen must not affect
|
||||
the extra cursors in any way. They remain at exactly the same position.
|
||||
It is up to applications to manage extra cursor positions when using these
|
||||
escape codes if needed. There are not a lot of use cases for scrolling
|
||||
extra cursors with screen content, since extra cursors are meant to be
|
||||
ephemeral and on screen only, not in scrollback. This allows terminals
|
||||
to avoid the extra overhead of adjusting positions of the extra cursors
|
||||
on every scroll.
|
||||
|
||||
|
||||
Footnotes
|
||||
-------------
|
||||
|
||||
.. [anim] kitty allows the cursor blink to be :opt:`animated
|
||||
<cursor_blink_interval>` using any CSS easing function. This cannot be
|
||||
implemented using fake cursors.
|
||||
|
||||
.. [rv] kitty has a special "reverse video" color mode for cursors where the
|
||||
color of the cursor and the text under the cursor is adjusted based on the
|
||||
color of the cell under the cursor. This also cannot be implemented using
|
||||
fake cursors.
|
||||
@@ -3,7 +3,7 @@ Scripting the mouse click
|
||||
|
||||
|kitty| has support for :term:`terminal hyperlinks <hyperlinks>`. These are
|
||||
generated by many terminal programs, such as ``ls``, ``gcc``, ``systemd``,
|
||||
:ref:`tool_mcat`, etc. You can customize exactly what happens when clicking on
|
||||
:ref:`tool_mdcat`, etc. You can customize exactly what happens when clicking on
|
||||
these hyperlinks in |kitty|.
|
||||
|
||||
You can tell kitty to take arbitrarily many, complex actions when a link is
|
||||
@@ -48,7 +48,7 @@ action per entry if you like, for example:
|
||||
action change_font_size current -2
|
||||
|
||||
|
||||
In the launch specification you can expand environment variables, as shown in
|
||||
In the action specification you can expand environment variables, as shown in
|
||||
the examples above. In addition to regular environment variables, there are
|
||||
some special variables, documented below:
|
||||
|
||||
@@ -126,12 +126,11 @@ lines. The various available criteria are:
|
||||
|
||||
.. _launch_actions:
|
||||
|
||||
Scripting the opening of files with kitty
|
||||
Scripting the opening of files with kitty on macOS
|
||||
-------------------------------------------------------
|
||||
|
||||
On macOS you can use :guilabel:`Open With` in Finder or drag and drop files and
|
||||
URLs onto the kitty dock icon to open them with kitty. Similarly on Linux, you
|
||||
can associate certain files types to open in kitty. The default actions are:
|
||||
URLs onto the kitty dock icon to open them with kitty. The default actions are:
|
||||
|
||||
* Open text files in your editor and images using the icat kitten.
|
||||
* Run shell scripts in a shell
|
||||
|
||||
@@ -33,9 +33,6 @@ frames-per-second. Press :sc:`edit_config_file` in kitty to open its fully
|
||||
commented sample config file in your text editor. For details see the
|
||||
:doc:`configuration docs <conf>`.
|
||||
|
||||
You can quickly browse all available mappable actions by pressing
|
||||
:sc:`command_palette`, see :doc:`kittens/command-palette` for details.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
@@ -99,16 +96,12 @@ used to create programs that leverage kitty's powerful features, for example,
|
||||
You can :doc:`create your own kittens to scratch your own itches
|
||||
<kittens/custom>`.
|
||||
|
||||
For a list of all the builtin kittens, run ``kitten`` in kitty, or to browse
|
||||
some of the more prominent ones, see :ref:`see here <kittens>`.
|
||||
For a list of all the builtin kittens, :ref:`see here <kittens>`.
|
||||
|
||||
Additionally, you can use the :ref:`watchers <Watchers>` framework
|
||||
to create Python scripts that run in response to various events such as windows
|
||||
being resized, closing, having their titles changed, etc.
|
||||
|
||||
Finally, there is remote control which allows you to control kitty from
|
||||
anywhere, even across a network! See below for more about remote control.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
|
||||
@@ -131,14 +124,84 @@ started.
|
||||
remote-control
|
||||
|
||||
|
||||
Sessions
|
||||
.. _sessions:
|
||||
|
||||
Startup Sessions
|
||||
------------------
|
||||
|
||||
You can control the :term:`tabs <tab>`, :term:`kitty window <window>` layout,
|
||||
working directory, startup programs, etc. by creating a *session* file and using
|
||||
the :option:`kitty --session` command line flag or the :opt:`startup_session`
|
||||
option in :file:`kitty.conf`. You can also easily switch between sessions with
|
||||
a keypress. See :doc:`sessions` for details.
|
||||
option in :file:`kitty.conf`. An example, showing all available commands:
|
||||
|
||||
.. code-block:: session
|
||||
|
||||
# Set the layout for the current tab
|
||||
layout tall
|
||||
# Set the working directory for windows in the current tab
|
||||
cd ~
|
||||
# Create a window and run the specified command in it
|
||||
launch zsh
|
||||
# Create a window with some environment variables set and run vim in it
|
||||
launch --env FOO=BAR vim
|
||||
# Set the title for the next window
|
||||
launch --title "Chat with x" irssi --profile x
|
||||
|
||||
# Create a new tab
|
||||
# The part after new_tab is the optional tab title which will be displayed in
|
||||
# the tab bar, if omitted, the title of the active window will be used instead.
|
||||
new_tab my tab
|
||||
cd ~/somewhere
|
||||
# Set the layouts allowed in this tab
|
||||
enabled_layouts tall,stack
|
||||
# Set the current layout
|
||||
layout stack
|
||||
launch zsh
|
||||
|
||||
# Create a new OS window
|
||||
# Any definitions specified before the first new_os_window will apply to first OS window.
|
||||
new_os_window
|
||||
# Set new window size to 80x24 cells
|
||||
os_window_size 80c 24c
|
||||
# Set the --class for the new OS window
|
||||
os_window_class mywindow
|
||||
# Change the OS window state to normal, fullscreen, maximized or minimized
|
||||
os_window_state normal
|
||||
launch sh
|
||||
# Resize the current window (see the resize_window action for details)
|
||||
resize_window wider 2
|
||||
# Make the current window the active (focused) window in its tab
|
||||
focus
|
||||
# Make the current OS Window the globally active window (not supported on Wayland)
|
||||
focus_os_window
|
||||
launch emacs
|
||||
|
||||
# Create a complex layout using multiple splits. Creates two columns of
|
||||
# windows with two windows in each column. The windows in the first column are
|
||||
# split 50:50. In the second column the windows are not evenly split.
|
||||
new_tab complex tab
|
||||
layout splits
|
||||
# First window, set a user variable on it so we can focus it later
|
||||
launch --var window=first
|
||||
# Create the second column by splitting the first window vertically
|
||||
launch --location=vsplit
|
||||
# Create the third window in the second column by splitting the second window horizontally
|
||||
# Make it take 40% of the height instead of 50%
|
||||
launch --location=hsplit --bias=40
|
||||
# Go back to focusing the first window, so that we can split it
|
||||
focus_matching_window var:window=first
|
||||
# Create the final window in the first column
|
||||
launch --location=hsplit
|
||||
|
||||
|
||||
.. note::
|
||||
The :doc:`launch <launch>` command when used in a session file cannot create
|
||||
new OS windows, or tabs.
|
||||
|
||||
.. note::
|
||||
Environment variables of the for :code:`${NAME}` or :code:`$NAME` are
|
||||
expanded in the session file, except in the *arguments* (not options) to the
|
||||
launch command.
|
||||
|
||||
|
||||
Creating tabs/windows
|
||||
@@ -179,14 +242,9 @@ All these actions can be customized in :file:`kitty.conf` as described
|
||||
|
||||
You can also customize what happens when clicking on :term:`hyperlinks` in
|
||||
kitty, having it open files in your editor, download remote files, open things
|
||||
in your browser, etc. For details, see :doc:`here <open_actions>`.
|
||||
in your browser, etc.
|
||||
|
||||
Additionally, various bits of the kitty UI itself work with the mouse. You can
|
||||
drag and drop tabs in the tab bar to re-order them or move them from one OS
|
||||
Window to another, or even pop them out into a new OS Window.
|
||||
You can drag window borders to resize windows. You can double click on empty regions
|
||||
of the tab bar to create new tabs or double click on an existing tab to rename
|
||||
it.
|
||||
For details, see :doc:`here <open_actions>`.
|
||||
|
||||
.. toctree::
|
||||
:hidden:
|
||||
@@ -211,10 +269,9 @@ The scrollback buffer
|
||||
-----------------------
|
||||
|
||||
|kitty| supports scrolling back to view history, just like most terminals. You
|
||||
can use either keyboard shortcuts or the mouse scroll wheel to do so. |kitty|
|
||||
displays an interactive :opt:`scrollbar` along the right edge
|
||||
of the window that shows your current position in the scrollback. You can click
|
||||
and drag the scrollbar to quickly navigate through the history.
|
||||
can use either keyboard shortcuts or the mouse scroll wheel to do so. While
|
||||
you are browsing the scrollback a :opt:`small indicator <scrollback_indicator_opacity>`
|
||||
is displayed along the right edge of the window to show how far back you are.
|
||||
|
||||
However, |kitty| has an extra, neat feature. Sometimes you need to explore the scrollback
|
||||
buffer in more detail, maybe search for some text or refer to it side-by-side
|
||||
@@ -233,7 +290,7 @@ arbitrary, command running in a new :term:`window`, :term:`tab` or
|
||||
Would open the scrollback buffer in a new :term:`window` when you press the
|
||||
:kbd:`F1` key. See :sc:`show_scrollback <show_scrollback>` for details.
|
||||
|
||||
If you want to use it with an editor such as :program:`nvim` to get more powerful
|
||||
If you want to use it with an editor such as :program:`vim` to get more powerful
|
||||
features, see for example, `kitty-scrollback.nvim
|
||||
<https://github.com/mikesmithgh/kitty-scrollback.nvim>`__ or `kitty-grab <https://github.com/yurikhan/kitty_grab>`__
|
||||
or see more tips for using various editor programs, in :iss:`this thread <719>`.
|
||||
|
||||
@@ -101,7 +101,7 @@ ASCII only text.
|
||||
|
||||
foot, iterm2 and Terminal.app are left out as they do not run under X11.
|
||||
Alacritty+tmux is included just to show the effect of putting a terminal
|
||||
multiplexer into the mix (halving throughput) and because alacritty isn't
|
||||
multiplexer into the mix (halving throughput) and because alacritty isnt
|
||||
remotely comparable to any of the other terminals feature wise without tmux.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -166,7 +166,7 @@ Legacy xterm compatibility
|
||||
----------------------------
|
||||
|
||||
The original xterm proposal for this escape code used shape names from the
|
||||
:file:`X11/cursorfont.h` header on X11 based systems. Terminal implementations
|
||||
file:`X11/cursorfont.h` header on X11 based systems. Terminal implementations
|
||||
wishing to maintain compatibility with xterm can also implement these names as
|
||||
aliases for the CSS based names defined in the :ref:`pointer_shape_names` table.
|
||||
|
||||
|
||||
@@ -27,9 +27,6 @@ please do so by opening issues in the `GitHub bug tracker
|
||||
underlines
|
||||
graphics-protocol
|
||||
keyboard-protocol
|
||||
text-sizing-protocol
|
||||
dnd-protocol
|
||||
multiple-cursors-protocol
|
||||
file-transfer-protocol
|
||||
desktop-notifications
|
||||
pointer-shapes
|
||||
@@ -37,4 +34,3 @@ please do so by opening issues in the `GitHub bug tracker
|
||||
color-stack
|
||||
deccara
|
||||
clipboard
|
||||
misc-protocol
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
|
||||
.. sidebar::
|
||||
|
||||
.. only:: not man
|
||||
|
||||
**Screenshots**
|
||||
|
||||
.. figure:: /screenshots/quake-macos.webp
|
||||
:alt: Screenshot, showing the kitty floating quick access terminal above the background which is the program btop, running inside kitty, on macOS
|
||||
:align: center
|
||||
:width: 100%
|
||||
|
||||
macOS
|
||||
|
||||
|
||||
.. figure:: /screenshots/quake-hypr.webp
|
||||
:alt: Screenshot, showing the kitty floating quick access terminal above the background which is the program btop, running inside kitty, on Hyprland in Linux
|
||||
:align: center
|
||||
:width: 100%
|
||||
|
||||
Linux
|
||||
|
||||
.. figure:: /screenshots/panel.png
|
||||
:alt: Screenshot, showing a sample panel
|
||||
:align: center
|
||||
:width: 100%
|
||||
|
||||
A sample panel on Linux
|
||||
|
||||
How the screenshots :ref:`were generated <quake_ss>`.
|
||||
@@ -18,8 +18,8 @@ package, but note that some Linux distribution packages are woefully outdated.
|
||||
|kitty| is available in a vast number of package repositories for macOS
|
||||
and Linux.
|
||||
|
||||
.. image:: https://repology.org/badge/tiny-repos/kitty-terminal.svg
|
||||
:target: https://repology.org/project/kitty-terminal/versions
|
||||
.. image:: https://repology.org/badge/tiny-repos/kitty.svg
|
||||
:target: https://repology.org/project/kitty/versions
|
||||
:alt: Number of repositories kitty is available in
|
||||
|
||||
See :doc:`Configuring kitty <conf>` for help on configuring |kitty| and
|
||||
|
||||
@@ -108,8 +108,7 @@ simpler :option:`kitty --single-instance` option, see ``kitty --help`` for that.
|
||||
|
||||
Remote control via a socket
|
||||
--------------------------------
|
||||
To control kitty from outside kitty, it is necessary to setup a socket to
|
||||
communicate with kitty. First, start |kitty| as::
|
||||
First, start |kitty| as::
|
||||
|
||||
kitty -o allow_remote_control=yes --listen-on unix:/tmp/mykitty
|
||||
|
||||
@@ -186,7 +185,7 @@ Now, using this password, you can, in scripts run the command::
|
||||
Any script with access to the password can now change colors in kitty using
|
||||
remote control, but only that and nothing else. You can even supply the
|
||||
password via the :envvar:`KITTY_RC_PASSWORD` environment variable, or the
|
||||
file :file:`~/.config/kitty/rc-pass` to avoid having to type it repeatedly.
|
||||
file :file:`~/.config/kitty/rc-password` to avoid having to type it repeatedly.
|
||||
See :option:`kitten @ --password-file` and :option:`kitten @ --password-env`.
|
||||
|
||||
The :opt:`remote_control_password` can be specified multiple times to create
|
||||
@@ -262,12 +261,6 @@ as shown below:
|
||||
return True
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
The payloads for the different remote control commands are documented in the
|
||||
:doc:`remote control protocol specification <rc_protocol>`.
|
||||
|
||||
|
||||
.. _rc_mapping:
|
||||
|
||||
Mapping key presses to remote control commands
|
||||
@@ -298,8 +291,7 @@ control commands as you like and process their output.
|
||||
:ac:`launch` command with ``--type=background --allow-remote-control``.
|
||||
For more advanced usage, including fine grained permissions, setting
|
||||
env vars, command line interpolation, passing data to STDIN, etc.
|
||||
the :doc:`launch <launch>` command should be used. Relative paths to scripts
|
||||
are interpreted with respect to the kitty config directory.
|
||||
the :doc:`launch <launch>` command should be used.
|
||||
|
||||
.. note:: You do not need :opt:`allow_remote_control` to use these mappings,
|
||||
as they are not actual remote programs, but are simply a way to reuse the
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# sphinx-inline-tabs breaks with sphinx >= 9
|
||||
sphinx <= 8.2.3
|
||||
sphinx
|
||||
furo
|
||||
sphinx-copybutton
|
||||
sphinxext-opengraph
|
||||
sphinx-inline-tabs
|
||||
sphinx-autobuild
|
||||
matplotlib
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 94 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 110 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 304 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 290 KiB |
@@ -1,377 +0,0 @@
|
||||
.. _sessions:
|
||||
|
||||
Sessions
|
||||
=============
|
||||
|
||||
kitty has robust support for sessions. A session is basically a simple text
|
||||
file where you can define kitty windows, tabs and what programs to run in them
|
||||
as well as how to layout the windows. kitty also supports actions to easily
|
||||
:ac:`create and switch between existing sessions <goto_session>`, so that you
|
||||
can move seamlessly from working on one project to another with a couple of keystrokes.
|
||||
|
||||
Let's see a quick example to get a feel of how easy it is to create sessions. First,
|
||||
a session file to develop a project:
|
||||
|
||||
.. code-block:: session
|
||||
|
||||
# Set the layout for the current tab
|
||||
layout tall
|
||||
# Set the working directory for windows in the current tab
|
||||
cd ~/path/to/myproject
|
||||
# Create the "main" window and run an editor in it to edit the project files
|
||||
launch --title "Edit My Project" /usr/bin/nvim
|
||||
# Create a side window to run a shell to build or test project
|
||||
launch --title "Build My Project"
|
||||
# Create another side window to keep an eye on some useful log file
|
||||
launch --title "Log for my project" /usr/bin/tail -f /path/to/project/log/file
|
||||
|
||||
Save this file as :file:`~/path/to/myproject/launch.kitty-session`. Now when
|
||||
you want to work on the project, simply run:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
kitty --session ~/path/to/myproject/launch.kitty-session
|
||||
|
||||
You can also set the session in :file:`kitty.conf` via :opt:`startup_session`.
|
||||
|
||||
Thus, it is very easy to create sessions and work on projects. To learn how to
|
||||
create more complex sessions, see :ref:`complex_sessions`.
|
||||
|
||||
|
||||
.. _goto_session:
|
||||
|
||||
Creating/Switching to sessions with a keypress
|
||||
------------------------------------------------
|
||||
|
||||
If you like to manage multiple sessions within a single terminal and
|
||||
easily swap between them, kitty has you covered. You can use the
|
||||
:ac:`goto_session` action in kitty.conf, like this:
|
||||
|
||||
.. code-block:: conf
|
||||
|
||||
# Press F7 and then c to jump to the "cool" project
|
||||
map f7>c goto_session ~/path/to/cool/cool.kitty-session
|
||||
# Press F7 and then h to jump to the "hot" project
|
||||
map f7>h goto_session ~/path/to/hot/hot.kitty-session
|
||||
# Browse and select from the list of known projects defined via goto_session commands
|
||||
map f7>/ goto_session
|
||||
# Browse and select from the list of active projects defined via goto_session commands
|
||||
map f7>/ goto_session --active-only [=no]
|
||||
# Same as above, but the sessions are listed alphabetically instead of by most recent
|
||||
map f7>/ goto_session --sort-by=alphabetical
|
||||
# Browse session files inside a directory and pick one
|
||||
map f7>p goto_session ~/.local/share/kitty/sessions
|
||||
# Go to the previously active session (larger negative numbers jump further back in history)
|
||||
map f7>- goto_session -1
|
||||
|
||||
In this manner you can define as many projects/sessions as you like and easily
|
||||
switch between them with a keypress.
|
||||
|
||||
When a directory path is supplied to :ac:`goto_session`, kitty scans it for
|
||||
files ending in ``.kitty-session``, ``.kitty_session`` or ``.session`` and
|
||||
presents an interactive list. The ``--sort-by`` option controls the ordering of that list just like it does
|
||||
for globally known sessions.
|
||||
|
||||
You can also close sessions using the :ac:`close_session` action, which closes
|
||||
all windows in the session with a single keypress.
|
||||
|
||||
|
||||
Displaying the currently active session name
|
||||
----------------------------------------------
|
||||
|
||||
You can display the name of the currently active session file in the kitty tab
|
||||
bar using :opt:`tab_title_template`. For example, using the value::
|
||||
|
||||
{session_name} {title}
|
||||
|
||||
will show you the name of the session file the current tab was loaded from, as
|
||||
well as the normal tab title. Or alternatively, you can set the tab title
|
||||
directly to a project name in the session file itself when creating the tab,
|
||||
like this::
|
||||
|
||||
new_tab My Project Name
|
||||
|
||||
.. _complex_sessions:
|
||||
|
||||
More complex sessions
|
||||
-------------------------
|
||||
|
||||
If you want to create more complex sessions, with sophisticated layouts, such
|
||||
as :ref:`splits_layout`, the easiest way is to set up the state you want to
|
||||
save manually by first starting kitty like this:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
kitty -o 'map f1 save_as_session --use-foreground-process --relocatable'
|
||||
|
||||
Now create whatever splits and tabs you need and start whatever programs such
|
||||
as editors, REPLs, debuggers, etc. you want to start in each of them. Once
|
||||
kitty is the way you want it, press the :kbd:`F1` key, and you will be prompted
|
||||
for a path at which to save the session file. Specify the path and the session
|
||||
will be saved there with the exact setup you created. The saved file will even
|
||||
be opened in your editor for you to review, automatically.
|
||||
|
||||
.. tip::
|
||||
If you want session files to be saved to a specific directory regardless of
|
||||
your current working directory, use the ``--base-dir`` option. For example::
|
||||
|
||||
map f7>s save_as_session --use-foreground-process --base-dir ~/.local/share/kitty/sessions
|
||||
|
||||
This is particularly useful when kitty is launched from system-wide shortcuts
|
||||
where the working directory might not be your home directory. Note that
|
||||
``--relocatable`` is typically not used with ``--base-dir``, since relocatable
|
||||
is meant for session files that are co-located with their project directories.
|
||||
|
||||
If instead, you want to create these by hand, see the example below which shows
|
||||
all the major keywords you can use in kitty session files:
|
||||
|
||||
.. code-block:: session
|
||||
|
||||
# Set the layout for the current tab
|
||||
layout tall
|
||||
# Set the working directory for windows in the current tab. Relative paths
|
||||
# are resolved with respect to the location of this session file.
|
||||
cd ~
|
||||
# Create a window and run the specified command in it
|
||||
launch zsh
|
||||
# Create a window with some environment variables set and run vim in it
|
||||
launch --env FOO=BAR vim
|
||||
# Set the title for the next window
|
||||
launch --title "Chat with x" irssi --profile x
|
||||
# Run a short lived command and see its output
|
||||
launch --hold message-of-the-day
|
||||
|
||||
# Create a new tab
|
||||
# The part after new_tab is the optional tab title which will be displayed in
|
||||
# the tab bar, if omitted, the title of the active window will be used instead.
|
||||
new_tab my tab
|
||||
cd somewhere
|
||||
# Set the layouts allowed in this tab
|
||||
enabled_layouts tall,stack
|
||||
# Set the current layout
|
||||
layout stack
|
||||
launch zsh
|
||||
|
||||
# Create a new OS window
|
||||
# Any definitions specified before the first new_os_window will apply to first OS window.
|
||||
new_os_window
|
||||
# Set new window size to 80x24 cells
|
||||
os_window_size 80c 24c
|
||||
# Set the --title for the new OS window
|
||||
os_window_title my fancy os window
|
||||
# Set the --class for the new OS window
|
||||
os_window_class mywindow
|
||||
# Set the --name for the new OS window
|
||||
os_window_name myname
|
||||
# Change the OS window state to normal, fullscreen, maximized or minimized
|
||||
os_window_state normal
|
||||
launch sh
|
||||
# Resize the current window (see the resize_window action for details)
|
||||
resize_window wider 2
|
||||
# Make the current window the active (focused) window in its tab
|
||||
focus
|
||||
# Make the current OS Window the globally active window
|
||||
focus_os_window
|
||||
launch emacs
|
||||
|
||||
# Create another tab
|
||||
new_tab logs
|
||||
launch tail -f /var/log/syslog
|
||||
|
||||
# Focus the first tab (index 0) when the session loads
|
||||
# You can also use a match expression like: focus_tab title:logs
|
||||
focus_tab 0
|
||||
|
||||
# Create a complex layout using multiple splits. Creates two columns of
|
||||
# windows with two windows in each column. The windows in the first column are
|
||||
# split 50:50. In the second column the windows are not evenly split.
|
||||
new_tab complex tab
|
||||
layout splits
|
||||
# First window, set a user variable on it so we can focus it later
|
||||
launch --var window=first
|
||||
# Create the second column by splitting the first window vertically
|
||||
launch --location=vsplit
|
||||
# Create the third window in the second column by splitting the second window horizontally
|
||||
# Make it take 40% of the height instead of 50%
|
||||
launch --location=hsplit --bias=40
|
||||
# Go back to focusing the first window, so that we can split it
|
||||
focus_matching_window var:window=first
|
||||
# Create the final window in the first column
|
||||
launch --location=hsplit
|
||||
|
||||
|
||||
.. note::
|
||||
The :doc:`launch <launch>` command when used in a session file cannot create
|
||||
new OS windows, or tabs.
|
||||
|
||||
.. note::
|
||||
Environment variables of the form :code:`${NAME}` or :code:`$NAME` are
|
||||
expanded in the session file, except in the *arguments* (not options) to the
|
||||
launch command. For example:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
launch --cwd=$THIS_IS_EXPANDED some-program $THIS_IS_NOT_EXPANDED
|
||||
|
||||
|
||||
Making newly created windows join an existing session
|
||||
---------------------------------------------------------
|
||||
|
||||
Normally, after activating a session, if you create new windows/tabs
|
||||
they don't belong to the session. If you would prefer to have them belong
|
||||
to the currently active session, you can use the :ac:`new_window_with_cwd`
|
||||
and :ac:`new_tab_with_cwd` actions instead, like this::
|
||||
|
||||
map kitty_mod+enter new_window_with_cwd
|
||||
map kitty_mod+t new_tab_with_cwd
|
||||
map kitty_mod+n new_os_window_with_cwd
|
||||
|
||||
This will cause newly created windows and tabs to belong to the currently active
|
||||
session, if any. Note that adding a window to a session in this way is
|
||||
temporary, it does not edit the session file. If you wish to update the
|
||||
session file of the currently active session, you can use the following
|
||||
mapping for it::
|
||||
|
||||
map f5 save_as_session --relocatable --use-foreground-process --match=session:. .
|
||||
|
||||
The two can be combined, using the :ac:`combine` action.
|
||||
For even more control of what session a window is added to use
|
||||
the :doc:`launch <launch>` command with the :option:`launch --add-to-session`
|
||||
flag.
|
||||
|
||||
|
||||
Sessions with remote connections
|
||||
-------------------------------------
|
||||
|
||||
If you use the :doc:`ssh kitten </kittens/ssh>` to connect to remote computers,
|
||||
:ac:`save_as_session` is smart enough to save the ssh kitten invocation to your
|
||||
session file, preserving the remote working directory and even the currently
|
||||
running program on the remote host! Try it, run kitty with::
|
||||
|
||||
kitty -o 'map f1 save_as_session --use-foreground-process --relocatable' --session <(echo "layout vertical\nlaunch\nlaunch")
|
||||
|
||||
Now in both windows, run::
|
||||
|
||||
kitten ssh localhost
|
||||
|
||||
To connect them both to a remote computer (replace ``localhost`` with another
|
||||
computer if you like). In one window change the directory to /tmp and in the
|
||||
other start some program. Then press :kbd:`F1` to save the session file.
|
||||
When you run the session file in another kitty instance you will see both
|
||||
windows re-created, as expected with the correct working directories and
|
||||
running programs.
|
||||
|
||||
Managing multi tab sessions in a single OS Window
|
||||
----------------------------------------------------
|
||||
|
||||
The natural way to organise sessions in kitty is one per :term:`os_window`.
|
||||
However, if you prefer to manage multiple sessions in a single OS Window, you
|
||||
can configure the kitty tab bar to only show tabs that belong to the currently
|
||||
active session. To do so, use :opt:`tab_bar_filter` in :file:`kitty.conf` set::
|
||||
|
||||
tab_bar_filter session:~ or session:^$
|
||||
|
||||
This will restrict the tab bar to only showing tabs from the currently active
|
||||
session as well tabs that do not belong to any session. Furthermore, when you
|
||||
are in a window or tab that does not belong to any session, the tab bar will
|
||||
show the tabs from the most recent active session, to maintain context.
|
||||
|
||||
Keyword reference
|
||||
---------------------
|
||||
|
||||
Below is the list of all supported keywords in session files along with
|
||||
documentation for them.
|
||||
|
||||
``cd [path]``
|
||||
Change the working directory for all windows in the current tab to
|
||||
``path``. Relative paths are resolved with respect to the directory
|
||||
containing the session file.
|
||||
|
||||
``focus``
|
||||
Give keyboard focus to the window created by the previous launch command
|
||||
|
||||
``focus_matching_window``
|
||||
Give keyboard focus to window that matches the specified expression. See
|
||||
:ref:`search_syntax` for the syntax for matching expressions.
|
||||
|
||||
``focus_os_window``
|
||||
Give keyboard focus to the current OS Window. This is guaranteed to work
|
||||
only is some other OS Window in the current kitty process has focus,
|
||||
otherwise the window manager might block changing focus to prevent *focus
|
||||
stealing*.
|
||||
|
||||
``focus_tab [tab specifier]``
|
||||
Set which tab should be active (focused) in the current OS Window. The tab
|
||||
specifier can be either a plain number (treated as a 0-based index) or a
|
||||
match expression. For example, ``focus_tab 0`` will focus the first tab,
|
||||
``focus_tab 1`` the second tab, and ``focus_tab title:logs`` will focus the
|
||||
tab whose title matches "logs". See :ref:`search_syntax` for the full syntax
|
||||
of match expressions. This is useful for session files that create multiple
|
||||
tabs and want to ensure a specific tab is active when the session is loaded.
|
||||
|
||||
``enabled_layouts comma separated list of layout names``
|
||||
Set the layouts allowed in the current tab. Same syntax as
|
||||
:opt:`enabled_layouts`.
|
||||
|
||||
``launch``
|
||||
Create a new window running the specified command or the default shell if
|
||||
no command is specified. See :doc:`launch` for details. Note that creating
|
||||
tabs and OS Windows using launch is not supported in session files, use the
|
||||
dedicated keywords for these.
|
||||
|
||||
``layout name``
|
||||
Set the layout for the current tab to the specified layout, including any
|
||||
specified options, see :doc:`layouts` for the available layouts and
|
||||
options.
|
||||
|
||||
``new_os_window``
|
||||
Create a new OS Window. Any OS window related keywords specified before the
|
||||
first ``new_os_window`` will apply to the first OS Window.
|
||||
|
||||
``new_tab [tab title]``
|
||||
Create a new tab with the specified title. If no title is specified, the
|
||||
title behaves just as for a regular tab in kitty.
|
||||
|
||||
``os_window_title``
|
||||
Set the title for the current OS Window. The OS Window will then always
|
||||
have this title, it will not change based on the title of the currently active
|
||||
window inside the OS Window.
|
||||
|
||||
``os_window_class``
|
||||
Set the class part of WM_CLASS or Wayland Application Id for the current OS Window
|
||||
|
||||
``os_window_name``
|
||||
Set the name part of WM_CLASS or Wayland Window tag for the current OS Window
|
||||
|
||||
``os_window_size``
|
||||
Set the size of the current OS Window, can be specified in pixels or cells.
|
||||
For example: 80c 24c is a window of width 80 cells by 24 cells.
|
||||
|
||||
``os_window_state``
|
||||
Set the state of the current OS Window, can be: ``normal``, ``fullscreen``, ``maximized`` or ``minimized``
|
||||
|
||||
``resize_window``
|
||||
Resize the current window. See the :ac:`resize_window` action for details.
|
||||
For example: resize_window wider 2
|
||||
|
||||
``set_layout_state``
|
||||
This keyword is only used in session files generated by the
|
||||
:ac:`save_as_session` action, it's syntax is undocumented and for internal
|
||||
use only.
|
||||
|
||||
``title``
|
||||
Set the title for the next window. Deprecated, use ``launch --title``
|
||||
instead.
|
||||
|
||||
|
||||
.. _save_as_session:
|
||||
|
||||
The save_as_session action
|
||||
------------------------------
|
||||
|
||||
This action can be mapped to a key press in :file:`kitty.conf`. It will save
|
||||
the currently open OS Windows, tabs, windows, running programs, working
|
||||
directories, etc. into a session file. It is a convenient way to
|
||||
:ref:`complex_sessions`. The options this action takes are documented below.
|
||||
|
||||
.. include:: generated/save-as-session.rst
|
||||
@@ -266,7 +266,7 @@ over SSH when using :doc:`kittens/ssh`.
|
||||
|
||||
The :command:`clone-in-kitty` command takes almost all the same arguments as the
|
||||
:doc:`launch <launch>` command, so you can open a new tab instead or a new OS
|
||||
window, etc. Arguments of launch that that don't
|
||||
window, etc. Arguments of launch that can cause code execution or that don't
|
||||
make sense when cloning are ignored. Most prominently, the following options are
|
||||
ignored: :option:`--allow-remote-control <launch --allow-remote-control>`,
|
||||
:option:`--copy-cmdline <launch --copy-cmdline>`, :option:`--copy-env <launch
|
||||
@@ -313,9 +313,7 @@ window, etc. Not all arguments are supported, see the discussion in the
|
||||
:ref:`clone_shell` section above.
|
||||
|
||||
In order to avoid remote code execution, kitty will only execute the configured
|
||||
editor and pass the file path to edit to it and it will strip all environment
|
||||
variables from the :command:`edit-in-kitty` command line. Additionally, parsing
|
||||
of colors is more limited, reading colors from config files is not allowed.
|
||||
editor and pass the file path to edit to it.
|
||||
|
||||
.. note:: To edit files using sudo the best method is to set the
|
||||
:code:`SUDO_EDITOR` environment variable to ``kitten edit-in-kitty`` and
|
||||
@@ -423,27 +421,19 @@ The protocol used for marking the prompt is very simple. You should consider
|
||||
adding it to your shell as a builtin. Many modern terminals make use of it, for
|
||||
example: kitty, iTerm2, WezTerm, DomTerm
|
||||
|
||||
Just before starting to draw the PS1 prompt send the escape code:
|
||||
|
||||
.. code-block:: none
|
||||
Just before starting to draw the PS1 prompt send the escape code::
|
||||
|
||||
<OSC>133;A<ST>
|
||||
|
||||
Just before starting to draw the PS2 prompt send the escape code:
|
||||
|
||||
.. code-block:: none
|
||||
Just before starting to draw the PS2 prompt send the escape code::
|
||||
|
||||
<OSC>133;A;k=s<ST>
|
||||
|
||||
Just before running a command/program, send the escape code:
|
||||
|
||||
.. code-block:: none
|
||||
Just before running a command/program, send the escape code::
|
||||
|
||||
<OSC>133;C<ST>
|
||||
|
||||
Optionally, when a command is finished its "exit status" can be reported as:
|
||||
|
||||
.. code-block:: none
|
||||
Optionally, when a command is finished its "exit status" can be reported as::
|
||||
|
||||
<OSC>133;D;exit status as base 10 integer<ST>
|
||||
|
||||
@@ -453,42 +443,27 @@ full protocol, that also marks the command region, see `the iTerm2 docs
|
||||
<https://iterm2.com/documentation-escape-codes.html>`_.
|
||||
|
||||
kitty additionally supports several extra fields for the ``<OSC>133;A`` command
|
||||
to control its behavior, separated by semi-colons. They are:
|
||||
to control its behavior, separated by semi-colons. They are::
|
||||
|
||||
|
||||
``redraw=0``
|
||||
this tells kitty that the shell will not redraw the prompt on
|
||||
redraw=0 - this tells kitty that the shell will not redraw the prompt on
|
||||
resize so it should not erase it
|
||||
|
||||
``special_key=1``
|
||||
this tells kitty to use a special key instead of arrow keys
|
||||
special_key=1 - this tells kitty to use a special key instead of arrow keys
|
||||
to move the cursor on mouse click. Useful if arrow keys have side-effects
|
||||
like triggering auto complete. The shell integration script then binds the
|
||||
special key, as needed.
|
||||
|
||||
``k=s``
|
||||
this tells kitty that the secondary (PS2) prompt is starting at the
|
||||
k=s - this tells kitty that the secondary (PS2) prompt is starting at the
|
||||
current line.
|
||||
|
||||
``click_events=1|2``
|
||||
this tells kitty that the shell is capable of handling
|
||||
click_events=1 - this tells kitty that the shell is capable of handling
|
||||
mouse click events. kitty will thus send a click event to the shell when
|
||||
the user clicks somewhere in the prompt. The shell can then move the cursor
|
||||
to that position or perform some other appropriate action. Without this,
|
||||
kitty will instead generate a number of fake key events to move the cursor
|
||||
to the clicked location, which is not fully robust. A value of ``1`` will
|
||||
cause the click events to have absolute y co-ordinates, a value of ``2``
|
||||
will cause them to have y-coordinates relative to the top line of the
|
||||
current prompt. In relative mode, y is zero for cells on the top line of
|
||||
the current prompt. The current prompt here is either the secondary (PS2) or
|
||||
primary prompt. If the secondary prompt is on the same line or above the
|
||||
mouse position, then the reported y will be with respect to that, otherwise
|
||||
with respect to the primary prompt. The click event is encoded in the SGR
|
||||
encoding from xterm.
|
||||
to the clicked location, which is not fully robust.
|
||||
|
||||
kitty also optionally supports sending the cmdline going to be executed with ``<OSC>133;C`` as:
|
||||
|
||||
.. code-block:: none
|
||||
kitty also optionally supports sending the cmdline going to be executed with ``<OSC>133;C`` as::
|
||||
|
||||
<OSC>133;C;cmdline=cmdline encoded by %q<ST>
|
||||
or
|
||||
|
||||
@@ -1,519 +0,0 @@
|
||||
The text sizing protocol
|
||||
==============================================
|
||||
|
||||
.. versionadded:: 0.40.0
|
||||
|
||||
Classically, because the terminal is a grid of equally sized characters, only
|
||||
a single text size was supported in terminals, with one minor exception, some
|
||||
characters were allowed to be rendered in two cells, to accommodate East Asian
|
||||
square aspect ratio characters and Emoji. Here, by single text size we mean the
|
||||
font size of all text on the screen is the same.
|
||||
|
||||
This protocol allows text to be displayed in the terminal in different sizes
|
||||
both larger and smaller than the base text. It also solves the long standing
|
||||
problem of robustly determining the width (in cells) a character should have.
|
||||
Applications can interleave text of different sizes on the screen allowing for
|
||||
typographic niceties like headlines, superscripts, etc.
|
||||
|
||||
Note that this protocol is fully backwards compatible, terminals that implement
|
||||
it will continue to work just the same with applications that do not use it.
|
||||
Because of this, it is not fully flexible in the font sizes it allows, as it
|
||||
still has to work with the character cell grid based fundamental nature of the
|
||||
terminal. Public discussion of this protocol is :iss:`here <8226>`.
|
||||
|
||||
Quickstart
|
||||
--------------
|
||||
|
||||
Using this protocol to display different sized text is very simple, let's
|
||||
illustrate with a few examples to give us a flavor:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
printf "\e]_text_size_code;s=2;Double sized text\a\n\n"
|
||||
printf "\e]_text_size_code;s=3;Triple sized text\a\n\n\n"
|
||||
printf "\e]_text_size_code;n=1:d=2;Half sized text\a\n"
|
||||
|
||||
Note that the last example, of half sized text, has half height characters, but
|
||||
they still each take one cell, this can be fixed with a little more work:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
printf "\e]_text_size_code;n=1:d=2:w=1;Ha\a\e]66;n=1:d=2:w=1;lf\a\n"
|
||||
|
||||
The ``w=1`` mechanism allows the program to tell the terminal what width the text
|
||||
should take. This not only fixes using smaller text but also solves the long
|
||||
standing terminal ecosystem bugs caused by the client program not knowing how
|
||||
many cells the terminal will render some text in.
|
||||
|
||||
|
||||
The escape code
|
||||
-----------------
|
||||
|
||||
There is a single escape code used by this protocol. It is sent by client
|
||||
programs to the terminal emulator to tell it to render the specified text
|
||||
at the specified size. It is an ``OSC`` code of the form::
|
||||
|
||||
<OSC> _text_size_code ; metadata ; text <terminator>
|
||||
|
||||
Here, ``OSC`` is the bytes ``ESC ] (0x1b 0x5b)``. The ``metadata`` is a colon
|
||||
separated list of ``key=value`` pairs. The final part of the escape code is the
|
||||
text which is simply plain text encoded as :ref:`safe_utf8`, the text must be
|
||||
no longer than ``4096`` bytes. Longer strings than that must be broken up into
|
||||
multiple escape codes. Spaces in this definition are for clarity only and
|
||||
should be ignored. The ``terminator`` is either the byte ``BEL (0x7)`` or the
|
||||
bytes ``ESC ST (0x1b 0x5c)``.
|
||||
|
||||
There are only a handful of metadata keys, defined in the table below:
|
||||
|
||||
|
||||
.. csv-table:: The text sizing metadata keys
|
||||
:header: "Key", "Value", "Default", "Description"
|
||||
|
||||
"s", "Integer from 1 to 7", "1", "The overall scale, the text will be rendered in a block of ``s * w`` by ``s`` cells"
|
||||
|
||||
"w", "Integer from 0 to 7", "0", "The width, in cells, in which the text should be rendered. When zero, the terminal should calculate the width as it would for normal text, splitting it up into scaled cells."
|
||||
|
||||
"n", "Integer from 0 to 15", "0", "The numerator for the fractional scale."
|
||||
|
||||
"d", "Integer from 0 to 15", "0", "The denominator for the fractional scale. Must be ``> n`` when non-zero."
|
||||
|
||||
"v", "Integer from 0 to 2", "0", "The vertical alignment to use for fractionally scaled text (n < d). ``0`` - top, ``1`` - bottom, ``2`` - centered"
|
||||
|
||||
"h", "Integer from 0 to 2", "0", "The horizontal alignment to use for fractionally scaled text (n < d). ``0`` - left, ``1`` - right, ``2`` - centered"
|
||||
|
||||
|
||||
How it works
|
||||
------------------
|
||||
|
||||
This protocol works by allowing the client program to tell the terminal to
|
||||
render text in multiple cells. The terminal can then adjust the actual font
|
||||
size used to render the specified text as appropriate for the specified space.
|
||||
|
||||
The space to render is controlled by four metadata keys, ``s (scale)``, ``w (width)``, ``n (numerator)``
|
||||
and ``d (denominator)``. The most important are the ``s`` and ``w`` keys. The text
|
||||
will be rendered in a block of ``s * w`` by ``s`` cells. A special case is ``w=0``
|
||||
(the default), which means the terminal splits up the text into cells as it
|
||||
would normally without this protocol, but now each cell is an ``s by s`` block of
|
||||
cells instead. So, for example, if the text is ``abc`` and ``s=2`` the terminal would normally
|
||||
split it into three cells::
|
||||
|
||||
│a│b│c│
|
||||
|
||||
But, because ``s=2`` it instead gets split as::
|
||||
|
||||
│a░│b░│c░│
|
||||
│░░│░░│░░│
|
||||
|
||||
The terminal multiplies the font size by ``s`` when rendering these
|
||||
characters and thus ends up rendering text at twice the base size.
|
||||
|
||||
When ``w`` is a non-zero value, it specifies the width in scaled cells of the
|
||||
following text. Note that **all** the text in that escape code must be rendered
|
||||
in ``s * w`` cells. When both ``s`` and ``w`` are present, the resulting multicell
|
||||
contains all the text in the escape code rendered in a grid of ``(s * w, s)``
|
||||
cells, i.e. the multicell is ``s*w`` cells wide and ``s`` cells high.
|
||||
|
||||
If the text does not fit, the terminal is free to do whatever it
|
||||
feels is best, including truncating the text or downsizing the font size when
|
||||
rendering it. It is up to client applications to use the ``w`` key wisely and not
|
||||
try to render too much text in too few cells. When sending a string of text
|
||||
with non zero ``w`` to the terminal emulator, the way to do it is to split up the
|
||||
text into chunks that fit in ``w`` cells and send one escape code per chunk. So
|
||||
for the string: ``cool-🐈`` the actual escape codes would be (ignoring the header
|
||||
and trailers)::
|
||||
|
||||
w=1;c w=1;o w=1;o w=1;l w=1;- w=2:🐈
|
||||
|
||||
Note, in particular, how the last character, the cat emoji, ``🐈`` has ``w=2``.
|
||||
In practice client applications can assume that terminal emulators get the
|
||||
width of all ASCII code points correct and use the ``w=0`` form for efficient
|
||||
transmission, so that the above becomes::
|
||||
|
||||
cool- w=2:🐈
|
||||
|
||||
The use of non-zero ``w`` should mainly be restricted to non-ASCII characters and
|
||||
when using fractional scaling, as described below.
|
||||
|
||||
.. note:: Text sizes specified by scale are relative to the base font size,
|
||||
thus if the base font size is changed, these sizes are changed as well.
|
||||
So if the terminal emulator is using a base font size of ``11pt``, then
|
||||
``s=2`` will be rendered in approximately ``22pt`` (approx. because the
|
||||
terminal may need to slightly adjust font size to ensure it fits as not all
|
||||
fonts scale sizes linearly). If the user changes the base font size of the
|
||||
terminal emulator to ``12pt`` then the scaled font size becomes ``~24pt``
|
||||
and so on.
|
||||
|
||||
|
||||
Fractional scaling
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Using the main scale parameter (``s``) gives us only 7 font sizes. Fortunately,
|
||||
this protocol allows specifying fractional scaling, fractional scaling is
|
||||
applied on top of the main scale specified by ``s``. It allows niceties like:
|
||||
|
||||
* Normal sized text but with half a line of blank space above and half a line below (``s=2:n=1:d=2:v=2``)
|
||||
* Superscripts (``n=1:d=2``)
|
||||
* Subscripts (``n=1:d=2:v=1``)
|
||||
* ...
|
||||
|
||||
The fractional scale **does not** affect the number of cells the text occupies,
|
||||
instead, it just adjusts the rendered font size within those cells.
|
||||
The fraction is specified using an integer numerator and denominator (``n`` and
|
||||
``d``). In addition, by using the ``v`` key one can vertically align the
|
||||
fractionally scaled render area at top, bottom or middle. Similarly, the ``h`` key
|
||||
does horizontal alignment — left, right or centered. Note that alignment
|
||||
here is not actual text alignment, it refers to how the fractionally scaled
|
||||
render area fits inside the full render area of size ``s * w`` by ``s`` cells.
|
||||
Thus, alignment only applies when ``n < d``.
|
||||
|
||||
When using fractional scaling one often wants to fit more than a single
|
||||
character per cell. To accommodate that, there is the ``w`` key. This specifies
|
||||
the number of cells in which to render the text. For example, for a superscript
|
||||
one would typically split the string into pairs of characters and use the
|
||||
following for each pair::
|
||||
|
||||
OSC _text_size_code ; n=1:d=2:w=1 ; ab <terminator>
|
||||
... repeat for each pair of characters
|
||||
|
||||
|
||||
Fixing the character width issue for the terminal ecosystem
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Terminals create user interfaces using text displayed in a cell grid. For
|
||||
terminal software that creates sophisticated user interfaces it is particularly
|
||||
important that the client program running in the terminal and the terminal
|
||||
itself agree on how many cells a particular string should be rendered in. If
|
||||
the two disagree, then the entire user interface can be broken, leading to
|
||||
catastrophic failures.
|
||||
|
||||
Fundamentally, this is a co-ordination problem. Both the client program and the
|
||||
terminal have to somehow share the same database of character properties and
|
||||
the same algorithm for computing string lengths in cells based on that shared
|
||||
database. Sadly, there is no such shared database in reality. The closest we
|
||||
have is the Unicode standard. Unfortunately, the Unicode standard has a new
|
||||
version almost every year and actually changes the width assigned to some
|
||||
characters in different versions. Furthermore, to actually get the "correct"
|
||||
width for a string using that standard one has to do grapheme segmentation,
|
||||
which is a :ref:`complex algorithm, specified below <gseg>`.
|
||||
Expecting all terminals and all terminal programs to have both up-to-date
|
||||
character databases and a bug free implementation of this algorithm is not
|
||||
realistic.
|
||||
|
||||
So instead, this protocol solves the issue robustly by removing the
|
||||
co-ordination problem and putting only one actor in charge of determining
|
||||
string width. The client becomes responsible for doing whatever level of
|
||||
grapheme segmentation it is comfortable with using whatever Unicode database is
|
||||
at its disposal and then it can transmit the segmented string to the terminal
|
||||
with the appropriate ``w`` values so that the terminal renders the text in the
|
||||
exact number of cells the client expects.
|
||||
|
||||
.. note::
|
||||
It is possible for a terminal to implement only the width part of this spec
|
||||
and ignore the scale part. This escape code works with only the `w` key as
|
||||
well, as a means of specifying how many cells each piece of text occupies.
|
||||
In such cases ``s`` defaults to 1.
|
||||
See the section on :ref:`detect_text_sizing` on how client applications can
|
||||
query for terminal emulator support.
|
||||
|
||||
|
||||
Wrapping and overwriting behavior
|
||||
-------------------------------------
|
||||
|
||||
If the multicell block (``s * w by s`` cells) is larger than the screen size in either
|
||||
dimension, the terminal must discard the character. Note that in particular
|
||||
this means that resizing a terminal screen so that it is too small to fit a
|
||||
multicell character can cause the character to be lost.
|
||||
|
||||
When drawing a multicell character, if wrapping is enabled (DECAWM is set) and
|
||||
the character's width (``s * w``) does not fit on the current line, the cursor is
|
||||
moved to the start of the next line and the character is drawn there.
|
||||
If wrapping is disabled and the character's width does not fit on the current
|
||||
line, the cursor is moved back as far as needed to fit ``s * w`` cells and then
|
||||
the character is drawn, following the overwriting rules described below.
|
||||
|
||||
When drawing text either normal text or text specified via this escape code,
|
||||
and this text would overwrite an existing multicell character, the following
|
||||
rules must be followed, in decreasing order of precedence:
|
||||
|
||||
#. If the text is a combining character it is added to the existing multicell
|
||||
character
|
||||
#. If the text will overwrite the top-left cell of the multicell character, the
|
||||
entire multicell character must be erased
|
||||
#. If the text will overwrite any cell in the topmost row of the multicell
|
||||
character, the entire multicell character must be replaced by spaces (this
|
||||
rule is present for backwards compatibility with how overwriting works for
|
||||
wide characters)
|
||||
#. If the text will overwrite cells from a row after the first row, then cursor should be moved past the
|
||||
cells of the multicell character on that row and only then the text should be
|
||||
written. Note that this behavior is independent of the value of DECAWM. This
|
||||
is done for simplicity of implementation.
|
||||
|
||||
The skipping behavior of the last rule can be complex requiring the terminal to
|
||||
skip over lots of cells, but it is needed to allow wrapping in the presence of
|
||||
multicell characters that extend over more than a single line.
|
||||
|
||||
.. _detect_text_sizing:
|
||||
|
||||
Detecting if the terminal supports this protocol
|
||||
-----------------------------------------------------
|
||||
|
||||
To detect support for this protocol use the `CPR (Cursor Position Report)
|
||||
<https://vt100.net/docs/vt510-rm/CPR.html>`__ escape code. Send a ``CR``
|
||||
(carriage return) followed by ``CPR`` followed by ``\e]_text_size_code;w=2; \a``
|
||||
which will draw a space character in two cells, followed by another ``CPR``.
|
||||
Then send ``\e]_text_size_code;s=2; \a`` which will draw a space in a ``2 by 2``
|
||||
block of cells, followed by another ``CPR``.
|
||||
|
||||
Then wait for the three responses from the terminal to the three CPR queries.
|
||||
If the cursor position in the three responses is the same, the terminal does
|
||||
not support this protocol at all, if the second response has the cursor
|
||||
moved by two cells, then the width part is supported and if the third response has the
|
||||
cursor moved by another two cells, then the scale part is supported.
|
||||
|
||||
|
||||
Interaction with other terminal controls
|
||||
--------------------------------------------------
|
||||
|
||||
This protocol does not change the character grid based nature of the terminal.
|
||||
Most terminal controls assume one character per cell so it is important to
|
||||
specify how these controls interact with the multicell characters created by
|
||||
this protocol.
|
||||
|
||||
Cursor movement
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Cursor movement is unaffected by multicell characters, all cursor movement
|
||||
commands move the cursor position by single cell increments, as has always been
|
||||
the case for terminals. This means that the cursor can be placed at any
|
||||
individual single cell inside a larger multicell character.
|
||||
|
||||
When a multicell character is created using this protocol, the cursor moves
|
||||
`s * w` cells to the right, in the same row it was in.
|
||||
|
||||
Terminals *should* display a large cursor covering the entire multicell block
|
||||
when the actual cursor position is on any cell within the block. Block cursors
|
||||
cover all the cells of the multicell character, bar cursors appear in all the
|
||||
cells in the first column of the character and so on.
|
||||
|
||||
|
||||
Editing controls
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are many controls used to edit existing screen content such as
|
||||
inserting characters, deleting characters and lines, etc. These were all
|
||||
originally specified for the one character per cell paradigm. Here we specify
|
||||
their interactions with multicell characters.
|
||||
|
||||
**Insert characters** (``CSI @`` aka ``ICH``)
|
||||
When inserting ``n`` characters at cursor position ``x, y`` all characters
|
||||
after ``x`` on line ``y`` are supposed to be right shifted. This means
|
||||
that any multi-line character that intersects with the cells on line ``y`` at ``x``
|
||||
and beyond must be erased. Any single line multicell character that is
|
||||
split by the cells at ``x`` and ``x + n - 1`` must also be erased.
|
||||
|
||||
**Delete characters** (``CSI P`` aka ``DCH``)
|
||||
When deleting ``n`` characters at cursor position ``x, y`` all characters
|
||||
after ``x`` on line ``y`` are supposed to be left shifted. This means
|
||||
that any multi-line character that intersects with the cells on line ``y`` at ``x``
|
||||
and beyond must be erased. Any single line multicell character that is
|
||||
split by the cells at ``x`` and ``x + n - 1`` must also be erased.
|
||||
|
||||
**Erase characters** (``CSI X`` aka ``ECH``)
|
||||
When erasing ``n`` characters at cursor position ``x, y`` the ``n`` cells
|
||||
starting at ``x`` are supposed to be cleared. This means that any multicell
|
||||
character that intersects with the ``n`` cells starting at ``x`` must be
|
||||
erased.
|
||||
|
||||
**Erase display** (``CSI J`` aka ``ED``)
|
||||
Any multicell character intersecting with the erased region of the screen
|
||||
must be erased. When using mode ``22`` the contents of the screen are first
|
||||
copied into the history, including all multicell characters.
|
||||
|
||||
**Erase in line** (``CSI K`` aka ``EL``)
|
||||
Works just like erase characters above. Any multicell character
|
||||
intersecting with the erased cells in the line is erased.
|
||||
|
||||
**Insert lines** (``CSI L`` aka ``IL``)
|
||||
When inserting ``n`` lines at cursor position ``y`` any multi-line
|
||||
characters that are split at the line ``y`` must be erased. A split happens
|
||||
when the second or subsequent row of the multi-line character is on the line
|
||||
``y``. The insertion causes ``n`` lines to be removed from the bottom of
|
||||
the screen, any multi-line characters are split at the bottom of the screen
|
||||
must be erased. A split is when any row of the multi-line character except
|
||||
the last row is on the last line of the screen after the insertion of ``n``
|
||||
lines.
|
||||
|
||||
**Delete lines** (``CSI M`` aka ``DL``)
|
||||
When deleting ``n`` lines at cursor position ``y`` any multicell character
|
||||
that intersects the deleted lines must be erased.
|
||||
|
||||
|
||||
.. _gseg:
|
||||
|
||||
The algorithm for splitting text into cells
|
||||
------------------------------------------------
|
||||
|
||||
.. note::
|
||||
kitty comes with a utility to test terminal compliance with this algorithm.
|
||||
Install kitty and run: ``kitten __width_test__`` in any terminal to test it.
|
||||
This uses tests published by the Unicode consortium, `GraphemeBreakTest.txt
|
||||
<https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt>`__.
|
||||
|
||||
.. warning::
|
||||
This algorithm is under public discussion in :iss:`8533`. If serious issues
|
||||
are brought to light in that discussion, there may be small changes to the
|
||||
algorithm to address them. Additionally, in the future if the Unicode standard
|
||||
changes in ways that affect this algorithm, it will be updated. Currently the
|
||||
algorithm is based on Unicode version 16.
|
||||
|
||||
Here, we specify how a terminal must split up text into cells, where a cell is
|
||||
a width one unit in the character grid the terminal displays.
|
||||
|
||||
The basis for the algorithm is the
|
||||
`Grapheme segmentation algorithm <https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries>`__
|
||||
from the Unicode standard. However, that algorithm alone is insufficient to
|
||||
fully specify text handling for terminals. The full algorithm is specified below.
|
||||
|
||||
A terminal using this algorithm must decode the bytes they receive
|
||||
into Unicode scalar values (i.e., code points except surrogates) using UTF-8.
|
||||
When it encounters any UTF-8 ill-formed subsequences,
|
||||
it must be replace each
|
||||
`maximal subpart of the ill-formed subsequence <https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-3/#G66453>`__
|
||||
with a :code:`U+FFFD REPLACEMENT CHARACTER` (<28>).
|
||||
|
||||
For each decoded code point:
|
||||
|
||||
#. First check if the code point is an ASCII control code, and handle it
|
||||
appropriately. ASCII control codes are the code points less than :code:`U+0032` and the
|
||||
code point :code:`U+0127 DEL`. The code point :code:`U+0000 NUL` must be discarded.
|
||||
|
||||
#. Next, check if the code point is *invalid*, and if it is, discard it
|
||||
and finish processing. Invalid code points are code points with Unicode category :code:`Cc or Cs`
|
||||
and 66 additional code points: :code:`[0xfdd0, 0xfdef]`, :code:`[0xfffe, 0x10ffff-1, 0x10000]`
|
||||
and :code:`[0xffff, 0x10ffff, 0x10000]`.
|
||||
|
||||
#. Next, check if there is a previous cell before the
|
||||
current cursor position. This means either the cursor is at x > 0 in which
|
||||
case the previous cell is at x-1 on the same line, or the previous cell is
|
||||
the last cell of the previous line, provided there is no line break
|
||||
between the previous and current lines.
|
||||
|
||||
#. Next, calculate the width in cells of the received code point,
|
||||
which can be 0, 1, or 2 depending on the code point properties in
|
||||
the Unicode standard.
|
||||
|
||||
#. If there is no previous cell and the code point's width is zero,
|
||||
the code point is discarded and its processing is finished.
|
||||
|
||||
#. If there is a previous cell, the
|
||||
`Grapheme segmentation algorithm UAX29-C1-1 <https://www.unicode.org/reports/tr29/#C1-1>`__
|
||||
is used to determine if there is a grapheme boundary between the previous cell
|
||||
and the current code point.
|
||||
|
||||
#. If there is no boundary, the current code point is added to the previous
|
||||
cell and processing of the code point is finished. See the :ref:`var_select`
|
||||
section below for handling of Unicode Variation selectors.
|
||||
|
||||
#. If there is a boundary, but the width of the current code point is zero,
|
||||
it is added to the previous cell and processing is finished.
|
||||
|
||||
#. The code point is added to the current cell and the cursor is moved forward
|
||||
(right) by either 1 or 2 cells depending on the width of the code point.
|
||||
|
||||
|
||||
It remains to specify how to calculate the width in cells of a code point.
|
||||
To do this, code points are divided into various classes, as
|
||||
described by the rules below, in order of decreasing priority:
|
||||
|
||||
.. note::
|
||||
Notation: :code:`[start, stop, step]` means the integers from :code:`start`
|
||||
to :code:`stop` in increments of :code:`step`. When the step is not
|
||||
specified, it defaults to one.
|
||||
|
||||
#. *Regional indicators*: 26 code points starting at :code:`0x1F1E6`. These all
|
||||
have width 2
|
||||
|
||||
#. *Doublewidth*: Parse `EastAsianWidth.txt
|
||||
<https://www.unicode.org/Public/UCD/latest/ucd/EastAsianWidth.txt>`__ from
|
||||
the Unicode standard. All code points marked :code:`W` or :code:`F` have
|
||||
width two. All code points in the following ranges have width two *unless*
|
||||
they are marked as :code:`A` in :code:`EastAsianWidth.txt`: :code:`[0x3400,
|
||||
0x4DBF], [0x4E00, 0x9FFF], [0xF900, 0xFAFF], [0x20000, 0x2FFFD], [0x30000, 0x3FFFD]`
|
||||
|
||||
#. *Wide emoji*: Parse `emoji-sequences.txt
|
||||
<https://www.unicode.org/Public/emoji/latest/emoji-sequences.txt>`__ from
|
||||
the Unicode standard. All :code:`Basic_Emoji` have width two unless they are
|
||||
followed by :code:`FE0F` in the file. The leading codepoints in all
|
||||
:code:`RGI_Emoji_Modifier_Sequence` and :code:`RGI_Emoji_Tag_Sequence` have width two.
|
||||
All code points in :code:`RGI_Emoji_Flag_Sequence` have width two.
|
||||
|
||||
#. *Marks*: These are all zero width code points. They are code points with Unicode
|
||||
categories whose first letter is :code:`M` or :code:`S`. Additionally,
|
||||
code points with Unicode category: :code:`Cf`. Finally, they include
|
||||
all modifier code points from :code:`RGI_Emoji_Modifier_Sequence` in the
|
||||
*Wide emoji* rule above.
|
||||
|
||||
#. All remaining code points have a width of one cell.
|
||||
|
||||
.. _var_select:
|
||||
|
||||
Unicode variation selectors
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are two code points (:code:`U+FE0E` and :code:`U+FE0F`) that can actually
|
||||
`alter the width of the previous code point <https://www.unicode.org/reports/tr11/#ED4>`__
|
||||
by changing their presentation between ``Emoji_Presentation`` and ``Text_Presentation``.
|
||||
When adding a code point to the previous cell these have to be handled specially.
|
||||
|
||||
``U+FE0E`` - Variation Selector 15
|
||||
When the previous cell has width two and the last code point in the previous
|
||||
cell is one of the ``Basic_Emoji`` code points from the *Wide emoji* rule above
|
||||
that is *not* followed by ``FEOF`` then the width of the previous cell is
|
||||
decreased to one.
|
||||
|
||||
``U+FE0F`` - Variation Selector 16
|
||||
When the previous cell has width one and the last code point in the previous
|
||||
cell is one of the ``Basic_Emoji`` code points from the *Wide emoji* rule above
|
||||
that is followed by ``FEOF`` then the width of the
|
||||
previous cell is increased to two.
|
||||
|
||||
Note that the rule for ``U+FE0E`` is particularly problematic for terminals as
|
||||
it means that the width of a string cannot be determined without knowing the
|
||||
width of the screen it will be rendered on. This is because when there is only
|
||||
one cell left on the current line and a wide emoji is received it wraps onto
|
||||
the next line. If subsequently a ``U+FE0E`` is received, the emoji becomes one
|
||||
cell wide but it is *not* moved back to the previous line.
|
||||
|
||||
To avoid this issue, it is recommended applications detect when ``U+FE0E`` is
|
||||
present and in such cases use the width part of the text sizing protocol
|
||||
to control rendering. Alternately, applications can segment text into graphemes
|
||||
and given a list of graphemes and their widths it is possible to write a simple
|
||||
function that will output them to the terminal so as to avoid this issue. Below
|
||||
is such a function in the Python language:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Grapheme:
|
||||
text: str
|
||||
width: int
|
||||
|
||||
def output_one_line(iterator_over_graphemes):
|
||||
' Output graphemes so that they affect exactly wcswidth cells only (works for >= 2 graphemes) '
|
||||
graphemes = tuple(iterator_over_graphemes)
|
||||
if not graphemes:
|
||||
return
|
||||
yield graphemes[0].text
|
||||
for i in range(1, len(graphemes)):
|
||||
g = graphemes[i]
|
||||
if g is graphemes[-1]:
|
||||
prev_g = graphemes[i-1]
|
||||
yield f'\x1b[{prev_g.width}D' # move cursor back
|
||||
yield g.text
|
||||
yield f'\x1b[{g.width}D' # move cursor back
|
||||
yield f'\x1b[{prev_g.width}@' # insert cells
|
||||
yield prev_g.text
|
||||
yield f'\x1b[{g.width}C' # move cursor forward
|
||||
|
||||
Then, using ``wcswidth()`` the application can split long text into lines of
|
||||
width no more than the screen width and use the above function to write each
|
||||
line to the terminal robustly.
|
||||
@@ -1,82 +0,0 @@
|
||||
Wide gamut color formats
|
||||
=========================
|
||||
|
||||
kitty supports modern wide gamut color formats for precise color specification.
|
||||
These formats can be used anywhere a color value is accepted in the configuration
|
||||
(foreground, background, color0-color255, etc.).
|
||||
|
||||
OKLCH Colors
|
||||
------------
|
||||
|
||||
OKLCH is a perceptually uniform color space, ideal for creating color themes.
|
||||
The format is::
|
||||
|
||||
foreground oklch(0.9 0.05 140)
|
||||
color1 oklch(0.7 0.25 25)
|
||||
|
||||
Parameters:
|
||||
|
||||
- **L** (Lightness): 0 to 1, where 0 is black and 1 is white
|
||||
- **C** (Chroma): 0 to approximately 0.4, represents color saturation
|
||||
- **H** (Hue): 0 to 360 degrees (0=red, 120=green, 240=blue)
|
||||
|
||||
Benefits:
|
||||
|
||||
- Perceptually uniform - equal changes produce equal perceived differences
|
||||
- Adjusting lightness preserves hue (unlike HSL)
|
||||
- Industry standard for modern color design
|
||||
|
||||
Example::
|
||||
|
||||
foreground oklch(0.9 0.05 140)
|
||||
color1 oklch(0.65 0.25 29) # Vibrant red-orange
|
||||
color2 oklch(0.65 0.25 142) # Vibrant green
|
||||
color3 oklch(0.70 0.19 90) # Warm yellow
|
||||
|
||||
CIE LAB Colors
|
||||
--------------
|
||||
|
||||
CIE LAB is a device-independent color space designed to approximate human vision.
|
||||
|
||||
The format is::
|
||||
|
||||
background lab(20 5 -10)
|
||||
color4 lab(50 0 -50)
|
||||
|
||||
Parameters:
|
||||
|
||||
- **L**: Lightness, 0 to 100 (0 = black, 100 = white)
|
||||
- **a**: Green (-) to red (+), typically -100 to +100
|
||||
- **b**: Blue (-) to yellow (+), typically -100 to +100
|
||||
|
||||
Example::
|
||||
|
||||
background lab(10 0 0) # Very dark neutral gray
|
||||
foreground lab(90 0 0) # Very light neutral gray
|
||||
color1 lab(50 60 40) # Red
|
||||
color4 lab(50 0 -50) # Blue
|
||||
|
||||
Gamut Mapping
|
||||
-------------
|
||||
|
||||
When you specify colors in OKLCH or CIE LAB formats that are outside the sRGB
|
||||
color gamut, kitty automatically converts them using the CSS Color Module Level 4
|
||||
gamut mapping algorithm:
|
||||
|
||||
- Preserves the original lightness and hue as much as possible
|
||||
- Reduces chroma (saturation) until the color fits within the displayable range
|
||||
- Uses perceptual color difference (deltaE OK) to minimize visible changes
|
||||
- Maximizes color saturation while staying in gamut
|
||||
|
||||
This ensures that wide gamut colors gracefully degrade on standard sRGB displays while
|
||||
taking full advantage of wide gamut displays when available. The mapping happens
|
||||
automatically - you don't need to do anything special.
|
||||
|
||||
For example, :code:`oklch(0.7 0.4 25)` might be too saturated for sRGB but will be
|
||||
automatically adjusted to fit while preserving the perceived hue and lightness.
|
||||
|
||||
References
|
||||
----------
|
||||
|
||||
- `CSS Color Module Level 4 <https://www.w3.org/TR/css-color-4/>`_
|
||||
- `OKLCH Color Space <https://bottosson.github.io/posts/oklab/>`_
|
||||
27
embeds.go
27
embeds.go
@@ -1,27 +0,0 @@
|
||||
package kitty
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
//go:embed logo/kitty.png
|
||||
var KittyLogoAsPNGData []byte
|
||||
|
||||
//go:embed kitty_tests/GraphemeBreakTest.json
|
||||
var grapheme_break_test_data []byte
|
||||
|
||||
type GraphemeBreakTest struct {
|
||||
Data []string `json:"data"`
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
func LoadGraphemeBreakTests() (ans []GraphemeBreakTest, err error) {
|
||||
if err := json.Unmarshal(grapheme_break_test_data, &ans); err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse GraphemeBreakTest JSON with error: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -34,9 +34,6 @@ def main(args: list[str]=sys.argv) -> None:
|
||||
elif which == 'cursors':
|
||||
from gen.cursors import main
|
||||
main(args)
|
||||
elif which == 'color-names':
|
||||
from gen.color_names import main
|
||||
main(args)
|
||||
else:
|
||||
raise SystemExit(f'Unknown which: {which}')
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ def parse_number(keymap: KeymapType) -> tuple[str, str]:
|
||||
return '; '.join(int_keys), '; '.join(uint_keys)
|
||||
|
||||
|
||||
def cmd_for_report(report_name: str, keymap: KeymapType, type_map: dict[str, Any], payload_allowed: bool, payload_is_base64: bool) -> str:
|
||||
def cmd_for_report(report_name: str, keymap: KeymapType, type_map: dict[str, Any], payload_allowed: bool) -> str:
|
||||
def group(atype: str, conv: str) -> tuple[str, str]:
|
||||
flag_fmt, flag_attrs = [], []
|
||||
cv = {'flag': 'c', 'int': 'i', 'uint': 'I'}[atype]
|
||||
@@ -85,20 +85,12 @@ def cmd_for_report(report_name: str, keymap: KeymapType, type_map: dict[str, Any
|
||||
|
||||
fmt = f'{flag_fmt} {uint_fmt} {int_fmt}'
|
||||
if payload_allowed:
|
||||
ans = [f'REPORT_VA_COMMAND("K s {{{fmt} ss#}}", self->window_id, "{report_name}",\n']
|
||||
ans = [f'REPORT_VA_COMMAND("K s {{{fmt} sI}} y#", self->window_id, "{report_name}", ']
|
||||
else:
|
||||
ans = [f'REPORT_VA_COMMAND("K s {{{fmt}}}", self->window_id, "{report_name}",\n']
|
||||
if flag_attrs:
|
||||
ans.append(f'{flag_attrs},\n')
|
||||
if uint_attrs:
|
||||
ans.append(f'{uint_attrs},\n')
|
||||
if int_attrs:
|
||||
ans.append(f'{int_attrs},\n')
|
||||
ans = [f'REPORT_VA_COMMAND("K s {{{fmt}}}", self->window_id, "{report_name}", ']
|
||||
ans.append(',\n '.join((flag_attrs, uint_attrs, int_attrs)))
|
||||
if payload_allowed:
|
||||
if payload_is_base64:
|
||||
ans.append('"", (char*)parser_buf, g.payload_sz')
|
||||
else:
|
||||
ans.append('"", (char*)parser_buf + payload_start, g.payload_sz')
|
||||
ans.append(', "payload_sz", g.payload_sz, parser_buf, g.payload_sz')
|
||||
ans.append(');')
|
||||
return '\n'.join(ans)
|
||||
|
||||
@@ -110,65 +102,46 @@ def generate(
|
||||
keymap: KeymapType,
|
||||
command_class: str,
|
||||
initial_key: str = 'a',
|
||||
payload_allowed: bool = True,
|
||||
payload_is_base64: bool = True,
|
||||
start_parsing_at: int = 1,
|
||||
field_sep: str = ',',
|
||||
post_init: str = '',
|
||||
payload_allowed: bool = True
|
||||
) -> str:
|
||||
type_map = resolve_keys(keymap)
|
||||
keys_enum = enum(keymap)
|
||||
handle_key = parse_key(keymap)
|
||||
flag_keys = parse_flag(keymap, type_map, command_class)
|
||||
int_keys, uint_keys = parse_number(keymap)
|
||||
report_cmd = cmd_for_report(report_name, keymap, type_map, payload_allowed, payload_is_base64)
|
||||
post_init_line = f'\n {post_init}' if post_init else ''
|
||||
extra_init = ''
|
||||
report_cmd = cmd_for_report(report_name, keymap, type_map, payload_allowed)
|
||||
if payload_allowed:
|
||||
payload_after_value = "case ';': state = PAYLOAD; break;"
|
||||
payload = ', PAYLOAD'
|
||||
if payload_is_base64:
|
||||
payload_case = f'''
|
||||
case PAYLOAD: {{
|
||||
sz = parser_buf_pos - pos;
|
||||
payload_case = f'''
|
||||
case PAYLOAD: {{
|
||||
sz = parser_buf_pos - pos;
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
if (!base64_decode8(parser_buf + pos, sz, parser_buf, &g.payload_sz)) {{
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
if (!base64_decode8(parser_buf + pos, sz, parser_buf, &g.payload_sz)) {{
|
||||
g.payload_sz = MAX(BUF_EXTRA, sz);
|
||||
REPORT_ERROR("Failed to parse {command_class} command payload with error: \
|
||||
invalid base64 data in chunk of size: %zu with output buffer size: %zu", sz, g.payload_sz); return; }}
|
||||
pos = parser_buf_pos;
|
||||
}} break;
|
||||
'''
|
||||
callback = f'{callback_name}(self->screen, &g, parser_buf)'
|
||||
else:
|
||||
payload_case = '''
|
||||
case PAYLOAD: {
|
||||
sz = parser_buf_pos - pos;
|
||||
payload_start = pos;
|
||||
g.payload_sz = sz;
|
||||
pos = parser_buf_pos;
|
||||
} break;
|
||||
'''
|
||||
extra_init = 'size_t payload_start = 0;'
|
||||
callback = f'{callback_name}(self->screen, &g, parser_buf + payload_start)'
|
||||
|
||||
REPORT_ERROR("Failed to parse {command_class} command payload with error: \
|
||||
invalid base64 data in chunk of size: %zu with output buffer size: %zu", sz, g.payload_sz); return; }}
|
||||
pos = parser_buf_pos;
|
||||
}}
|
||||
break;
|
||||
'''
|
||||
callback = f'{callback_name}(self->screen, &g, parser_buf)'
|
||||
else:
|
||||
payload_after_value = payload = payload_case = ''
|
||||
callback = f'{callback_name}(self->screen, &g)'
|
||||
|
||||
return f'''
|
||||
#include "base64.h"
|
||||
|
||||
static inline void
|
||||
{function_name}(PS *self, uint8_t *parser_buf, const size_t parser_buf_pos) {{
|
||||
unsigned int pos = {start_parsing_at};
|
||||
{extra_init}
|
||||
unsigned int pos = 1;
|
||||
enum PARSER_STATES {{ KEY, EQUAL, UINT, INT, FLAG, AFTER_VALUE {payload} }};
|
||||
enum PARSER_STATES state = KEY, value_state = FLAG;
|
||||
{command_class} g = {{0}};{post_init_line}
|
||||
static {command_class} g;
|
||||
unsigned int i, code;
|
||||
uint64_t lcode; int64_t accumulator;
|
||||
bool is_negative; (void)is_negative;
|
||||
bool is_negative;
|
||||
memset(&g, 0, sizeof(g));
|
||||
size_t sz;
|
||||
{keys_enum}
|
||||
enum KEYS key = '{initial_key}';
|
||||
@@ -241,10 +214,10 @@ static inline void
|
||||
case AFTER_VALUE:
|
||||
switch (parser_buf[pos++]) {{
|
||||
default:
|
||||
REPORT_ERROR("Malformed {command_class} control block, expecting a {field_sep} or semi-colon after a value, found: 0x%x",
|
||||
REPORT_ERROR("Malformed {command_class} control block, expecting a comma or semi-colon after a value, found: 0x%x",
|
||||
parser_buf[pos - 1]);
|
||||
return;
|
||||
case '{field_sep}':
|
||||
case ',':
|
||||
state = KEY;
|
||||
break;
|
||||
{payload_after_value}
|
||||
@@ -283,7 +256,7 @@ def write_header(text: str, path: str) -> None:
|
||||
subprocess.check_call(['clang-format', '-i', path])
|
||||
|
||||
|
||||
def parsers() -> None:
|
||||
def graphics_parser() -> None:
|
||||
flag = frozenset
|
||||
keymap: KeymapType = {
|
||||
'a': ('action', flag('tTqpdfac')),
|
||||
@@ -319,37 +292,9 @@ def parsers() -> None:
|
||||
text = generate('parse_graphics_code', 'screen_handle_graphics_command', 'graphics_command', keymap, 'GraphicsCommand')
|
||||
write_header(text, 'kitty/parse-graphics-command.h')
|
||||
|
||||
keymap = {
|
||||
'w': ('width', 'uint'),
|
||||
's': ('scale', 'uint'),
|
||||
'n': ('subscale_n', 'uint'),
|
||||
'd': ('subscale_d', 'uint'),
|
||||
'v': ('vertical_align', 'uint'),
|
||||
'h': ('horizontal_align', 'uint'),
|
||||
}
|
||||
text = generate(
|
||||
'parse_multicell_code', 'screen_handle_multicell_command', 'multicell_command', keymap, 'MultiCellCommand',
|
||||
payload_is_base64=False, start_parsing_at=0, field_sep=':')
|
||||
write_header(text, 'kitty/parse-multicell-command.h')
|
||||
|
||||
keymap = {
|
||||
't': ('type', flag('aAmMrRopPqeEk')),
|
||||
'm': ('more', 'uint'),
|
||||
'i': ('client_id', 'uint'),
|
||||
'o': ('operation', 'uint'),
|
||||
'x': ('cell_x', 'int'),
|
||||
'y': ('cell_y', 'int'),
|
||||
'X': ('pixel_x', 'int'),
|
||||
'Y': ('pixel_y', 'int'),
|
||||
}
|
||||
text = generate(
|
||||
'parse_dnd_code', 'screen_handle_dnd_command', 'dnd_command', keymap, 'DnDCommand',
|
||||
payload_is_base64=False, start_parsing_at=0, field_sep=':')
|
||||
write_header(text, 'kitty/parse-dnd-command.h')
|
||||
|
||||
|
||||
def main(args: list[str]=sys.argv) -> None:
|
||||
parsers()
|
||||
graphics_parser()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# License: GPLv3 Copyright: 2025, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
from typing import NamedTuple
|
||||
|
||||
|
||||
class BitField(NamedTuple):
|
||||
name: str
|
||||
bits: int
|
||||
|
||||
|
||||
def typename_for_bitsize(bits: int) -> str:
|
||||
if bits <= 8:
|
||||
return 'uint8'
|
||||
if bits <= 16:
|
||||
return 'uint16'
|
||||
if bits <= 32:
|
||||
return 'uint32'
|
||||
return 'uint64'
|
||||
|
||||
|
||||
def make_bitfield(dest: str, typename: str, *fields_: str, add_package: bool = True) -> tuple[str, str]:
|
||||
output_path = os.path.join(dest, f'{typename.lower()}_generated.go')
|
||||
ans = [f'package {os.path.basename(dest)}', '']
|
||||
a = ans.append
|
||||
if not add_package:
|
||||
del ans[0]
|
||||
|
||||
def fieldify(spec: str) -> BitField:
|
||||
name, num = spec.partition(' ')[::2]
|
||||
return BitField(name, int(num))
|
||||
|
||||
fields = tuple(map(fieldify, fields_))
|
||||
total_size = sum(x.bits for x in fields)
|
||||
if total_size > 64:
|
||||
raise ValueError(f'Total size of bit fields: {total_size} for {typename} is larger than 64 bits')
|
||||
a(f'// Total number of bits used: {total_size}')
|
||||
itype = typename_for_bitsize(total_size)
|
||||
a(f'type {typename} {itype}')
|
||||
a('')
|
||||
shift = 0
|
||||
for bf in reversed(fields):
|
||||
tn = typename_for_bitsize(bf.bits)
|
||||
mask = '0b' + '1' * bf.bits
|
||||
a(f'func (s {typename}) {bf.name.capitalize()}() {tn} {{') # }}
|
||||
if shift:
|
||||
a(f' return {tn}((s >> {shift}) & {mask})')
|
||||
else:
|
||||
a(f' return {tn}(s & {mask})')
|
||||
a('}')
|
||||
a('')
|
||||
a(f'func (s *{typename}) Set_{bf.name}(val {tn}) {{') # }}
|
||||
if shift:
|
||||
a(f' *s &^= {mask} << {shift}')
|
||||
a(f' *s |= {typename}(val&{mask}) << {shift}')
|
||||
else:
|
||||
a(f' *s &^= {mask}')
|
||||
a(f' *s |= {typename}(val & {mask})')
|
||||
a('}')
|
||||
a('')
|
||||
shift += bf.bits
|
||||
|
||||
return output_path, '\n'.join(ans)
|
||||
@@ -1,794 +0,0 @@
|
||||
#!./kitty/launcher/kitty +launch
|
||||
# License: GPLv3 Copyright: 2025, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
if __name__ == '__main__' and not __package__:
|
||||
import __main__
|
||||
__main__.__package__ = 'gen'
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
|
||||
|
||||
def Color(r: int, g: int, b: int) -> int:
|
||||
return (r << 16) | (g << 8) | b
|
||||
|
||||
# BEGIN_DATA_SECTION {{{
|
||||
color_names = {
|
||||
'alice blue': Color(240, 248, 255),
|
||||
'aliceblue': Color(240, 248, 255),
|
||||
'antique white': Color(250, 235, 215),
|
||||
'antiquewhite': Color(250, 235, 215),
|
||||
'antiquewhite1': Color(255, 239, 219),
|
||||
'antiquewhite2': Color(238, 223, 204),
|
||||
'antiquewhite3': Color(205, 192, 176),
|
||||
'antiquewhite4': Color(139, 131, 120),
|
||||
'aquamarine': Color(127, 255, 212),
|
||||
'aquamarine1': Color(127, 255, 212),
|
||||
'aquamarine2': Color(118, 238, 198),
|
||||
'aquamarine3': Color(102, 205, 170),
|
||||
'aquamarine4': Color(69, 139, 116),
|
||||
'azure': Color(240, 255, 255),
|
||||
'azure1': Color(240, 255, 255),
|
||||
'azure2': Color(224, 238, 238),
|
||||
'azure3': Color(193, 205, 205),
|
||||
'azure4': Color(131, 139, 139),
|
||||
'beige': Color(245, 245, 220),
|
||||
'bisque': Color(255, 228, 196),
|
||||
'bisque1': Color(255, 228, 196),
|
||||
'bisque2': Color(238, 213, 183),
|
||||
'bisque3': Color(205, 183, 158),
|
||||
'bisque4': Color(139, 125, 107),
|
||||
'black': Color(0, 0, 0),
|
||||
'blanched almond': Color(255, 235, 205),
|
||||
'blanchedalmond': Color(255, 235, 205),
|
||||
'blue': Color(0, 0, 255),
|
||||
'blue violet': Color(138, 43, 226),
|
||||
'blue1': Color(0, 0, 255),
|
||||
'blue2': Color(0, 0, 238),
|
||||
'blue3': Color(0, 0, 205),
|
||||
'blue4': Color(0, 0, 139),
|
||||
'blueviolet': Color(138, 43, 226),
|
||||
'brown': Color(165, 42, 42),
|
||||
'brown1': Color(255, 64, 64),
|
||||
'brown2': Color(238, 59, 59),
|
||||
'brown3': Color(205, 51, 51),
|
||||
'brown4': Color(139, 35, 35),
|
||||
'burlywood': Color(222, 184, 135),
|
||||
'burlywood1': Color(255, 211, 155),
|
||||
'burlywood2': Color(238, 197, 145),
|
||||
'burlywood3': Color(205, 170, 125),
|
||||
'burlywood4': Color(139, 115, 85),
|
||||
'cadet blue': Color(95, 158, 160),
|
||||
'cadetblue': Color(95, 158, 160),
|
||||
'cadetblue1': Color(152, 245, 255),
|
||||
'cadetblue2': Color(142, 229, 238),
|
||||
'cadetblue3': Color(122, 197, 205),
|
||||
'cadetblue4': Color(83, 134, 139),
|
||||
'chartreuse': Color(127, 255, 0),
|
||||
'chartreuse1': Color(127, 255, 0),
|
||||
'chartreuse2': Color(118, 238, 0),
|
||||
'chartreuse3': Color(102, 205, 0),
|
||||
'chartreuse4': Color(69, 139, 0),
|
||||
'chocolate': Color(210, 105, 30),
|
||||
'chocolate1': Color(255, 127, 36),
|
||||
'chocolate2': Color(238, 118, 33),
|
||||
'chocolate3': Color(205, 102, 29),
|
||||
'chocolate4': Color(139, 69, 19),
|
||||
'coral': Color(255, 127, 80),
|
||||
'coral1': Color(255, 114, 86),
|
||||
'coral2': Color(238, 106, 80),
|
||||
'coral3': Color(205, 91, 69),
|
||||
'coral4': Color(139, 62, 47),
|
||||
'cornflower blue': Color(100, 149, 237),
|
||||
'cornflowerblue': Color(100, 149, 237),
|
||||
'cornsilk': Color(255, 248, 220),
|
||||
'cornsilk1': Color(255, 248, 220),
|
||||
'cornsilk2': Color(238, 232, 205),
|
||||
'cornsilk3': Color(205, 200, 177),
|
||||
'cornsilk4': Color(139, 136, 120),
|
||||
'cyan': Color(0, 255, 255),
|
||||
'cyan1': Color(0, 255, 255),
|
||||
'cyan2': Color(0, 238, 238),
|
||||
'cyan3': Color(0, 205, 205),
|
||||
'cyan4': Color(0, 139, 139),
|
||||
'dark blue': Color(0, 0, 139),
|
||||
'dark cyan': Color(0, 139, 139),
|
||||
'dark goldenrod': Color(184, 134, 11),
|
||||
'dark gray': Color(169, 169, 169),
|
||||
'dark green': Color(0, 100, 0),
|
||||
'dark grey': Color(169, 169, 169),
|
||||
'dark khaki': Color(189, 183, 107),
|
||||
'dark magenta': Color(139, 0, 139),
|
||||
'dark olive green': Color(85, 107, 47),
|
||||
'dark orange': Color(255, 140, 0),
|
||||
'dark orchid': Color(153, 50, 204),
|
||||
'dark red': Color(139, 0, 0),
|
||||
'dark salmon': Color(233, 150, 122),
|
||||
'dark sea green': Color(143, 188, 143),
|
||||
'dark slate blue': Color(72, 61, 139),
|
||||
'dark slate gray': Color(47, 79, 79),
|
||||
'dark slate grey': Color(47, 79, 79),
|
||||
'dark turquoise': Color(0, 206, 209),
|
||||
'dark violet': Color(148, 0, 211),
|
||||
'darkblue': Color(0, 0, 139),
|
||||
'darkcyan': Color(0, 139, 139),
|
||||
'darkgoldenrod': Color(184, 134, 11),
|
||||
'darkgoldenrod1': Color(255, 185, 15),
|
||||
'darkgoldenrod2': Color(238, 173, 14),
|
||||
'darkgoldenrod3': Color(205, 149, 12),
|
||||
'darkgoldenrod4': Color(139, 101, 8),
|
||||
'darkgray': Color(169, 169, 169),
|
||||
'darkgreen': Color(0, 100, 0),
|
||||
'darkgrey': Color(169, 169, 169),
|
||||
'darkkhaki': Color(189, 183, 107),
|
||||
'darkmagenta': Color(139, 0, 139),
|
||||
'darkolivegreen': Color(85, 107, 47),
|
||||
'darkolivegreen1': Color(202, 255, 112),
|
||||
'darkolivegreen2': Color(188, 238, 104),
|
||||
'darkolivegreen3': Color(162, 205, 90),
|
||||
'darkolivegreen4': Color(110, 139, 61),
|
||||
'darkorange': Color(255, 140, 0),
|
||||
'darkorange1': Color(255, 127, 0),
|
||||
'darkorange2': Color(238, 118, 0),
|
||||
'darkorange3': Color(205, 102, 0),
|
||||
'darkorange4': Color(139, 69, 0),
|
||||
'darkorchid': Color(153, 50, 204),
|
||||
'darkorchid1': Color(191, 62, 255),
|
||||
'darkorchid2': Color(178, 58, 238),
|
||||
'darkorchid3': Color(154, 50, 205),
|
||||
'darkorchid4': Color(104, 34, 139),
|
||||
'darkred': Color(139, 0, 0),
|
||||
'darksalmon': Color(233, 150, 122),
|
||||
'darkseagreen': Color(143, 188, 143),
|
||||
'darkseagreen1': Color(193, 255, 193),
|
||||
'darkseagreen2': Color(180, 238, 180),
|
||||
'darkseagreen3': Color(155, 205, 155),
|
||||
'darkseagreen4': Color(105, 139, 105),
|
||||
'darkslateblue': Color(72, 61, 139),
|
||||
'darkslategray': Color(47, 79, 79),
|
||||
'darkslategray1': Color(151, 255, 255),
|
||||
'darkslategray2': Color(141, 238, 238),
|
||||
'darkslategray3': Color(121, 205, 205),
|
||||
'darkslategray4': Color(82, 139, 139),
|
||||
'darkslategrey': Color(47, 79, 79),
|
||||
'darkturquoise': Color(0, 206, 209),
|
||||
'darkviolet': Color(148, 0, 211),
|
||||
'debianred': Color(215, 7, 81),
|
||||
'deep pink': Color(255, 20, 147),
|
||||
'deep sky blue': Color(0, 191, 255),
|
||||
'deeppink': Color(255, 20, 147),
|
||||
'deeppink1': Color(255, 20, 147),
|
||||
'deeppink2': Color(238, 18, 137),
|
||||
'deeppink3': Color(205, 16, 118),
|
||||
'deeppink4': Color(139, 10, 80),
|
||||
'deepskyblue': Color(0, 191, 255),
|
||||
'deepskyblue1': Color(0, 191, 255),
|
||||
'deepskyblue2': Color(0, 178, 238),
|
||||
'deepskyblue3': Color(0, 154, 205),
|
||||
'deepskyblue4': Color(0, 104, 139),
|
||||
'dim gray': Color(105, 105, 105),
|
||||
'dim grey': Color(105, 105, 105),
|
||||
'dimgray': Color(105, 105, 105),
|
||||
'dimgrey': Color(105, 105, 105),
|
||||
'dodger blue': Color(30, 144, 255),
|
||||
'dodgerblue': Color(30, 144, 255),
|
||||
'dodgerblue1': Color(30, 144, 255),
|
||||
'dodgerblue2': Color(28, 134, 238),
|
||||
'dodgerblue3': Color(24, 116, 205),
|
||||
'dodgerblue4': Color(16, 78, 139),
|
||||
'firebrick': Color(178, 34, 34),
|
||||
'firebrick1': Color(255, 48, 48),
|
||||
'firebrick2': Color(238, 44, 44),
|
||||
'firebrick3': Color(205, 38, 38),
|
||||
'firebrick4': Color(139, 26, 26),
|
||||
'floral white': Color(255, 250, 240),
|
||||
'floralwhite': Color(255, 250, 240),
|
||||
'forest green': Color(34, 139, 34),
|
||||
'forestgreen': Color(34, 139, 34),
|
||||
'gainsboro': Color(220, 220, 220),
|
||||
'ghost white': Color(248, 248, 255),
|
||||
'ghostwhite': Color(248, 248, 255),
|
||||
'gold': Color(255, 215, 0),
|
||||
'gold1': Color(255, 215, 0),
|
||||
'gold2': Color(238, 201, 0),
|
||||
'gold3': Color(205, 173, 0),
|
||||
'gold4': Color(139, 117, 0),
|
||||
'goldenrod': Color(218, 165, 32),
|
||||
'goldenrod1': Color(255, 193, 37),
|
||||
'goldenrod2': Color(238, 180, 34),
|
||||
'goldenrod3': Color(205, 155, 29),
|
||||
'goldenrod4': Color(139, 105, 20),
|
||||
'gray': Color(190, 190, 190),
|
||||
'gray0': Color(0, 0, 0),
|
||||
'gray1': Color(3, 3, 3),
|
||||
'gray10': Color(26, 26, 26),
|
||||
'gray100': Color(255, 255, 255),
|
||||
'gray11': Color(28, 28, 28),
|
||||
'gray12': Color(31, 31, 31),
|
||||
'gray13': Color(33, 33, 33),
|
||||
'gray14': Color(36, 36, 36),
|
||||
'gray15': Color(38, 38, 38),
|
||||
'gray16': Color(41, 41, 41),
|
||||
'gray17': Color(43, 43, 43),
|
||||
'gray18': Color(46, 46, 46),
|
||||
'gray19': Color(48, 48, 48),
|
||||
'gray2': Color(5, 5, 5),
|
||||
'gray20': Color(51, 51, 51),
|
||||
'gray21': Color(54, 54, 54),
|
||||
'gray22': Color(56, 56, 56),
|
||||
'gray23': Color(59, 59, 59),
|
||||
'gray24': Color(61, 61, 61),
|
||||
'gray25': Color(64, 64, 64),
|
||||
'gray26': Color(66, 66, 66),
|
||||
'gray27': Color(69, 69, 69),
|
||||
'gray28': Color(71, 71, 71),
|
||||
'gray29': Color(74, 74, 74),
|
||||
'gray3': Color(8, 8, 8),
|
||||
'gray30': Color(77, 77, 77),
|
||||
'gray31': Color(79, 79, 79),
|
||||
'gray32': Color(82, 82, 82),
|
||||
'gray33': Color(84, 84, 84),
|
||||
'gray34': Color(87, 87, 87),
|
||||
'gray35': Color(89, 89, 89),
|
||||
'gray36': Color(92, 92, 92),
|
||||
'gray37': Color(94, 94, 94),
|
||||
'gray38': Color(97, 97, 97),
|
||||
'gray39': Color(99, 99, 99),
|
||||
'gray4': Color(10, 10, 10),
|
||||
'gray40': Color(102, 102, 102),
|
||||
'gray41': Color(105, 105, 105),
|
||||
'gray42': Color(107, 107, 107),
|
||||
'gray43': Color(110, 110, 110),
|
||||
'gray44': Color(112, 112, 112),
|
||||
'gray45': Color(115, 115, 115),
|
||||
'gray46': Color(117, 117, 117),
|
||||
'gray47': Color(120, 120, 120),
|
||||
'gray48': Color(122, 122, 122),
|
||||
'gray49': Color(125, 125, 125),
|
||||
'gray5': Color(13, 13, 13),
|
||||
'gray50': Color(127, 127, 127),
|
||||
'gray51': Color(130, 130, 130),
|
||||
'gray52': Color(133, 133, 133),
|
||||
'gray53': Color(135, 135, 135),
|
||||
'gray54': Color(138, 138, 138),
|
||||
'gray55': Color(140, 140, 140),
|
||||
'gray56': Color(143, 143, 143),
|
||||
'gray57': Color(145, 145, 145),
|
||||
'gray58': Color(148, 148, 148),
|
||||
'gray59': Color(150, 150, 150),
|
||||
'gray6': Color(15, 15, 15),
|
||||
'gray60': Color(153, 153, 153),
|
||||
'gray61': Color(156, 156, 156),
|
||||
'gray62': Color(158, 158, 158),
|
||||
'gray63': Color(161, 161, 161),
|
||||
'gray64': Color(163, 163, 163),
|
||||
'gray65': Color(166, 166, 166),
|
||||
'gray66': Color(168, 168, 168),
|
||||
'gray67': Color(171, 171, 171),
|
||||
'gray68': Color(173, 173, 173),
|
||||
'gray69': Color(176, 176, 176),
|
||||
'gray7': Color(18, 18, 18),
|
||||
'gray70': Color(179, 179, 179),
|
||||
'gray71': Color(181, 181, 181),
|
||||
'gray72': Color(184, 184, 184),
|
||||
'gray73': Color(186, 186, 186),
|
||||
'gray74': Color(189, 189, 189),
|
||||
'gray75': Color(191, 191, 191),
|
||||
'gray76': Color(194, 194, 194),
|
||||
'gray77': Color(196, 196, 196),
|
||||
'gray78': Color(199, 199, 199),
|
||||
'gray79': Color(201, 201, 201),
|
||||
'gray8': Color(20, 20, 20),
|
||||
'gray80': Color(204, 204, 204),
|
||||
'gray81': Color(207, 207, 207),
|
||||
'gray82': Color(209, 209, 209),
|
||||
'gray83': Color(212, 212, 212),
|
||||
'gray84': Color(214, 214, 214),
|
||||
'gray85': Color(217, 217, 217),
|
||||
'gray86': Color(219, 219, 219),
|
||||
'gray87': Color(222, 222, 222),
|
||||
'gray88': Color(224, 224, 224),
|
||||
'gray89': Color(227, 227, 227),
|
||||
'gray9': Color(23, 23, 23),
|
||||
'gray90': Color(229, 229, 229),
|
||||
'gray91': Color(232, 232, 232),
|
||||
'gray92': Color(235, 235, 235),
|
||||
'gray93': Color(237, 237, 237),
|
||||
'gray94': Color(240, 240, 240),
|
||||
'gray95': Color(242, 242, 242),
|
||||
'gray96': Color(245, 245, 245),
|
||||
'gray97': Color(247, 247, 247),
|
||||
'gray98': Color(250, 250, 250),
|
||||
'gray99': Color(252, 252, 252),
|
||||
'green': Color(0, 255, 0),
|
||||
'green yellow': Color(173, 255, 47),
|
||||
'green1': Color(0, 255, 0),
|
||||
'green2': Color(0, 238, 0),
|
||||
'green3': Color(0, 205, 0),
|
||||
'green4': Color(0, 139, 0),
|
||||
'greenyellow': Color(173, 255, 47),
|
||||
'grey': Color(190, 190, 190),
|
||||
'grey0': Color(0, 0, 0),
|
||||
'grey1': Color(3, 3, 3),
|
||||
'grey10': Color(26, 26, 26),
|
||||
'grey100': Color(255, 255, 255),
|
||||
'grey11': Color(28, 28, 28),
|
||||
'grey12': Color(31, 31, 31),
|
||||
'grey13': Color(33, 33, 33),
|
||||
'grey14': Color(36, 36, 36),
|
||||
'grey15': Color(38, 38, 38),
|
||||
'grey16': Color(41, 41, 41),
|
||||
'grey17': Color(43, 43, 43),
|
||||
'grey18': Color(46, 46, 46),
|
||||
'grey19': Color(48, 48, 48),
|
||||
'grey2': Color(5, 5, 5),
|
||||
'grey20': Color(51, 51, 51),
|
||||
'grey21': Color(54, 54, 54),
|
||||
'grey22': Color(56, 56, 56),
|
||||
'grey23': Color(59, 59, 59),
|
||||
'grey24': Color(61, 61, 61),
|
||||
'grey25': Color(64, 64, 64),
|
||||
'grey26': Color(66, 66, 66),
|
||||
'grey27': Color(69, 69, 69),
|
||||
'grey28': Color(71, 71, 71),
|
||||
'grey29': Color(74, 74, 74),
|
||||
'grey3': Color(8, 8, 8),
|
||||
'grey30': Color(77, 77, 77),
|
||||
'grey31': Color(79, 79, 79),
|
||||
'grey32': Color(82, 82, 82),
|
||||
'grey33': Color(84, 84, 84),
|
||||
'grey34': Color(87, 87, 87),
|
||||
'grey35': Color(89, 89, 89),
|
||||
'grey36': Color(92, 92, 92),
|
||||
'grey37': Color(94, 94, 94),
|
||||
'grey38': Color(97, 97, 97),
|
||||
'grey39': Color(99, 99, 99),
|
||||
'grey4': Color(10, 10, 10),
|
||||
'grey40': Color(102, 102, 102),
|
||||
'grey41': Color(105, 105, 105),
|
||||
'grey42': Color(107, 107, 107),
|
||||
'grey43': Color(110, 110, 110),
|
||||
'grey44': Color(112, 112, 112),
|
||||
'grey45': Color(115, 115, 115),
|
||||
'grey46': Color(117, 117, 117),
|
||||
'grey47': Color(120, 120, 120),
|
||||
'grey48': Color(122, 122, 122),
|
||||
'grey49': Color(125, 125, 125),
|
||||
'grey5': Color(13, 13, 13),
|
||||
'grey50': Color(127, 127, 127),
|
||||
'grey51': Color(130, 130, 130),
|
||||
'grey52': Color(133, 133, 133),
|
||||
'grey53': Color(135, 135, 135),
|
||||
'grey54': Color(138, 138, 138),
|
||||
'grey55': Color(140, 140, 140),
|
||||
'grey56': Color(143, 143, 143),
|
||||
'grey57': Color(145, 145, 145),
|
||||
'grey58': Color(148, 148, 148),
|
||||
'grey59': Color(150, 150, 150),
|
||||
'grey6': Color(15, 15, 15),
|
||||
'grey60': Color(153, 153, 153),
|
||||
'grey61': Color(156, 156, 156),
|
||||
'grey62': Color(158, 158, 158),
|
||||
'grey63': Color(161, 161, 161),
|
||||
'grey64': Color(163, 163, 163),
|
||||
'grey65': Color(166, 166, 166),
|
||||
'grey66': Color(168, 168, 168),
|
||||
'grey67': Color(171, 171, 171),
|
||||
'grey68': Color(173, 173, 173),
|
||||
'grey69': Color(176, 176, 176),
|
||||
'grey7': Color(18, 18, 18),
|
||||
'grey70': Color(179, 179, 179),
|
||||
'grey71': Color(181, 181, 181),
|
||||
'grey72': Color(184, 184, 184),
|
||||
'grey73': Color(186, 186, 186),
|
||||
'grey74': Color(189, 189, 189),
|
||||
'grey75': Color(191, 191, 191),
|
||||
'grey76': Color(194, 194, 194),
|
||||
'grey77': Color(196, 196, 196),
|
||||
'grey78': Color(199, 199, 199),
|
||||
'grey79': Color(201, 201, 201),
|
||||
'grey8': Color(20, 20, 20),
|
||||
'grey80': Color(204, 204, 204),
|
||||
'grey81': Color(207, 207, 207),
|
||||
'grey82': Color(209, 209, 209),
|
||||
'grey83': Color(212, 212, 212),
|
||||
'grey84': Color(214, 214, 214),
|
||||
'grey85': Color(217, 217, 217),
|
||||
'grey86': Color(219, 219, 219),
|
||||
'grey87': Color(222, 222, 222),
|
||||
'grey88': Color(224, 224, 224),
|
||||
'grey89': Color(227, 227, 227),
|
||||
'grey9': Color(23, 23, 23),
|
||||
'grey90': Color(229, 229, 229),
|
||||
'grey91': Color(232, 232, 232),
|
||||
'grey92': Color(235, 235, 235),
|
||||
'grey93': Color(237, 237, 237),
|
||||
'grey94': Color(240, 240, 240),
|
||||
'grey95': Color(242, 242, 242),
|
||||
'grey96': Color(245, 245, 245),
|
||||
'grey97': Color(247, 247, 247),
|
||||
'grey98': Color(250, 250, 250),
|
||||
'grey99': Color(252, 252, 252),
|
||||
'honeydew': Color(240, 255, 240),
|
||||
'honeydew1': Color(240, 255, 240),
|
||||
'honeydew2': Color(224, 238, 224),
|
||||
'honeydew3': Color(193, 205, 193),
|
||||
'honeydew4': Color(131, 139, 131),
|
||||
'hot pink': Color(255, 105, 180),
|
||||
'hotpink': Color(255, 105, 180),
|
||||
'hotpink1': Color(255, 110, 180),
|
||||
'hotpink2': Color(238, 106, 167),
|
||||
'hotpink3': Color(205, 96, 144),
|
||||
'hotpink4': Color(139, 58, 98),
|
||||
'indian red': Color(205, 92, 92),
|
||||
'indianred': Color(205, 92, 92),
|
||||
'indianred1': Color(255, 106, 106),
|
||||
'indianred2': Color(238, 99, 99),
|
||||
'indianred3': Color(205, 85, 85),
|
||||
'indianred4': Color(139, 58, 58),
|
||||
'ivory': Color(255, 255, 240),
|
||||
'ivory1': Color(255, 255, 240),
|
||||
'ivory2': Color(238, 238, 224),
|
||||
'ivory3': Color(205, 205, 193),
|
||||
'ivory4': Color(139, 139, 131),
|
||||
'khaki': Color(240, 230, 140),
|
||||
'khaki1': Color(255, 246, 143),
|
||||
'khaki2': Color(238, 230, 133),
|
||||
'khaki3': Color(205, 198, 115),
|
||||
'khaki4': Color(139, 134, 78),
|
||||
'lavender': Color(230, 230, 250),
|
||||
'lavender blush': Color(255, 240, 245),
|
||||
'lavenderblush': Color(255, 240, 245),
|
||||
'lavenderblush1': Color(255, 240, 245),
|
||||
'lavenderblush2': Color(238, 224, 229),
|
||||
'lavenderblush3': Color(205, 193, 197),
|
||||
'lavenderblush4': Color(139, 131, 134),
|
||||
'lawn green': Color(124, 252, 0),
|
||||
'lawngreen': Color(124, 252, 0),
|
||||
'lemon chiffon': Color(255, 250, 205),
|
||||
'lemonchiffon': Color(255, 250, 205),
|
||||
'lemonchiffon1': Color(255, 250, 205),
|
||||
'lemonchiffon2': Color(238, 233, 191),
|
||||
'lemonchiffon3': Color(205, 201, 165),
|
||||
'lemonchiffon4': Color(139, 137, 112),
|
||||
'light blue': Color(173, 216, 230),
|
||||
'light coral': Color(240, 128, 128),
|
||||
'light cyan': Color(224, 255, 255),
|
||||
'light goldenrod': Color(238, 221, 130),
|
||||
'light goldenrod yellow': Color(250, 250, 210),
|
||||
'light gray': Color(211, 211, 211),
|
||||
'light green': Color(144, 238, 144),
|
||||
'light grey': Color(211, 211, 211),
|
||||
'light pink': Color(255, 182, 193),
|
||||
'light salmon': Color(255, 160, 122),
|
||||
'light sea green': Color(32, 178, 170),
|
||||
'light sky blue': Color(135, 206, 250),
|
||||
'light slate blue': Color(132, 112, 255),
|
||||
'light slate gray': Color(119, 136, 153),
|
||||
'light slate grey': Color(119, 136, 153),
|
||||
'light steel blue': Color(176, 196, 222),
|
||||
'light yellow': Color(255, 255, 224),
|
||||
'lightblue': Color(173, 216, 230),
|
||||
'lightblue1': Color(191, 239, 255),
|
||||
'lightblue2': Color(178, 223, 238),
|
||||
'lightblue3': Color(154, 192, 205),
|
||||
'lightblue4': Color(104, 131, 139),
|
||||
'lightcoral': Color(240, 128, 128),
|
||||
'lightcyan': Color(224, 255, 255),
|
||||
'lightcyan1': Color(224, 255, 255),
|
||||
'lightcyan2': Color(209, 238, 238),
|
||||
'lightcyan3': Color(180, 205, 205),
|
||||
'lightcyan4': Color(122, 139, 139),
|
||||
'lightgoldenrod': Color(238, 221, 130),
|
||||
'lightgoldenrod1': Color(255, 236, 139),
|
||||
'lightgoldenrod2': Color(238, 220, 130),
|
||||
'lightgoldenrod3': Color(205, 190, 112),
|
||||
'lightgoldenrod4': Color(139, 129, 76),
|
||||
'lightgoldenrodyellow': Color(250, 250, 210),
|
||||
'lightgray': Color(211, 211, 211),
|
||||
'lightgreen': Color(144, 238, 144),
|
||||
'lightgrey': Color(211, 211, 211),
|
||||
'lightpink': Color(255, 182, 193),
|
||||
'lightpink1': Color(255, 174, 185),
|
||||
'lightpink2': Color(238, 162, 173),
|
||||
'lightpink3': Color(205, 140, 149),
|
||||
'lightpink4': Color(139, 95, 101),
|
||||
'lightsalmon': Color(255, 160, 122),
|
||||
'lightsalmon1': Color(255, 160, 122),
|
||||
'lightsalmon2': Color(238, 149, 114),
|
||||
'lightsalmon3': Color(205, 129, 98),
|
||||
'lightsalmon4': Color(139, 87, 66),
|
||||
'lightseagreen': Color(32, 178, 170),
|
||||
'lightskyblue': Color(135, 206, 250),
|
||||
'lightskyblue1': Color(176, 226, 255),
|
||||
'lightskyblue2': Color(164, 211, 238),
|
||||
'lightskyblue3': Color(141, 182, 205),
|
||||
'lightskyblue4': Color(96, 123, 139),
|
||||
'lightslateblue': Color(132, 112, 255),
|
||||
'lightslategray': Color(119, 136, 153),
|
||||
'lightslategrey': Color(119, 136, 153),
|
||||
'lightsteelblue': Color(176, 196, 222),
|
||||
'lightsteelblue1': Color(202, 225, 255),
|
||||
'lightsteelblue2': Color(188, 210, 238),
|
||||
'lightsteelblue3': Color(162, 181, 205),
|
||||
'lightsteelblue4': Color(110, 123, 139),
|
||||
'lightyellow': Color(255, 255, 224),
|
||||
'lightyellow1': Color(255, 255, 224),
|
||||
'lightyellow2': Color(238, 238, 209),
|
||||
'lightyellow3': Color(205, 205, 180),
|
||||
'lightyellow4': Color(139, 139, 122),
|
||||
'lime green': Color(50, 205, 50),
|
||||
'limegreen': Color(50, 205, 50),
|
||||
'linen': Color(250, 240, 230),
|
||||
'magenta': Color(255, 0, 255),
|
||||
'magenta1': Color(255, 0, 255),
|
||||
'magenta2': Color(238, 0, 238),
|
||||
'magenta3': Color(205, 0, 205),
|
||||
'magenta4': Color(139, 0, 139),
|
||||
'maroon': Color(176, 48, 96),
|
||||
'maroon1': Color(255, 52, 179),
|
||||
'maroon2': Color(238, 48, 167),
|
||||
'maroon3': Color(205, 41, 144),
|
||||
'maroon4': Color(139, 28, 98),
|
||||
'medium aquamarine': Color(102, 205, 170),
|
||||
'medium blue': Color(0, 0, 205),
|
||||
'medium orchid': Color(186, 85, 211),
|
||||
'medium purple': Color(147, 112, 219),
|
||||
'medium sea green': Color(60, 179, 113),
|
||||
'medium slate blue': Color(123, 104, 238),
|
||||
'medium spring green': Color(0, 250, 154),
|
||||
'medium turquoise': Color(72, 209, 204),
|
||||
'medium violet red': Color(199, 21, 133),
|
||||
'mediumaquamarine': Color(102, 205, 170),
|
||||
'mediumblue': Color(0, 0, 205),
|
||||
'mediumorchid': Color(186, 85, 211),
|
||||
'mediumorchid1': Color(224, 102, 255),
|
||||
'mediumorchid2': Color(209, 95, 238),
|
||||
'mediumorchid3': Color(180, 82, 205),
|
||||
'mediumorchid4': Color(122, 55, 139),
|
||||
'mediumpurple': Color(147, 112, 219),
|
||||
'mediumpurple1': Color(171, 130, 255),
|
||||
'mediumpurple2': Color(159, 121, 238),
|
||||
'mediumpurple3': Color(137, 104, 205),
|
||||
'mediumpurple4': Color(93, 71, 139),
|
||||
'mediumseagreen': Color(60, 179, 113),
|
||||
'mediumslateblue': Color(123, 104, 238),
|
||||
'mediumspringgreen': Color(0, 250, 154),
|
||||
'mediumturquoise': Color(72, 209, 204),
|
||||
'mediumvioletred': Color(199, 21, 133),
|
||||
'midnight blue': Color(25, 25, 112),
|
||||
'midnightblue': Color(25, 25, 112),
|
||||
'mint cream': Color(245, 255, 250),
|
||||
'mintcream': Color(245, 255, 250),
|
||||
'misty rose': Color(255, 228, 225),
|
||||
'mistyrose': Color(255, 228, 225),
|
||||
'mistyrose1': Color(255, 228, 225),
|
||||
'mistyrose2': Color(238, 213, 210),
|
||||
'mistyrose3': Color(205, 183, 181),
|
||||
'mistyrose4': Color(139, 125, 123),
|
||||
'moccasin': Color(255, 228, 181),
|
||||
'navajo white': Color(255, 222, 173),
|
||||
'navajowhite': Color(255, 222, 173),
|
||||
'navajowhite1': Color(255, 222, 173),
|
||||
'navajowhite2': Color(238, 207, 161),
|
||||
'navajowhite3': Color(205, 179, 139),
|
||||
'navajowhite4': Color(139, 121, 94),
|
||||
'navy': Color(0, 0, 128),
|
||||
'navy blue': Color(0, 0, 128),
|
||||
'navyblue': Color(0, 0, 128),
|
||||
'old lace': Color(253, 245, 230),
|
||||
'oldlace': Color(253, 245, 230),
|
||||
'olive drab': Color(107, 142, 35),
|
||||
'olivedrab': Color(107, 142, 35),
|
||||
'olivedrab1': Color(192, 255, 62),
|
||||
'olivedrab2': Color(179, 238, 58),
|
||||
'olivedrab3': Color(154, 205, 50),
|
||||
'olivedrab4': Color(105, 139, 34),
|
||||
'orange': Color(255, 165, 0),
|
||||
'orange red': Color(255, 69, 0),
|
||||
'orange1': Color(255, 165, 0),
|
||||
'orange2': Color(238, 154, 0),
|
||||
'orange3': Color(205, 133, 0),
|
||||
'orange4': Color(139, 90, 0),
|
||||
'orangered': Color(255, 69, 0),
|
||||
'orangered1': Color(255, 69, 0),
|
||||
'orangered2': Color(238, 64, 0),
|
||||
'orangered3': Color(205, 55, 0),
|
||||
'orangered4': Color(139, 37, 0),
|
||||
'orchid': Color(218, 112, 214),
|
||||
'orchid1': Color(255, 131, 250),
|
||||
'orchid2': Color(238, 122, 233),
|
||||
'orchid3': Color(205, 105, 201),
|
||||
'orchid4': Color(139, 71, 137),
|
||||
'pale goldenrod': Color(238, 232, 170),
|
||||
'pale green': Color(152, 251, 152),
|
||||
'pale turquoise': Color(175, 238, 238),
|
||||
'pale violet red': Color(219, 112, 147),
|
||||
'palegoldenrod': Color(238, 232, 170),
|
||||
'palegreen': Color(152, 251, 152),
|
||||
'palegreen1': Color(154, 255, 154),
|
||||
'palegreen2': Color(144, 238, 144),
|
||||
'palegreen3': Color(124, 205, 124),
|
||||
'palegreen4': Color(84, 139, 84),
|
||||
'paleturquoise': Color(175, 238, 238),
|
||||
'paleturquoise1': Color(187, 255, 255),
|
||||
'paleturquoise2': Color(174, 238, 238),
|
||||
'paleturquoise3': Color(150, 205, 205),
|
||||
'paleturquoise4': Color(102, 139, 139),
|
||||
'palevioletred': Color(219, 112, 147),
|
||||
'palevioletred1': Color(255, 130, 171),
|
||||
'palevioletred2': Color(238, 121, 159),
|
||||
'palevioletred3': Color(205, 104, 137),
|
||||
'palevioletred4': Color(139, 71, 93),
|
||||
'papaya whip': Color(255, 239, 213),
|
||||
'papayawhip': Color(255, 239, 213),
|
||||
'peach puff': Color(255, 218, 185),
|
||||
'peachpuff': Color(255, 218, 185),
|
||||
'peachpuff1': Color(255, 218, 185),
|
||||
'peachpuff2': Color(238, 203, 173),
|
||||
'peachpuff3': Color(205, 175, 149),
|
||||
'peachpuff4': Color(139, 119, 101),
|
||||
'peru': Color(205, 133, 63),
|
||||
'pink': Color(255, 192, 203),
|
||||
'pink1': Color(255, 181, 197),
|
||||
'pink2': Color(238, 169, 184),
|
||||
'pink3': Color(205, 145, 158),
|
||||
'pink4': Color(139, 99, 108),
|
||||
'plum': Color(221, 160, 221),
|
||||
'plum1': Color(255, 187, 255),
|
||||
'plum2': Color(238, 174, 238),
|
||||
'plum3': Color(205, 150, 205),
|
||||
'plum4': Color(139, 102, 139),
|
||||
'powder blue': Color(176, 224, 230),
|
||||
'powderblue': Color(176, 224, 230),
|
||||
'purple': Color(160, 32, 240),
|
||||
'purple1': Color(155, 48, 255),
|
||||
'purple2': Color(145, 44, 238),
|
||||
'purple3': Color(125, 38, 205),
|
||||
'purple4': Color(85, 26, 139),
|
||||
'red': Color(255, 0, 0),
|
||||
'red1': Color(255, 0, 0),
|
||||
'red2': Color(238, 0, 0),
|
||||
'red3': Color(205, 0, 0),
|
||||
'red4': Color(139, 0, 0),
|
||||
'rosy brown': Color(188, 143, 143),
|
||||
'rosybrown': Color(188, 143, 143),
|
||||
'rosybrown1': Color(255, 193, 193),
|
||||
'rosybrown2': Color(238, 180, 180),
|
||||
'rosybrown3': Color(205, 155, 155),
|
||||
'rosybrown4': Color(139, 105, 105),
|
||||
'royal blue': Color(65, 105, 225),
|
||||
'royalblue': Color(65, 105, 225),
|
||||
'royalblue1': Color(72, 118, 255),
|
||||
'royalblue2': Color(67, 110, 238),
|
||||
'royalblue3': Color(58, 95, 205),
|
||||
'royalblue4': Color(39, 64, 139),
|
||||
'saddle brown': Color(139, 69, 19),
|
||||
'saddlebrown': Color(139, 69, 19),
|
||||
'salmon': Color(250, 128, 114),
|
||||
'salmon1': Color(255, 140, 105),
|
||||
'salmon2': Color(238, 130, 98),
|
||||
'salmon3': Color(205, 112, 84),
|
||||
'salmon4': Color(139, 76, 57),
|
||||
'sandy brown': Color(244, 164, 96),
|
||||
'sandybrown': Color(244, 164, 96),
|
||||
'sea green': Color(46, 139, 87),
|
||||
'seagreen': Color(46, 139, 87),
|
||||
'seagreen1': Color(84, 255, 159),
|
||||
'seagreen2': Color(78, 238, 148),
|
||||
'seagreen3': Color(67, 205, 128),
|
||||
'seagreen4': Color(46, 139, 87),
|
||||
'seashell': Color(255, 245, 238),
|
||||
'seashell1': Color(255, 245, 238),
|
||||
'seashell2': Color(238, 229, 222),
|
||||
'seashell3': Color(205, 197, 191),
|
||||
'seashell4': Color(139, 134, 130),
|
||||
'sienna': Color(160, 82, 45),
|
||||
'sienna1': Color(255, 130, 71),
|
||||
'sienna2': Color(238, 121, 66),
|
||||
'sienna3': Color(205, 104, 57),
|
||||
'sienna4': Color(139, 71, 38),
|
||||
'sky blue': Color(135, 206, 235),
|
||||
'skyblue': Color(135, 206, 235),
|
||||
'skyblue1': Color(135, 206, 255),
|
||||
'skyblue2': Color(126, 192, 238),
|
||||
'skyblue3': Color(108, 166, 205),
|
||||
'skyblue4': Color(74, 112, 139),
|
||||
'slate blue': Color(106, 90, 205),
|
||||
'slate gray': Color(112, 128, 144),
|
||||
'slate grey': Color(112, 128, 144),
|
||||
'slateblue': Color(106, 90, 205),
|
||||
'slateblue1': Color(131, 111, 255),
|
||||
'slateblue2': Color(122, 103, 238),
|
||||
'slateblue3': Color(105, 89, 205),
|
||||
'slateblue4': Color(71, 60, 139),
|
||||
'slategray': Color(112, 128, 144),
|
||||
'slategray1': Color(198, 226, 255),
|
||||
'slategray2': Color(185, 211, 238),
|
||||
'slategray3': Color(159, 182, 205),
|
||||
'slategray4': Color(108, 123, 139),
|
||||
'slategrey': Color(112, 128, 144),
|
||||
'snow': Color(255, 250, 250),
|
||||
'snow1': Color(255, 250, 250),
|
||||
'snow2': Color(238, 233, 233),
|
||||
'snow3': Color(205, 201, 201),
|
||||
'snow4': Color(139, 137, 137),
|
||||
'spring green': Color(0, 255, 127),
|
||||
'springgreen': Color(0, 255, 127),
|
||||
'springgreen1': Color(0, 255, 127),
|
||||
'springgreen2': Color(0, 238, 118),
|
||||
'springgreen3': Color(0, 205, 102),
|
||||
'springgreen4': Color(0, 139, 69),
|
||||
'steel blue': Color(70, 130, 180),
|
||||
'steelblue': Color(70, 130, 180),
|
||||
'steelblue1': Color(99, 184, 255),
|
||||
'steelblue2': Color(92, 172, 238),
|
||||
'steelblue3': Color(79, 148, 205),
|
||||
'steelblue4': Color(54, 100, 139),
|
||||
'tan': Color(210, 180, 140),
|
||||
'tan1': Color(255, 165, 79),
|
||||
'tan2': Color(238, 154, 73),
|
||||
'tan3': Color(205, 133, 63),
|
||||
'tan4': Color(139, 90, 43),
|
||||
'thistle': Color(216, 191, 216),
|
||||
'thistle1': Color(255, 225, 255),
|
||||
'thistle2': Color(238, 210, 238),
|
||||
'thistle3': Color(205, 181, 205),
|
||||
'thistle4': Color(139, 123, 139),
|
||||
'tomato': Color(255, 99, 71),
|
||||
'tomato1': Color(255, 99, 71),
|
||||
'tomato2': Color(238, 92, 66),
|
||||
'tomato3': Color(205, 79, 57),
|
||||
'tomato4': Color(139, 54, 38),
|
||||
'turquoise': Color(64, 224, 208),
|
||||
'turquoise1': Color(0, 245, 255),
|
||||
'turquoise2': Color(0, 229, 238),
|
||||
'turquoise3': Color(0, 197, 205),
|
||||
'turquoise4': Color(0, 134, 139),
|
||||
'violet': Color(238, 130, 238),
|
||||
'violet red': Color(208, 32, 144),
|
||||
'violetred': Color(208, 32, 144),
|
||||
'violetred1': Color(255, 62, 150),
|
||||
'violetred2': Color(238, 58, 140),
|
||||
'violetred3': Color(205, 50, 120),
|
||||
'violetred4': Color(139, 34, 82),
|
||||
'wheat': Color(245, 222, 179),
|
||||
'wheat1': Color(255, 231, 186),
|
||||
'wheat2': Color(238, 216, 174),
|
||||
'wheat3': Color(205, 186, 150),
|
||||
'wheat4': Color(139, 126, 102),
|
||||
'white': Color(255, 255, 255),
|
||||
'white smoke': Color(245, 245, 245),
|
||||
'whitesmoke': Color(245, 245, 245),
|
||||
'yellow': Color(255, 255, 0),
|
||||
'yellow green': Color(154, 205, 50),
|
||||
'yellow1': Color(255, 255, 0),
|
||||
'yellow2': Color(238, 238, 0),
|
||||
'yellow3': Color(205, 205, 0),
|
||||
'yellow4': Color(139, 139, 0),
|
||||
'yellowgreen': Color(154, 205, 50)}
|
||||
# END_DATA_SECTION }}}
|
||||
|
||||
def main(args: list[str]=sys.argv) -> None:
|
||||
with tempfile.TemporaryFile(suffix='.gperf', mode='w+') as tf:
|
||||
print('struct Keyword { int name, value; };\n%%', file=tf)
|
||||
names = sorted(color_names)
|
||||
for name in names:
|
||||
print(f'{name}, {color_names[name]}', file=tf)
|
||||
print('%%', file=tf)
|
||||
tf.flush()
|
||||
tf.seek(0)
|
||||
with open('kitty/color-names.h', 'w') as header:
|
||||
subprocess.check_call(
|
||||
'gperf -m 2000 --struct-type --includes --readonly-tables --lookup-function-name in_color_name_set'
|
||||
' --global-table --null-strings --hash-function-name color_name_hash /dev/stdin'
|
||||
' --word-array-name color_names --pic --compare-strncmp'.split(), stdout=header, stdin=tf)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import runpy
|
||||
m = runpy.run_path(os.path.dirname(os.path.abspath(__file__)))
|
||||
m['main']([sys.executable, 'color-names'])
|
||||
@@ -43,29 +43,17 @@ def main(args: list[str]=sys.argv) -> None:
|
||||
from kitty.options.definition import definition
|
||||
nullable_colors = []
|
||||
all_colors = []
|
||||
special_colors = []
|
||||
for opt in definition.iter_all_options():
|
||||
if callable(opt.parser_func):
|
||||
match opt.parser_func.__name__:
|
||||
case 'to_color':
|
||||
all_colors.append(opt.name)
|
||||
case 'macos_titlebar_color' | 'titlebar_color' | 'scrollbar_color':
|
||||
all_colors.append(opt.name)
|
||||
special_colors.append(opt.name)
|
||||
case 'to_color_or_none' | 'cursor_text_color':
|
||||
all_colors.append(opt.name)
|
||||
nullable_colors.append(opt.name)
|
||||
|
||||
if opt.parser_func.__name__ in ('to_color_or_none', 'cursor_text_color'):
|
||||
nullable_colors.append(opt.name)
|
||||
all_colors.append(opt.name)
|
||||
elif opt.parser_func.__name__ in ('to_color', 'titlebar_color', 'macos_titlebar_color'):
|
||||
all_colors.append(opt.name)
|
||||
patch_color_list('tools/cmd/at/set_colors.go', nullable_colors, 'NULLABLE')
|
||||
patch_color_list('tools/themes/collection.go', all_colors, 'ALL')
|
||||
nc = ',\n '.join(f'{x!r}' for x in nullable_colors)
|
||||
sc = ',\n '.join(f'{x!r}' for x in special_colors)
|
||||
ac = ',\n '.join(f'{x!r}' for x in all_colors)
|
||||
write_output('kitty', definition,
|
||||
f'\nnullable_colors = frozenset({{\n {nc}\n}})\n'
|
||||
f'\nspecial_colors = frozenset({{\n {sc}\n}})\n'
|
||||
f'\nall_colors = frozenset({{\n {ac}\n}})\n'
|
||||
)
|
||||
nc = '\n '.join(f'{x!r}' for x in nullable_colors)
|
||||
write_output('kitty', definition, f'\nnullable_colors = frozenset({{\n {nc}\n}})')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -118,7 +118,7 @@ def main(args: list[str]=sys.argv) -> None:
|
||||
patch_file('glfw/x11_window.c', 'glfw to xc mapping', '\n'.join(f' {x}' for x in glfw_xfont_map))
|
||||
patch_file('kitty/data-types.h', 'mouse shapes', '\n'.join(f' {x},' for x in enum_to_glfw_map))
|
||||
patch_file(
|
||||
'kitty/options/utils.py', 'pointer shape names', '\n'.join(f' {x!r},' for x in kitty_to_enum_map),
|
||||
'kitty/options/definition.py', 'pointer shape names', '\n'.join(f' {x!r},' for x in kitty_to_enum_map),
|
||||
start_marker='# ', end_marker='',
|
||||
)
|
||||
patch_file('kitty/options/to-c.h', 'pointer shapes', '\n'.join(
|
||||
|
||||
@@ -29,20 +29,21 @@ from kittens.tui.operations import Mode
|
||||
from kittens.tui.spinners import spinners
|
||||
from kitty.actions import get_all_actions
|
||||
from kitty.cli import (
|
||||
CompletionSpec,
|
||||
GoOption,
|
||||
go_options_for_seq,
|
||||
parse_option_spec,
|
||||
serialize_as_go_string,
|
||||
)
|
||||
from kitty.conf.generate import gen_go_code
|
||||
from kitty.conf.types import Definition
|
||||
from kitty.config import commented_out_default_config
|
||||
from kitty.fast_data_types import all_color_names
|
||||
from kitty.guess_mime_type import known_extensions, text_mimes
|
||||
from kitty.key_encoding import config_mod_map
|
||||
from kitty.key_names import character_key_name_aliases, functional_key_name_aliases
|
||||
from kitty.options.types import Options
|
||||
from kitty.rc.base import RemoteCommand, all_command_names, command_for_name
|
||||
from kitty.remote_control import global_options_spec
|
||||
from kitty.simple_cli_definitions import CompletionSpec, parse_option_spec, serialize_as_go_string
|
||||
from kitty.rgb import color_names
|
||||
|
||||
if __name__ == '__main__' and not __package__:
|
||||
import __main__
|
||||
@@ -177,33 +178,6 @@ def stringify() -> None:
|
||||
stringify_file(path)
|
||||
# }}}
|
||||
|
||||
# {{{ Bitfields
|
||||
|
||||
def make_bitfields() -> None:
|
||||
from kitty.fast_data_types import SCALE_BITS, SUBSCALE_BITS, WIDTH_BITS
|
||||
|
||||
from .bitfields import make_bitfield
|
||||
|
||||
def mb(*args: str) -> None:
|
||||
output_path, ans = make_bitfield(*args)
|
||||
with replace_if_needed(output_path) as buf:
|
||||
print(ans, file=buf)
|
||||
|
||||
mb(
|
||||
'tools/vt', 'CellAttrs',
|
||||
'decoration 3', 'bold 1', 'italic 1', 'reverse 1', 'strike 1', 'dim 1', 'hyperlink_id 16',
|
||||
)
|
||||
mb('tools/vt', 'Ch', 'is_idx 1', 'ch_or_idx 31')
|
||||
mb(
|
||||
'tools/vt', 'MultiCell',
|
||||
'is_multicell 1', 'natural_width 1', f'scale {SCALE_BITS}', f'subscale_n {SUBSCALE_BITS}', f'subscale_d {SUBSCALE_BITS}',
|
||||
f'width {WIDTH_BITS}', f'x {WIDTH_BITS + SCALE_BITS + 1}', f'y {SCALE_BITS + 1}', 'vertical_align 3',
|
||||
)
|
||||
mb('tools/vt', 'CellColor', 'is_idx 1', 'red 8', 'green 8', 'blue 8')
|
||||
mb('tools/vt', 'LineAttrs', 'prompt_kind 2',)
|
||||
mb('kittens/choose_files', 'CombinedScore', 'score 16', 'length 16', 'index 32')
|
||||
# }}}
|
||||
|
||||
# Completions {{{
|
||||
|
||||
@lru_cache
|
||||
@@ -247,7 +221,7 @@ def clone_safe_launch_opts() -> Sequence[GoOption]:
|
||||
ans = []
|
||||
allowed = clone_safe_opts()
|
||||
for o in go_options_for_seq(parse_option_spec(options_spec())[0]):
|
||||
if o.obj_defn.name in allowed:
|
||||
if o.obj_dict['name'] in allowed:
|
||||
ans.append(o)
|
||||
return tuple(ans)
|
||||
|
||||
@@ -260,9 +234,9 @@ def completion_for_launch_wrappers(*names: str) -> None:
|
||||
|
||||
def generate_completions_for_kitty() -> None:
|
||||
print('package completion\n')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cli"')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cmd/tool"')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cmd/at"')
|
||||
print('import "kitty/tools/cli"')
|
||||
print('import "kitty/tools/cmd/tool"')
|
||||
print('import "kitty/tools/cmd/at"')
|
||||
|
||||
print('func kitty(root *cli.Command) {')
|
||||
|
||||
@@ -451,6 +425,15 @@ def go_code_for_remote_command(name: str, cmd: RemoteCommand, template: str) ->
|
||||
|
||||
# kittens {{{
|
||||
|
||||
@lru_cache
|
||||
def wrapped_kittens() -> tuple[str, ...]:
|
||||
with open('shell-integration/ssh/kitty') as f:
|
||||
for line in f:
|
||||
if line.startswith(' wrapped_kittens="'):
|
||||
val = line.strip().partition('"')[2][:-1]
|
||||
return tuple(sorted(filter(None, val.split())))
|
||||
raise Exception('Failed to read wrapped kittens from kitty wrapper script')
|
||||
|
||||
|
||||
def generate_conf_parser(kitten: str, defn: Definition) -> None:
|
||||
with replace_if_needed(f'kittens/{kitten}/conf_generated.go'):
|
||||
@@ -459,7 +442,7 @@ def generate_conf_parser(kitten: str, defn: Definition) -> None:
|
||||
|
||||
|
||||
def generate_extra_cli_parser(name: str, spec: str) -> None:
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cli"')
|
||||
print('import "kitty/tools/cli"')
|
||||
go_opts = tuple(go_options_for_seq(parse_option_spec(spec)[0]))
|
||||
print(f'type {name}_options struct ''{')
|
||||
for opt in go_opts:
|
||||
@@ -504,13 +487,10 @@ def kitten_clis() -> None:
|
||||
|
||||
with replace_if_needed(f'kittens/{kitten}/cli_generated.go'):
|
||||
od = []
|
||||
ser = []
|
||||
kcd = kitten_cli_docs(kitten)
|
||||
has_underscore = '_' in kitten
|
||||
print(f'package {kitten}')
|
||||
print('import "fmt"')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cli"')
|
||||
print('var _ = fmt.Sprintf')
|
||||
print('import "kitty/tools/cli"')
|
||||
print('func create_cmd(root *cli.Command, run_func func(*cli.Command, *Options, []string)(int, error)) {')
|
||||
print('ans := root.AddSubCommand(&cli.Command{')
|
||||
print(f'Name: "{kitten}",')
|
||||
@@ -531,7 +511,6 @@ def kitten_clis() -> None:
|
||||
for opt in gopts:
|
||||
print(opt.as_option('ans'))
|
||||
od.append(opt.struct_declaration())
|
||||
ser.append('\n'.join(opt.as_string_for_commandline()))
|
||||
if ac is not None:
|
||||
print(''.join(ac.as_go_code('ans.ArgCompleter', ' = ')))
|
||||
if not kcd:
|
||||
@@ -544,14 +523,6 @@ def kitten_clis() -> None:
|
||||
print('type Options struct {')
|
||||
print('\n'.join(od))
|
||||
print('}')
|
||||
print('func (opts Options) AsCommandLine() (ans []string) {')
|
||||
if ser:
|
||||
print('\t sval := ""')
|
||||
print('\t _ = sval')
|
||||
for x in ser:
|
||||
print('\t' + x)
|
||||
print('return')
|
||||
print('}')
|
||||
|
||||
# }}}
|
||||
|
||||
@@ -585,7 +556,7 @@ def generate_color_names() -> str:
|
||||
cursor = "" if Options.cursor is None else Options.cursor.as_sharp
|
||||
return 'package style\n\nvar ColorNames = map[string]RGBA{' + '\n'.join(
|
||||
f'\t"{name}": RGBA{{ Red:{val.red}, Green:{val.green}, Blue:{val.blue} }},'
|
||||
for name, val in all_color_names()
|
||||
for name, val in color_names.items()
|
||||
) + '\n}' + '\n\nvar ColorTable = [256]uint32{' + ', '.join(
|
||||
f'{x}' for x in Options.color_table) + '}\n' + f'''
|
||||
var DefaultColors = struct {{
|
||||
@@ -611,11 +582,9 @@ def load_ref_map() -> dict[str, dict[str, str]]:
|
||||
def generate_constants() -> str:
|
||||
from kittens.hints.main import DEFAULT_REGEX
|
||||
from kittens.query_terminal.main import all_queries
|
||||
from kitty.colors import ThemeFile
|
||||
from kitty.config import option_names_for_completion
|
||||
from kitty.fast_data_types import DND_CODE, FILE_TRANSFER_CODE
|
||||
from kitty.fast_data_types import FILE_TRANSFER_CODE
|
||||
from kitty.options.utils import allowed_shell_integration_values, url_style_map
|
||||
from kitty.simple_cli_definitions import CONFIG_HELP
|
||||
del sys.modules['kittens.hints.main']
|
||||
del sys.modules['kittens.query_terminal.main']
|
||||
ref_map = load_ref_map()
|
||||
@@ -637,7 +606,6 @@ type VersionType struct {{
|
||||
const VersionString string = "{kc.str_version}"
|
||||
const WebsiteBaseURL string = "{kc.website_base_url}"
|
||||
const FileTransferCode int = {FILE_TRANSFER_CODE}
|
||||
const DndCode int = {DND_CODE}
|
||||
const ImagePlaceholderChar rune = {placeholder_char}
|
||||
const SSHControlMasterTemplate = "{kc.ssh_control_master_template}"
|
||||
const RC_ENCRYPTION_PROTOCOL_VERSION string = "{kc.RC_ENCRYPTION_PROTOCOL_VERSION}"
|
||||
@@ -649,7 +617,6 @@ const HintsDefaultRegex = `{DEFAULT_REGEX}`
|
||||
const DefaultTermName = `{Options.term}`
|
||||
const DefaultUrlStyle = `{url_style}`
|
||||
const DefaultUrlColor = `{Options.url_color.as_sharp}`
|
||||
const ConfigHelp = "{serialize_as_go_string(CONFIG_HELP)}"
|
||||
var Version VersionType = VersionType{{Major: {kc.version.major}, Minor: {kc.version.minor}, Patch: {kc.version.patch},}}
|
||||
var DefaultPager []string = []string{{ {dp} }}
|
||||
var FunctionalKeyNameAliases = map[string]string{serialize_go_dict(functional_key_name_aliases)}
|
||||
@@ -659,10 +626,9 @@ var RefMap = map[string]string{serialize_go_dict(ref_map['ref'])}
|
||||
var DocTitleMap = map[string]string{serialize_go_dict(ref_map['doc'])}
|
||||
var AllowedShellIntegrationValues = []string{{ {str(sorted(allowed_shell_integration_values))[1:-1].replace("'", '"')} }}
|
||||
var QueryNames = []string{{ {query_names} }}
|
||||
var CommentedOutDefaultConfig = "{serialize_as_go_string(commented_out_default_config())}"
|
||||
var KittyConfigDefaults = struct {{
|
||||
Term, Shell_integration, Select_by_word_characters, Url_excluded_characters, Shell string
|
||||
Wheel_scroll_multiplier float64
|
||||
Wheel_scroll_multiplier int
|
||||
Url_prefixes []string
|
||||
}}{{
|
||||
Term: "{Options.term}", Shell_integration: "{' '.join(Options.shell_integration)}", Url_prefixes: []string{{ {url_prefixes} }},
|
||||
@@ -670,9 +636,6 @@ Select_by_word_characters: `{Options.select_by_word_characters}`, Wheel_scroll_m
|
||||
Shell: "{Options.shell}", Url_excluded_characters: "{Options.url_excluded_characters}",
|
||||
}}
|
||||
const OptionNames = {option_names}
|
||||
const DarkThemeFileName = "{ThemeFile.dark.value}"
|
||||
const LightThemeFileName = "{ThemeFile.light.value}"
|
||||
const NoPreferenceThemeFileName = "{ThemeFile.no_preference.value}"
|
||||
''' # }}}
|
||||
|
||||
|
||||
@@ -727,7 +690,7 @@ def update_at_commands() -> None:
|
||||
odef = '\n'.join(opt_def)
|
||||
code = f'''
|
||||
package at
|
||||
import "github.com/kovidgoyal/kitty/tools/cli"
|
||||
import "kitty/tools/cli"
|
||||
type rc_global_options struct {{
|
||||
{sdef}
|
||||
}}
|
||||
@@ -755,11 +718,10 @@ def update_completion() -> None:
|
||||
|
||||
with replace_if_needed('tools/cmd/edit_in_kitty/launch_generated.go'):
|
||||
print('package edit_in_kitty')
|
||||
print('import "github.com/kovidgoyal/kitty/tools/cli"')
|
||||
print('import "kitty/tools/cli"')
|
||||
print('func AddCloneSafeOpts(cmd *cli.Command) {')
|
||||
completion_for_launch_wrappers('cmd')
|
||||
m = ','.join(text_mimes)
|
||||
print(''.join(CompletionSpec.from_string(f'type:file mime:text/*,{m} ext:bash,zsh group:"Text files"').as_go_code('cmd.ArgCompleter', ' = ')))
|
||||
print(''.join(CompletionSpec.from_string('type:file mime:text/* group:"Text files"').as_go_code('cmd.ArgCompleter', ' = ')))
|
||||
print('}')
|
||||
|
||||
|
||||
@@ -938,7 +900,6 @@ def main(args: list[str]=sys.argv) -> None:
|
||||
update_at_commands()
|
||||
kitten_clis()
|
||||
stringify()
|
||||
make_bitfields()
|
||||
print(json.dumps(changed, indent=2))
|
||||
stdout, stderr = simdgen_process.communicate()
|
||||
if simdgen_process.wait() != 0:
|
||||
|
||||
11101
gen/nerd-fonts-glyphs.txt
Normal file
11101
gen/nerd-fonts-glyphs.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@ def generate_srgb_lut(line_prefix: str = ' ') -> list[str]:
|
||||
lines: list[str] = []
|
||||
|
||||
for i in range(256):
|
||||
values.append(f'{to_linear(i / 255.0):1.8f}f')
|
||||
values.append(f'{to_linear(i / 255.0):1.5f}f')
|
||||
|
||||
for i in range(16):
|
||||
lines.append(line_prefix + ', '.join(values[i * 16:(i + 1) * 16]) + ',')
|
||||
|
||||
1122
gen/wcwidth.py
1122
gen/wcwidth.py
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,7 @@ import subprocess
|
||||
|
||||
cmdline = (
|
||||
'glad --out-path {dest} --api gl:core=3.1 '
|
||||
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,'
|
||||
'GL_ARB_instanced_arrays,GL_KHR_debug,GL_ARB_framebuffer_sRGB,GL_EXT_framebuffer_sRGB '
|
||||
' --extensions GL_ARB_texture_storage,GL_ARB_copy_image,GL_ARB_multisample,GL_ARB_robustness,GL_ARB_instanced_arrays,GL_KHR_debug '
|
||||
'c --header-only --debug'
|
||||
)
|
||||
|
||||
|
||||
32
glfw/backend_utils.c
vendored
32
glfw/backend_utils.c
vendored
@@ -31,6 +31,7 @@ update_fds(EventLoopData *eld) {
|
||||
}
|
||||
}
|
||||
|
||||
static id_type watch_counter = 0;
|
||||
|
||||
id_type
|
||||
addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled, watch_callback_func cb, void *cb_data) {
|
||||
@@ -38,7 +39,6 @@ addWatch(EventLoopData *eld, const char* name, int fd, int events, int enabled,
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many watches added");
|
||||
return 0;
|
||||
}
|
||||
static id_type watch_counter = 0;
|
||||
Watch *w = eld->watches + eld->watches_count++;
|
||||
w->name = name;
|
||||
w->fd = fd; w->events = events; w->enabled = enabled;
|
||||
@@ -234,12 +234,6 @@ mark_wakep_fd_ready(int fd UNUSED, int events UNUSED, void *data) {
|
||||
((EventLoopData*)(data))->wakeup_fd_ready = true;
|
||||
}
|
||||
|
||||
static void
|
||||
mark_key_repeat_fd_ready(int fd UNUSED, int events UNUSED, void *data) {
|
||||
((EventLoopData*)(data))->key_repeat_fd_ready = true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
initPollData(EventLoopData *eld, int display_fd) {
|
||||
if (!addWatch(eld, "display", display_fd, POLLIN, 1, NULL, NULL)) return false;
|
||||
@@ -252,20 +246,6 @@ initPollData(EventLoopData *eld, int display_fd) {
|
||||
const int wakeup_fd = eld->wakeupFds[0];
|
||||
#endif
|
||||
if (!addWatch(eld, "wakeup", wakeup_fd, POLLIN, 1, mark_wakep_fd_ready, eld)) return false;
|
||||
|
||||
#ifdef HAS_TIMER_FD
|
||||
eld->key_repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
|
||||
if (eld->key_repeat_fd < 0) return false;
|
||||
const int key_repeat_fd = eld->key_repeat_fd;
|
||||
#else
|
||||
if (pipe2(eld->key_repeat_fds, O_CLOEXEC | O_NONBLOCK) != 0) return false;
|
||||
const int key_repeat_fd = eld->key_repeat_fds[0];
|
||||
#endif
|
||||
#ifdef _GLFW_WAYLAND
|
||||
if (!addWatch(eld, "key_repeat", key_repeat_fd, POLLIN, 1, mark_key_repeat_fd_ready, eld)) return false;
|
||||
#else
|
||||
(void)key_repeat_fd; (void)mark_key_repeat_fd_ready;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -289,6 +269,7 @@ wakeupEventLoop(EventLoopData *eld) {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef HAS_EVENT_FD
|
||||
static void
|
||||
closeFds(int *fds, size_t count) {
|
||||
while(count--) {
|
||||
@@ -299,20 +280,15 @@ closeFds(int *fds, size_t count) {
|
||||
fds++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
finalizePollData(EventLoopData *eld) {
|
||||
(void)closeFds;
|
||||
#ifdef HAS_EVENT_FD
|
||||
close(eld->wakeupFd); eld->wakeupFd = -1;
|
||||
#else
|
||||
closeFds(eld->wakeupFds, arraysz(eld->wakeupFds));
|
||||
#endif
|
||||
#ifdef HAS_TIMER_FD
|
||||
close(eld->key_repeat_fd); eld->key_repeat_fd = -1;
|
||||
#else
|
||||
closeFds(eld->key_repeat_fds, arraysz(eld->key_repeat_fds));
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
@@ -322,7 +298,7 @@ pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func displ
|
||||
EVDBG("pollForEvents final timeout: %.3f", monotonic_t_to_s_double(timeout));
|
||||
int result;
|
||||
monotonic_t end_time = monotonic() + timeout;
|
||||
eld->wakeup_fd_ready = false; eld->key_repeat_fd_ready = false;
|
||||
eld->wakeup_fd_ready = false;
|
||||
|
||||
while(1) {
|
||||
if (timeout >= 0) {
|
||||
|
||||
16
glfw/backend_utils.h
vendored
16
glfw/backend_utils.h
vendored
@@ -36,10 +36,6 @@
|
||||
#define HAS_EVENT_FD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
#if __has_include(<sys/timerfd.h>)
|
||||
#define HAS_TIMER_FD
|
||||
#include <sys/timerfd.h>
|
||||
#endif
|
||||
#else
|
||||
#define HAS_EVENT_FD
|
||||
#include <sys/eventfd.h>
|
||||
@@ -69,23 +65,17 @@ typedef struct {
|
||||
bool repeats;
|
||||
} Timer;
|
||||
|
||||
#define MAX_NUM_OF_WATCHED_FDS 64
|
||||
|
||||
typedef struct {
|
||||
struct pollfd fds[MAX_NUM_OF_WATCHED_FDS];
|
||||
struct pollfd fds[32];
|
||||
#ifdef HAS_EVENT_FD
|
||||
int wakeupFd;
|
||||
#else
|
||||
int wakeupFds[2];
|
||||
#endif
|
||||
#ifdef HAS_TIMER_FD
|
||||
int key_repeat_fd;
|
||||
#else
|
||||
int key_repeat_fds[2];
|
||||
#endif
|
||||
bool wakeup_data_read, wakeup_fd_ready, key_repeat_fd_ready;
|
||||
bool wakeup_data_read, wakeup_fd_ready;
|
||||
nfds_t watches_count, timers_count;
|
||||
Watch watches[MAX_NUM_OF_WATCHED_FDS];
|
||||
Watch watches[32];
|
||||
Timer timers[128];
|
||||
} EventLoopData;
|
||||
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
/*
|
||||
* cocoa_displaylink.m
|
||||
* Copyright (C) 2024 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
// CVDisplayLink is deprecated replace with CADisplayLink via [NSScreen displayLink] once base macOS version is 14
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
#include "internal.h"
|
||||
#include <CoreVideo/CVDisplayLink.h>
|
||||
#include <os/lock.h>
|
||||
|
||||
#define DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL s_to_monotonic_t(30ll)
|
||||
#define MAX_NUM_OF_DISPLAYS 256
|
||||
|
||||
typedef struct _GLFWDisplayLinkNS
|
||||
{
|
||||
CVDisplayLinkRef displayLink;
|
||||
CGDirectDisplayID displayID;
|
||||
monotonic_t lastRenderFrameRequestedAt, first_unserviced_render_frame_request_at;
|
||||
bool pending_dispatch;
|
||||
} _GLFWDisplayLinkNS;
|
||||
|
||||
static struct {
|
||||
_GLFWDisplayLinkNS entries[MAX_NUM_OF_DISPLAYS];
|
||||
os_unfair_lock locks[MAX_NUM_OF_DISPLAYS];
|
||||
bool locks_initialized[MAX_NUM_OF_DISPLAYS];
|
||||
size_t count;
|
||||
} displayLinks = {0};
|
||||
|
||||
static inline size_t
|
||||
index_for_entry(_GLFWDisplayLinkNS *entry) {
|
||||
return (size_t)(entry - displayLinks.entries);
|
||||
}
|
||||
|
||||
static inline os_unfair_lock*
|
||||
lock_for_entry(_GLFWDisplayLinkNS *entry) {
|
||||
return &displayLinks.locks[index_for_entry(entry)];
|
||||
}
|
||||
|
||||
static CGDirectDisplayID
|
||||
displayIDForWindow(_GLFWwindow *w) {
|
||||
NSWindow *nw = w->ns.object;
|
||||
NSDictionary *dict = [nw.screen deviceDescription];
|
||||
NSNumber *displayIDns = dict[@"NSScreenNumber"];
|
||||
if (displayIDns) return [displayIDns unsignedIntValue];
|
||||
return (CGDirectDisplayID)-1;
|
||||
}
|
||||
|
||||
void
|
||||
_glfwClearDisplayLinks(void) {
|
||||
for (size_t i = 0; i < displayLinks.count; i++) {
|
||||
_GLFWDisplayLinkNS *entry = &displayLinks.entries[i];
|
||||
os_unfair_lock *lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(lock);
|
||||
CVDisplayLinkRef link = entry->displayLink;
|
||||
entry->displayLink = NULL;
|
||||
entry->displayID = (CGDirectDisplayID)0;
|
||||
entry->lastRenderFrameRequestedAt = 0;
|
||||
entry->first_unserviced_render_frame_request_at = 0;
|
||||
entry->pending_dispatch = false;
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (link) {
|
||||
CVDisplayLinkStop(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
}
|
||||
displayLinks.count = 0;
|
||||
}
|
||||
|
||||
static void _glfwDispatchRenderFrame(void *);
|
||||
|
||||
static CVReturn
|
||||
displayLinkCallback(
|
||||
CVDisplayLinkRef displayLink UNUSED,
|
||||
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
|
||||
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo) {
|
||||
_GLFWDisplayLinkNS *entry = (_GLFWDisplayLinkNS *)userInfo;
|
||||
if (entry) {
|
||||
os_unfair_lock *lock = lock_for_entry(entry);
|
||||
os_unfair_lock_lock(lock);
|
||||
const bool should_dispatch = entry->first_unserviced_render_frame_request_at &&
|
||||
!entry->pending_dispatch;
|
||||
CGDirectDisplayID displayID = entry->displayID;
|
||||
if (should_dispatch) entry->pending_dispatch = true;
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (should_dispatch) dispatch_async_f(dispatch_get_main_queue(), (void*)(uintptr_t)displayID, _glfwDispatchRenderFrame);
|
||||
}
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
static void
|
||||
_glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry) {
|
||||
CVDisplayLinkCreateWithCGDisplay(entry->displayID, &entry->displayLink);
|
||||
if (entry->displayLink) CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, entry);
|
||||
}
|
||||
|
||||
unsigned
|
||||
_glfwCreateDisplayLink(CGDirectDisplayID displayID) {
|
||||
for (unsigned i = 0; i < displayLinks.count; i++) {
|
||||
os_unfair_lock *existing_lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(existing_lock);
|
||||
const bool already_created = displayLinks.entries[i].displayID == displayID;
|
||||
os_unfair_lock_unlock(existing_lock);
|
||||
if (already_created) return i;
|
||||
}
|
||||
if (displayLinks.count >= MAX_NUM_OF_DISPLAYS) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many monitors cannot create display link");
|
||||
return displayLinks.count;
|
||||
}
|
||||
unsigned idx = displayLinks.count;
|
||||
_GLFWDisplayLinkNS *entry = &displayLinks.entries[idx];
|
||||
if (!displayLinks.locks_initialized[idx]) {
|
||||
displayLinks.locks[idx] = OS_UNFAIR_LOCK_INIT;
|
||||
displayLinks.locks_initialized[idx] = true;
|
||||
}
|
||||
os_unfair_lock *lock = &displayLinks.locks[idx];
|
||||
os_unfair_lock_lock(lock);
|
||||
memset(entry, 0, sizeof(entry[0]));
|
||||
entry->displayID = displayID;
|
||||
displayLinks.count++;
|
||||
_glfw_create_cv_display_link(entry);
|
||||
os_unfair_lock_unlock(lock);
|
||||
return idx;
|
||||
}
|
||||
|
||||
static unsigned long long display_link_shutdown_timer = 0;
|
||||
|
||||
static void
|
||||
_glfwShutdownCVDisplayLink(unsigned long long timer_id UNUSED, void *user_data UNUSED) {
|
||||
display_link_shutdown_timer = 0;
|
||||
for (size_t i = 0; i < displayLinks.count; i++) {
|
||||
_GLFWDisplayLinkNS *dl = &displayLinks.entries[i];
|
||||
os_unfair_lock *lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(lock);
|
||||
CVDisplayLinkRef link = dl->displayLink;
|
||||
if (link) CVDisplayLinkRetain(link);
|
||||
dl->lastRenderFrameRequestedAt = 0;
|
||||
dl->first_unserviced_render_frame_request_at = 0;
|
||||
dl->pending_dispatch = false;
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (link) {
|
||||
CVDisplayLinkStop(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_glfwRequestRenderFrame(_GLFWwindow *w) {
|
||||
CGDirectDisplayID displayID = displayIDForWindow(w);
|
||||
if (display_link_shutdown_timer) {
|
||||
_glfwPlatformUpdateTimer(display_link_shutdown_timer, DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, true);
|
||||
} else {
|
||||
display_link_shutdown_timer = _glfwPlatformAddTimer(DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL, false, _glfwShutdownCVDisplayLink, NULL, NULL);
|
||||
}
|
||||
monotonic_t now = glfwGetTime();
|
||||
bool found_display_link = false;
|
||||
_GLFWDisplayLinkNS *dl = NULL;
|
||||
for (size_t i = 0; i < displayLinks.count; i++) {
|
||||
dl = &displayLinks.entries[i];
|
||||
bool need_start = false, need_stop = false, need_recreate = false;
|
||||
bool retain_link = false;
|
||||
CVDisplayLinkRef link = NULL;
|
||||
CVDisplayLinkRef new_link = NULL;
|
||||
bool new_link_retained = false;
|
||||
os_unfair_lock *lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(lock);
|
||||
link = dl->displayLink;
|
||||
if (dl->displayID == displayID) {
|
||||
found_display_link = true;
|
||||
monotonic_t first_unserviced = dl->first_unserviced_render_frame_request_at;
|
||||
dl->lastRenderFrameRequestedAt = now;
|
||||
if (!first_unserviced) {
|
||||
dl->first_unserviced_render_frame_request_at = now;
|
||||
first_unserviced = now;
|
||||
}
|
||||
dl->pending_dispatch = false;
|
||||
if (link) {
|
||||
if (!CVDisplayLinkIsRunning(link)) {
|
||||
need_start = true;
|
||||
retain_link = true;
|
||||
} else if (now - first_unserviced > s_to_monotonic_t(1ll)) {
|
||||
need_recreate = true;
|
||||
dl->first_unserviced_render_frame_request_at = now;
|
||||
dl->displayLink = NULL;
|
||||
}
|
||||
}
|
||||
} else if (link && dl->lastRenderFrameRequestedAt && now - dl->lastRenderFrameRequestedAt >= DISPLAY_LINK_SHUTDOWN_CHECK_INTERVAL) {
|
||||
need_stop = true;
|
||||
retain_link = true;
|
||||
dl->lastRenderFrameRequestedAt = 0;
|
||||
dl->first_unserviced_render_frame_request_at = 0;
|
||||
dl->pending_dispatch = false;
|
||||
}
|
||||
if (retain_link && link) CVDisplayLinkRetain(link);
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (need_recreate && link) {
|
||||
CVDisplayLinkStop(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
os_unfair_lock_lock(lock);
|
||||
_glfw_create_cv_display_link(dl);
|
||||
new_link = dl->displayLink;
|
||||
if (new_link) {
|
||||
CVDisplayLinkRetain(new_link);
|
||||
new_link_retained = true;
|
||||
}
|
||||
dl->pending_dispatch = false;
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (new_link) {
|
||||
if (!CVDisplayLinkIsRunning(new_link)) CVDisplayLinkStart(new_link);
|
||||
if (new_link_retained) CVDisplayLinkRelease(new_link);
|
||||
}
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR,
|
||||
"CVDisplayLink stuck possibly because of sleep/screensaver + Apple's incompetence, recreating.");
|
||||
} else {
|
||||
if (need_start && link) CVDisplayLinkStart(link);
|
||||
else if (need_stop && link) CVDisplayLinkStop(link);
|
||||
if (retain_link && link) CVDisplayLinkRelease(link);
|
||||
}
|
||||
}
|
||||
if (!found_display_link) {
|
||||
unsigned idx = _glfwCreateDisplayLink(displayID);
|
||||
if (idx < displayLinks.count) {
|
||||
dl = &displayLinks.entries[idx];
|
||||
os_unfair_lock *lock = &displayLinks.locks[idx];
|
||||
os_unfair_lock_lock(lock);
|
||||
dl->lastRenderFrameRequestedAt = now;
|
||||
dl->first_unserviced_render_frame_request_at = now;
|
||||
dl->pending_dispatch = false;
|
||||
CVDisplayLinkRef link = dl->displayLink;
|
||||
if (link) CVDisplayLinkRetain(link);
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (link) {
|
||||
if (!CVDisplayLinkIsRunning(link)) CVDisplayLinkStart(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_glfwDispatchRenderFrame(void *passed_in_data) {
|
||||
CGDirectDisplayID displayID = (uintptr_t)passed_in_data;
|
||||
_GLFWwindow *w = _glfw.windowListHead;
|
||||
while (w) {
|
||||
if (w->ns.renderFrameRequested && displayID == displayIDForWindow(w)) {
|
||||
w->ns.renderFrameRequested = false;
|
||||
w->ns.renderFrameCallback((GLFWwindow*)w);
|
||||
}
|
||||
w = w->next;
|
||||
}
|
||||
for (size_t i = 0; i < displayLinks.count; i++) {
|
||||
_GLFWDisplayLinkNS *dl = &displayLinks.entries[i];
|
||||
bool need_stop = false;
|
||||
CVDisplayLinkRef link = NULL;
|
||||
os_unfair_lock *lock = &displayLinks.locks[i];
|
||||
os_unfair_lock_lock(lock);
|
||||
if (dl->displayID == displayID) {
|
||||
dl->first_unserviced_render_frame_request_at = 0;
|
||||
dl->pending_dispatch = false;
|
||||
bool any_pending_request = false;
|
||||
_GLFWwindow *window = _glfw.windowListHead;
|
||||
while (window) {
|
||||
if (window->ns.renderFrameRequested && displayID == displayIDForWindow(window)) {
|
||||
any_pending_request = true;
|
||||
break;
|
||||
}
|
||||
window = window->next;
|
||||
}
|
||||
link = dl->displayLink;
|
||||
if (!any_pending_request && link && CVDisplayLinkIsRunning(link)) {
|
||||
need_stop = true;
|
||||
CVDisplayLinkRetain(link);
|
||||
dl->lastRenderFrameRequestedAt = 0;
|
||||
}
|
||||
}
|
||||
os_unfair_lock_unlock(lock);
|
||||
if (need_stop && link) {
|
||||
CVDisplayLinkStop(link);
|
||||
CVDisplayLinkRelease(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@
|
||||
#include "internal.h"
|
||||
#include "../kitty/monotonic.h"
|
||||
#include <sys/param.h> // For MAXPATHLEN
|
||||
#include <sys/sysctl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// Needed for _NSGetProgname
|
||||
@@ -298,37 +297,10 @@ static NSDictionary<NSString*,NSNumber*> *global_shortcuts = nil;
|
||||
// Delegate for application related notifications {{{
|
||||
|
||||
@interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
|
||||
- (void)handleAppearanceChange;
|
||||
@end
|
||||
|
||||
@implementation GLFWApplicationDelegate
|
||||
|
||||
- (void)applicationDidActivate:(NSNotification *)notification {
|
||||
NSRunningApplication *app = notification.userInfo[NSWorkspaceApplicationKey];
|
||||
if (app && app.processIdentifier != getpid()) {
|
||||
_glfw.ns.previous_front_most_application = app.processIdentifier;
|
||||
debug_rendering("Front most application changed to: %s pid: %d\n", app.bundleIdentifier.UTF8String, app.processIdentifier)
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification {
|
||||
(void)notification;
|
||||
// When the application becomes active after switching spaces (e.g., swiping
|
||||
// back from a fullscreen app on another space), macOS may not send
|
||||
// windowDidBecomeKey: for the already-key window. This leaves GLFW thinking
|
||||
// no window has focus (since windowDidResignKey: was sent when leaving).
|
||||
// Ensure GLFW's focus state is updated to match the actual key window.
|
||||
NSWindow *keyWindow = [NSApp keyWindow];
|
||||
if (keyWindow && !_glfw.focusedWindowId) {
|
||||
for (_GLFWwindow *window = _glfw.windowListHead; window; window = window->next) {
|
||||
if (window->ns.object == keyWindow) {
|
||||
if (_glfw.focusedWindowId != window->id) _glfwInputWindowFocus(window, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
|
||||
{
|
||||
(void)sender;
|
||||
@@ -386,7 +358,8 @@ static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
|
||||
else
|
||||
createMenuBar();
|
||||
}
|
||||
if (finish_launching_callback) finish_launching_callback(false);
|
||||
if (finish_launching_callback)
|
||||
finish_launching_callback();
|
||||
}
|
||||
|
||||
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
|
||||
@@ -435,76 +408,19 @@ static GLFWapplicationwillfinishlaunchingfun finish_launching_callback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void *AppearanceObservationContext = &AppearanceObservationContext;
|
||||
static NSDate *application_finished_launching_at = nil;
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
(void)notification;
|
||||
[[NSApplication sharedApplication] addObserver:self
|
||||
forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
|
||||
context:AppearanceObservationContext];
|
||||
|
||||
if (finish_launching_callback) finish_launching_callback(true);
|
||||
[NSApp stop:nil];
|
||||
|
||||
CGDisplayRegisterReconfigurationCallback(display_reconfigured, NULL);
|
||||
_glfwCocoaPostEmptyEvent();
|
||||
application_finished_launching_at = [NSDate date];
|
||||
}
|
||||
|
||||
GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialized) {
|
||||
(void)query_if_unintialized;
|
||||
int theme_type = GLFW_COLOR_SCHEME_NO_PREFERENCE;
|
||||
NSAppearance *changedAppearance = NSApp.effectiveAppearance;
|
||||
NSAppearanceName newAppearance = [changedAppearance bestMatchFromAppearancesWithNames:@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
|
||||
if([newAppearance isEqualToString:NSAppearanceNameDarkAqua]){
|
||||
theme_type = GLFW_COLOR_SCHEME_DARK;
|
||||
} else {
|
||||
theme_type = GLFW_COLOR_SCHEME_LIGHT;
|
||||
}
|
||||
return theme_type;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary<NSKeyValueChangeKey, id> *)change
|
||||
context:(void *)context {
|
||||
if (context == AppearanceObservationContext) {
|
||||
if ([keyPath isEqualToString:@"effectiveAppearance"]) {
|
||||
// The initial call (from NSKeyValueObservingOptionInitial) might happen on a background thread.
|
||||
// Dispatch to the main thread to be safe, especially if updating UI.
|
||||
__block __typeof__(self) weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[weakSelf handleAppearanceChange];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// If the context doesn't match, pass the notification to the superclass.
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleAppearanceChange {
|
||||
static GLFWColorScheme previously_reported_appearance = GLFW_COLOR_SCHEME_NO_PREFERENCE;
|
||||
GLFWColorScheme new_appearance = glfwGetCurrentSystemColorTheme(true);
|
||||
if (new_appearance != previously_reported_appearance) {
|
||||
previously_reported_appearance = new_appearance;
|
||||
_glfwInputColorScheme(new_appearance, false);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)aNotification
|
||||
{
|
||||
(void)aNotification;
|
||||
CGDisplayRemoveReconfigurationCallback(display_reconfigured, NULL);
|
||||
@try {
|
||||
[[NSApplication sharedApplication] removeObserver:self
|
||||
forKeyPath:@"effectiveAppearance"
|
||||
context:AppearanceObservationContext];
|
||||
} @catch (NSException * __unused exception) {
|
||||
// Ignore exceptions, which can happen if the observer was never added.
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidHide:(NSNotification *)notification
|
||||
@@ -522,6 +438,7 @@ GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialize
|
||||
|
||||
@interface GLFWApplication : NSApplication
|
||||
- (void)tick_callback;
|
||||
- (void)render_frame_received:(id)displayIDAsID;
|
||||
@end
|
||||
|
||||
@implementation GLFWApplication
|
||||
@@ -530,6 +447,11 @@ GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialize
|
||||
_glfwDispatchTickCallback();
|
||||
}
|
||||
|
||||
- (void)render_frame_received:(id)displayIDAsID
|
||||
{
|
||||
CGDirectDisplayID displayID = [(NSNumber*)displayIDAsID unsignedIntValue];
|
||||
_glfwDispatchRenderFrame(displayID);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@@ -857,24 +779,6 @@ is_apple_jis_layout_function_key(NSEvent *event) {
|
||||
return [event keyCode] == 0x66 /* kVK_JIS_Eisu */ || [event keyCode] == 0x68 /* kVK_JIS_Kana */;
|
||||
}
|
||||
|
||||
static bool
|
||||
has_apple_fn_global_shortcut(void) {
|
||||
NSDictionary *hitoolbox_settings = [[NSUserDefaults standardUserDefaults] persistentDomainForName:@"com.apple.HIToolbox"];
|
||||
id obj = [hitoolbox_settings objectForKey:@"AppleFnUsageType"];
|
||||
if (![obj isKindOfClass:[NSNumber class]]) return false;
|
||||
// Non-zero AppleFnUsageType means macOS has reserved Fn/Globe for a
|
||||
// system action such as input source switching, emoji picker, or dictation.
|
||||
return [obj integerValue] != 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_apple_fn_global_shortcut(NSEvent *event) {
|
||||
if ([event keyCode] != 0x3f /* kVK_Function */) return false;
|
||||
NSEventModifierFlags mods = USEFUL_MODS([event modifierFlags]);
|
||||
if (mods != 0 && mods != NSEventModifierFlagFunction) return false;
|
||||
return has_apple_fn_global_shortcut();
|
||||
}
|
||||
|
||||
GLFWAPI GLFWapplicationshouldhandlereopenfun glfwSetApplicationShouldHandleReopen(GLFWapplicationshouldhandlereopenfun callback) {
|
||||
GLFWapplicationshouldhandlereopenfun previous = handle_reopen_callback;
|
||||
handle_reopen_callback = callback;
|
||||
@@ -887,11 +791,10 @@ GLFWAPI GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunch
|
||||
return previous;
|
||||
}
|
||||
|
||||
int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
int _glfwPlatformInit(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
||||
*supports_window_occlusion = true;
|
||||
_glfw.ns.helper = [[GLFWHelper alloc] init];
|
||||
|
||||
[NSThread detachNewThreadSelector:@selector(doNothing:)
|
||||
@@ -912,11 +815,6 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
}
|
||||
|
||||
[NSApp setDelegate:_glfw.ns.delegate];
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter]
|
||||
addObserver:_glfw.ns.delegate
|
||||
selector:@selector(applicationDidActivate:)
|
||||
name:NSWorkspaceDidActivateApplicationNotification
|
||||
object:nil];
|
||||
static struct {
|
||||
unsigned short virtual_key_code;
|
||||
NSEventModifierFlags input_source_switch_modifiers;
|
||||
@@ -927,12 +825,12 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
|
||||
NSEvent* (^keydown_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
debug_input("---------------- key down -------------------\n");
|
||||
debug_input("%s\n", [[event description] UTF8String]);
|
||||
if (!_glfw.ignoreOSKeyboardProcessing && !_glfw.keyboard_grabbed) {
|
||||
debug_key("---------------- key down -------------------\n");
|
||||
debug_key("%s\n", [[event description] UTF8String]);
|
||||
if (!_glfw.ignoreOSKeyboardProcessing) {
|
||||
// first check if there is a global menu bar shortcut
|
||||
if ([[NSApp mainMenu] performKeyEquivalent:event]) {
|
||||
debug_input("keyDown triggered global menu bar action ignoring\n");
|
||||
debug_key("keyDown triggered global menu bar action ignoring\n");
|
||||
last_keydown_shortcut_event.virtual_key_code = [event keyCode];
|
||||
last_keydown_shortcut_event.input_source_switch_modifiers = 0;
|
||||
last_keydown_shortcut_event.timestamp = [event timestamp];
|
||||
@@ -941,7 +839,7 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
// now check if there is a useful apple shortcut
|
||||
int global_shortcut = is_active_apple_global_shortcut(event);
|
||||
if (is_useful_apple_global_shortcut(global_shortcut)) {
|
||||
debug_input("keyDown triggered global macOS shortcut ignoring\n");
|
||||
debug_key("keyDown triggered global macOS shortcut ignoring\n");
|
||||
last_keydown_shortcut_event.virtual_key_code = [event keyCode];
|
||||
// record the modifier keys if switching to the next input source
|
||||
last_keydown_shortcut_event.input_source_switch_modifiers = (global_shortcut == kSHKSelectNextSourceInInputMenu) ? USEFUL_MODS([event modifierFlags]) : 0;
|
||||
@@ -950,7 +848,7 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
}
|
||||
// check for JIS keyboard layout function keys
|
||||
if (is_apple_jis_layout_function_key(event)) {
|
||||
debug_input("keyDown triggered JIS layout function key ignoring\n");
|
||||
debug_key("keyDown triggered JIS layout function key ignoring\n");
|
||||
last_keydown_shortcut_event.virtual_key_code = [event keyCode];
|
||||
last_keydown_shortcut_event.input_source_switch_modifiers = 0;
|
||||
last_keydown_shortcut_event.timestamp = [event timestamp];
|
||||
@@ -960,35 +858,31 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
last_keydown_shortcut_event.virtual_key_code = 0xffff;
|
||||
NSWindow *kw = [NSApp keyWindow];
|
||||
if (kw && kw.contentView) [kw.contentView keyDown:event];
|
||||
else debug_input("keyDown ignored as no keyWindow present\n");
|
||||
else debug_key("keyDown ignored as no keyWindow present\n");
|
||||
return nil;
|
||||
};
|
||||
|
||||
NSEvent* (^keyup_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
debug_input("----------------- key up --------------------\n");
|
||||
debug_input("%s\n", [[event description] UTF8String]);
|
||||
debug_key("----------------- key up --------------------\n");
|
||||
debug_key("%s\n", [[event description] UTF8String]);
|
||||
if (last_keydown_shortcut_event.virtual_key_code != 0xffff && last_keydown_shortcut_event.virtual_key_code == [event keyCode]) {
|
||||
// ignore as the corresponding key down event triggered a menu bar or macOS shortcut
|
||||
last_keydown_shortcut_event.virtual_key_code = 0xffff;
|
||||
debug_input("keyUp ignored as corresponds to previous keyDown that triggered a shortcut\n");
|
||||
debug_key("keyUp ignored as corresponds to previous keyDown that triggered a shortcut\n");
|
||||
return nil;
|
||||
}
|
||||
NSWindow *kw = [NSApp keyWindow];
|
||||
if (kw && kw.contentView) [kw.contentView keyUp:event];
|
||||
else debug_input("keyUp ignored as no keyWindow present\n");
|
||||
else debug_key("keyUp ignored as no keyWindow present\n");
|
||||
return nil;
|
||||
};
|
||||
|
||||
NSEvent* (^flags_changed_block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
|
||||
{
|
||||
debug_input("-------------- flags changed -----------------\n");
|
||||
debug_input("%s\n", [[event description] UTF8String]);
|
||||
debug_key("-------------- flags changed -----------------\n");
|
||||
debug_key("%s\n", [[event description] UTF8String]);
|
||||
last_keydown_shortcut_event.virtual_key_code = 0xffff;
|
||||
if (!_glfw.ignoreOSKeyboardProcessing && !_glfw.keyboard_grabbed && is_apple_fn_global_shortcut(event)) {
|
||||
debug_input("flagsChanged triggered global fn shortcut ignoring\n");
|
||||
return event;
|
||||
}
|
||||
// switching to the next input source is only confirmed when all modifier keys are released
|
||||
if (last_keydown_shortcut_event.input_source_switch_modifiers) {
|
||||
if (!([event modifierFlags] & last_keydown_shortcut_event.input_source_switch_modifiers))
|
||||
@@ -997,7 +891,7 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
}
|
||||
NSWindow *kw = [NSApp keyWindow];
|
||||
if (kw && kw.contentView) [kw.contentView flagsChanged:event];
|
||||
else debug_input("flagsChanged ignored as no keyWindow present\n");
|
||||
else debug_key("flagsChanged ignored as no keyWindow present\n");
|
||||
return nil;
|
||||
};
|
||||
|
||||
@@ -1014,16 +908,13 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
if (_glfw.hints.init.ns.chdir)
|
||||
changeToResourcesDirectory();
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:@{
|
||||
NSDictionary* defaults = @{
|
||||
// Press and Hold prevents some keys from emitting repeated characters
|
||||
@"ApplePressAndHoldEnabled": @NO,
|
||||
// Dont generate openFile events from command line arguments
|
||||
@"NSTreatUnknownArgumentsAsOpen": @"NO",
|
||||
// This Tahoe nonsense causes slowdowns in some situations, see for example:
|
||||
// https://issues.chromium.org/issues/452372350 it doesnt affect
|
||||
// autofill via Edit->Autofill
|
||||
@"NSAutoFillHeuristicControllerEnabled" : @NO,
|
||||
}];
|
||||
};
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
|
||||
|
||||
NSUserDefaults *apple_settings = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.symbolichotkeys"];
|
||||
[apple_settings addObserver:_glfw.ns.helper
|
||||
@@ -1052,47 +943,11 @@ int _glfwPlatformInit(bool *supports_window_occlusion)
|
||||
|
||||
} // autoreleasepool
|
||||
}
|
||||
static NSDate*
|
||||
get_process_start_time(pid_t pid) {
|
||||
struct kinfo_proc kp;
|
||||
size_t len = sizeof(kp);
|
||||
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
|
||||
|
||||
if (sysctl(mib, 4, &kp, &len, NULL, 0) == 0 && len == sizeof(kp)) {
|
||||
struct timeval start_tv = kp.kp_proc.p_starttime;
|
||||
time_t start_sec = start_tv.tv_sec;
|
||||
suseconds_t start_usec = start_tv.tv_usec;
|
||||
NSTimeInterval t = (NSTimeInterval)start_sec + ((NSTimeInterval)start_usec / 1000000.0);
|
||||
return [NSDate dateWithTimeIntervalSince1970:t];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
void _glfwPlatformTerminate(void)
|
||||
{
|
||||
@autoreleasepool {
|
||||
|
||||
// Kill the AutoFill helper process that macOS Tahoe starts and fails to
|
||||
// shutdown on application exit, see https://github.com/kovidgoyal/kitty/issues/9299
|
||||
// Only kill helpers that were launched within a few seconds of this process to
|
||||
// avoid killing helpers from other processes. This is obviously not robust
|
||||
// but since Apple cant design its way out of a paper bag, it's the best we
|
||||
// can do.
|
||||
if (application_finished_launching_at != nil) {
|
||||
for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
|
||||
if ([app.bundleIdentifier isEqualToString:@"com.apple.SafariPlatformSupport.Helper"] &&
|
||||
[[app.localizedName lowercaseString] containsString:@"autofill (kitty)"]) {
|
||||
NSDate *st = get_process_start_time(app.processIdentifier);
|
||||
if (st != nil) {
|
||||
NSTimeInterval timeDifference = [application_finished_launching_at timeIntervalSinceDate:st];
|
||||
[st release];
|
||||
if (fabs(timeDifference) <= 5) [app forceTerminate];
|
||||
}
|
||||
}
|
||||
}
|
||||
[application_finished_launching_at release]; application_finished_launching_at = nil;
|
||||
}
|
||||
|
||||
_glfwClearDisplayLinks();
|
||||
|
||||
if (_glfw.ns.inputSource)
|
||||
@@ -1288,4 +1143,3 @@ void _glfwPlatformUpdateTimer(unsigned long long timer_id, monotonic_t interval,
|
||||
}
|
||||
|
||||
void _glfwPlatformInputColorScheme(GLFWColorScheme appearance UNUSED) { }
|
||||
bool _glfwPlatformGrabKeyboard(bool grab UNUSED) { return true; /* directly uses _glfw.keyboard_grabbed */ }
|
||||
|
||||
@@ -32,10 +32,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
#include <CoreVideo/CVBase.h>
|
||||
#include <CoreVideo/CVDisplayLink.h>
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
|
||||
@@ -323,7 +323,54 @@ static double getFallbackRefreshRate(CGDirectDisplayID displayID)
|
||||
////// GLFW internal API //////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwClearDisplayLinks(void) {
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
if (_glfw.ns.displayLinks.entries[i].displayLink) {
|
||||
CVDisplayLinkStop(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||
CVDisplayLinkRelease(_glfw.ns.displayLinks.entries[i].displayLink);
|
||||
}
|
||||
}
|
||||
memset(_glfw.ns.displayLinks.entries, 0, sizeof(_GLFWDisplayLinkNS) * _glfw.ns.displayLinks.count);
|
||||
_glfw.ns.displayLinks.count = 0;
|
||||
}
|
||||
|
||||
static CVReturn displayLinkCallback(
|
||||
CVDisplayLinkRef displayLink UNUSED,
|
||||
const CVTimeStamp* now UNUSED, const CVTimeStamp* outputTime UNUSED,
|
||||
CVOptionFlags flagsIn UNUSED, CVOptionFlags* flagsOut UNUSED, void* userInfo)
|
||||
{
|
||||
CGDirectDisplayID displayID = (uintptr_t)userInfo;
|
||||
NSNumber *arg = [NSNumber numberWithUnsignedInt:displayID];
|
||||
[NSApp performSelectorOnMainThread:@selector(render_frame_received:) withObject:arg waitUntilDone:NO];
|
||||
[arg release];
|
||||
return kCVReturnSuccess;
|
||||
}
|
||||
|
||||
void
|
||||
_glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry) {
|
||||
CVDisplayLinkCreateWithCGDisplay(entry->displayID, &entry->displayLink);
|
||||
CVDisplayLinkSetOutputCallback(entry->displayLink, &displayLinkCallback, (void*)(uintptr_t)entry->displayID);
|
||||
}
|
||||
|
||||
_GLFWDisplayLinkNS*
|
||||
_glfw_create_display_link(CGDirectDisplayID displayID) {
|
||||
if (_glfw.ns.displayLinks.count >= arraysz(_glfw.ns.displayLinks.entries) - 1) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Too many monitors cannot create display link");
|
||||
return NULL;
|
||||
}
|
||||
for (size_t i = 0; i < _glfw.ns.displayLinks.count; i++) {
|
||||
// already created in this run
|
||||
if (_glfw.ns.displayLinks.entries[i].displayID == displayID) return _glfw.ns.displayLinks.entries + i;
|
||||
}
|
||||
_GLFWDisplayLinkNS *entry = &_glfw.ns.displayLinks.entries[_glfw.ns.displayLinks.count++];
|
||||
memset(entry, 0, sizeof(_GLFWDisplayLinkNS));
|
||||
entry->displayID = displayID;
|
||||
_glfw_create_cv_display_link(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Poll for changes in the set of connected monitors
|
||||
//
|
||||
void _glfwPollMonitorsNS(void)
|
||||
{
|
||||
uint32_t displayCount;
|
||||
@@ -379,7 +426,7 @@ void _glfwPollMonitorsNS(void)
|
||||
{
|
||||
disconnected[j]->ns.displayID = displays[i];
|
||||
disconnected[j]->ns.screen = screen;
|
||||
_glfwCreateDisplayLink(displays[i]);
|
||||
_glfw_create_display_link(displays[i]);
|
||||
disconnected[j] = NULL;
|
||||
break;
|
||||
}
|
||||
@@ -400,7 +447,7 @@ void _glfwPollMonitorsNS(void)
|
||||
monitor->ns.displayID = displays[i];
|
||||
monitor->ns.unitNumber = unitNumber;
|
||||
monitor->ns.screen = screen;
|
||||
_glfwCreateDisplayLink(monitor->ns.displayID);
|
||||
_glfw_create_display_link(monitor->ns.displayID);
|
||||
|
||||
free(name);
|
||||
|
||||
@@ -636,8 +683,6 @@ void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
|
||||
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle)
|
||||
{
|
||||
_GLFWmonitor* monitor = (_GLFWmonitor*) handle;
|
||||
assert(monitor != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(kCGNullDirectDisplay);
|
||||
return monitor->ns.displayID;
|
||||
}
|
||||
|
||||
67
glfw/cocoa_platform.h
vendored
67
glfw/cocoa_platform.h
vendored
@@ -30,8 +30,10 @@
|
||||
#include <Carbon/Carbon.h>
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <CoreVideo/CoreVideo.h>
|
||||
#else
|
||||
typedef void* id;
|
||||
typedef void* CVDisplayLinkRef;
|
||||
#endif
|
||||
|
||||
// NOTE: Many Cocoa enum values have been renamed and we need to build across
|
||||
@@ -62,10 +64,12 @@ typedef void* id;
|
||||
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
|
||||
#endif
|
||||
|
||||
#define debug_key(...) if (_glfw.hints.init.debugKeyboard) { fprintf(stderr, __VA_ARGS__); fflush(stderr); }
|
||||
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int, unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef bool (* GLFWhandleurlopen)(const char*);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(bool);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
|
||||
@@ -114,21 +118,6 @@ typedef void* (*PFN_TISGetInputSourceProperty)(TISInputSourceRef,CFStringRef);
|
||||
typedef UInt8 (*PFN_LMGetKbdType)(void);
|
||||
#define LMGetKbdType _glfw.ns.tis.GetKbdType
|
||||
|
||||
typedef struct _GLFWDropData {
|
||||
const char **mimes; // Original MIME list; strings are owned here, never reordered
|
||||
size_t mimes_count;
|
||||
const char **copy_mimes; // Working copy passed to callbacks; pointers into mimes[]
|
||||
size_t copy_mimes_count; // Accepted count after last callback
|
||||
bool drag_accepted;
|
||||
struct {
|
||||
unsigned long long request_id;
|
||||
id temp_dir;
|
||||
id data_map; // map MIME to NSError or NSInputStream
|
||||
id path_map; // map MIME to NSError or NSInputStream or NSUrl
|
||||
id pending_requests;
|
||||
bool promises_loaded;
|
||||
} in_progress_drop;
|
||||
} _GLFWDropData;
|
||||
|
||||
// Cocoa-specific per-window data
|
||||
//
|
||||
@@ -143,23 +132,14 @@ typedef struct _GLFWwindowNS
|
||||
bool retina;
|
||||
bool in_traditional_fullscreen;
|
||||
bool in_fullscreen_transition;
|
||||
bool suppress_frame_constraints;
|
||||
id notch_cover_window;
|
||||
unsigned int notch_cover_color;
|
||||
float notch_cover_opacity;
|
||||
bool titlebar_hidden;
|
||||
unsigned long pre_full_screen_style_mask;
|
||||
CGRect pre_traditional_fullscreen_frame;
|
||||
|
||||
// Cached window properties to filter out duplicate events
|
||||
int width, height;
|
||||
int fbWidth, fbHeight;
|
||||
float xscale, yscale;
|
||||
int blur_radius;
|
||||
bool live_resize_in_progress;
|
||||
struct {
|
||||
struct { CGFloat red, green, blue, alpha; bool was_set; } color; bool transparent;
|
||||
} last_applied_titlebar_settings;
|
||||
|
||||
// The total sum of the distances the cursor has been warped
|
||||
// since the last cursor motion event was processed
|
||||
@@ -172,26 +152,21 @@ typedef struct _GLFWwindowNS
|
||||
GLFWcocoatogglefullscreenfun toggleFullscreenCallback;
|
||||
// Dead key state
|
||||
UInt32 deadKeyState;
|
||||
|
||||
// Layer shell windows
|
||||
struct {
|
||||
bool is_active;
|
||||
GLFWLayerShellConfig config;
|
||||
} layer_shell;
|
||||
|
||||
// Whether a render frame has been requested for this window
|
||||
bool renderFrameRequested;
|
||||
GLFWcocoarenderframefun renderFrameCallback;
|
||||
// update cursor after switching desktops with Mission Control
|
||||
bool delayed_cursor_update_requested;
|
||||
GLFWcocoarenderframefun resizeCallback;
|
||||
|
||||
// Cached MIME types from drag enter (for move events)
|
||||
_GLFWDropData drop_data;
|
||||
unsigned long long drop_request_counter;
|
||||
|
||||
} _GLFWwindowNS;
|
||||
|
||||
typedef struct _GLFWDisplayLinkNS
|
||||
{
|
||||
CVDisplayLinkRef displayLink;
|
||||
CGDirectDisplayID displayID;
|
||||
monotonic_t lastRenderFrameRequestedAt, first_unserviced_render_frame_request_at;
|
||||
} _GLFWDisplayLinkNS;
|
||||
|
||||
// Cocoa-specific global data
|
||||
//
|
||||
typedef struct _GLFWlibraryNS
|
||||
@@ -215,7 +190,6 @@ typedef struct _GLFWlibraryNS
|
||||
double restoreCursorPosX, restoreCursorPosY;
|
||||
// The window whose disabled cursor mode is active
|
||||
_GLFWwindow* disabledCursorWindow;
|
||||
pid_t previous_front_most_application;
|
||||
|
||||
struct {
|
||||
CFBundleRef bundle;
|
||||
@@ -225,11 +199,13 @@ typedef struct _GLFWlibraryNS
|
||||
CFStringRef kPropertyUnicodeKeyLayoutData;
|
||||
} tis;
|
||||
|
||||
struct {
|
||||
_GLFWDisplayLinkNS entries[256];
|
||||
size_t count;
|
||||
} displayLinks;
|
||||
// the callback to handle url open events
|
||||
GLFWhandleurlopen url_open_callback;
|
||||
|
||||
// Active drag session (NSDraggingSession*) and view (NSView*)
|
||||
id drag_session, drag_view, drag_image;
|
||||
} _GLFWlibraryNS;
|
||||
|
||||
// Cocoa-specific per-monitor data
|
||||
@@ -268,15 +244,12 @@ float _glfwTransformYNS(float y);
|
||||
|
||||
void* _glfwLoadLocalVulkanLoaderNS(void);
|
||||
|
||||
|
||||
// display links
|
||||
void _glfwClearDisplayLinks(void);
|
||||
void _glfwRestartDisplayLinks(void);
|
||||
unsigned _glfwCreateDisplayLink(CGDirectDisplayID);
|
||||
void _glfwRequestRenderFrame(_GLFWwindow *w);
|
||||
|
||||
// event loop
|
||||
void _glfwDispatchTickCallback(void);
|
||||
void _glfwDispatchRenderFrame(CGDirectDisplayID);
|
||||
void _glfwShutdownCVDisplayLink(unsigned long long, void*);
|
||||
void _glfwCocoaPostEmptyEvent(void);
|
||||
|
||||
void _glfw_create_cv_display_link(_GLFWDisplayLinkNS *entry);
|
||||
_GLFWDisplayLinkNS* _glfw_create_display_link(CGDirectDisplayID);
|
||||
uint32_t vk_to_unicode_key_with_current_layout(uint16_t keycode);
|
||||
|
||||
2190
glfw/cocoa_window.m
2190
glfw/cocoa_window.m
File diff suppressed because it is too large
Load Diff
40
glfw/dbus_glfw.c
vendored
40
glfw/dbus_glfw.c
vendored
@@ -214,6 +214,13 @@ typedef struct {
|
||||
void *user_data;
|
||||
} MethodResponse;
|
||||
|
||||
static const char*
|
||||
format_message_error(DBusError *err) {
|
||||
static char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "[%s] %s", err->name ? err->name : "", err->message);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
method_reply_received(DBusPendingCall *pending, void *user_data) {
|
||||
MethodResponse *res = (MethodResponse*)user_data;
|
||||
@@ -221,27 +228,18 @@ method_reply_received(DBusPendingCall *pending, void *user_data) {
|
||||
if (msg) {
|
||||
DBusError err;
|
||||
dbus_error_init(&err);
|
||||
if (dbus_set_error_from_message(&err, msg)) res->callback(NULL, &err, res->user_data);
|
||||
if (dbus_set_error_from_message(&err, msg)) res->callback(NULL, format_message_error(&err), res->user_data);
|
||||
else res->callback(msg, NULL, res->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data, bool block) {
|
||||
call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data) {
|
||||
bool retval = false;
|
||||
#define REPORT(errs) _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: node=%s path=%s interface=%s method=%s, with error: %s", dbus_message_get_destination(msg), dbus_message_get_path(msg), dbus_message_get_interface(msg), dbus_message_get_member(msg), errs)
|
||||
if (callback) {
|
||||
DBusPendingCall *pending = NULL;
|
||||
if (block) {
|
||||
DBusError error; dbus_error_init(&error);
|
||||
RAII_MSG(reply, dbus_connection_send_with_reply_and_block(session_bus, msg, timeout, &error));
|
||||
if (dbus_error_is_set(&error)) {
|
||||
callback(reply, &error, user_data);
|
||||
return false;
|
||||
} else if (reply) {
|
||||
callback(reply, NULL, user_data);
|
||||
} else return false;
|
||||
} else if (dbus_connection_send_with_reply(conn, msg, &pending, timeout)) {
|
||||
if (dbus_connection_send_with_reply(conn, msg, &pending, timeout)) {
|
||||
MethodResponse *res = malloc(sizeof(MethodResponse));
|
||||
if (!res) return false;
|
||||
res->callback = callback;
|
||||
@@ -263,7 +261,7 @@ call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_p
|
||||
}
|
||||
|
||||
static bool
|
||||
call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void *user_data, bool blocking, va_list ap) {
|
||||
call_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void *user_data, va_list ap) {
|
||||
if (!conn || !path) return false;
|
||||
RAII_MSG(msg, dbus_message_new_method_call(node, path, interface, method));
|
||||
if (!msg) return false;
|
||||
@@ -271,7 +269,7 @@ call_method(DBusConnection *conn, const char *node, const char *path, const char
|
||||
|
||||
int firstarg = va_arg(ap, int);
|
||||
if ((firstarg == DBUS_TYPE_INVALID) || dbus_message_append_args_valist(msg, firstarg, ap)) {
|
||||
retval = call_method_with_msg(conn, msg, timeout, callback, user_data, blocking);
|
||||
retval = call_method_with_msg(conn, msg, timeout, callback, user_data);
|
||||
} else {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to call DBUS method: %s on node: %s and interface: %s could not add arguments", method, node, interface);
|
||||
}
|
||||
@@ -284,17 +282,7 @@ glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const c
|
||||
bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, user_data);
|
||||
retval = call_method(conn, node, path, interface, method, timeout, callback, user_data, false, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
bool
|
||||
glfw_dbus_call_blocking_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void* user_data, ...) {
|
||||
bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, user_data);
|
||||
retval = call_method(conn, node, path, interface, method, timeout, callback, user_data, true, ap);
|
||||
retval = call_method(conn, node, path, interface, method, timeout, callback, user_data, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
@@ -304,7 +292,7 @@ glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const cha
|
||||
bool retval;
|
||||
va_list ap;
|
||||
va_start(ap, method);
|
||||
retval = call_method(conn, node, path, interface, method, DBUS_TIMEOUT_USE_DEFAULT, NULL, NULL, false, ap);
|
||||
retval = call_method(conn, node, path, interface, method, DBUS_TIMEOUT_USE_DEFAULT, NULL, NULL, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
6
glfw/dbus_glfw.h
vendored
6
glfw/dbus_glfw.h
vendored
@@ -33,7 +33,7 @@
|
||||
static inline void cleanup_msg(void *p) { DBusMessage *m = *(DBusMessage**)p; if (m) dbus_message_unref(m); m = NULL; }
|
||||
#define RAII_MSG(name, initializer) __attribute__((cleanup(cleanup_msg))) DBusMessage *name = initializer
|
||||
|
||||
typedef void(*dbus_pending_callback)(DBusMessage *msg, const DBusError *err, void* data);
|
||||
typedef void(*dbus_pending_callback)(DBusMessage *msg, const char* err, void* data);
|
||||
|
||||
typedef struct {
|
||||
EventLoopData* eld;
|
||||
@@ -45,13 +45,11 @@ void glfw_dbus_terminate(_GLFWDBUSData *dbus);
|
||||
DBusConnection* glfw_dbus_connect_to(const char *path, const char* err_msg, const char* name, bool register_on_bus);
|
||||
void glfw_dbus_close_connection(DBusConnection *conn);
|
||||
bool
|
||||
call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data, bool block);
|
||||
call_method_with_msg(DBusConnection *conn, DBusMessage *msg, int timeout, dbus_pending_callback callback, void *user_data);
|
||||
bool
|
||||
glfw_dbus_call_method_no_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
|
||||
bool
|
||||
glfw_dbus_call_method_with_reply(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout_ms, dbus_pending_callback callback, void *user_data, ...);
|
||||
bool
|
||||
glfw_dbus_call_blocking_method(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, int timeout, dbus_pending_callback callback, void* user_data, ...);
|
||||
void glfw_dbus_dispatch(DBusConnection *);
|
||||
void glfw_dbus_session_bus_dispatch(void);
|
||||
bool glfw_dbus_get_args(DBusMessage *msg, const char *failmsg, ...);
|
||||
|
||||
32
glfw/egl_context.c
vendored
32
glfw/egl_context.c
vendored
@@ -223,7 +223,6 @@ static int extensionSupportedEGL(const char* extension)
|
||||
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||
{
|
||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||
assert(window != NULL);
|
||||
|
||||
if (window->context.egl.client)
|
||||
{
|
||||
@@ -388,7 +387,6 @@ bool _glfwInitEGL(void)
|
||||
}
|
||||
|
||||
_glfw.egl.platform = _glfwPlatformGetEGLPlatform(&attribs);
|
||||
_glfw.egl.display = EGL_NO_DISPLAY;
|
||||
if (_glfw.egl.platform)
|
||||
{
|
||||
_glfw.egl.display =
|
||||
@@ -396,18 +394,16 @@ bool _glfwInitEGL(void)
|
||||
_glfwPlatformGetEGLNativeDisplay(),
|
||||
attribs);
|
||||
}
|
||||
else
|
||||
_glfw.egl.display = eglGetDisplay(_glfwPlatformGetEGLNativeDisplay());
|
||||
|
||||
free(attribs);
|
||||
|
||||
if (_glfw.egl.display == EGL_NO_DISPLAY)
|
||||
_glfw.egl.display = eglGetDisplay(_glfwPlatformGetEGLNativeDisplay());
|
||||
|
||||
|
||||
EGLint egl_err;
|
||||
if (_glfw.egl.display == EGL_NO_DISPLAY && (egl_err = eglGetError()) != EGL_SUCCESS)
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to get EGL display: %s",
|
||||
getEGLErrorString(egl_err));
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return false;
|
||||
@@ -416,8 +412,8 @@ bool _glfwInitEGL(void)
|
||||
if (!eglInitialize(_glfw.egl.display, &_glfw.egl.major, &_glfw.egl.minor))
|
||||
{
|
||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||
"EGL: Failed to initialize EGL: %s display_present: %d egl_platform_present: %d",
|
||||
getEGLErrorString(eglGetError()), _glfw.egl.display != EGL_NO_DISPLAY, _glfw.egl.platform != 0);
|
||||
"EGL: Failed to initialize EGL: %s",
|
||||
getEGLErrorString(eglGetError()));
|
||||
|
||||
_glfwTerminateEGL();
|
||||
return false;
|
||||
@@ -546,18 +542,18 @@ bool _glfwCreateContextEGL(_GLFWwindow* window,
|
||||
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (ctxconfig->noerror)
|
||||
{
|
||||
if (_glfw.egl.KHR_create_context_no_error)
|
||||
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, true);
|
||||
}
|
||||
|
||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||
{
|
||||
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||
}
|
||||
|
||||
if (mask)
|
||||
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
||||
|
||||
@@ -793,8 +789,6 @@ GLFWAPI EGLDisplay glfwGetEGLDisplay(void)
|
||||
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_CONTEXT);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
@@ -809,8 +803,6 @@ GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* handle)
|
||||
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(EGL_NO_SURFACE);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
|
||||
14
glfw/glfw.py
14
glfw/glfw.py
@@ -175,7 +175,7 @@ def init_env(
|
||||
|
||||
elif module == 'cocoa':
|
||||
ans.cppflags.append('-DGL_SILENCE_DEPRECATION')
|
||||
for f_ in 'Cocoa IOKit CoreFoundation CoreVideo QuartzCore UniformTypeIdentifiers'.split():
|
||||
for f_ in 'Cocoa IOKit CoreFoundation CoreVideo UniformTypeIdentifiers'.split():
|
||||
ans.ldpaths.extend(('-framework', f_))
|
||||
|
||||
elif module == 'wayland':
|
||||
@@ -309,15 +309,12 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
GLFWapplicationwillfinishlaunchingfun glfwSetApplicationWillFinishLaunching(GLFWapplicationwillfinishlaunchingfun callback)
|
||||
uint32_t glfwGetCocoaKeyEquivalent(uint32_t glfw_key, int glfw_mods, int* cocoa_mods)
|
||||
void glfwCocoaRequestRenderFrame(GLFWwindow *w, GLFWcocoarenderframefun callback)
|
||||
bool glfwCocoaRecreateGLDrawable(GLFWwindow *w)
|
||||
GLFWcocoarenderframefun glfwCocoaSetWindowResizeCallback(GLFWwindow *w, GLFWcocoarenderframefun callback)
|
||||
void* glfwGetX11Display(void)
|
||||
unsigned long glfwGetX11Window(GLFWwindow* window)
|
||||
void glfwSetPrimarySelectionString(GLFWwindow* window, const char* string)
|
||||
void glfwCocoaCycleThroughOSWindows(bool backwards)
|
||||
void glfwCocoaSetWindowChrome(GLFWwindow* window, unsigned int color, bool use_system_color, unsigned int system_color,\
|
||||
int background_blur, unsigned int hide_window_decorations, bool show_text_in_titlebar, int color_space, float background_opacity, bool resizable)
|
||||
void glfwCocoaRegisterMIMETypes(GLFWwindow *window, const char **mimes, size_t count)
|
||||
const char* glfwGetPrimarySelectionString(GLFWwindow* window, void)
|
||||
int glfwGetNativeKeyForName(const char* key_name, int case_sensitive)
|
||||
void glfwRequestWaylandFrameEvent(GLFWwindow *handle, unsigned long long id, GLFWwaylandframecallbackfunc callback)
|
||||
@@ -325,15 +322,14 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
const char* glfwWaylandMissingCapabilities(void)
|
||||
void glfwWaylandRunWithActivationToken(GLFWwindow *handle, GLFWactivationcallback cb, void *cb_data)
|
||||
bool glfwWaylandSetTitlebarColor(GLFWwindow *handle, uint32_t color, bool use_system_color)
|
||||
void glfwWaylandSetTitlebarHidden(GLFWwindow *handle, bool hidden)
|
||||
void glfwWaylandRedrawCSDWindowTitle(GLFWwindow *handle)
|
||||
bool glfwWaylandIsWindowFullyCreated(GLFWwindow *handle)
|
||||
bool glfwWaylandBeep(GLFWwindow *handle)
|
||||
void glfwWaylandSetupLayerShellForNextWindow(const GLFWLayerShellConfig *c)
|
||||
pid_t glfwWaylandCompositorPID(void)
|
||||
void glfwConfigureMomentumScroller(double friction, double min_velocity, double max_velocity, unsigned timer_interval)
|
||||
unsigned long long glfwDBusUserNotify(const GLFWDBUSNotificationData *n, GLFWDBusnotificationcreatedfun callback, void *data)
|
||||
void glfwDBusSetUserNotificationHandler(GLFWDBusnotificationactivatedfun handler)
|
||||
int glfwSetX11LaunchCommand(GLFWwindow *handle, char **argv, int argc)
|
||||
void glfwSetX11WindowAsDock(int32_t x11_window_id)
|
||||
void glfwSetX11WindowStrut(int32_t x11_window_id, uint32_t dimensions[12])
|
||||
'''.splitlines():
|
||||
if line:
|
||||
functions.append(Function(line.strip(), check_fail=False))
|
||||
@@ -362,7 +358,7 @@ def generate_wrappers(glfw_header: str) -> None:
|
||||
typedef int (* GLFWcocoatextinputfilterfun)(int,int,unsigned int,unsigned long);
|
||||
typedef bool (* GLFWapplicationshouldhandlereopenfun)(int);
|
||||
typedef bool (* GLFWhandleurlopen)(const char*);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(bool);
|
||||
typedef void (* GLFWapplicationwillfinishlaunchingfun)(void);
|
||||
typedef bool (* GLFWcocoatogglefullscreenfun)(GLFWwindow*);
|
||||
typedef void (* GLFWcocoarenderframefun)(GLFWwindow*);
|
||||
typedef void (*GLFWwaylandframecallbackfunc)(unsigned long long id);
|
||||
|
||||
260
glfw/glfw3.h
vendored
260
glfw/glfw3.h
vendored
@@ -109,16 +109,6 @@ extern "C" {
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Include for ssize_t on POSIX systems. On Windows we define it if needed. */
|
||||
#if !defined(_WIN32)
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#if !defined(SSIZE_T_DEFINED)
|
||||
typedef intptr_t ssize_t;
|
||||
#define SSIZE_T_DEFINED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_INCLUDE_VULKAN)
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif /* Vulkan header */
|
||||
@@ -556,30 +546,6 @@ typedef enum GLFWColorScheme {
|
||||
GLFW_COLOR_SCHEME_LIGHT = 2
|
||||
} GLFWColorScheme;
|
||||
|
||||
typedef enum GLFWMomentumType {
|
||||
GLFW_NO_MOMENTUM_DATA = 0,
|
||||
GLFW_MOMENTUM_PHASE_BEGAN = 1,
|
||||
GLFW_MOMENTUM_PHASE_STATIONARY = 2,
|
||||
GLFW_MOMENTUM_PHASE_ACTIVE = 3,
|
||||
GLFW_MOMENTUM_PHASE_ENDED = 4,
|
||||
GLFW_MOMENTUM_PHASE_CANCELED = 5,
|
||||
GLFW_MOMENTUM_PHASE_MAY_BEGIN = 6,
|
||||
} GLFWMomentumType;
|
||||
|
||||
typedef enum GLFWOffsetType {
|
||||
GLFW_SCROLL_OFFSET_LINES = 0,
|
||||
GLFW_SCROLL_OFFEST_V120 = 1,
|
||||
GLFW_SCROLL_OFFEST_HIGHRES = 2,
|
||||
} GLFWOffsetType;
|
||||
|
||||
typedef struct GLFWScrollEvent {
|
||||
double x_offset, y_offset; // offsets are scaled by the window scale for HIGHRES
|
||||
struct { double x, y; } unscaled; // unscaled offsets, aka logical pixels
|
||||
GLFWMomentumType momentum_type;
|
||||
GLFWOffsetType offset_type;
|
||||
int keyboard_modifiers;
|
||||
} GLFWScrollEvent;
|
||||
|
||||
/*! @defgroup joysticks Joysticks
|
||||
* @brief Joystick IDs.
|
||||
*
|
||||
@@ -1090,7 +1056,6 @@ typedef enum {
|
||||
|
||||
#define GLFW_WAYLAND_APP_ID 0x00025001
|
||||
#define GLFW_WAYLAND_BGCOLOR 0x00025002
|
||||
#define GLFW_WAYLAND_WINDOW_TAG 0x00025003
|
||||
/*! @} */
|
||||
|
||||
#define GLFW_NO_API 0
|
||||
@@ -1277,20 +1242,6 @@ typedef struct GLFWwindow GLFWwindow;
|
||||
*/
|
||||
typedef struct GLFWcursor GLFWcursor;
|
||||
|
||||
/*! @brief Opaque drop data object.
|
||||
*
|
||||
* Opaque drop data object representing data from a drag and drop operation.
|
||||
* This object is passed to the drop callback and can be used to query
|
||||
* available MIME types and read the dropped data in chunks.
|
||||
*
|
||||
* @see @ref path_drop
|
||||
* @see @ref glfwGetDropMimeTypes
|
||||
* @see @ref glfwReadDropData
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef enum {
|
||||
GLFW_RELEASE = 0,
|
||||
GLFW_PRESS = 1,
|
||||
@@ -1349,32 +1300,19 @@ typedef struct GLFWkeyevent
|
||||
bool fake_event_on_focus_change;
|
||||
} GLFWkeyevent;
|
||||
|
||||
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL, GLFW_LAYER_SHELL_TOP, GLFW_LAYER_SHELL_OVERLAY } GLFWLayerShellType;
|
||||
typedef enum { GLFW_LAYER_SHELL_NONE, GLFW_LAYER_SHELL_BACKGROUND, GLFW_LAYER_SHELL_PANEL } GLFWLayerShellType;
|
||||
|
||||
typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT, GLFW_EDGE_CENTER, GLFW_EDGE_NONE, GLFW_EDGE_CENTER_SIZED } GLFWEdge;
|
||||
typedef enum { GLFW_EDGE_TOP, GLFW_EDGE_BOTTOM, GLFW_EDGE_LEFT, GLFW_EDGE_RIGHT } GLFWEdge;
|
||||
|
||||
typedef enum { GLFW_FOCUS_NOT_ALLOWED, GLFW_FOCUS_EXCLUSIVE, GLFW_FOCUS_ON_DEMAND} GLFWFocusPolicy;
|
||||
|
||||
typedef struct GLFWLayerShellConfig {
|
||||
GLFWLayerShellType type;
|
||||
GLFWEdge edge;
|
||||
struct {
|
||||
GLFWEdge edge;
|
||||
int requested_top_margin, requested_left_margin, requested_bottom_margin, requested_right_margin;
|
||||
} previous;
|
||||
bool was_toggled_to_fullscreen;
|
||||
char output_name[128];
|
||||
char output_name[64];
|
||||
GLFWFocusPolicy focus_policy;
|
||||
unsigned x_size_in_cells, x_size_in_pixels;
|
||||
unsigned y_size_in_cells, y_size_in_pixels;
|
||||
int requested_top_margin, requested_left_margin, requested_bottom_margin, requested_right_margin;
|
||||
int requested_exclusive_zone, hide_on_focus_loss;
|
||||
unsigned override_exclusive_zone;
|
||||
void (*size_callback)(GLFWwindow *window, float xscale, float yscale, unsigned *cell_width, unsigned *cell_height, double *left_edge_spacing, double *top_edge_spacing, double *right_edge_spacing, double *bottom_edge_spacing);
|
||||
struct { float xscale, yscale; } expected;
|
||||
struct {
|
||||
float background_opacity; int background_blur, color_space;
|
||||
} related;
|
||||
unsigned size_in_cells;
|
||||
void (*size_callback)(GLFWwindow *window, const struct GLFWLayerShellConfig *config, unsigned monitor_width, unsigned monitor_height, uint32_t *width, uint32_t *height);
|
||||
} GLFWLayerShellConfig;
|
||||
|
||||
typedef struct GLFWDBUSNotificationData {
|
||||
@@ -1382,39 +1320,6 @@ typedef struct GLFWDBUSNotificationData {
|
||||
int32_t timeout; uint8_t urgency; uint32_t replaces; int muted;
|
||||
} GLFWDBUSNotificationData;
|
||||
|
||||
typedef enum { GLFW_DROP_ENTER, GLFW_DROP_MOVE, GLFW_DROP_LEAVE, GLFW_DROP_DROP, GLFW_DROP_STATUS_UPDATE, GLFW_DROP_DATA_AVAILABLE } GLFWDropEventType;
|
||||
|
||||
/*! @brief Drag operation types.
|
||||
*
|
||||
* These constants specify the type of drag operation (copy, move, or generic).
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef enum {
|
||||
GLFW_DRAG_OPERATION_NONE = 0, // no operation, drop was not accepted
|
||||
/*! Move the dragged data to the destination. */
|
||||
GLFW_DRAG_OPERATION_MOVE = 1,
|
||||
/*! Copy the dragged data to the destination. */
|
||||
GLFW_DRAG_OPERATION_COPY = 2,
|
||||
/*! Generic drag operation (platform decides semantics). */
|
||||
GLFW_DRAG_OPERATION_GENERIC = 4
|
||||
} GLFWDragOperationType;
|
||||
|
||||
|
||||
typedef struct GLFWDropEvent {
|
||||
GLFWDropEventType type;
|
||||
const char **mimes; size_t num_mimes;
|
||||
// Positions are only valid for GLFW_DROP_ENTER and GLFW_DROP_MOVE.
|
||||
// They are in window co-ordinates same as for mouse events
|
||||
double xpos, ypos;
|
||||
struct { GLFWDragOperationType preferred; int allowed, source_actions; } operation;
|
||||
bool from_self; // Only valid upto GLFW_DROP_DROP
|
||||
ssize_t (*read_data)(GLFWwindow *w, struct GLFWDropEvent* ev, char *buffer, size_t sz); // Only valid for GLFW_DROP_DATA_AVAILABLE
|
||||
void (*finish_drop)(GLFWwindow *w, GLFWDragOperationType op); // Only valid for GLFW_DROP_DROP and GLFW_DROP_DATA_AVAILABLE
|
||||
} GLFWDropEvent;
|
||||
typedef void (* GLFWdropeventfun)(GLFWwindow*, GLFWDropEvent *event);
|
||||
|
||||
|
||||
/*! @brief The function pointer type for error callbacks.
|
||||
*
|
||||
* This is the function pointer type for error callbacks. An error callback
|
||||
@@ -1520,22 +1425,20 @@ typedef void (* GLFWwindowclosefun)(GLFWwindow*);
|
||||
*/
|
||||
typedef void (* GLFWapplicationclosefun)(int);
|
||||
|
||||
|
||||
/*! @brief The function pointer type for system color theme change callbacks.
|
||||
*
|
||||
* This is the function pointer type for system color theme changes.
|
||||
* @code
|
||||
* void function_name(GLFWColorScheme theme_type, bool is_initial_value)
|
||||
* void function_name(int theme_type)
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] theme_type 0 for unknown, 1 for dark and 2 for light
|
||||
* @param[in] is_initial_value true if this is the initial read of the color theme on systems where it is asynchronous such as Linux
|
||||
*
|
||||
* @sa @ref glfwSetSystemColorThemeChangeCallback
|
||||
*
|
||||
* @ingroup window
|
||||
*/
|
||||
typedef void (* GLFWsystemcolorthemechangefun)(GLFWColorScheme, bool);
|
||||
typedef void (* GLFWsystemcolorthemechangefun)(GLFWColorScheme);
|
||||
|
||||
|
||||
/*! @brief The function pointer type for window content refresh callbacks.
|
||||
@@ -1779,7 +1682,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef void (* GLFWscrollfun)(GLFWwindow*,const GLFWScrollEvent*);
|
||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int,int);
|
||||
|
||||
/*! @brief The function pointer type for key callbacks.
|
||||
*
|
||||
@@ -1813,77 +1716,32 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,const GLFWScrollEvent*);
|
||||
*/
|
||||
typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
||||
|
||||
typedef enum {
|
||||
GLFW_DRAG_DATA_REQUEST, // request data for specified mime type
|
||||
GLFW_DRAG_CANCELLED,
|
||||
GLFW_DRAG_FINSHED,
|
||||
GLFW_DRAG_ACCEPTED, // mimetype was accepted or NULL if drag was accepted but no mime type specified
|
||||
GLFW_DRAG_ACTION_CHANGED, // action was changed 0 or GLFWDragOperationType
|
||||
GLFW_DRAG_DROPPED, // drop was performed but no data transferred yet
|
||||
} GLFWDragEventType;
|
||||
|
||||
typedef struct GLFWDragSourceItem {
|
||||
const char *mime_type;
|
||||
// Can be on null to provide data when the drag is started should be used only when the data is relatively small
|
||||
const char *optional_data;
|
||||
size_t data_size;
|
||||
bool is_remote_client;
|
||||
int type; // used for file promises type of entry 0 = regular, 1 = symlink, 2 = directory
|
||||
} GLFWDragSourceItem;
|
||||
|
||||
typedef struct GLFWDragEvent {
|
||||
GLFWDragEventType type;
|
||||
// When the drag event callback is called with a mimetype and no data, the
|
||||
// application should set the data ans data_sz and err_num fields.
|
||||
// Once glfw is done reading the data the drag event callback will be
|
||||
// called with the data pointer unchanged. The application is now free
|
||||
// to delete the data, as needed.
|
||||
const char *mime_type;
|
||||
const char *data; size_t data_sz;
|
||||
int err_num; // POSIX error code indicating failure fetching data
|
||||
GLFWDragOperationType action; // can be 0 indicating no action
|
||||
bool drop_maybe_a_cancel; // Happens on wayland compositors that dont implement top-level drag
|
||||
} GLFWDragEvent;
|
||||
|
||||
typedef void (* GLFWdragsourcefun)(GLFWwindow* window, GLFWDragEvent *ev);
|
||||
|
||||
/*! @brief The function pointer type for drag event callbacks.
|
||||
/*! @brief The function pointer type for drag and drop callbacks.
|
||||
*
|
||||
* This is the function pointer type for drag event callbacks. A drag event
|
||||
* This is the function pointer type for drop callbacks. A drop
|
||||
* callback function has the following signature:
|
||||
* @code
|
||||
* int function_name(GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int* mime_count)
|
||||
* int function_name(GLFWwindow* window, const char* mime, const char* text)
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] window The window that received the drag event.
|
||||
* @param[in] event The drag event type: @ref GLFW_DRAG_ENTER, @ref GLFW_DRAG_MOVE,
|
||||
* or @ref GLFW_DRAG_LEAVE.
|
||||
* @param[in] xpos The x-coordinate of the drag position in window coordinates.
|
||||
* @param[in] ypos The y-coordinate of the drag position in window coordinates.
|
||||
* @param[in,out] mime_types A writable array of MIME type strings available from the drag source.
|
||||
* For @ref GLFW_DRAG_ENTER and @ref GLFW_DRAG_MOVE events this is non-NULL and contains all
|
||||
* available MIME types. The callback is responsible for sorting this list by priority and
|
||||
* keeping only the MIME types it wants to accept. The first MIME type in the sorted list
|
||||
* will be used for the drop operation. The strings are only valid for the duration of the
|
||||
* callback; if you need to store them, make copies. For @ref GLFW_DRAG_LEAVE events this
|
||||
* is `NULL`.
|
||||
* @param[in,out] mime_count Pointer to the number of MIME types in the array. The callback
|
||||
* should update this to reflect the new count after sorting and filtering. For
|
||||
* @ref GLFW_DRAG_LEAVE events this is `NULL`.
|
||||
* @return For @ref GLFW_DRAG_ENTER and @ref GLFW_DRAG_MOVE events, return non-zero
|
||||
* to accept the drag or zero to reject it. This allows the application to
|
||||
* dynamically accept or reject the drag based on the current position.
|
||||
* Return value is ignored for @ref GLFW_DRAG_LEAVE events.
|
||||
* @param[in] window The window that received the event.
|
||||
* @param[in] mime The UTF-8 encoded drop mime-type
|
||||
* @param[in] data The dropped data or NULL for drag enter events
|
||||
* @param[in] sz The size of the dropped data
|
||||
* @return For drag events should return the priority for the specified mime type. A priority of zero
|
||||
* or lower means the mime type is not accepted. Highest priority will be the finally accepted mime-type.
|
||||
*
|
||||
* @sa @ref drag_events
|
||||
* @sa @ref glfwSetDragCallback
|
||||
* @sa @ref glfwUpdateDragState
|
||||
* @pointer_lifetime The text is valid until the
|
||||
* callback function returns.
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
* @sa @ref path_drop
|
||||
* @sa @ref glfwSetDropCallback
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef int (* GLFWdragfun)(GLFWwindow*, GLFWDragEventType event, double xpos, double ypos, const char** mime_types, int* mime_count);
|
||||
typedef int (* GLFWdropfun)(GLFWwindow*, const char *, const char*, size_t);
|
||||
|
||||
typedef void (* GLFWliveresizefun)(GLFWwindow*, bool);
|
||||
|
||||
@@ -1948,7 +1806,6 @@ typedef enum {
|
||||
typedef GLFWDataChunk (* GLFWclipboarditerfun)(const char *mime_type, void *iter, GLFWClipboardType ctype);
|
||||
typedef bool (* GLFWclipboardwritedatafun)(void *object, const char *data, size_t sz);
|
||||
typedef bool (* GLFWimecursorpositionfun)(GLFWwindow *window, GLFWIMEUpdateEvent *ev);
|
||||
typedef void (* GLFWclipboardlostfun )(GLFWClipboardType);
|
||||
|
||||
/*! @brief Video mode type.
|
||||
*
|
||||
@@ -2036,7 +1893,7 @@ typedef struct GLFWimage
|
||||
int height;
|
||||
/*! The pixel data of this image, arranged left-to-right, top-to-bottom.
|
||||
*/
|
||||
const unsigned char* pixels;
|
||||
unsigned char* pixels;
|
||||
} GLFWimage;
|
||||
|
||||
/*! @brief Gamepad input state
|
||||
@@ -2099,7 +1956,7 @@ typedef struct GLFWgamepadstate
|
||||
*
|
||||
* @ingroup init
|
||||
*/
|
||||
GLFWAPI int glfwInit(monotonic_t start_time, bool *supports_window_occlusion);
|
||||
GLFWAPI int glfwInit(monotonic_t start_time);
|
||||
GLFWAPI void glfwRunMainLoop(GLFWtickcallback callback, void *callback_data);
|
||||
GLFWAPI void glfwStopMainLoop(void);
|
||||
GLFWAPI unsigned long long glfwAddTimer(monotonic_t interval, bool repeats, GLFWuserdatafun callback, void * callback_data, GLFWuserdatafun free_callback);
|
||||
@@ -2109,7 +1966,6 @@ GLFWAPI GLFWdrawtextfun glfwSetDrawTextFunction(GLFWdrawtextfun function);
|
||||
GLFWAPI GLFWcurrentselectionfun glfwSetCurrentSelectionCallback(GLFWcurrentselectionfun callback);
|
||||
GLFWAPI GLFWhascurrentselectionfun glfwSetHasCurrentSelectionCallback(GLFWhascurrentselectionfun callback);
|
||||
GLFWAPI GLFWimecursorpositionfun glfwSetIMECursorPositionCallback(GLFWimecursorpositionfun callback);
|
||||
GLFWAPI bool glfwIsLayerShellSupported(void);
|
||||
|
||||
/*! @brief Terminates the GLFW library.
|
||||
*
|
||||
@@ -2512,7 +2368,6 @@ GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, flo
|
||||
* @ingroup monitor
|
||||
*/
|
||||
GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor);
|
||||
GLFWAPI const char* glfwGetMonitorDescription(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Sets the user pointer of the specified monitor.
|
||||
*
|
||||
@@ -3003,12 +2858,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
|
||||
*
|
||||
* @ingroup window
|
||||
*/
|
||||
GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share, const GLFWLayerShellConfig *lsc);
|
||||
GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share);
|
||||
GLFWAPI bool glfwToggleFullscreen(GLFWwindow *window, unsigned int flags);
|
||||
GLFWAPI bool glfwIsFullscreen(GLFWwindow *window, unsigned int flags);
|
||||
GLFWAPI bool glfwAreSwapsAllowed(const GLFWwindow* window);
|
||||
GLFWAPI const GLFWLayerShellConfig* glfwGetLayerShellConfig(GLFWwindow* handle);
|
||||
GLFWAPI bool glfwSetLayerShellConfig(GLFWwindow* handle, const GLFWLayerShellConfig *value);
|
||||
|
||||
/*! @brief Destroys the specified window and its context.
|
||||
*
|
||||
@@ -3139,6 +2992,10 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
|
||||
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
|
||||
* in the Mac Developer Library.
|
||||
*
|
||||
* @remark @wayland There is no existing protocol to change an icon, the
|
||||
* window will thus inherit the one defined in the application's desktop file.
|
||||
* This function will emit @ref GLFW_FEATURE_UNAVAILABLE.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref window_icon
|
||||
@@ -3705,7 +3562,7 @@ GLFWAPI void glfwMaximizeWindow(GLFWwindow* window);
|
||||
*
|
||||
* @ingroup window
|
||||
*/
|
||||
GLFWAPI void glfwShowWindow(GLFWwindow* window, bool move_to_active_screen);
|
||||
GLFWAPI void glfwShowWindow(GLFWwindow* window);
|
||||
|
||||
/*! @brief Hides the specified window.
|
||||
*
|
||||
@@ -4124,8 +3981,7 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind
|
||||
GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback);
|
||||
GLFWAPI GLFWapplicationclosefun glfwSetApplicationCloseCallback(GLFWapplicationclosefun callback);
|
||||
GLFWAPI GLFWsystemcolorthemechangefun glfwSetSystemColorThemeChangeCallback(GLFWsystemcolorthemechangefun callback);
|
||||
GLFWAPI GLFWclipboardlostfun glfwSetClipboardLostCallback(GLFWclipboardlostfun callback);
|
||||
GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(bool query_if_unintialized);
|
||||
GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void);
|
||||
|
||||
/*! @brief Sets the refresh callback for the specified window.
|
||||
*
|
||||
@@ -4373,8 +4229,6 @@ GLFWAPI void glfwPostEmptyEvent(void);
|
||||
|
||||
GLFWAPI bool glfwGetIgnoreOSKeyboardProcessing(void);
|
||||
GLFWAPI void glfwSetIgnoreOSKeyboardProcessing(bool enabled);
|
||||
GLFWAPI bool glfwGrabKeyboard(int grab);
|
||||
GLFWAPI void glfwGetKeyboardRepeatDelay(monotonic_t *delay, monotonic_t *interval);
|
||||
|
||||
/*! @brief Returns the value of an input option for the specified window.
|
||||
*
|
||||
@@ -4978,20 +4832,44 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu
|
||||
*/
|
||||
GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback);
|
||||
|
||||
/*! @brief Sets the path drop callback.
|
||||
*
|
||||
* This function sets the path drop callback of the specified window, which is
|
||||
* called when one or more dragged paths are dropped on the window.
|
||||
*
|
||||
* Because the path array and its strings may have been generated specifically
|
||||
* for that event, they are not guaranteed to be valid after the callback has
|
||||
* returned. If you wish to use them after the callback returns, you need to
|
||||
* make a deep copy.
|
||||
*
|
||||
* @param[in] window The window whose callback to set.
|
||||
* @param[in] callback The new file drop callback, or `NULL` to remove the
|
||||
* currently set callback.
|
||||
* @return The previously set callback, or `NULL` if no callback was set or the
|
||||
* library had not been [initialized](@ref intro_init).
|
||||
*
|
||||
* @callback_signature
|
||||
* @code
|
||||
* void function_name(GLFWwindow* window, int path_count, const char* paths[])
|
||||
* @endcode
|
||||
* For more information about the callback parameters, see the
|
||||
* [function pointer type](@ref GLFWdropfun).
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @remark @wayland File drop is currently unimplemented.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref path_drop
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback);
|
||||
GLFWAPI GLFWliveresizefun glfwSetLiveResizeCallback(GLFWwindow* window, GLFWliveresizefun callback);
|
||||
|
||||
GLFWAPI GLFWdropeventfun glfwSetDropEventCallback(GLFWwindow *window, GLFWdropeventfun callback);
|
||||
// ask for update before GLFW_DROP_DROP happens
|
||||
GLFWAPI void glfwRequestDropUpdate(GLFWwindow *window);
|
||||
GLFWAPI int glfwRequestDropData(GLFWwindow *window, const char *mime);
|
||||
GLFWAPI void glfwEndDrop(GLFWwindow *window, GLFWDragOperationType op);
|
||||
GLFWAPI GLFWdragsourcefun glfwSetDragSourceCallback(GLFWwindow* window, GLFWdragsourcefun callback);
|
||||
|
||||
// Start a drag. If called with operations == -1 indicates that previously
|
||||
// requested data via GLFW_DRAG_DATA_REQUEST is ready. operations == -2 means
|
||||
// that the drag image is changed. operations == -3 cancels any existing drag.
|
||||
GLFWAPI int glfwStartDrag(GLFWwindow* window, const GLFWDragSourceItem *items, size_t mime_count, const GLFWimage* thumbnail, int operations, bool needs_toplevel_on_wayland);
|
||||
|
||||
/*! @brief Returns whether the specified joystick is present.
|
||||
*
|
||||
* This function returns whether the specified joystick is present.
|
||||
|
||||
4
glfw/glx_context.c
vendored
4
glfw/glx_context.c
vendored
@@ -658,8 +658,6 @@ bool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig UNUSED,
|
||||
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
@@ -674,8 +672,6 @@ GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* handle)
|
||||
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(None);
|
||||
|
||||
if (window->context.client == GLFW_NO_API)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user